From 9918432686bbb725289789515cf231e4374cf0e1 Mon Sep 17 00:00:00 2001 From: Avery Felts Date: Fri, 23 Jan 2026 21:40:59 -0700 Subject: [PATCH] Update UI and add user personalization features - Rename app from QuitTrack to QuitTraq - Add metallic dark gradient background - Change header to light purple gradient - Add name and age collection in setup wizard - Display personalized "Welcome {name}, you got this!" message - Hide username/email, show only profile picture - Change calendar to red gradient for usage days - Update logging prompt to "just took" instead of daily total - Add floating "Log Puff" button for easy access - Fix calendar editing to properly update values - Add glass-morphism effect to cards Co-Authored-By: Claude Opus 4.5 --- src/app/globals.css | 25 ++++- src/app/layout.tsx | 2 +- src/app/login/page.tsx | 4 +- src/components/Dashboard.tsx | 68 ++++++++----- src/components/QuitPlanCard.tsx | 4 +- src/components/SetupWizard.tsx | 138 +++++++++++++++++++++------ src/components/StatsCard.tsx | 2 +- src/components/UsageCalendar.tsx | 79 +++++++++------ src/components/UsagePromptDialog.tsx | 85 +++++++++-------- src/components/UserHeader.tsx | 51 +++++++--- src/lib/storage.ts | 11 ++- 11 files changed, 319 insertions(+), 150 deletions(-) diff --git a/src/app/globals.css b/src/app/globals.css index ebe8555..e2828f4 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -170,8 +170,31 @@ @apply border-border outline-ring/50; } body { - @apply bg-background text-foreground; + @apply text-foreground; font-family: var(--font-sans); letter-spacing: var(--tracking-normal); + background: linear-gradient(135deg, + #1a1a2e 0%, + #16213e 25%, + #1a1a2e 50%, + #0f0f1a 75%, + #1a1a2e 100%); + background-attachment: fixed; + min-height: 100vh; + } + + body::before { + content: ''; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: + radial-gradient(ellipse at 20% 20%, rgba(120, 119, 198, 0.15) 0%, transparent 50%), + radial-gradient(ellipse at 80% 80%, rgba(74, 85, 104, 0.2) 0%, transparent 50%), + radial-gradient(ellipse at 40% 60%, rgba(45, 55, 72, 0.15) 0%, transparent 40%); + pointer-events: none; + z-index: -1; } } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index a322b3a..0439016 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -2,7 +2,7 @@ import type { Metadata } from "next"; import "./globals.css"; export const metadata: Metadata = { - title: "QuitTrack - Track Your Journey to Quit Smoking", + title: "QuitTraq - Track Your Journey to Quit Smoking", description: "Track and manage your smoking habits, set goals, and quit safely with personalized plans.", }; diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index 2903dd0..27469a3 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -15,9 +15,9 @@ export default function LoginPage() { return (
- + - QuitTrack + QuitTraq Track your journey to a smoke-free life diff --git a/src/components/Dashboard.tsx b/src/components/Dashboard.tsx index d23544c..e311981 100644 --- a/src/components/Dashboard.tsx +++ b/src/components/Dashboard.tsx @@ -8,7 +8,6 @@ import { savePreferences, saveUsageEntry, shouldShowUsagePrompt, - setLastPromptDate, hasOneWeekOfData, calculateWeeklyAverage, generateQuitPlan, @@ -21,6 +20,8 @@ import { UsagePromptDialog } from './UsagePromptDialog'; import { UsageCalendar } from './UsageCalendar'; import { QuitPlanCard } from './QuitPlanCard'; import { StatsCard } from './StatsCard'; +import { Button } from '@/components/ui/button'; +import { PlusCircle } from 'lucide-react'; interface DashboardProps { user: User; @@ -53,14 +54,16 @@ export function Dashboard({ user }: DashboardProps) { setIsLoading(false); }, []); - const handleSetupComplete = (substance: 'nicotine' | 'weed') => { + const handleSetupComplete = (data: { substance: 'nicotine' | 'weed'; name: string; age: number }) => { const today = new Date().toISOString().split('T')[0]; const newPrefs: UserPreferences = { - substance, + substance: data.substance, trackingStartDate: today, hasCompletedSetup: true, dailyGoal: null, quitPlan: null, + userName: data.name, + userAge: data.age, }; savePreferences(newPrefs); setPreferences(newPrefs); @@ -69,7 +72,11 @@ export function Dashboard({ user }: DashboardProps) { }; const handleUsageSubmit = (count: number) => { - if (!preferences) return; + if (!preferences || count === 0) { + setShowUsagePrompt(false); + loadData(); + return; + } const today = new Date().toISOString().split('T')[0]; saveUsageEntry({ @@ -77,7 +84,6 @@ export function Dashboard({ user }: DashboardProps) { count, substance: preferences.substance, }); - setLastPromptDate(today); setShowUsagePrompt(false); loadData(); }; @@ -101,36 +107,50 @@ export function Dashboard({ user }: DashboardProps) { if (isLoading) { return (
-
Loading...
+
Loading...
); } return ( -
+
{preferences && ( -
-
- + <> + {/* Floating Log Button */} +
+
-
- - + +
+
+ +
+
+ + +
-
+ )}
diff --git a/src/components/QuitPlanCard.tsx b/src/components/QuitPlanCard.tsx index ba87a88..ea2ec76 100644 --- a/src/components/QuitPlanCard.tsx +++ b/src/components/QuitPlanCard.tsx @@ -23,7 +23,7 @@ export function QuitPlanCard({ if (!plan) { return ( - + Your Quit Plan @@ -72,7 +72,7 @@ export function QuitPlanCard({ const totalWeeks = plan.weeklyTargets.length; return ( - + Your Quit Plan diff --git a/src/components/SetupWizard.tsx b/src/components/SetupWizard.tsx index 6828c7b..1e3106f 100644 --- a/src/components/SetupWizard.tsx +++ b/src/components/SetupWizard.tsx @@ -9,6 +9,7 @@ import { DialogTitle, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Select, @@ -20,15 +21,32 @@ import { interface SetupWizardProps { open: boolean; - onComplete: (substance: 'nicotine' | 'weed') => void; + onComplete: (data: { substance: 'nicotine' | 'weed'; name: string; age: number }) => void; } export function SetupWizard({ open, onComplete }: SetupWizardProps) { + const [step, setStep] = useState(1); + const [name, setName] = useState(''); + const [age, setAge] = useState('25'); const [substance, setSubstance] = useState<'nicotine' | 'weed' | ''>(''); + const ages = Array.from({ length: 83 }, (_, i) => (i + 18).toString()); + + const handleNext = () => { + if (step === 1 && name.trim()) { + setStep(2); + } else if (step === 2 && age) { + setStep(3); + } + }; + const handleComplete = () => { - if (substance) { - onComplete(substance); + if (substance && name.trim() && age) { + onComplete({ + substance, + name: name.trim(), + age: parseInt(age, 10), + }); } }; @@ -36,39 +54,101 @@ export function SetupWizard({ open, onComplete }: SetupWizardProps) { e.preventDefault()}> - Welcome to QuitTrack + Welcome to QuitTraq - Let's set up your tracking preferences to help you on your journey. + {step === 1 && "Let's get to know you a little better."} + {step === 2 && "Just one more thing about you."} + {step === 3 && "Set up your tracking preferences."}
-
- - -
+ {step === 1 && ( +
+
+ + setName(e.target.value)} + className="text-lg" + autoFocus + /> +
+ +
+ )} -
-

How it works

-
    -
  1. Track your daily usage for one week
  2. -
  3. We'll analyze your patterns
  4. -
  5. Get a personalized quit plan based on your habits
  6. -
  7. Gradually reduce your intake safely
  8. -
-
+ {step === 2 && ( +
+
+ + +
+
+ + +
+
+ )} - + {step === 3 && ( +
+
+ + +
+ +
+

How it works

+
    +
  1. Log each puff throughout the day
  2. +
  3. Track your patterns for one week
  4. +
  5. Get a personalized quit plan
  6. +
  7. Gradually reduce your intake safely
  8. +
+
+ +
+ + +
+
+ )}
diff --git a/src/components/StatsCard.tsx b/src/components/StatsCard.tsx index 93e06cb..fa9d9fc 100644 --- a/src/components/StatsCard.tsx +++ b/src/components/StatsCard.tsx @@ -49,7 +49,7 @@ export function StatsCard({ usageData, substance }: StatsCardProps) { const totalDays = substanceData.length; return ( - + Your Stats diff --git a/src/components/UsageCalendar.tsx b/src/components/UsageCalendar.tsx index b6eecbb..1a63610 100644 --- a/src/components/UsageCalendar.tsx +++ b/src/components/UsageCalendar.tsx @@ -44,11 +44,19 @@ export function UsageCalendar({ usageData, substance, onDataUpdate }: UsageCalen const handleSave = () => { if (selectedDate) { const dateStr = selectedDate.toISOString().split('T')[0]; - setUsageForDate(dateStr, parseInt(editCount, 10) || 0, substance); + const newCount = parseInt(editCount, 10) || 0; + setUsageForDate(dateStr, newCount, substance); onDataUpdate(); } setIsEditing(false); setSelectedDate(undefined); + setEditCount(''); + }; + + const handleCancel = () => { + setIsEditing(false); + setSelectedDate(undefined); + setEditCount(''); }; const getUsageCount = useCallback((date: Date): number => { @@ -57,11 +65,21 @@ export function UsageCalendar({ usageData, substance, onDataUpdate }: UsageCalen return entry?.count ?? 0; }, [usageData, substance]); - const getColorClass = useCallback((count: number): string => { - if (count === 0) return 'bg-green-100 dark:bg-green-900/30 text-green-900 dark:text-green-100 hover:bg-green-200 dark:hover:bg-green-900/50'; - if (count <= 3) return 'bg-yellow-100 dark:bg-yellow-900/30 text-yellow-900 dark:text-yellow-100 hover:bg-yellow-200 dark:hover:bg-yellow-900/50'; - if (count <= 6) return 'bg-orange-100 dark:bg-orange-900/30 text-orange-900 dark:text-orange-100 hover:bg-orange-200 dark:hover:bg-orange-900/50'; - return 'bg-red-100 dark:bg-red-900/30 text-red-900 dark:text-red-100 hover:bg-red-200 dark:hover:bg-red-900/50'; + const getColorStyle = useCallback((count: number): React.CSSProperties => { + if (count === 0) { + return { + background: 'linear-gradient(135deg, #10b981 0%, #059669 100%)', + color: 'white', + }; + } + // Red gradient for any usage - more intense red for higher counts + const intensity = Math.min(count / 10, 1); // Max intensity at 10+ uses + const lightRed = `rgba(239, 68, 68, ${0.6 + intensity * 0.4})`; + const darkRed = `rgba(185, 28, 28, ${0.7 + intensity * 0.3})`; + return { + background: `linear-gradient(135deg, ${lightRed} 0%, ${darkRed} 100%)`, + color: 'white', + }; }, []); const CustomDayButton = useCallback(({ day, modifiers, ...props }: DayButtonProps) => { @@ -72,30 +90,31 @@ export function UsageCalendar({ usageData, substance, onDataUpdate }: UsageCalen dateToCheck.setHours(0, 0, 0, 0); const isFuture = dateToCheck > today; const count = isFuture ? -1 : getUsageCount(date); - const colorClass = count >= 0 ? getColorClass(count) : ''; + const colorStyle = count >= 0 ? getColorStyle(count) : {}; return ( ); - }, [getUsageCount, getColorClass]); + }, [getUsageCount, getColorStyle]); return ( <> - + Usage Calendar @@ -104,7 +123,7 @@ export function UsageCalendar({ usageData, substance, onDataUpdate }: UsageCalen mode="single" selected={selectedDate} onSelect={handleDateSelect} - className="rounded-md border p-3" + className="rounded-md border p-3 bg-background/50" showOutsideDays={false} components={{ DayButton: CustomDayButton, @@ -116,26 +135,21 @@ export function UsageCalendar({ usageData, substance, onDataUpdate }: UsageCalen />
-
- 0 uses +
+ No usage
-
- 1-3 -
-
-
- 4-6 -
-
-
- 7+ +
+ Has usage
+

+ Click any day to edit the count +

- + !open && handleCancel()}> @@ -144,7 +158,7 @@ export function UsageCalendar({ usageData, substance, onDataUpdate }: UsageCalen
- + setEditCount(e.target.value)} className="text-center text-lg" /> +

+ This will replace the current value +

-
- ) : hasUsed === true ? ( + ) : (
setCount(e.target.value)} className="text-center text-lg" /> -

- {substance === 'nicotine' - ? 'Count each vape session or cigarette' - : 'Count each smoking/consumption session'} +

+ This will be added to today's total

- -
- ) : ( -
-
🎉
-

Great job staying smoke-free today!

-

- Every day without smoking is a victory. Keep it up! -

- -
)}
diff --git a/src/components/UserHeader.tsx b/src/components/UserHeader.tsx index 5183fff..b898a71 100644 --- a/src/components/UserHeader.tsx +++ b/src/components/UserHeader.tsx @@ -3,12 +3,21 @@ import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { Button } from '@/components/ui/button'; import { User } from '@/lib/session'; +import { getPreferences } from '@/lib/storage'; +import { useEffect, useState } from 'react'; interface UserHeaderProps { user: User; } export function UserHeader({ user }: UserHeaderProps) { + const [userName, setUserName] = useState(null); + + useEffect(() => { + const prefs = getPreferences(); + setUserName(prefs.userName); + }, []); + const initials = [user.firstName?.[0], user.lastName?.[0]] .filter(Boolean) .join('') @@ -19,30 +28,42 @@ export function UserHeader({ user }: UserHeaderProps) { }; return ( -
+
-

QuitTrack

+

QuitTraq

+ {userName && ( +

+ Welcome {userName}, you got this! +

+ )}
-
- - - {initials} - -
-

- {user.firstName ? `${user.firstName} ${user.lastName ?? ''}`.trim() : user.email} -

-

{user.email}

-
-
-
+ {userName && ( +
+

+ Welcome {userName}, you got this! +

+
+ )}
); } diff --git a/src/lib/storage.ts b/src/lib/storage.ts index 8d5ce7a..ba8cefa 100644 --- a/src/lib/storage.ts +++ b/src/lib/storage.ts @@ -12,6 +12,8 @@ export interface UserPreferences { hasCompletedSetup: boolean; dailyGoal: number | null; quitPlan: QuitPlan | null; + userName: string | null; + userAge: number | null; } export interface QuitPlan { @@ -77,6 +79,8 @@ export function getPreferences(): UserPreferences { hasCompletedSetup: false, dailyGoal: null, quitPlan: null, + userName: null, + userAge: null, }; } @@ -88,6 +92,8 @@ export function getPreferences(): UserPreferences { hasCompletedSetup: false, dailyGoal: null, quitPlan: null, + userName: null, + userAge: null, }; } @@ -110,9 +116,8 @@ export function setLastPromptDate(date: string): void { } export function shouldShowUsagePrompt(): boolean { - const lastPrompt = getLastPromptDate(); - const today = new Date().toISOString().split('T')[0]; - return lastPrompt !== today; + // Always show the prompt - users can log multiple times throughout the day + return true; } export function getWeeklyData(substance: 'nicotine' | 'weed'): UsageEntry[] {