import type { DocMeta } from "$types"; import type { ChangeEvent, FormEvent } from "react"; import { useCallback, useEffect, useMemo, useState } from "react"; import { type DialogAnchor, OperationDialog } from "./OperationDialog"; export type DocumentOperationType = "rename" | "move" | "delete"; export type DocumentOperationRequest = { type: DocumentOperationType; doc: DocMeta; anchor?: DialogAnchor }; type DocumentOperationDialogProps = { operation: DocumentOperationRequest | null; onClose: () => void; onRenameDocument: (locationId: number, relPath: string, newName: string) => Promise; onMoveDocument: (locationId: number, relPath: string, newRelPath: string) => Promise; onDeleteDocument: (locationId: number, relPath: string) => Promise; onRefreshSidebar: (locationId?: number) => void; }; export function DocumentOperationDialog( { operation, onClose, onRenameDocument, onMoveDocument, onDeleteDocument, onRefreshSidebar }: DocumentOperationDialogProps, ) { const [renameName, setRenameName] = useState(""); const [movePath, setMovePath] = useState(""); const [isPending, setIsPending] = useState(false); const activeDoc = operation?.doc ?? null; const operationType = operation?.type; const currentFilename = useMemo(() => activeDoc?.rel_path.split("/").pop() || "", [activeDoc?.rel_path]); const currentPath = activeDoc?.rel_path ?? ""; const displayLabel = useMemo(() => { if (!activeDoc) { return ""; } return activeDoc.title || activeDoc.rel_path.split("/").pop() || "Untitled"; }, [activeDoc]); const renameConfirm = useMemo(() => ({ type: "submit" as const, formId: "rename-document-form" }), []); const moveConfirm = useMemo(() => ({ type: "submit" as const, formId: "move-document-form" }), []); useEffect(() => { if (!operation) { return; } setRenameName(operation.doc.rel_path.split("/").pop() || ""); setMovePath(operation.doc.rel_path); setIsPending(false); }, [operation]); const closeDialog = useCallback(() => { if (!isPending) { onClose(); } }, [isPending, onClose]); const handleRenameSubmit = useCallback(async (event: FormEvent) => { event.preventDefault(); if (!activeDoc) { return; } const nextName = renameName.trim(); if (!nextName || nextName === currentFilename) { closeDialog(); return; } setIsPending(true); try { const renamed = await onRenameDocument(activeDoc.location_id, activeDoc.rel_path, nextName); if (!renamed) { return; } onRefreshSidebar(activeDoc.location_id); onClose(); } finally { setIsPending(false); } }, [activeDoc, closeDialog, currentFilename, onClose, onRefreshSidebar, onRenameDocument, renameName]); const handleMoveSubmit = useCallback(async (event: FormEvent) => { event.preventDefault(); if (!activeDoc) { return; } const nextPath = movePath.trim(); if (!nextPath || nextPath === currentPath) { closeDialog(); return; } setIsPending(true); try { const moved = await onMoveDocument(activeDoc.location_id, activeDoc.rel_path, nextPath); if (!moved) { return; } onRefreshSidebar(activeDoc.location_id); onClose(); } finally { setIsPending(false); } }, [activeDoc, closeDialog, currentPath, movePath, onClose, onMoveDocument, onRefreshSidebar]); const handleDelete = useCallback(async () => { if (!activeDoc) { return; } setIsPending(true); try { const deleted = await onDeleteDocument(activeDoc.location_id, activeDoc.rel_path); if (!deleted) { return; } onRefreshSidebar(activeDoc.location_id); onClose(); } finally { setIsPending(false); } }, [activeDoc, onClose, onDeleteDocument, onRefreshSidebar]); const deleteConfirm = useMemo(() => ({ type: "action" as const, onConfirm: handleDelete }), [handleDelete]); const handleRenameNameChange = useCallback((event: ChangeEvent) => { setRenameName(event.target.value); }, []); const handleMovePathChange = useCallback((event: ChangeEvent) => { setMovePath(event.target.value); }, []); if (!operation || !activeDoc || !operationType) { return null; } if (operationType === "rename") { return (
); } if (operationType === "move") { return (

Enter the new relative path for the document.

); } return (

Are you sure you want to delete{" "} {displayLabel}? This action cannot be undone.

); }