- 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>
227 lines
7.1 KiB
TypeScript
227 lines
7.1 KiB
TypeScript
// 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
|
|
count: number;
|
|
substance: 'nicotine' | 'weed';
|
|
}
|
|
|
|
export interface UserPreferences {
|
|
substance: 'nicotine' | 'weed';
|
|
trackingStartDate: string | null;
|
|
hasCompletedSetup: boolean;
|
|
dailyGoal: number | null;
|
|
quitPlan: QuitPlan | null;
|
|
userName: string | null;
|
|
userAge: number | null;
|
|
}
|
|
|
|
export interface QuitPlan {
|
|
startDate: string;
|
|
endDate: string;
|
|
weeklyTargets: number[];
|
|
baselineAverage: number;
|
|
}
|
|
|
|
const CURRENT_USER_KEY = 'quit_smoking_current_user';
|
|
|
|
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 key = getStorageKey('quit_smoking_usage', userId);
|
|
const data = localStorage.getItem(key);
|
|
return data ? JSON.parse(data) : [];
|
|
}
|
|
|
|
export function saveUsageEntry(entry: UsageEntry, userId?: string): void {
|
|
if (typeof window === 'undefined') return;
|
|
const key = getStorageKey('quit_smoking_usage', userId);
|
|
const data = getUsageData(userId);
|
|
const existingIndex = data.findIndex(
|
|
(e) => e.date === entry.date && e.substance === entry.substance
|
|
);
|
|
|
|
if (existingIndex >= 0) {
|
|
data[existingIndex].count += entry.count;
|
|
} else {
|
|
data.push(entry);
|
|
}
|
|
|
|
localStorage.setItem(key, JSON.stringify(data));
|
|
}
|
|
|
|
export function setUsageForDate(date: string, count: number, substance: 'nicotine' | 'weed', userId?: string): void {
|
|
if (typeof window === 'undefined') return;
|
|
const key = getStorageKey('quit_smoking_usage', userId);
|
|
const data = getUsageData(userId);
|
|
const existingIndex = data.findIndex(
|
|
(e) => e.date === date && e.substance === substance
|
|
);
|
|
|
|
if (existingIndex >= 0) {
|
|
data[existingIndex].count = count;
|
|
} else {
|
|
data.push({ date, count, substance });
|
|
}
|
|
|
|
localStorage.setItem(key, JSON.stringify(data));
|
|
}
|
|
|
|
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(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 defaultPrefs;
|
|
}
|
|
|
|
const key = getStorageKey('quit_smoking_preferences', userId);
|
|
const data = localStorage.getItem(key);
|
|
if (!data) {
|
|
return defaultPrefs;
|
|
}
|
|
|
|
return { ...defaultPrefs, ...JSON.parse(data) };
|
|
}
|
|
|
|
export function savePreferences(preferences: UserPreferences, userId?: string): void {
|
|
if (typeof window === 'undefined') return;
|
|
const key = getStorageKey('quit_smoking_preferences', userId);
|
|
localStorage.setItem(key, JSON.stringify(preferences));
|
|
}
|
|
|
|
export function getLastPromptDate(userId?: string): string | null {
|
|
if (typeof window === 'undefined') return null;
|
|
const key = getStorageKey('quit_smoking_last_prompt', userId);
|
|
return localStorage.getItem(key);
|
|
}
|
|
|
|
export function setLastPromptDate(date: string, userId?: string): void {
|
|
if (typeof window === 'undefined') return;
|
|
const key = getStorageKey('quit_smoking_last_prompt', userId);
|
|
localStorage.setItem(key, date);
|
|
}
|
|
|
|
export function shouldShowUsagePrompt(): boolean {
|
|
// Always show the prompt - users can log multiple times throughout the day
|
|
return true;
|
|
}
|
|
|
|
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);
|
|
|
|
return data.filter((entry) => {
|
|
const entryDate = new Date(entry.date);
|
|
return entry.substance === substance && entryDate >= weekAgo && entryDate <= today;
|
|
});
|
|
}
|
|
|
|
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', userId?: string): boolean {
|
|
const prefs = getPreferences(userId);
|
|
if (!prefs.trackingStartDate) return false;
|
|
|
|
const startDate = new Date(prefs.trackingStartDate);
|
|
const today = new Date();
|
|
const daysDiff = Math.floor((today.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24));
|
|
|
|
return daysDiff >= 7;
|
|
}
|
|
|
|
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];
|
|
|
|
// 6-week reduction plan
|
|
const endDate = new Date(today);
|
|
endDate.setDate(endDate.getDate() + 42);
|
|
|
|
// Gradual reduction: each week reduce by ~15-20%
|
|
const weeklyTargets: number[] = [];
|
|
let current = baseline;
|
|
for (let i = 0; i < 6; i++) {
|
|
current = Math.max(0, Math.round(current * 0.8));
|
|
weeklyTargets.push(current);
|
|
}
|
|
|
|
return {
|
|
startDate,
|
|
endDate: endDate.toISOString().split('T')[0],
|
|
weeklyTargets,
|
|
baselineAverage: baseline,
|
|
};
|
|
}
|
|
|
|
export function getCurrentWeekTarget(userId?: string): number | null {
|
|
const prefs = getPreferences(userId);
|
|
if (!prefs.quitPlan) return null;
|
|
|
|
const startDate = new Date(prefs.quitPlan.startDate);
|
|
const today = new Date();
|
|
const weekNumber = Math.floor((today.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24 * 7));
|
|
|
|
if (weekNumber >= prefs.quitPlan.weeklyTargets.length) {
|
|
return 0; // Goal achieved
|
|
}
|
|
|
|
return prefs.quitPlan.weeklyTargets[weekNumber];
|
|
}
|
|
|
|
export function clearDayData(date: string, substance: 'nicotine' | 'weed', userId?: string): void {
|
|
if (typeof window === 'undefined') return;
|
|
const key = getStorageKey('quit_smoking_usage', userId);
|
|
const data = getUsageData(userId);
|
|
const filtered = data.filter((e) => !(e.date === date && e.substance === substance));
|
|
localStorage.setItem(key, JSON.stringify(filtered));
|
|
}
|
|
|
|
export function clearAllData(userId?: string): void {
|
|
if (typeof window === 'undefined') return;
|
|
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);
|
|
}
|