From 3dd20d13c00ffdbdd359dd1f1d171558a5156304 Mon Sep 17 00:00:00 2001 From: pat Date: Mon, 31 Aug 2026 07:33:18 +0000 Subject: [PATCH] feat(reader): persist Try-it activation in localStorage --- .../components/reader/useActivation.js | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 marketing-site/components/reader/useActivation.js diff --git a/marketing-site/components/reader/useActivation.js b/marketing-site/components/reader/useActivation.js new file mode 100644 index 0000000..4a93216 --- /dev/null +++ b/marketing-site/components/reader/useActivation.js @@ -0,0 +1,43 @@ +import { useCallback, useEffect, useMemo, useState } from "react"; + +function keyFor(id) { + return `aibook-demo-activation:${id}`; +} + +/** + * Demo-only activation state. Completing a Try-it writes + * localStorage key `aibook-demo-activation:`. + */ +export default function useActivation(ids) { + const list = useMemo(() => ids, [ids.join("|")]); + const [complete, setComplete] = useState(() => + Object.fromEntries(list.map((id) => [id, false])) + ); + + useEffect(() => { + const next = {}; + list.forEach((id) => { + try { + next[id] = window.localStorage.getItem(keyFor(id)) === "1"; + } catch { + next[id] = false; + } + }); + setComplete(next); + }, [list]); + + const toggle = useCallback((id) => { + setComplete((prev) => { + const value = !prev[id]; + try { + window.localStorage.setItem(keyFor(id), value ? "1" : "0"); + } catch { + /* private mode: still toggle in memory */ + } + return { ...prev, [id]: value }; + }); + }, []); + + const count = list.filter((id) => complete[id]).length; + return { complete, toggle, count, total: list.length }; +}