import { useEffect, useRef, useState } from "react"; import { useOpenGeniText } from "../messages/runtime"; import type { TurnStepsItem } from "./types"; /** * Loads an opened turn's steps. Mounted only inside an open work row, so a * turn's steps are read when a reader opens it, newest first, and kept while * it stays open. A row that opens by itself (`autoLoad={false}`, for example * a failed turn or one with an image) waits for the reader to ask. */ export function TurnStepsLoader({ steps, autoLoad = true, }: { steps: TurnStepsItem; autoLoad?: boolean | undefined; }) { const { state, load, retain } = steps; const [requested, setRequested] = useState(autoLoad); // An open row keeps its steps (live ones too) while mounted; only the // read waits for the reader. useEffect(() => retain(), [retain]); useEffect(() => { if (requested && state === "idle") load(); }, [requested, state, load]); const ask = () => { setRequested(true); if (state !== "idle") load(); }; return ; } /** * Timelines without readable turn rows place this at the turn's start: its * steps load when the reader asks, and are kept from then on. */ export function TurnStepsAction({ steps }: { steps: TurnStepsItem }) { const release = useRef<(() => void) | null>(null); useEffect(() => () => release.current?.(), []); const load = () => { release.current ??= steps.retain(); steps.load(); }; return ; } function TurnStepsStatus({ steps, onLoad, }: { steps: TurnStepsItem; onLoad?: (() => void) | undefined; }) { const t = useOpenGeniText(); const { state } = steps; const load = onLoad ?? steps.load; if (state === "complete") return null; // An opened row loads by itself; elsewhere the reader asks. if (state === "partial" || (state === "idle" && onLoad)) { return (
); } if (state === "error") { return (
{t("timeline.turnSteps.couldNotLoadSteps")}
); } return (
{t("timeline.turnSteps.loadingSteps")}
); }