"use client"; import { useCallback, useEffect, useMemo, useState } from "react"; import { AppShell } from "@/components/AppShell"; import { ErrorState, LoadingState } from "@/components/StateBlocks"; import { getVideoWalk } from "@/lib/api/client"; import type { FlowLedgerVideoWalkResponse, RawRecord } from "@/lib/api/types"; import { asRecord, text } from "@/lib/flow-ledger/format"; import { WalkTree } from "@/features/walk/WalkTree"; export function VideoWalkPage({ runId, contentId }: { runId: string; contentId: string }) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const load = useCallback(async () => { setLoading(true); setError(null); try { const debug = new URLSearchParams(window.location.search).get("debug") === "1"; setData(await getVideoWalk(runId, contentId, debug)); } catch (err) { setError(err instanceof Error ? err.message : String(err)); } finally { setLoading(false); } }, [contentId, runId]); useEffect(() => { void load(); }, [load]); const root = asRecord(data?.root_video); const rootTitle = cleanTitle(text(root.title, "这条视频")); const actions = useMemo( () => (data?.actions || []).filter((a): a is RawRecord => typeof a === "object" && a !== null), [data?.actions] ); return ( {loading ? : null} {error ? : null} {data && !loading && !error ? ( ) : null} ); } function cleanTitle(value: string): string { return value.replace(/#[^\s#]+/g, " ").replace(/\s+/g, " ").trim() || value; }