Download src/hooks/useSyncedStudentActivity.ts from asnannp/DocDoeAI: direct link, hf CLI and curl.
- Browser
- Download file 2.13 kB
-
https://huggingface.co/spaces/asnannp/DocDoeAI/resolve/main/src/hooks/useSyncedStudentActivity.ts
- Command line
-
hf download hf://spaces/asnannp/DocDoeAI/src/hooks/useSyncedStudentActivity.ts
-
curl -L -o useSyncedStudentActivity.ts https://huggingface.co/spaces/asnannp/DocDoeAI/resolve/main/src/hooks/useSyncedStudentActivity.ts
2.13 kB
| "use client"; | |
| import { useEffect, useMemo, useState } from "react"; | |
| import { useStudentActivityVersion } from "@/hooks/useStudentActivity"; | |
| import { | |
| getSyncedProgress, | |
| syncProgressEvents, | |
| } from "@/lib/api/progress-sync"; | |
| import { learnerScopeId } from "@/lib/phase3-learning"; | |
| import { | |
| listActivities, | |
| mergeActivityEvents, | |
| type ActivityEvent, | |
| } from "@/lib/student-activity"; | |
| export type ActivitySyncState = "device" | "syncing" | "synced" | "error"; | |
| /** | |
| * One account-aware activity ledger for Home and Progress. Offline events stay | |
| * visible immediately, then upload idempotently and merge with activity from | |
| * the student's other devices. | |
| */ | |
| export function useSyncedStudentActivity(limit = 50) { | |
| const version = useStudentActivityVersion(); | |
| const scopeId = learnerScopeId(); | |
| const localEvents = useMemo(() => { | |
| void version; | |
| return listActivities(Math.min(limit, 100)); | |
| }, [limit, version]); | |
| const [remoteEvents, setRemoteEvents] = useState<ActivityEvent[]>([]); | |
| const [syncState, setSyncState] = useState<ActivitySyncState>(() => | |
| scopeId ? "syncing" : "device", | |
| ); | |
| useEffect(() => { | |
| let cancelled = false; | |
| async function refresh() { | |
| // Defer state changes so the effect never performs a synchronous state | |
| // write during React's commit phase. | |
| await Promise.resolve(); | |
| if (cancelled) return; | |
| if (!scopeId) { | |
| setRemoteEvents([]); | |
| setSyncState("device"); | |
| return; | |
| } | |
| setSyncState("syncing"); | |
| try { | |
| if (localEvents.length) await syncProgressEvents(localEvents); | |
| const remote = await getSyncedProgress(); | |
| if (cancelled) return; | |
| setRemoteEvents(remote.recent_events); | |
| setSyncState("synced"); | |
| } catch { | |
| if (!cancelled) setSyncState("error"); | |
| } | |
| } | |
| void refresh(); | |
| return () => { | |
| cancelled = true; | |
| }; | |
| }, [localEvents, scopeId]); | |
| const events = useMemo( | |
| () => mergeActivityEvents(remoteEvents, localEvents).slice(0, limit), | |
| [limit, localEvents, remoteEvents], | |
| ); | |
| return { events, syncState, version }; | |
| } | |