1"use client"
2
3import { useEffect } from "react"
4
5import { useBoothStore } from "@/stores/booth"
6import {
7 clearSession,
8 loadSession,
9 saveSession,
10 serializeSession,
11 validateRecord,
12} from "./sessionDb"
13
14/* FR-14: memulihkan sesi dari IndexedDB saat kerangka booth dipasang, lalu
15 menyimpannya kembali dengan jeda supaya setiap perubahan kecil tidak menulis
16 ke disk. Dipasang di `src/app/booth/layout.tsx`, jadi berlaku untuk semua
17 langkah booth. */
18
19const SAVE_DELAY_MS = 400
20
21export function SessionSync() {
22 useEffect(() => {
23 let cancelled = false
24 let timer: number | null = null
25 let unsubscribe = () => {}
26
27 async function hydrate() {
28 const stored = await loadSession()
29 if (cancelled) {
30 return
31 }
32 const record = validateRecord(stored)
33
34 /* Rekaman hanya dipakai bila store masih segar: alur galeri dari Welcome
35 mengisi store sebelum IndexedDB selesai dibaca, dan itu tidak boleh
36 tertimpa. */
37 if (record !== null && useBoothStore.getState().layoutId === null) {
38 useBoothStore.setState({
39 layoutId: record.layoutId,
40 shots: record.shots,
41 frameId: record.frameId,
42 effectId: record.effectId,
43 stickers: record.stickers,
44 texts: record.texts,
45 showDate: record.showDate,
46 share: record.share,
47 relay: record.relay ?? null,
48 localOnly: record.localOnly === true,
49 })
50 } else if (stored !== null && record === null) {
51 /* Rekaman rusak atau dari versi lain: dibuang. */
52 void clearSession()
53 }
54 useBoothStore.setState({ sessionReady: true })
55
56 unsubscribe = useBoothStore.subscribe(() => {
57 if (timer !== null) {
58 window.clearTimeout(timer)
59 }
60 timer = window.setTimeout(() => {
61 void saveSession(serializeSession(useBoothStore.getState()))
62 }, SAVE_DELAY_MS)
63 })
64 }
65
66 void hydrate()
67 return () => {
68 cancelled = true
69 unsubscribe()
70 if (timer !== null) {
71 window.clearTimeout(timer)
72 }
73 }
74 }, [])
75
76 return null
77}
78