working version 2

This commit is contained in:
Harivansh Rathi 2024-11-17 21:12:21 -05:00
parent 33a5f26ec1
commit d412046627
4 changed files with 75 additions and 26 deletions

BIN
habits.db

Binary file not shown.

View file

@ -137,15 +137,21 @@ export default function HabitTracker() {
// Prevent negative streaks // Prevent negative streaks
if (newStreak < 0) return; if (newStreak < 0) return;
// Update in database try {
await db.habits.update(id, { manualStreak: newStreak }); // Update in database
await fetch(`http://localhost:5000/api/habits/${id}/streak`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ streak: newStreak }),
});
// Update state // Update state
setHabits(habits.map(habit => setHabits(habits.map(habit =>
habit.id === id habit.id === id ? { ...habit, manualStreak: newStreak } : habit
? { ...habit, manualStreak: newStreak } ));
: habit } catch (error) {
)); console.error('Error updating streak:', error);
}
}; };
return ( return (

View file

@ -9,35 +9,60 @@ interface HabitListProps {
onToggleHabit: (id: number, date: string) => void; onToggleHabit: (id: number, date: string) => void;
onUpdateHabit: (id: number, name: string) => void; onUpdateHabit: (id: number, name: string) => void;
onDeleteHabit: (id: number) => void; onDeleteHabit: (id: number) => void;
onUpdateStreak: (id: number, newStreak: number) => Promise<void>;
} }
const calculateStreak = (completedDates: string[]): number => { const calculateStreak = (completedDates: string[]): { currentStreak: number; bestStreak: number } => {
if (completedDates.length === 0) return 0; if (completedDates.length === 0) return { currentStreak: 0, bestStreak: 0 };
// Sort dates in ascending order
const sortedDates = [...completedDates].sort((a, b) => const sortedDates = [...completedDates].sort((a, b) =>
new Date(a).getTime() - new Date(b).getTime() new Date(a).getTime() - new Date(b).getTime()
); );
let currentStreak = 1; let currentStreak = 1;
let maxStreak = 1; let bestStreak = 1;
let tempStreak = 1;
// Go through the dates and count consecutive completions // Check if the last completion was today or yesterday
const lastDate = new Date(sortedDates[sortedDates.length - 1]);
const today = new Date();
today.setHours(0, 0, 0, 0);
lastDate.setHours(0, 0, 0, 0);
const diffDays = Math.floor((today.getTime() - lastDate.getTime()) / (24 * 60 * 60 * 1000));
// If the last completion was more than a day ago, current streak is 0
if (diffDays > 1) {
currentStreak = 0;
}
// Calculate streaks
for (let i = 1; i < sortedDates.length; i++) { for (let i = 1; i < sortedDates.length; i++) {
const prevDate = new Date(sortedDates[i - 1]); const prevDate = new Date(sortedDates[i - 1]);
const currDate = new Date(sortedDates[i]); const currDate = new Date(sortedDates[i]);
prevDate.setHours(0, 0, 0, 0);
currDate.setHours(0, 0, 0, 0);
// If dates are consecutive or same day, increment streak const diffTime = currDate.getTime() - prevDate.getTime();
if (currDate.getTime() - prevDate.getTime() <= 24 * 60 * 60 * 1000) { const diffDays = Math.floor(diffTime / (24 * 60 * 60 * 1000));
currentStreak++;
maxStreak = Math.max(maxStreak, currentStreak); if (diffDays === 1) {
tempStreak++;
bestStreak = Math.max(bestStreak, tempStreak);
} else if (diffDays === 0) {
// Same day completions don't affect streak
continue;
} else { } else {
// Reset streak counter when there's a gap tempStreak = 1;
currentStreak = 1;
} }
} }
return maxStreak; // Current streak should be the same as tempStreak if the last completion was today or yesterday
if (diffDays <= 1) {
currentStreak = tempStreak;
}
return { currentStreak, bestStreak };
}; };
export function HabitList({ export function HabitList({
@ -47,6 +72,7 @@ export function HabitList({
onToggleHabit, onToggleHabit,
onUpdateHabit, onUpdateHabit,
onDeleteHabit, onDeleteHabit,
onUpdateStreak,
}: HabitListProps) { }: HabitListProps) {
return ( return (
<table className="w-full"> <table className="w-full">
@ -61,11 +87,11 @@ export function HabitList({
</div> </div>
</th> </th>
))} ))}
<th className="px-4 py-2 text-center dark:text-white">
Current Streak
</th>
<th className="px-4 py-2 text-center dark:text-white"> <th className="px-4 py-2 text-center dark:text-white">
Best Streak Best Streak
<div className="text-xs text-gray-500 dark:text-gray-400">
consecutive completions
</div>
</th> </th>
<th className="px-4 py-2 text-center dark:text-white">Actions</th> <th className="px-4 py-2 text-center dark:text-white">Actions</th>
</tr> </tr>
@ -78,6 +104,8 @@ export function HabitList({
type="text" type="text"
value={habit.name} value={habit.name}
onChange={(e) => onUpdateHabit(habit.id, e.target.value)} onChange={(e) => onUpdateHabit(habit.id, e.target.value)}
aria-label="Habit name"
placeholder="Enter habit name"
className="bg-transparent border-none focus:outline-none focus:ring-2 focus:ring-gray-300 rounded px-2" className="bg-transparent border-none focus:outline-none focus:ring-2 focus:ring-gray-300 rounded px-2"
/> />
</td> </td>
@ -86,14 +114,28 @@ export function HabitList({
<input <input
type="checkbox" type="checkbox"
checked={habit.completedDates.includes(date)} checked={habit.completedDates.includes(date)}
onChange={() => onToggleHabit(habit.id, date)} onChange={() => {
onToggleHabit(habit.id, date);
const newCompletedDates = habit.completedDates.includes(date)
? habit.completedDates.filter(d => d !== date)
: [...habit.completedDates, date];
const { currentStreak, bestStreak } = calculateStreak(newCompletedDates);
onUpdateStreak(habit.id, bestStreak);
}}
aria-label={`Mark ${habit.name} as completed for ${date}`}
className="w-4 h-4 rounded border-gray-300 dark:border-gray-600" className="w-4 h-4 rounded border-gray-300 dark:border-gray-600"
/> />
</td> </td>
))} ))}
<td className="px-4 py-2 text-center"> <td className="px-4 py-2 text-center">
<span className="dark:text-white font-medium"> <span className="dark:text-white font-medium">
{calculateStreak(habit.completedDates)} {calculateStreak(habit.completedDates).currentStreak}
</span>
</td>
<td className="px-4 py-2 text-center">
<span className="dark:text-white font-medium">
{calculateStreak(habit.completedDates).bestStreak}
</span> </span>
</td> </td>
<td className="px-4 py-2 text-center"> <td className="px-4 py-2 text-center">
@ -109,4 +151,4 @@ export function HabitList({
</tbody> </tbody>
</table> </table>
); );
} }

View file

@ -2,4 +2,5 @@ export interface Habit {
id: number; id: number;
name: string; name: string;
completedDates: string[]; completedDates: string[];
bestStreak: number;
} }