From 6783ff77b8721213d188cec03e41ed8af763cb11 Mon Sep 17 00:00:00 2001 From: Andrew Shiroma Date: Sun, 23 Mar 2025 18:47:48 -0700 Subject: [PATCH 01/12] feat: create updateStreakStart function handles streakDays update when user manually sets their streak start date --- src/pages/Dashboard.tsx | 2 +- src/utils/firebase.ts | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index 2b9f4fb..2059958 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect } from 'react'; import { Link } from 'react-router-dom'; import { useAuth } from '../utils/auth'; -import { updateStreak, getUserProfile } from '../utils/firebase'; +import { updateStreak, getUserProfile, updateStreakStart } from '../utils/firebase'; import { cn } from '@/lib/utils'; import { ArrowRight, diff --git a/src/utils/firebase.ts b/src/utils/firebase.ts index e1183a9..3db02ee 100644 --- a/src/utils/firebase.ts +++ b/src/utils/firebase.ts @@ -93,6 +93,7 @@ export const register = async (email: string, password: string, username: string role: 'member', // Default role joinedAt: Timestamp.now(), streakDays: 0, + streakStart: Timestamp.now(), lastCheckIn: Timestamp.now() }); @@ -247,6 +248,32 @@ export const updateStreak = async (userId: string) => { } }; +export const updateStreakStart = async (userId: string, startDate: Date) => { + try { + const userRef = doc(db, 'users', userId); + const userDoc = await getDoc(userRef); + + if (userDoc.exists()) { + const userData = userDoc.data(); + const lastCheckIn = userData.lastCheckIn?.toDate() || new Date(0); + + const diffInMilliseconds = startDate.getTime() - lastCheckIn.getTime(); + const diffInDays = Math.floor(diffInMilliseconds / (1000 * 60 * 60 * 24)); + + await updateDoc(userRef, { + streakDays: diffInDays > 0 ? diffInDays : 0, // Ensure streakDays is not negative + }); + + return { success: true, diffInDays, message: 'Streak start updated successfully' }; + } + + return { success: false, message: 'User not found' }; + } catch (error) { + console.error('Error setting streak:', error); + return { success: false, message: error.message }; + } +}; + // Log relapse with multiple triggers (used for analytics) export const logRelapse = async (userId: string, triggers: string[], notes?: string) => { try { From ecedf04e65209c8981672d73e551ec14da4ae5fa Mon Sep 17 00:00:00 2001 From: Andrew Shiroma Date: Sun, 23 Mar 2025 18:48:37 -0700 Subject: [PATCH 02/12] feat: create handleStreakSet function to call updateStreakStart function in firebase --- src/pages/Dashboard.tsx | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index 2059958..3221142 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -109,6 +109,33 @@ const Dashboard: React.FC = () => { } }; + const handleStreakSet = async (startDate: Date) => { + if (!currentUser) return; + + try { + const result = await updateStreakStart(currentUser.uid, startDate); + + if (result.success) { + // Refresh user data + const updatedProfile = await getUserProfile(currentUser.uid); + + if (updatedProfile) { + setStreak(updatedProfile.streakDays || 0); + } + + if (result.message === 'Streak start updated successfully') { + toast.success("Streak start updated!", { + description: `Your streak has been reset to start from ${formatDate(startDate)}.`, + }); + } + } + } catch (error) { + console.error('Error updating streak:', error); + toast.error("Failed to set streak start date", { + description: "Please try again later.", + }); + } + }; return ( From 0efdfa2948a08a380e137e00653cadc7708543db Mon Sep 17 00:00:00 2001 From: Andrew Shiroma Date: Thu, 20 Mar 2025 21:31:51 -0700 Subject: [PATCH 03/12] fix: verseslideshow animation renders properly and remove multiple cards --- src/components/VerseSlide.tsx | 20 ++------------------ src/components/VerseSlideshow.tsx | 3 ++- src/pages/Dashboard.tsx | 3 --- 3 files changed, 4 insertions(+), 22 deletions(-) diff --git a/src/components/VerseSlide.tsx b/src/components/VerseSlide.tsx index cad23dd..0d7a753 100644 --- a/src/components/VerseSlide.tsx +++ b/src/components/VerseSlide.tsx @@ -16,24 +16,8 @@ const VerseSlide: React.FC = ({ }) => { return (
- - - {verseReference} - - {/* - */} - -
{verseText}
-
- {/*
-
*/} -
+
{verseReference}
+
{verseText}
); }; diff --git a/src/components/VerseSlideshow.tsx b/src/components/VerseSlideshow.tsx index 3f8624a..b141611 100644 --- a/src/components/VerseSlideshow.tsx +++ b/src/components/VerseSlideshow.tsx @@ -29,7 +29,7 @@ const VerseSlideshow: React.FC = ({ className }) => { return (
- + {Object.entries(verseReferences).map( ([reference, text], index) => index === currentIndex && ( @@ -38,6 +38,7 @@ const VerseSlideshow: React.FC = ({ className }) => { initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} + transition={{ duration: 0.5, ease: "easeInOut" }} > diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index f7159c0..2b9f4fb 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -307,10 +307,7 @@ const Dashboard: React.FC = () => {

Daily Inspiration

-
"-- QUOTE HERE --" -
-

Scripture Quote

); From 2afed6fee27f653e1be14f7729ce87d36f89e14c Mon Sep 17 00:00:00 2001 From: Andrew Shiroma Date: Fri, 21 Mar 2025 09:00:01 -0700 Subject: [PATCH 04/12] refactor: remove unneeded imports to VerseSlide --- src/components/VerseSlide.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/VerseSlide.tsx b/src/components/VerseSlide.tsx index 0d7a753..2378eb3 100644 --- a/src/components/VerseSlide.tsx +++ b/src/components/VerseSlide.tsx @@ -1,7 +1,5 @@ import React from "react"; import { cn } from "@/lib/utils"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { motion, AnimatePresence } from "framer-motion"; interface VerseSlideProps { className?: string; From 754a978c355b069a3a6305df9fab1bc379b8e403 Mon Sep 17 00:00:00 2001 From: Andrew Shiroma Date: Sun, 23 Mar 2025 18:47:48 -0700 Subject: [PATCH 05/12] feat: create updateStreakStart function handles streakDays update when user manually sets their streak start date --- src/pages/Dashboard.tsx | 2 +- src/utils/firebase.ts | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index 2b9f4fb..2059958 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect } from 'react'; import { Link } from 'react-router-dom'; import { useAuth } from '../utils/auth'; -import { updateStreak, getUserProfile } from '../utils/firebase'; +import { updateStreak, getUserProfile, updateStreakStart } from '../utils/firebase'; import { cn } from '@/lib/utils'; import { ArrowRight, diff --git a/src/utils/firebase.ts b/src/utils/firebase.ts index 5a37ef6..181e666 100644 --- a/src/utils/firebase.ts +++ b/src/utils/firebase.ts @@ -154,6 +154,7 @@ export const register = async (email: string, password: string, username: string role: 'member', // Default role joinedAt: Timestamp.now(), streakDays: 0, + streakStart: Timestamp.now(), lastCheckIn: Timestamp.now() }); @@ -308,6 +309,32 @@ export const updateStreak = async (userId: string) => { } }; +export const updateStreakStart = async (userId: string, startDate: Date) => { + try { + const userRef = doc(db, 'users', userId); + const userDoc = await getDoc(userRef); + + if (userDoc.exists()) { + const userData = userDoc.data(); + const lastCheckIn = userData.lastCheckIn?.toDate() || new Date(0); + + const diffInMilliseconds = startDate.getTime() - lastCheckIn.getTime(); + const diffInDays = Math.floor(diffInMilliseconds / (1000 * 60 * 60 * 24)); + + await updateDoc(userRef, { + streakDays: diffInDays > 0 ? diffInDays : 0, // Ensure streakDays is not negative + }); + + return { success: true, diffInDays, message: 'Streak start updated successfully' }; + } + + return { success: false, message: 'User not found' }; + } catch (error) { + console.error('Error setting streak:', error); + return { success: false, message: error.message }; + } +}; + // Log relapse with multiple triggers (used for analytics) export const logRelapse = async (userId: string, triggers: string[], notes?: string) => { try { From 60649358640d8e90f8993a00332096beca8f9a3b Mon Sep 17 00:00:00 2001 From: Andrew Shiroma Date: Sun, 23 Mar 2025 18:48:37 -0700 Subject: [PATCH 06/12] feat: create handleStreakSet function to call updateStreakStart function in firebase --- src/pages/Dashboard.tsx | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index 2059958..3221142 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -109,6 +109,33 @@ const Dashboard: React.FC = () => { } }; + const handleStreakSet = async (startDate: Date) => { + if (!currentUser) return; + + try { + const result = await updateStreakStart(currentUser.uid, startDate); + + if (result.success) { + // Refresh user data + const updatedProfile = await getUserProfile(currentUser.uid); + + if (updatedProfile) { + setStreak(updatedProfile.streakDays || 0); + } + + if (result.message === 'Streak start updated successfully') { + toast.success("Streak start updated!", { + description: `Your streak has been reset to start from ${formatDate(startDate)}.`, + }); + } + } + } catch (error) { + console.error('Error updating streak:', error); + toast.error("Failed to set streak start date", { + description: "Please try again later.", + }); + } + }; return ( From 2ea10ef267bd6115465379afba16f92b992c8513 Mon Sep 17 00:00:00 2001 From: Andrew Shiroma Date: Mon, 24 Mar 2025 16:58:39 -0700 Subject: [PATCH 07/12] feat: handling for date selection --- src/pages/Dashboard.tsx | 126 ++++++++++++++++++++++++++++------------ 1 file changed, 90 insertions(+), 36 deletions(-) diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index 3221142..f2eca9a 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -10,7 +10,9 @@ import { TrendingUp, MessageCircle, Map, - HeartPulse + HeartPulse, + ArrowDown, + ArrowUp } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'; @@ -21,6 +23,7 @@ import CommunityMap from '@/components/CommunityMap'; import { motion } from 'framer-motion'; import { toast } from 'sonner'; import VerseSlideshow from '@/components/VerseSlideshow'; +import DatePicker from '@/components/ui/date-picker'; const formatDate = (date: Date) => { return new Intl.DateTimeFormat('en-US', { @@ -35,6 +38,8 @@ const Dashboard: React.FC = () => { const [streak, setStreak] = useState(0); const [lastCheckIn, setLastCheckIn] = useState(null); const [isCheckedInToday, setIsCheckedInToday] = useState(false); + const [isCheckInSide, setIsCheckInSide] = useState(true); + const [selectedDate, setSelectedDate] = useState(new Date()); // Simulate featured meditations const featuredMeditations = [ @@ -77,9 +82,10 @@ const Dashboard: React.FC = () => { const handleCheckIn = async () => { if (!currentUser) return; - + console.log(currentUser.uid) try { const result = await updateStreak(currentUser.uid); + console.log(result) if (result.success) { // Refresh user data @@ -109,11 +115,11 @@ const Dashboard: React.FC = () => { } }; - const handleStreakSet = async (startDate: Date) => { + const handleStreakSet = async () => { if (!currentUser) return; try { - const result = await updateStreakStart(currentUser.uid, startDate); + const result = await updateStreakStart(currentUser.uid, selectedDate); if (result.success) { // Refresh user data @@ -125,7 +131,7 @@ const Dashboard: React.FC = () => { if (result.message === 'Streak start updated successfully') { toast.success("Streak start updated!", { - description: `Your streak has been reset to start from ${formatDate(startDate)}.`, + description: `Your streak has been reset to start from ${formatDate(selectedDate)}.`, }); } } @@ -134,6 +140,8 @@ const Dashboard: React.FC = () => { toast.error("Failed to set streak start date", { description: "Please try again later.", }); + } finally { + setIsCheckInSide(true); } }; @@ -175,40 +183,86 @@ const Dashboard: React.FC = () => { "border-primary/20 h-full", streak > 0 && "bg-gradient-to-br from-primary/10 to-transparent" )}> - - - - Your Current Streak - - - {isCheckedInToday - ? 'You\'ve checked in today. Great job!' - : 'Remember to check in daily to maintain your streak'} - - - -
-
-
- {streak} + {/* Current Streak Card - Check In Side */} + {isCheckInSide ? ( +
+ + + + Your Current Streak + + + {isCheckedInToday + ? 'You\'ve checked in today. Great job!' + : 'Remember to check in daily to maintain your streak'} + + + +
+
+
+ {streak} +
+
+ consecutive {streak === 1 ? 'day' : 'days'} +
+
-
- consecutive {streak === 1 ? 'day' : 'days'} + + + + + +
+ ) : ( + // Current Streak Card - Set Streak Start Date Side +
+ + + + Set Your Streak + + + Change Your Streak Start Date + + + +
+ {/* calculate the streak start date to display in DatePicker */} +
-
+
+ + + +
- - - - + )} From 52614c944bf2b7faa618bc2a9774ba67425a452f Mon Sep 17 00:00:00 2001 From: Andrew Shiroma Date: Mon, 24 Mar 2025 16:58:51 -0700 Subject: [PATCH 08/12] feat: create date-picker ui --- src/components/ui/date-picker.tsx | 120 ++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 src/components/ui/date-picker.tsx diff --git a/src/components/ui/date-picker.tsx b/src/components/ui/date-picker.tsx new file mode 100644 index 0000000..8893e7f --- /dev/null +++ b/src/components/ui/date-picker.tsx @@ -0,0 +1,120 @@ +import * as React from "react"; +import { ChevronLeft, ChevronRight } from "lucide-react"; + +import { cn } from "@/lib/utils"; + +interface DatePickerProps extends React.HTMLAttributes { + preselectedDate?: Date; + onDateChange?: (date: Date) => void; +} + +const DatePicker = React.forwardRef( + ({ className, preselectedDate, onDateChange, ...props }, ref) => { + const [currentDate, setCurrentDate] = React.useState(new Date()); + const [selectedDate, setSelectedDate] = React.useState(preselectedDate || new Date()); + + const daysInMonth = (month: number, year: number) => { + return new Date(year, month + 1, 0).getDate(); + }; + + const startDayOfMonth = (month: number, year: number) => { + return new Date(year, month, 1).getDay(); + }; + + const handlePrevMonth = () => { + setCurrentDate( + new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1) + ); + }; + + const handleNextMonth = () => { + setCurrentDate( + new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1) + ); + }; + + const handleDateClick = (day: number) => { + const newDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), day); + setSelectedDate(newDate); + if (onDateChange) { + onDateChange(newDate); + } + }; + + const renderDays = () => { + const days = []; + const daysInCurrentMonth = daysInMonth( + currentDate.getMonth(), + currentDate.getFullYear() + ); + const startDay = startDayOfMonth( + currentDate.getMonth(), + currentDate.getFullYear() + ); + + for (let i = 0; i < startDay; i++) { + days.push(
); + } + + for (let day = 1; day <= daysInCurrentMonth; day++) { + days.push( +
handleDateClick(day)} + > + {day} +
+ ); + } + + return days; + }; + + return ( +
+
+ + + {currentDate.toLocaleString("default", { month: "long" })}{" "} + {currentDate.getFullYear()} + + +
+
+ {["S", "M", "T", "W", "T", "F", "S"].map((date, index) => ( +
+ {date} +
+ ))} + {renderDays()} +
+
+ ); + } +); + +DatePicker.displayName = "DatePicker"; + +export default DatePicker; From 785cb0bef97991d0de8e6e4a332bcd181a68f5a8 Mon Sep 17 00:00:00 2001 From: Andrew Shiroma Date: Mon, 24 Mar 2025 17:23:46 -0700 Subject: [PATCH 09/12] feat: add fade animation to streak card flip --- src/components/ui/date-picker.tsx | 55 +++++++++++++++++++++++-------- src/pages/Dashboard.tsx | 25 +++++++++----- 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/src/components/ui/date-picker.tsx b/src/components/ui/date-picker.tsx index 8893e7f..8b37e59 100644 --- a/src/components/ui/date-picker.tsx +++ b/src/components/ui/date-picker.tsx @@ -1,5 +1,6 @@ import * as React from "react"; import { ChevronLeft, ChevronRight } from "lucide-react"; +import { motion } from "framer-motion"; import { cn } from "@/lib/utils"; @@ -58,7 +59,10 @@ const DatePicker = React.forwardRef( for (let day = 1; day <= daysInCurrentMonth; day++) { days.push( -
( onClick={() => handleDateClick(day)} > {day} -
+ ); } @@ -89,24 +93,47 @@ const DatePicker = React.forwardRef( {...props} >
- - + + + + {currentDate.toLocaleString("default", { month: "long" })}{" "} {currentDate.getFullYear()} - - + + + +
{["S", "M", "T", "W", "T", "F", "S"].map((date, index) => ( -
+ {date} -
+ ))} {renderDays()}
diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index f2eca9a..bc7af0f 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -11,8 +11,7 @@ import { MessageCircle, Map, HeartPulse, - ArrowDown, - ArrowUp + CheckIcon } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'; @@ -185,7 +184,12 @@ const Dashboard: React.FC = () => { )}> {/* Current Streak Card - Check In Side */} {isCheckInSide ? ( -
+ @@ -227,10 +231,15 @@ const Dashboard: React.FC = () => { Edit Streak Start Date -
+ ) : ( // Current Streak Card - Set Streak Start Date Side -
+ @@ -241,7 +250,7 @@ const Dashboard: React.FC = () => { -
+
{/* calculate the streak start date to display in DatePicker */}
@@ -251,7 +260,7 @@ const Dashboard: React.FC = () => { onClick={handleStreakSet} className="w-full" > - Set Streak Start Date + Set Streak Start Date -
+
)} From 3dece5793dc96a558ef4ee985d32375684e7634d Mon Sep 17 00:00:00 2001 From: Andrew Shiroma Date: Mon, 24 Mar 2025 17:38:09 -0700 Subject: [PATCH 10/12] feat: add highlights to current date --- src/components/ui/date-picker.tsx | 5 +++++ src/pages/Dashboard.tsx | 7 +++++++ src/utils/firebase.ts | 8 ++++++-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/components/ui/date-picker.tsx b/src/components/ui/date-picker.tsx index 8b37e59..50fb74f 100644 --- a/src/components/ui/date-picker.tsx +++ b/src/components/ui/date-picker.tsx @@ -71,6 +71,11 @@ const DatePicker = React.forwardRef( selectedDate?.getDate() === day && selectedDate?.getMonth() === currentDate.getMonth() && selectedDate?.getFullYear() === currentDate.getFullYear(), + }, { + "hover:border-0 bg-primary/20": + new Date().getDate() === day && + new Date().getMonth() === currentDate.getMonth() && + new Date().getFullYear() === currentDate.getFullYear() } )} onClick={() => handleDateClick(day)} diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index bc7af0f..44b69c6 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -134,6 +134,13 @@ const Dashboard: React.FC = () => { }); } } + + if (!result.success && result.message === 'Invalid Date') { + toast.error("Invalid date selected", { + description: "Please select a valid date to start your streak.", + }); + } + } catch (error) { console.error('Error updating streak:', error); toast.error("Failed to set streak start date", { diff --git a/src/utils/firebase.ts b/src/utils/firebase.ts index 181e666..ce30e9a 100644 --- a/src/utils/firebase.ts +++ b/src/utils/firebase.ts @@ -318,14 +318,18 @@ export const updateStreakStart = async (userId: string, startDate: Date) => { const userData = userDoc.data(); const lastCheckIn = userData.lastCheckIn?.toDate() || new Date(0); - const diffInMilliseconds = startDate.getTime() - lastCheckIn.getTime(); + const diffInMilliseconds = lastCheckIn.getTime() - startDate.getTime(); const diffInDays = Math.floor(diffInMilliseconds / (1000 * 60 * 60 * 24)); + if (diffInDays < 0) { + return { success: false, message: 'Invalid Date' }; + } + await updateDoc(userRef, { streakDays: diffInDays > 0 ? diffInDays : 0, // Ensure streakDays is not negative }); - return { success: true, diffInDays, message: 'Streak start updated successfully' }; + return { success: true, message: 'Streak start updated successfully' }; } return { success: false, message: 'User not found' }; From 04badde02c1d5b56beee4a1e005caf2f2a1497b2 Mon Sep 17 00:00:00 2001 From: Andrew Shiroma Date: Mon, 24 Mar 2025 17:39:26 -0700 Subject: [PATCH 11/12] fix: add streakStart to updateDoc --- src/utils/firebase.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/firebase.ts b/src/utils/firebase.ts index ce30e9a..de0129e 100644 --- a/src/utils/firebase.ts +++ b/src/utils/firebase.ts @@ -327,6 +327,7 @@ export const updateStreakStart = async (userId: string, startDate: Date) => { await updateDoc(userRef, { streakDays: diffInDays > 0 ? diffInDays : 0, // Ensure streakDays is not negative + streakStart: Timestamp.fromDate(startDate) }); return { success: true, message: 'Streak start updated successfully' }; From 0193b58d00975393e2d1e830b93240bc958a5923 Mon Sep 17 00:00:00 2001 From: Andrew Shiroma Date: Mon, 24 Mar 2025 17:47:27 -0700 Subject: [PATCH 12/12] fix: firestore streakStart is now streakStartDate --- src/utils/firebase.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/firebase.ts b/src/utils/firebase.ts index de0129e..b54ab76 100644 --- a/src/utils/firebase.ts +++ b/src/utils/firebase.ts @@ -154,7 +154,7 @@ export const register = async (email: string, password: string, username: string role: 'member', // Default role joinedAt: Timestamp.now(), streakDays: 0, - streakStart: Timestamp.now(), + streakStartDate: Timestamp.now(), lastCheckIn: Timestamp.now() }); @@ -327,7 +327,7 @@ export const updateStreakStart = async (userId: string, startDate: Date) => { await updateDoc(userRef, { streakDays: diffInDays > 0 ? diffInDays : 0, // Ensure streakDays is not negative - streakStart: Timestamp.fromDate(startDate) + streakStartDate: Timestamp.fromDate(startDate) }); return { success: true, message: 'Streak start updated successfully' };