export type CourseProgress = { lastLessonId: string | null; completedLessonIds: string[]; }; const STORAGE_KEY = "acve.local-progress.v1"; const PROGRESS_UPDATED_EVENT = "acve:progress-updated"; type ProgressStore = Record>; const defaultProgress: CourseProgress = { lastLessonId: null, completedLessonIds: [], }; const isBrowser = () => typeof window !== "undefined"; const readStore = (): ProgressStore => { if (!isBrowser()) return {}; const raw = window.localStorage.getItem(STORAGE_KEY); if (!raw) return {}; try { return JSON.parse(raw) as ProgressStore; } catch { return {}; } }; const writeStore = (store: ProgressStore) => { if (!isBrowser()) return; window.localStorage.setItem(STORAGE_KEY, JSON.stringify(store)); window.dispatchEvent(new Event(PROGRESS_UPDATED_EVENT)); }; const getOrCreateProgress = (store: ProgressStore, userId: string, courseSlug: string) => { if (!store[userId]) { store[userId] = {}; } if (!store[userId][courseSlug]) { store[userId][courseSlug] = { ...defaultProgress }; } return store[userId][courseSlug]; }; export const getCourseProgress = (userId: string, courseSlug: string): CourseProgress => { const store = readStore(); return store[userId]?.[courseSlug] ?? { ...defaultProgress }; }; export const getCourseProgressPercent = ( userId: string, courseSlug: string, totalLessons: number, ): number => { if (totalLessons <= 0) return 0; const progress = getCourseProgress(userId, courseSlug); return Math.round((progress.completedLessonIds.length / totalLessons) * 100); }; export const setLastLesson = (userId: string, courseSlug: string, lessonId: string) => { const store = readStore(); const progress = getOrCreateProgress(store, userId, courseSlug); progress.lastLessonId = lessonId; writeStore(store); }; export const markLessonComplete = (userId: string, courseSlug: string, lessonId: string) => { const store = readStore(); const progress = getOrCreateProgress(store, userId, courseSlug); if (!progress.completedLessonIds.includes(lessonId)) { progress.completedLessonIds = [...progress.completedLessonIds, lessonId]; } progress.lastLessonId = lessonId; writeStore(store); }; export const clearCourseProgress = (userId: string, courseSlug: string) => { const store = readStore(); if (!store[userId]) return; delete store[userId][courseSlug]; writeStore(store); }; export const progressUpdatedEventName = PROGRESS_UPDATED_EVENT;