Refactor: Unified independent quit plans for Nicotine and Weed, fixed persistence, and upgraded UI with expandable sections

This commit is contained in:
Avery Felts 2026-01-31 17:37:25 -07:00
parent 75a75fd499
commit 3a31c8a956
4 changed files with 312 additions and 266 deletions

View File

@ -23,12 +23,21 @@ export async function GET() {
}); });
} }
// Parse JSON to construct quitState
const rawJson = preferences.quitPlanJson ? JSON.parse(preferences.quitPlanJson) : null;
const isNewFormat = rawJson && 'nicotine' in rawJson;
const quitState = isNewFormat ? rawJson : {
nicotine: preferences.substance === 'nicotine' ? { plan: rawJson, startDate: preferences.trackingStartDate } : { plan: null, startDate: null },
weed: preferences.substance === 'weed' ? { plan: rawJson, startDate: preferences.trackingStartDate } : { plan: null, startDate: null }
};
return NextResponse.json({ return NextResponse.json({
substance: preferences.substance, substance: preferences.substance,
trackingStartDate: preferences.trackingStartDate, trackingStartDate: preferences.trackingStartDate,
hasCompletedSetup: !!preferences.hasCompletedSetup, hasCompletedSetup: !!preferences.hasCompletedSetup,
dailyGoal: preferences.dailyGoal, dailyGoal: preferences.dailyGoal,
quitPlan: preferences.quitPlanJson ? JSON.parse(preferences.quitPlanJson) : null, quitPlan: null,
quitState,
userName: preferences.userName, userName: preferences.userName,
userAge: preferences.userAge, userAge: preferences.userAge,
religion: preferences.religion, religion: preferences.religion,

View File

@ -28,7 +28,7 @@ import { SetupWizard } from './SetupWizard';
import { UsagePromptDialog } from './UsagePromptDialog'; import { UsagePromptDialog } from './UsagePromptDialog';
import { UsageCalendar } from './UsageCalendar'; import { UsageCalendar } from './UsageCalendar';
import { StatsCard } from './StatsCard'; import { StatsCard } from './StatsCard';
import { QuitPlanCard } from './QuitPlanCard'; import { UnifiedQuitPlanCard } from './UnifiedQuitPlanCard';
import { AchievementsCard } from './AchievementsCard'; import { AchievementsCard } from './AchievementsCard';
import { CelebrationAnimation } from './CelebrationAnimation'; import { CelebrationAnimation } from './CelebrationAnimation';
import { HealthTimelineCard } from './HealthTimelineCard'; import { HealthTimelineCard } from './HealthTimelineCard';
@ -358,41 +358,13 @@ export function Dashboard({ user }: DashboardProps) {
</div> </div>
<div className="space-y-4 sm:grid sm:grid-cols-2 sm:gap-6 sm:space-y-0"> <div className="space-y-4 sm:grid sm:grid-cols-2 sm:gap-6 sm:space-y-0">
<MoodTracker /> <MoodTracker />
{/* Nicotine Plan */} {/* Unified Quit Plan Placard */}
{(preferences.substance === 'nicotine' || usageData.some(e => e.substance === 'nicotine')) && ( <UnifiedQuitPlanCard
<QuitPlanCard preferences={preferences}
key={`quit-plan-nicotine-${refreshKey}`}
plan={preferences.quitState?.nicotine.plan || (preferences.substance === 'nicotine' ? preferences.quitPlan : null)}
onGeneratePlan={() => handleGeneratePlan('nicotine')}
usageData={usageData} usageData={usageData}
trackingStartDate={ onGeneratePlan={handleGeneratePlan}
preferences.quitState?.nicotine.startDate || refreshKey={refreshKey}
(preferences.substance === 'nicotine' ? preferences.trackingStartDate : null) ||
// Fallback: Find earliest usage date
usageData.filter(e => e.substance === 'nicotine').sort((a, b) => a.date.localeCompare(b.date))[0]?.date ||
null
}
substance="nicotine"
/> />
)}
{/* Weed Plan */}
{(preferences.substance === 'weed' || usageData.some(e => e.substance === 'weed')) && (
<QuitPlanCard
key={`quit-plan-weed-${refreshKey}`}
plan={preferences.quitState?.weed.plan || (preferences.substance === 'weed' ? preferences.quitPlan : null)}
onGeneratePlan={() => handleGeneratePlan('weed')}
usageData={usageData}
trackingStartDate={
preferences.quitState?.weed.startDate ||
(preferences.substance === 'weed' ? preferences.trackingStartDate : null) ||
// Fallback: Find earliest usage date
usageData.filter(e => e.substance === 'weed').sort((a, b) => a.date.localeCompare(b.date))[0]?.date ||
null
}
substance="weed"
/>
)}
</div> </div>
</div> </div>

View File

@ -1,229 +0,0 @@
'use client';
import React from 'react';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { QuitPlan, UsageEntry } from '@/lib/storage';
import { Target, TrendingDown } from 'lucide-react';
import { useTheme } from '@/lib/theme-context';
import { getTodayString } from '@/lib/date-utils';
interface QuitPlanCardProps {
plan: QuitPlan | null;
onGeneratePlan: () => void;
usageData: UsageEntry[];
trackingStartDate: string | null;
substance: 'nicotine' | 'weed';
}
function QuitPlanCardComponent({
plan,
onGeneratePlan,
usageData,
trackingStartDate,
substance,
}: QuitPlanCardProps) {
const { theme } = useTheme();
// Count unique days with any logged data
const uniqueDaysWithData = new Set(usageData.filter(e => e.substance === substance).map(e => e.date)).size;
const daysRemaining = Math.max(0, 7 - uniqueDaysWithData);
// Logic: Unlocked if 7+ days tracked AND (It's Day 8+ OR usage exists for Day 8+)
// This effectively locks it until 12:01 AM next day after Day 7 is done
const isUnlocked = React.useMemo(() => {
// Determine the local start date cleanly (ignoring time)
if (!trackingStartDate || uniqueDaysWithData < 7) return false;
// Parse YYYY-MM-DD
const [y, m, d] = trackingStartDate.split('-').map(Number);
const startObj = new Date(y, m - 1, d); // Local midnight
const now = new Date();
// Get today's local midnight
const todayObj = new Date(now.getFullYear(), now.getMonth(), now.getDate());
// Calculate difference in full days
// Jan 1 to Jan 8: difference of 7 days.
const diffTime = todayObj.getTime() - startObj.getTime();
const daysPassed = Math.floor(diffTime / (1000 * 60 * 60 * 24));
// If 7 days have passed (meaning we are on Day 8 or later), unlock.
if (daysPassed >= 7) return true;
// Also check if usage count is > 7, implying usage beyond the first week
if (uniqueDaysWithData > 7) return true;
return false;
}, [uniqueDaysWithData, trackingStartDate]);
// Calculate current average
const totalUsage = usageData.filter(e => e.substance === substance).reduce((sum, e) => sum + e.count, 0);
const currentAverage = uniqueDaysWithData > 0 ? Math.round(totalUsage / uniqueDaysWithData) : 0;
// Yellow gradient for tracking phase (darker in light mode)
const yellowBackground = theme === 'light'
? 'linear-gradient(135deg, rgba(161, 98, 7, 0.85) 0%, rgba(133, 77, 14, 0.9) 100%)'
: 'linear-gradient(135deg, rgba(234, 179, 8, 0.2) 0%, rgba(202, 138, 4, 0.15) 100%)';
// Pink gradient for active plan (darker in light mode)
const pinkBackground = theme === 'light'
? 'linear-gradient(135deg, rgba(157, 23, 77, 0.85) 0%, rgba(131, 24, 67, 0.9) 100%)'
: 'linear-gradient(135deg, rgba(236, 72, 153, 0.2) 0%, rgba(219, 39, 119, 0.15) 100%)';
if (!plan) {
return (
<Card className="backdrop-blur-xl shadow-xl drop-shadow-lg border-yellow-500/40 hover-lift transition-all duration-300 overflow-hidden relative" style={{
background: yellowBackground
}}>
<div className="absolute top-0 right-0 w-40 h-40 bg-gradient-to-br from-yellow-500/10 to-transparent rounded-full -translate-y-1/2 translate-x-1/2 pointer-events-none" />
<CardHeader className="relative z-10">
<CardTitle className="flex items-center gap-2 text-white text-shadow-sm">
<Target className="h-5 w-5 text-yellow-400" />
Your {substance === 'nicotine' ? 'Nicotine' : 'Weed'} Quit Plan
</CardTitle>
<CardDescription className="text-white/70">
We&apos;re tracking your usage to build your custom quit plan
</CardDescription>
</CardHeader>
<CardContent className="space-y-4 relative z-10">
<div className="bg-yellow-500/20 border border-yellow-500/30 p-4 rounded-xl backdrop-blur-sm">
<div className="flex justify-between items-center mb-3">
<span className="text-sm font-medium text-white">Tracking Progress</span>
<span className="text-sm text-yellow-300 font-bold">
{daysRemaining > 0 ? `${daysRemaining} days left` : 'Ready!'}
</span>
</div>
<div className="w-full bg-white/10 rounded-full h-3 overflow-hidden">
<div
className="bg-gradient-to-r from-yellow-400 to-yellow-500 h-3 rounded-full transition-all duration-700 ease-out"
style={{ width: `${Math.min(100, (uniqueDaysWithData / 7) * 100)}%` }}
/>
</div>
<p className="text-xs text-white/60 mt-2 text-center">
{uniqueDaysWithData} of 7 days tracked
</p>
</div>
{isUnlocked ? (
<div className="space-y-3">
<p className="text-sm text-white text-center">
Great work! Your average daily usage is{' '}
<strong className="text-yellow-300">{currentAverage}</strong> per day.
</p>
<Button onClick={onGeneratePlan} className="w-full bg-yellow-500 hover:bg-yellow-600 text-black font-semibold transition-all duration-300 hover:scale-[1.02] active:scale-[0.98]">
<TrendingDown className="mr-2 h-4 w-4" />
Generate My Quit Plan
</Button>
</div>
) : (
<div className="text-center space-y-2">
<p className="text-sm text-white">
Log your usage each day. After 7 days, we&apos;ll create a personalized plan to help you reduce by <strong className="text-yellow-300">25% each week</strong>.
</p>
<p className="text-xs text-white/60">
Your plan will be tailored to your habits
</p>
</div>
)}
</CardContent>
</Card>
);
}
const startDate = new Date(plan.startDate);
const today = new Date();
const weekNumber = Math.floor(
(today.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24 * 7)
) + 1;
const totalWeeks = plan.weeklyTargets.length;
const currentTarget = weekNumber <= totalWeeks ? plan.weeklyTargets[weekNumber - 1] : 0;
// Calculate today's usage for progress bar
const todayStr = getTodayString();
const todayUsage = usageData
.filter(e => e.date === todayStr && e.substance === substance)
.reduce((sum, e) => sum + e.count, 0);
const usagePercent = currentTarget > 0 ? (todayUsage / currentTarget) * 100 : 0;
// Progress bar color based on usage
let progressColor = 'bg-emerald-400'; // Good
if (usagePercent >= 100) progressColor = 'bg-red-500'; // Over limit
else if (usagePercent >= 80) progressColor = 'bg-yellow-400'; // Warning
return (
<Card className="backdrop-blur-xl shadow-xl drop-shadow-lg border-pink-500/40 hover-lift transition-all duration-300 overflow-hidden relative" style={{
background: pinkBackground
}}>
<div className="absolute top-0 right-0 w-40 h-40 bg-gradient-to-br from-pink-500/10 to-transparent rounded-full -translate-y-1/2 translate-x-1/2 pointer-events-none" />
<CardHeader className="relative z-10">
<CardTitle className="flex items-center gap-2 text-white text-shadow-sm">
<TrendingDown className="h-5 w-5 text-pink-400" />
Your {substance === 'nicotine' ? 'Nicotine' : 'Weed'} Plan
</CardTitle>
<CardDescription className="text-white/70">
Week {Math.min(weekNumber, totalWeeks)} of {totalWeeks} - 25% weekly reduction
</CardDescription>
</CardHeader>
<CardContent className="space-y-4 relative z-10">
<div className="bg-gradient-to-br from-pink-500/25 to-pink-600/20 border border-pink-500/40 p-5 rounded-xl text-center backdrop-blur-sm">
<p className="text-sm text-white/70 mb-1">{substance === 'nicotine' ? 'Nicotine' : 'Weed'} Max Puffs Target</p>
<p className="text-5xl font-bold text-pink-300 text-shadow">
{currentTarget !== null && currentTarget > 0 ? currentTarget : '0'}
</p>
<p className="text-sm text-white/60 mb-3">per day</p>
{/* Daily Progress Bar */}
<div className="w-full bg-black/20 rounded-full h-2 mb-1 overflow-hidden">
<div
className={`h-full rounded-full transition-all duration-500 ${progressColor}`}
style={{ width: `${Math.min(100, usagePercent)}%` }}
/>
</div>
<p className="text-xs text-white/60">
{todayUsage} used / {currentTarget} allowed
</p>
</div>
<div className="space-y-2 relative z-10">
<p className="text-sm font-medium text-white">Weekly targets:</p>
<div className="grid grid-cols-4 gap-2">
{plan.weeklyTargets.map((target, index) => {
const weekNum = index + 1;
const isFuture = weekNum > weekNumber;
const isCurrent = weekNum === weekNumber;
return (
<div
key={index}
className={`text-center p-2 rounded-lg transition-all duration-200 ${isCurrent
? 'bg-gradient-to-br from-pink-500 to-pink-600 text-white shadow-lg shadow-pink-500/30 scale-105'
: isFuture
? 'bg-white/5 text-white/40'
: 'bg-pink-900/50 text-pink-200'
}`}
>
<p className="text-xs">Week {weekNum}</p>
<p className="font-bold">
{isFuture ? '?' : target}
</p>
</div>
)
})}
</div>
</div>
<div className="text-sm text-white/70 bg-white/5 p-3 rounded-lg">
<p>
<strong className="text-white">Started at:</strong> {plan.baselineAverage}/day
</p>
<p>
<strong className="text-white">Goal:</strong> Quit by {new Date(plan.endDate).toLocaleDateString()}
</p>
</div>
</CardContent>
</Card>
);
}
export const QuitPlanCard = React.memo(QuitPlanCardComponent);

View File

@ -0,0 +1,294 @@
'use client';
import React, { useState, useMemo } from 'react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { QuitPlan, UsageEntry, UserPreferences } from '@/lib/storage';
import { Target, TrendingDown, ChevronDown, ChevronUp, Cigarette, Leaf } from 'lucide-react';
import { useTheme } from '@/lib/theme-context';
import { getTodayString } from '@/lib/date-utils';
import { cn } from '@/lib/utils';
interface SubstancePlanSectionProps {
substance: 'nicotine' | 'weed';
plan: QuitPlan | null;
usageData: UsageEntry[];
trackingStartDate: string | null;
onGeneratePlan: () => void;
isExpanded: boolean;
onToggle: () => void;
}
function SubstancePlanSection({
substance,
plan,
usageData,
trackingStartDate,
onGeneratePlan,
isExpanded,
onToggle
}: SubstancePlanSectionProps) {
const { theme } = useTheme();
// 1. Data Processing
const substanceUsage = useMemo(() => usageData.filter(e => e.substance === substance), [usageData, substance]);
const uniqueDaysWithData = useMemo(() => new Set(substanceUsage.map(e => e.date)).size, [substanceUsage]);
const daysRemaining = Math.max(0, 7 - uniqueDaysWithData);
const totalUsage = substanceUsage.reduce((sum, e) => sum + e.count, 0);
const currentAverage = uniqueDaysWithData > 0 ? Math.round(totalUsage / uniqueDaysWithData) : 0;
// 2. Unlock Logic
const isUnlocked = useMemo(() => {
if (!trackingStartDate || uniqueDaysWithData < 7) return false;
const [y, m, d] = trackingStartDate.split('-').map(Number);
const startObj = new Date(y, m - 1, d);
const now = new Date();
const todayObj = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const daysPassed = Math.floor((todayObj.getTime() - startObj.getTime()) / (1000 * 60 * 60 * 24));
return daysPassed >= 7 || uniqueDaysWithData > 7;
}, [uniqueDaysWithData, trackingStartDate]);
// 3. Plan Validation & Calculations
const isValidPlan = plan && plan.startDate && plan.weeklyTargets && Array.isArray(plan.weeklyTargets);
const activePlan = isValidPlan ? plan : null;
const todayStr = getTodayString();
const todayUsage = substanceUsage
.filter(e => e.date === todayStr)
.reduce((sum, e) => sum + e.count, 0);
let weekNumber = 0;
let currentTarget = 0;
let totalWeeks = 0;
let usagePercent = 0;
if (activePlan) {
const startDate = new Date(activePlan.startDate);
const today = new Date();
weekNumber = Math.floor((today.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24 * 7)) + 1;
totalWeeks = activePlan.weeklyTargets.length;
currentTarget = weekNumber <= totalWeeks ? activePlan.weeklyTargets[weekNumber - 1] : 0;
usagePercent = currentTarget > 0 ? (todayUsage / currentTarget) * 100 : 0;
}
// 4. Styling
const isNicotine = substance === 'nicotine';
const Icon = isNicotine ? Cigarette : Leaf;
const label = isNicotine ? 'Nicotine' : 'Weed';
// Base Colors
const bgColor = isNicotine
? (theme === 'light' ? 'bg-yellow-500/10' : 'bg-yellow-500/5')
: (theme === 'light' ? 'bg-emerald-500/10' : 'bg-emerald-500/5');
const borderColor = isNicotine
? (theme === 'light' ? 'border-yellow-500/20' : 'border-yellow-500/10')
: (theme === 'light' ? 'border-emerald-500/20' : 'border-emerald-500/10');
const accentColor = isNicotine ? 'text-yellow-500' : 'text-emerald-500';
const progressFill = isNicotine ? 'bg-yellow-500' : 'bg-emerald-500';
// Specific plan color for the progress bar alert states
let progressColor = progressFill;
if (activePlan) {
if (usagePercent >= 100) progressColor = 'bg-red-500';
else if (usagePercent >= 80) progressColor = isNicotine ? 'bg-orange-400' : 'bg-yellow-400';
}
return (
<div className={cn("rounded-xl border transition-all duration-300 overflow-hidden mb-3", bgColor, borderColor)}>
{/* HEADER / SUMMARY ROW */}
<div
onClick={onToggle}
className="flex items-center justify-between p-4 cursor-pointer hover:bg-black/5 active:bg-black/10 transition-colors"
>
<div className="flex items-center gap-3">
<div className={cn("p-2 rounded-lg", isNicotine ? "bg-yellow-500/20" : "bg-emerald-500/20")}>
<Icon className={cn("h-5 w-5", accentColor)} />
</div>
<div>
<h3 className="font-bold text-sm sm:text-base">{label} Plan</h3>
<p className="text-[10px] opacity-50 uppercase tracking-wider font-bold">
{activePlan ? `Week ${Math.min(weekNumber, totalWeeks)} of ${totalWeeks}` : `Tracking: Day ${uniqueDaysWithData}/7`}
</p>
</div>
</div>
<div className="flex items-center gap-4">
<div className="hidden sm:flex flex-col items-end">
<span className="text-xs font-bold opacity-60 uppercase">Today</span>
<span className={cn("text-sm font-black", activePlan && usagePercent >= 100 ? "text-red-500" : accentColor)}>
{todayUsage}{activePlan ? ` / ${currentTarget}` : ''}
</span>
</div>
{isExpanded ? <ChevronUp className="h-5 w-5 opacity-30" /> : <ChevronDown className="h-5 w-5 opacity-30" />}
</div>
</div>
{/* EXPANDED CONTENT */}
{isExpanded && (
<div className="px-4 pb-4 animate-in slide-in-from-top-2 duration-200">
<div className="h-px w-full bg-border mb-4 opacity-30" />
{!activePlan ? (
<div className="space-y-4">
<div className="bg-black/5 p-4 rounded-lg">
<div className="flex justify-between items-center mb-2">
<span className="text-xs font-medium">Weekly Baseline Progress</span>
<span className={cn("text-xs font-bold", accentColor)}>
{daysRemaining > 0 ? `${daysRemaining} days left` : 'Ready!'}
</span>
</div>
<div className="w-full bg-black/10 rounded-full h-2 overflow-hidden">
<div
className={cn("h-full transition-all duration-700", progressFill)}
style={{ width: `${Math.min(100, (uniqueDaysWithData / 7) * 100)}%` }}
/>
</div>
</div>
{isUnlocked ? (
<div className="text-center space-y-3">
<p className="text-sm">
Baseline established: <strong className={accentColor}>{currentAverage} puffs/day</strong>
</p>
<Button onClick={(e) => { e.stopPropagation(); onGeneratePlan(); }} size="sm" className={cn("w-full h-10 font-bold", progressFill, "text-white hover:opacity-90")}>
Generate Plan
</Button>
</div>
) : (
<p className="text-xs text-center opacity-70 italic">
Keep logging for {daysRemaining} more days to calculate your personalized reduction plan.
</p>
)}
</div>
) : (
<div className="space-y-6">
{/* Active Plan Detail */}
<div className="text-center">
<p className="text-[10px] font-bold uppercase opacity-50 mb-1">Current Daily Limit</p>
<p className={cn("text-4xl font-black", accentColor)}>{currentTarget}</p>
<p className="text-xs opacity-50 mt-1">puffs allowed today</p>
</div>
{/* Progress Bar Detail */}
<div className="space-y-1.5">
<div className="flex justify-between text-[10px] uppercase font-bold opacity-60">
<span>Usage Progress</span>
<span>{Math.round(usagePercent)}%</span>
</div>
<div className="w-full bg-black/10 rounded-full h-3 overflow-hidden">
<div
className={cn("h-full transition-all duration-500", progressColor)}
style={{ width: `${Math.min(100, usagePercent)}%` }}
/>
</div>
</div>
{/* Weekly Matrix */}
<div className="grid grid-cols-4 gap-2">
{activePlan.weeklyTargets.map((target, idx) => {
const wNum = idx + 1;
const isFuture = wNum > weekNumber;
const isCurrent = wNum === weekNumber;
return (
<div
key={idx}
className={cn(
"text-center p-2 rounded-lg border transition-all",
isCurrent
? `${progressFill} border-transparent text-white shadow-lg scale-105`
: isFuture
? "bg-black/5 opacity-40 border-transparent"
: "opacity-60 border-current"
)}
>
<p className="text-[9px] uppercase font-black">Wk {wNum}</p>
<p className="text-sm font-bold">{isFuture ? '?' : target}</p>
</div>
);
})}
</div>
<div className="bg-black/5 p-3 rounded-lg flex justify-between items-center text-[10px] uppercase font-bold opacity-50">
<span>Start: {activePlan.baselineAverage}/day</span>
<span>End: {new Date(activePlan.endDate).toLocaleDateString()}</span>
</div>
</div>
)}
</div>
)}
</div>
);
}
interface UnifiedQuitPlanCardProps {
preferences: UserPreferences | null;
usageData: UsageEntry[];
onGeneratePlan: (substance: 'nicotine' | 'weed') => void;
refreshKey: number;
}
export function UnifiedQuitPlanCard({
preferences,
usageData,
onGeneratePlan,
refreshKey
}: UnifiedQuitPlanCardProps) {
const [expandedSubstance, setExpandedSubstance] = useState<'nicotine' | 'weed' | 'none'>('nicotine');
if (!preferences) return null;
// Determine which substances to show
const showNicotine = preferences.substance === 'nicotine' || usageData.some(e => e.substance === 'nicotine');
const showWeed = preferences.substance === 'weed' || usageData.some(e => e.substance === 'weed');
if (!showNicotine && !showWeed) return null;
return (
<Card className="backdrop-blur-xl shadow-xl border-white/10 overflow-hidden">
<CardHeader className="pb-3 border-b border-white/5 bg-white/5">
<CardTitle className="flex items-center gap-2 text-sm sm:text-base font-black uppercase tracking-widest opacity-80">
<TrendingDown className="h-5 w-5 text-primary" />
Quit Journey Plan
</CardTitle>
</CardHeader>
<CardContent className="pt-4 p-3 sm:p-6">
{showNicotine && (
<SubstancePlanSection
substance="nicotine"
isExpanded={expandedSubstance === 'nicotine'}
onToggle={() => setExpandedSubstance(expandedSubstance === 'nicotine' ? 'none' : 'nicotine')}
plan={preferences.quitState?.nicotine?.plan || (preferences.substance === 'nicotine' ? preferences.quitPlan : null)}
usageData={usageData}
trackingStartDate={
preferences.quitState?.nicotine?.startDate ||
(preferences.substance === 'nicotine' ? preferences.trackingStartDate : null) ||
usageData.filter(e => e.substance === 'nicotine').sort((a, b) => a.date.localeCompare(b.date))[0]?.date ||
null
}
onGeneratePlan={() => onGeneratePlan('nicotine')}
/>
)}
{showWeed && (
<SubstancePlanSection
substance="weed"
isExpanded={expandedSubstance === 'weed'}
onToggle={() => setExpandedSubstance(expandedSubstance === 'weed' ? 'none' : 'weed')}
plan={preferences.quitState?.weed?.plan || (preferences.substance === 'weed' ? preferences.quitPlan : null)}
usageData={usageData}
trackingStartDate={
preferences.quitState?.weed?.startDate ||
(preferences.substance === 'weed' ? preferences.trackingStartDate : null) ||
usageData.filter(e => e.substance === 'weed').sort((a, b) => a.date.localeCompare(b.date))[0]?.date ||
null
}
onGeneratePlan={() => onGeneratePlan('weed')}
/>
)}
</CardContent>
</Card>
);
}