import * as React from "react"; import { useStorage } from "@tensamin/storage/context"; import { Button } from "@tensamin/ui/button"; import { Checkbox, CheckboxLabel, CheckboxControl, } from "@tensamin/ui/checkbox"; import { z } from "zod"; import ErrorScreen from "@tensamin/ui/screens/error"; import { legalDocsSchema } from "@tensamin/shared/features/legal/schema"; import { log } from "@tensamin/shared/log"; import Link from "@tensamin/ui/link"; export default function Screen(props: { children: React.ReactNode }) { const { load, save } = useStorage(); const [error, setError] = React.useState(""); const [errorDescription, setErrorDescription] = React.useState(""); const [remoteDocs, setRemoteDocs] = React.useState< z.infer | undefined >(undefined); const [loading, setLoading] = React.useState(true); const [PPandToSDone, setPPandToSDone] = React.useState(false); const [acceptedPP, acceptPP] = React.useState(false); const [acceptedTOS, acceptTOS] = React.useState(false); const [doneWithAnalytics, setDoneWithAnalytics] = React.useState(false); const [crashReports, setCrashReports] = React.useState(false); const [usageData, setUsageData] = React.useState(false); React.useEffect(() => { let active = true; void load("user_id").then(async (id) => { if (!active) { return; } if (id === 0) { setPPandToSDone(true); setDoneWithAnalytics(true); setLoading(false); return; } const current = await fetch("https://legal.tensamin.net/api/current") .then((res) => res.json()) .catch((err) => { if (!active) { return undefined; } setError("Failed to load legal documents"); setErrorDescription( "An error occurred while fetching the legal documents from the server. Please try again later.", ); log(0, "Legal", "red", "Failed to fetch legal documents", err); return undefined; }); if (!active || current === undefined) { return; } const safeCurrent = legalDocsSchema.safeParse(current); if (!safeCurrent.success) { setError("Failed to load legal documents"); setErrorDescription( "The legal documents data received from the server is invalid. Please try again later.", ); log(0, "Legal", "red", "Invalid legal documents data", safeCurrent.error); return; } setRemoteDocs(safeCurrent.data); const localDocs = await load("legal_docs"); const [ loadedPPAndTOS, loadedAcceptedPP, loadedAcceptedTOS, loadedAnalyticsDone, loadedCrashReports, loadedUsageData, ] = await Promise.all([ load("ppandtos_done"), load("accepted_privacy_policy"), load("accepted_terms_of_service"), load("analytics_done"), load("analytics_crash_reports"), load("analytics_usage_data"), ]); if (!active) { return; } setPPandToSDone(loadedPPAndTOS); acceptPP(loadedAcceptedPP); acceptTOS(loadedAcceptedTOS); setDoneWithAnalytics(loadedAnalyticsDone); setCrashReports(loadedCrashReports); setUsageData(loadedUsageData); if (localDocs.pp.hash !== safeCurrent.data.pp.hash) { acceptPP(false); setPPandToSDone(false); } if (localDocs.tos.hash !== safeCurrent.data.tos.hash) { acceptTOS(false); setPPandToSDone(false); } setLoading(false); }); return () => { active = false; }; }, [load]); if (error !== "" && errorDescription !== "") { return ; } if (loading) { return null; } if (PPandToSDone && doneWithAnalytics) { return <>{props.children}; } return (
{!PPandToSDone ? ( <>

Privacy Policy & ToS

{remoteDocs?.pp.version} / {remoteDocs?.tos.version}

{ const currentDocs = remoteDocs; if (!currentDocs) { return; } void (async () => { await save("accepted_privacy_policy", true); await save("accepted_terms_of_service", true); await save("ppandtos_done", true); await save("legal_docs", currentDocs); setPPandToSDone(true); })(); }} /> ) : ( <>

Analytics

{ const currentCrashReports = crashReports; const currentUsageData = usageData; void save("analytics_crash_reports", currentCrashReports).then(() => { setCrashReports(currentCrashReports); }); void save("analytics_usage_data", currentUsageData).then(() => { setUsageData(currentUsageData); }); void save("analytics_done", true).then(() => { setDoneWithAnalytics(true); }); }} /> )}
); } function ContinueButton(props: { onClick: () => void; disabled?: boolean }) { return (
); } export function BigCheckbox(props: { label: string; checked: boolean; onChange: (checked: boolean) => void; }) { return ( {props.label} ); }