From a244e740c9d7b0a11730cad90fba903e32f8ddd3 Mon Sep 17 00:00:00 2001 From: Avery Felts Date: Fri, 23 Jan 2026 21:52:00 -0700 Subject: [PATCH] Store data per-user using unique account ID - Add user ID prefix to all localStorage keys - Each user now has isolated data storage - New users see fresh setup wizard - Switching accounts loads that user's specific data Co-Authored-By: Claude Opus 4.5 --- src/components/Dashboard.tsx | 6 +- src/lib/storage.ts | 134 ++++++++++++++++++++--------------- 2 files changed, 82 insertions(+), 58 deletions(-) diff --git a/src/components/Dashboard.tsx b/src/components/Dashboard.tsx index e311981..f860823 100644 --- a/src/components/Dashboard.tsx +++ b/src/components/Dashboard.tsx @@ -11,6 +11,7 @@ import { hasOneWeekOfData, calculateWeeklyAverage, generateQuitPlan, + setCurrentUserId, UserPreferences, UsageEntry, } from '@/lib/storage'; @@ -43,6 +44,9 @@ export function Dashboard({ user }: DashboardProps) { }; useEffect(() => { + // Set the current user ID for all storage operations + setCurrentUserId(user.id); + const prefs = loadData(); if (!prefs.hasCompletedSetup) { @@ -52,7 +56,7 @@ export function Dashboard({ user }: DashboardProps) { } setIsLoading(false); - }, []); + }, [user.id]); const handleSetupComplete = (data: { substance: 'nicotine' | 'weed'; name: string; age: number }) => { const today = new Date().toISOString().split('T')[0]; diff --git a/src/lib/storage.ts b/src/lib/storage.ts index 6c57b0a..8bccfb9 100644 --- a/src/lib/storage.ts +++ b/src/lib/storage.ts @@ -1,4 +1,5 @@ // Client-side storage utilities for tracking data +// All data is stored per-user using their unique ID as a prefix export interface UsageEntry { date: string; // ISO date string YYYY-MM-DD @@ -23,19 +24,35 @@ export interface QuitPlan { baselineAverage: number; } -const USAGE_KEY = 'quit_smoking_usage'; -const PREFERENCES_KEY = 'quit_smoking_preferences'; -const LAST_PROMPT_KEY = 'quit_smoking_last_prompt'; +const CURRENT_USER_KEY = 'quit_smoking_current_user'; -export function getUsageData(): UsageEntry[] { +function getStorageKey(baseKey: string, userId?: string): string { + const uid = userId || getCurrentUserId(); + if (!uid) return baseKey; + return `${baseKey}_${uid}`; +} + +export function setCurrentUserId(userId: string): void { + if (typeof window === 'undefined') return; + localStorage.setItem(CURRENT_USER_KEY, userId); +} + +export function getCurrentUserId(): string | null { + if (typeof window === 'undefined') return null; + return localStorage.getItem(CURRENT_USER_KEY); +} + +export function getUsageData(userId?: string): UsageEntry[] { if (typeof window === 'undefined') return []; - const data = localStorage.getItem(USAGE_KEY); + const key = getStorageKey('quit_smoking_usage', userId); + const data = localStorage.getItem(key); return data ? JSON.parse(data) : []; } -export function saveUsageEntry(entry: UsageEntry): void { +export function saveUsageEntry(entry: UsageEntry, userId?: string): void { if (typeof window === 'undefined') return; - const data = getUsageData(); + const key = getStorageKey('quit_smoking_usage', userId); + const data = getUsageData(userId); const existingIndex = data.findIndex( (e) => e.date === entry.date && e.substance === entry.substance ); @@ -46,12 +63,13 @@ export function saveUsageEntry(entry: UsageEntry): void { data.push(entry); } - localStorage.setItem(USAGE_KEY, JSON.stringify(data)); + localStorage.setItem(key, JSON.stringify(data)); } -export function setUsageForDate(date: string, count: number, substance: 'nicotine' | 'weed'): void { +export function setUsageForDate(date: string, count: number, substance: 'nicotine' | 'weed', userId?: string): void { if (typeof window === 'undefined') return; - const data = getUsageData(); + const key = getStorageKey('quit_smoking_usage', userId); + const data = getUsageData(userId); const existingIndex = data.findIndex( (e) => e.date === date && e.substance === substance ); @@ -62,57 +80,55 @@ export function setUsageForDate(date: string, count: number, substance: 'nicotin data.push({ date, count, substance }); } - localStorage.setItem(USAGE_KEY, JSON.stringify(data)); + localStorage.setItem(key, JSON.stringify(data)); } -export function getUsageForDate(date: string, substance: 'nicotine' | 'weed'): number { - const data = getUsageData(); +export function getUsageForDate(date: string, substance: 'nicotine' | 'weed', userId?: string): number { + const data = getUsageData(userId); const entry = data.find((e) => e.date === date && e.substance === substance); return entry?.count ?? 0; } -export function getPreferences(): UserPreferences { +export function getPreferences(userId?: string): UserPreferences { + const defaultPrefs: UserPreferences = { + substance: 'nicotine', + trackingStartDate: null, + hasCompletedSetup: false, + dailyGoal: null, + quitPlan: null, + userName: null, + userAge: null, + }; + if (typeof window === 'undefined') { - return { - substance: 'nicotine', - trackingStartDate: null, - hasCompletedSetup: false, - dailyGoal: null, - quitPlan: null, - userName: null, - userAge: null, - }; + return defaultPrefs; } - const data = localStorage.getItem(PREFERENCES_KEY); + const key = getStorageKey('quit_smoking_preferences', userId); + const data = localStorage.getItem(key); if (!data) { - return { - substance: 'nicotine', - trackingStartDate: null, - hasCompletedSetup: false, - dailyGoal: null, - quitPlan: null, - userName: null, - userAge: null, - }; + return defaultPrefs; } - return JSON.parse(data); + return { ...defaultPrefs, ...JSON.parse(data) }; } -export function savePreferences(preferences: UserPreferences): void { +export function savePreferences(preferences: UserPreferences, userId?: string): void { if (typeof window === 'undefined') return; - localStorage.setItem(PREFERENCES_KEY, JSON.stringify(preferences)); + const key = getStorageKey('quit_smoking_preferences', userId); + localStorage.setItem(key, JSON.stringify(preferences)); } -export function getLastPromptDate(): string | null { +export function getLastPromptDate(userId?: string): string | null { if (typeof window === 'undefined') return null; - return localStorage.getItem(LAST_PROMPT_KEY); + const key = getStorageKey('quit_smoking_last_prompt', userId); + return localStorage.getItem(key); } -export function setLastPromptDate(date: string): void { +export function setLastPromptDate(date: string, userId?: string): void { if (typeof window === 'undefined') return; - localStorage.setItem(LAST_PROMPT_KEY, date); + const key = getStorageKey('quit_smoking_last_prompt', userId); + localStorage.setItem(key, date); } export function shouldShowUsagePrompt(): boolean { @@ -120,8 +136,8 @@ export function shouldShowUsagePrompt(): boolean { return true; } -export function getWeeklyData(substance: 'nicotine' | 'weed'): UsageEntry[] { - const data = getUsageData(); +export function getWeeklyData(substance: 'nicotine' | 'weed', userId?: string): UsageEntry[] { + const data = getUsageData(userId); const today = new Date(); const weekAgo = new Date(today); weekAgo.setDate(weekAgo.getDate() - 7); @@ -132,16 +148,16 @@ export function getWeeklyData(substance: 'nicotine' | 'weed'): UsageEntry[] { }); } -export function calculateWeeklyAverage(substance: 'nicotine' | 'weed'): number { - const weeklyData = getWeeklyData(substance); +export function calculateWeeklyAverage(substance: 'nicotine' | 'weed', userId?: string): number { + const weeklyData = getWeeklyData(substance, userId); if (weeklyData.length === 0) return 0; const total = weeklyData.reduce((sum, entry) => sum + entry.count, 0); return Math.round(total / weeklyData.length); } -export function hasOneWeekOfData(substance: 'nicotine' | 'weed'): boolean { - const prefs = getPreferences(); +export function hasOneWeekOfData(substance: 'nicotine' | 'weed', userId?: string): boolean { + const prefs = getPreferences(userId); if (!prefs.trackingStartDate) return false; const startDate = new Date(prefs.trackingStartDate); @@ -151,8 +167,8 @@ export function hasOneWeekOfData(substance: 'nicotine' | 'weed'): boolean { return daysDiff >= 7; } -export function generateQuitPlan(substance: 'nicotine' | 'weed'): QuitPlan { - const baseline = calculateWeeklyAverage(substance); +export function generateQuitPlan(substance: 'nicotine' | 'weed', userId?: string): QuitPlan { + const baseline = calculateWeeklyAverage(substance, userId); const today = new Date(); const startDate = today.toISOString().split('T')[0]; @@ -176,8 +192,8 @@ export function generateQuitPlan(substance: 'nicotine' | 'weed'): QuitPlan { }; } -export function getCurrentWeekTarget(): number | null { - const prefs = getPreferences(); +export function getCurrentWeekTarget(userId?: string): number | null { + const prefs = getPreferences(userId); if (!prefs.quitPlan) return null; const startDate = new Date(prefs.quitPlan.startDate); @@ -191,16 +207,20 @@ export function getCurrentWeekTarget(): number | null { return prefs.quitPlan.weeklyTargets[weekNumber]; } -export function clearDayData(date: string, substance: 'nicotine' | 'weed'): void { +export function clearDayData(date: string, substance: 'nicotine' | 'weed', userId?: string): void { if (typeof window === 'undefined') return; - const data = getUsageData(); + const key = getStorageKey('quit_smoking_usage', userId); + const data = getUsageData(userId); const filtered = data.filter((e) => !(e.date === date && e.substance === substance)); - localStorage.setItem(USAGE_KEY, JSON.stringify(filtered)); + localStorage.setItem(key, JSON.stringify(filtered)); } -export function clearAllData(): void { +export function clearAllData(userId?: string): void { if (typeof window === 'undefined') return; - localStorage.removeItem(USAGE_KEY); - localStorage.removeItem(PREFERENCES_KEY); - localStorage.removeItem(LAST_PROMPT_KEY); + const usageKey = getStorageKey('quit_smoking_usage', userId); + const prefsKey = getStorageKey('quit_smoking_preferences', userId); + const promptKey = getStorageKey('quit_smoking_last_prompt', userId); + localStorage.removeItem(usageKey); + localStorage.removeItem(prefsKey); + localStorage.removeItem(promptKey); }