From ec0d83586d355f04f168ba82818e5c3974c18ac2 Mon Sep 17 00:00:00 2001 From: Avery Felts Date: Sat, 24 Jan 2026 01:45:59 -0700 Subject: [PATCH] Add QuitPlanCard with 7-day tracking and personalized quit plan - Restore QuitPlanCard component under calendar on dashboard - Yellow gradient during tracking phase (before 7 days of data) - Pink gradient when quit plan is active - Track unique days with logged data for countdown - Generate 4-week plan with 25% weekly reduction - White text throughout for readability Co-Authored-By: Claude Opus 4.5 --- src/components/Dashboard.tsx | 21 ++++++ src/components/QuitPlanCard.tsx | 115 ++++++++++++++++++++------------ src/lib/storage.ts | 10 +-- 3 files changed, 97 insertions(+), 49 deletions(-) diff --git a/src/components/Dashboard.tsx b/src/components/Dashboard.tsx index b3a8c62..f93449c 100644 --- a/src/components/Dashboard.tsx +++ b/src/components/Dashboard.tsx @@ -8,6 +8,7 @@ import { savePreferencesAsync, saveUsageEntryAsync, shouldShowUsagePrompt, + generateQuitPlan, UserPreferences, UsageEntry, } from '@/lib/storage'; @@ -16,6 +17,7 @@ import { SetupWizard } from './SetupWizard'; import { UsagePromptDialog } from './UsagePromptDialog'; import { UsageCalendar } from './UsageCalendar'; import { StatsCard } from './StatsCard'; +import { QuitPlanCard } from './QuitPlanCard'; import { Button } from '@/components/ui/button'; import { PlusCircle } from 'lucide-react'; @@ -98,6 +100,19 @@ export function Dashboard({ user }: DashboardProps) { setRefreshKey(prev => prev + 1); }; + const handleGeneratePlan = async () => { + if (!preferences) return; + + const plan = generateQuitPlan(preferences.substance); + const updatedPrefs = { + ...preferences, + quitPlan: plan, + }; + await savePreferencesAsync(updatedPrefs); + setPreferences(updatedPrefs); + setRefreshKey(prev => prev + 1); + }; + if (isLoading) { return (
@@ -133,6 +148,12 @@ export function Dashboard({ user }: DashboardProps) { onDataUpdate={loadData} userId={user.id} /> +
diff --git a/src/components/QuitPlanCard.tsx b/src/components/QuitPlanCard.tsx index ea2ec76..0cb31a6 100644 --- a/src/components/QuitPlanCard.tsx +++ b/src/components/QuitPlanCard.tsx @@ -2,62 +2,82 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; -import { QuitPlan, getCurrentWeekTarget } from '@/lib/storage'; +import { QuitPlan, UsageEntry } from '@/lib/storage'; +import { Target, TrendingDown } from 'lucide-react'; interface QuitPlanCardProps { plan: QuitPlan | null; onGeneratePlan: () => void; - hasEnoughData: boolean; - daysTracked: number; - currentAverage: number; + usageData: UsageEntry[]; } export function QuitPlanCard({ plan, onGeneratePlan, - hasEnoughData, - daysTracked, - currentAverage, + usageData, }: QuitPlanCardProps) { - const currentTarget = getCurrentWeekTarget(); + // Count unique days with any logged data + const uniqueDaysWithData = new Set(usageData.map(e => e.date)).size; + const daysRemaining = Math.max(0, 7 - uniqueDaysWithData); + const hasEnoughData = uniqueDaysWithData >= 7; + + // Calculate current average + const totalUsage = usageData.reduce((sum, e) => sum + e.count, 0); + const currentAverage = uniqueDaysWithData > 0 ? Math.round(totalUsage / uniqueDaysWithData) : 0; if (!plan) { return ( - + - Your Quit Plan - - Track your usage for 7 days to receive a personalized quit plan + + + Your Personalized Plan + + + We're tracking your usage to build your custom quit plan -
-
- Tracking Progress - {daysTracked}/7 days +
+
+ Tracking Progress + + {daysRemaining > 0 ? `${daysRemaining} days left` : 'Ready!'} +
-
+
+

+ {uniqueDaysWithData} of 7 days tracked +

{hasEnoughData ? (
-

- You've tracked for a week. Your average daily usage is{' '} - {currentAverage} times per day. +

+ Great work! Your average daily usage is{' '} + {currentAverage} per day.

-
) : ( -

- Keep tracking! We need at least 7 days of data to create your personalized plan. -

+
+

+ Log your usage each day. After 7 days, we'll create a personalized plan to help you reduce by 25% each week. +

+

+ Your plan will be tailored to your habits +

+
)} @@ -70,50 +90,57 @@ export function QuitPlanCard({ (today.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24 * 7) ) + 1; const totalWeeks = plan.weeklyTargets.length; + const currentTarget = weekNumber <= totalWeeks ? plan.weeklyTargets[weekNumber - 1] : 0; return ( - + - Your Quit Plan - - Week {Math.min(weekNumber, totalWeeks)} of {totalWeeks} + + + Your Quit Plan + + + Week {Math.min(weekNumber, totalWeeks)} of {totalWeeks} - 25% weekly reduction -
-

This week's target

-

- {currentTarget !== null ? `${currentTarget} per day` : 'Complete!'} +

+

This week's daily target

+

+ {currentTarget !== null && currentTarget > 0 ? currentTarget : '0'}

+

per day

-

Weekly reduction plan:

-
+

Weekly targets:

+
{plan.weeklyTargets.map((target, index) => (
-

W{index + 1}

+

Week {index + 1}

{target}

))}
-
+

- Baseline: {plan.baselineAverage} uses/day + Started at: {plan.baselineAverage}/day

- End date: {new Date(plan.endDate).toLocaleDateString()} + Goal: Quit by {new Date(plan.endDate).toLocaleDateString()}

diff --git a/src/lib/storage.ts b/src/lib/storage.ts index b250ded..4f43193 100644 --- a/src/lib/storage.ts +++ b/src/lib/storage.ts @@ -231,15 +231,15 @@ export function generateQuitPlan(substance: 'nicotine' | 'weed', _userId?: strin const today = new Date(); const startDate = today.toISOString().split('T')[0]; - // 6-week reduction plan + // 4-week reduction plan with 25% weekly reduction const endDate = new Date(today); - endDate.setDate(endDate.getDate() + 42); + endDate.setDate(endDate.getDate() + 28); - // Gradual reduction: each week reduce by ~15-20% + // Gradual reduction: each week reduce by 25% const weeklyTargets: number[] = []; let current = baseline; - for (let i = 0; i < 6; i++) { - current = Math.max(0, Math.round(current * 0.8)); + for (let i = 0; i < 4; i++) { + current = Math.max(0, Math.round(current * 0.75)); weeklyTargets.push(current); }