// What someone sees when they open a read-only outline link: a calm page with the outline, a switcher // when there is more than one, and Print / PDF. Nothing is editable. import { useCallback, useEffect, useState } from 'react'; import { getSharedOutline } from '../syncService.js'; import { themeVars } from './reader/readerThemes.js'; import SharedPasscodeForm from './SharedPasscodeForm.jsx'; import OutlineDocument from './OutlineDocument.jsx'; import { printOutline } from '../utils/outlineExport.js'; import { flatten } from '../utils/outline.js'; const pill = (active) => `shrink-0 rounded-full px-3.5 py-1.5 text-sm transition ${active ? 'bg-[var(--r-text)] text-[var(--r-bg)]' : 'text-[var(--r-sub)] hover:bg-black/5'}`; function Frame({ children }) { return
{children}
; } export default function SharedOutlineView({ token }) { const [data, setData] = useState(null); const [error, setError] = useState(''); const [scope, setScope] = useState('study'); const [needsPasscode, setNeedsPasscode] = useState(false); const [passcodeError, setPasscodeError] = useState(''); const [checking, setChecking] = useState(false); const load = useCallback((passcode) => { setChecking(true); return getSharedOutline(token, passcode).then((result) => { setChecking(false); if (result.ok) { setData(result.data); setNeedsPasscode(false); setScope(result.data.outlines[0]?.scope ?? 'study'); return; } if (result.data?.needsPasscode) { setNeedsPasscode(true); setPasscodeError(passcode ? result.error : ''); return; } setNeedsPasscode(false); setError(result.error ?? 'This outline link is invalid or has been turned off.'); }); }, [token]); useEffect(() => { load(); }, [load]); useEffect(() => { if (data?.title) document.title = `${data.title} — Outline`; }, [data]); if (needsPasscode) return ; if (error) { return (

Bible Study Project

{error}

); } if (!data) return

Loading outline…

; const current = data.outlines.find((o) => o.scope === scope) ?? data.outlines[0]; const title = current && current.scope !== 'study' ? `${data.title} — ${current.label}` : data.title; const minutes = current ? flatten(current.tree).reduce((sum, { node }) => sum + (Number.isFinite(node.minutes) ? node.minutes : 0), 0) : 0; const meta = current ? [current.scope === 'study' ? data.translation : `${current.label} · ${data.translation}`, minutes > 0 ? `About ${minutes} minute${minutes === 1 ? '' : 's'}` : ''].filter(Boolean).join(' · ') : ''; const outline = current ? { title, subtitle: current.scope === 'study' ? data.translation : `${current.label} · ${data.translation}`, tree: current.tree } : null; return (
Bible Study {data.outlines.length > 1 ? ( ) : } {outline && }
{current ? :

This study doesn’t have an outline yet.

} ); }