// Export → Earlier versions: the copies the server kept of this study as you worked. Look at what is different // from now, and put one back. The version you replace is kept, so putting one back can be undone too. import { useCallback, useEffect, useState } from 'react'; import { getStudyVersion, listStudyVersions } from '../syncService.js'; import { describeDiff, diffProjects } from '../utils/projectDiff.js'; const btn = 'rounded-lg border border-[var(--r-line)] px-3 py-1.5 text-xs hover:bg-black/5 disabled:opacity-50'; export default function VersionHistory({ project, onRestore }) { const [state, setState] = useState({ status: 'loading', versions: [] }); const [open, setOpen] = useState(null); // { id, lines } the version being looked at const [busy, setBusy] = useState(false); const [error, setError] = useState(''); const load = useCallback(async () => { if (!project?.id) return; const r = await listStudyVersions(project.id); setState(r.ok ? { status: 'ready', versions: r.data.versions } : { status: 'unavailable', versions: [] }); }, [project?.id]); useEffect(() => { load(); }, [load]); const preview = async (v) => { if (open?.id === v.id) { setOpen(null); return; } setError(''); const r = await getStudyVersion(project.id, v.id); if (!r.ok) { setError(r.error ?? 'Could not open that version.'); return; } setOpen({ id: v.id, lines: describeDiff(diffProjects(project, r.data)) }); }; const restore = async (v) => { if (!window.confirm(`Put back the version from ${new Date(v.savedAt).toLocaleString()}? What you have now is kept in this list, so you can undo it.`)) return; setBusy(true); setError(''); const ok = await onRestore(v.id); setBusy(false); if (ok) { setOpen(null); load(); } else setError('Could not restore that version. Check your connection and try again.'); }; return (

Earlier versions

As you work, your account keeps earlier copies of this study (about one for every ten minutes of editing, the latest 30). Use one to undo a bad merge or a deletion.

{state.status === 'loading' &&

Loading…

} {state.status === 'unavailable' &&

Earlier versions need your account and a connection, and the study has to have synced once.

} {state.status === 'ready' && state.versions.length === 0 &&

Nothing kept yet. The first earlier version appears after you’ve changed the study a couple of times.

} {state.versions.length > 0 && ( )} {error &&

{error}

}
); }