import { useState, useCallback, useEffect } from "react"; import { useParams, useNavigate } from "react-router"; import { Masthead } from "../components/Masthead"; import { FileList } from "../components/files/FileList"; import { FileDetail } from "../components/files/FileDetail"; import { CliInput } from "../components/files/CliInput"; import { useFiles } from "../hooks/useFiles"; import type { FileDetail as FileDetailType, BodyElement } from "../lib/api"; export default function FilesPage() { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const { files, loading, error, fetchFile, editFile, removeFile, saveFile } = useFiles(); const [fileDetail, setFileDetail] = useState(null); const [detailLoading, setDetailLoading] = useState(false); const [creating, setCreating] = useState(false); // Load file detail when URL has an id useEffect(() => { if (id) { setDetailLoading(true); fetchFile(id).then((detail) => { setFileDetail(detail); setDetailLoading(false); }); } else { setFileDetail(null); } }, [id, fetchFile]); const handleSelectFile = useCallback( (fileId: string) => { navigate(`/files/${fileId}`); }, [navigate] ); const handleBack = useCallback(() => { navigate("/files"); }, [navigate]); const handleDelete = useCallback( async (fileId: string) => { if (confirm("Are you sure you want to delete this file?")) { const success = await removeFile(fileId); if (success && id === fileId) { navigate("/files"); } } }, [removeFile, id, navigate] ); const handleSave = useCallback( async (fileId: string, name: string, description: string) => { await editFile(fileId, { name, description }); const detail = await fetchFile(fileId); setFileDetail(detail); }, [editFile, fetchFile] ); const handleBodyUpdate = useCallback( (body: BodyElement[], summary: string | null) => { if (fileDetail) { setFileDetail({ ...fileDetail, body, summary, }); } }, [fileDetail] ); const handleBodyElementUpdate = useCallback( async (index: number, element: BodyElement) => { if (fileDetail && id) { // Create new body array with updated element const newBody = [...fileDetail.body]; newBody[index] = element; // Update local state immediately for responsiveness setFileDetail({ ...fileDetail, body: newBody, }); // Save to backend await editFile(id, { body: newBody }); } }, [fileDetail, id, editFile] ); const handleBodyReorder = useCallback( async (fromIndex: number, toIndex: number) => { if (fileDetail && id) { // Create new body array with reordered elements const newBody = [...fileDetail.body]; const [movedElement] = newBody.splice(fromIndex, 1); newBody.splice(toIndex, 0, movedElement); // Update local state immediately for responsiveness setFileDetail({ ...fileDetail, body: newBody, }); // Save to backend await editFile(id, { body: newBody }); } }, [fileDetail, id, editFile] ); const handleCreate = useCallback(async () => { if (creating) return; setCreating(true); try { const newFile = await saveFile({ name: `Untitled ${new Date().toLocaleDateString()}`, transcript: [], }); if (newFile) { navigate(`/files/${newFile.id}`); } } finally { setCreating(false); } }, [creating, saveFile, navigate]); return (
{error && (
{error}
)} {id && fileDetail ? (
) : id && detailLoading ? (
Loading...
) : ( )}
); }