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 <noreply@anthropic.com>
This commit is contained in:
Avery Felts 2026-01-23 21:52:00 -07:00
parent cab5e5810a
commit a244e740c9
2 changed files with 82 additions and 58 deletions

View File

@ -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];

View File

@ -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);
}