From 1a298422f124ad4000cd363beba24de5568eef78 Mon Sep 17 00:00:00 2001 From: vedhapprakashni Date: Fri, 6 Feb 2026 21:33:49 +0530 Subject: [PATCH 1/5] feat(habits): add core habit tracking components --- frontend/src/components/CheckInModal.tsx | 167 ++++++++++++++++++ frontend/src/components/CreateHabitModal.tsx | 130 ++++++++++++++ .../src/components/DeleteConfirmModal.tsx | 64 +++++++ frontend/src/components/EditHabitModal.tsx | 139 +++++++++++++++ frontend/src/components/HabitCard.tsx | 85 +++++++++ frontend/src/index.css | 109 ++++++++++++ 6 files changed, 694 insertions(+) create mode 100644 frontend/src/components/CheckInModal.tsx create mode 100644 frontend/src/components/CreateHabitModal.tsx create mode 100644 frontend/src/components/DeleteConfirmModal.tsx create mode 100644 frontend/src/components/EditHabitModal.tsx create mode 100644 frontend/src/components/HabitCard.tsx diff --git a/frontend/src/components/CheckInModal.tsx b/frontend/src/components/CheckInModal.tsx new file mode 100644 index 0000000..9ffb3f6 --- /dev/null +++ b/frontend/src/components/CheckInModal.tsx @@ -0,0 +1,167 @@ +import React, { useState, useEffect } from 'react'; + +interface CheckInModalProps { + isOpen: boolean; + habit: { + id: string; + name: string; + } | null; + currentStreak: number; + onClose: () => void; + onCheckIn: (habitId: string, notes?: string) => Promise; +} + +const MILESTONES = [7, 30, 100]; + +export default function CheckInModal({ + isOpen, + habit, + currentStreak, + onClose, + onCheckIn +}: CheckInModalProps) { + const [notes, setNotes] = useState(''); + const [loading, setLoading] = useState(false); + const [success, setSuccess] = useState(false); + const [showConfetti, setShowConfetti] = useState(false); + const [milestone, setMilestone] = useState(null); + + useEffect(() => { + if (!isOpen) { + // Reset state when modal closes + setNotes(''); + setSuccess(false); + setShowConfetti(false); + setMilestone(null); + } + }, [isOpen]); + + if (!isOpen || !habit) return null; + + async function handleCheckIn() { + setLoading(true); + + try { + await onCheckIn(habit.id, notes.trim() || undefined); + setSuccess(true); + + // Check for milestone + const newStreak = currentStreak + 1; + if (MILESTONES.includes(newStreak)) { + setMilestone(newStreak); + setShowConfetti(true); + } + + // Auto-close after delay + setTimeout(() => { + onClose(); + }, showConfetti ? 3000 : 1500); + } catch (err) { + console.error('Check-in failed:', err); + } finally { + setLoading(false); + } + } + + return ( +
+
e.stopPropagation()}> + {success ? ( +
+ {showConfetti && ( +
+ {[...Array(50)].map((_, i) => ( +
+ ))} +
+ )} + +
🎉
+ + {milestone ? ( + <> +

+ 🏆 {milestone} Day Streak! +

+

+ Amazing! You've completed {habit.name} for {milestone} days in a row! +

+ + ) : ( + <> +

+ Great job! +

+

+ You completed {habit.name} today! +

+
+ 🔥 + {currentStreak + 1} + day streak +
+ + )} +
+ ) : ( + <> +
+

Check In

+ +
+ +
+
+

{habit.name}

+

Current streak: {currentStreak} days

+
+ +
+ +