"use client"; import { useEffect, useRef, useState } from "react"; import { Check, ChevronDown, Loader2, Upload } from "lucide-react"; import type { Document, Project, Workflow } from "../shared/types"; import { getProject, listProjects, listStandaloneDocuments, listWorkflows, uploadProjectDocument, uploadStandaloneDocument, } from "@/app/lib/mikeApi"; import { FileDirectory } from "../shared/FileDirectory"; import { BUILT_IN_WORKFLOWS } from "../workflows/builtinWorkflows"; import { Modal } from "../shared/Modal"; interface Props { open: boolean; onClose: () => void; onAdd: ( title: string, projectId?: string, documentIds?: string[], columnsConfig?: Workflow["columns_config"], ) => void; projects?: Project[]; /** When provided, skip the project/directory picker and show only these docs */ projectDocs?: Document[]; projectName?: string; projectCmNumber?: string | null; } export function AddNewTRModal({ open, onClose, onAdd, projects = [], projectDocs: fixedProjectDocs, projectName, projectCmNumber, }: Props) { const isProjectMode = fixedProjectDocs !== undefined; const [title, setTitle] = useState(""); const [underProject, setUnderProject] = useState(false); const [selectedProjectId, setSelectedProjectId] = useState(""); const [projectDropdownOpen, setProjectDropdownOpen] = useState(false); // Project-scoped docs (when underProject is true and no fixedProjectDocs) const [projectDocs, setProjectDocs] = useState([]); const [loadingDocs, setLoadingDocs] = useState(false); // Full directory (when underProject is false) const [standaloneDocs, setStandaloneDocs] = useState([]); const [directoryProjects, setDirectoryProjects] = useState( [], ); const [loadingDirectory, setLoadingDirectory] = useState(false); const [selectedDocIds, setSelectedDocIds] = useState>( new Set(), ); const [uploading, setUploading] = useState(false); const fileInputRef = useRef(null); // Workflow templates const [workflows, setWorkflows] = useState([]); const [loadingWorkflows, setLoadingWorkflows] = useState(false); const [selectedWorkflowId, setSelectedWorkflowId] = useState( null, ); const [workflowDropdownOpen, setWorkflowDropdownOpen] = useState(false); const formId = "new-tabular-review-modal-form"; useEffect(() => { if (!open) return; setLoadingWorkflows(true); const builtinTabular = BUILT_IN_WORKFLOWS.filter( (w) => w.type === "tabular", ); listWorkflows("tabular") .then((custom) => setWorkflows([...builtinTabular, ...custom])) .catch(() => setWorkflows(builtinTabular)) .finally(() => setLoadingWorkflows(false)); if (isProjectMode) { setSelectedDocIds( new Set((fixedProjectDocs ?? []).map((d) => d.id)), ); return; } setLoadingDirectory(true); // /projects only returns counts, not the documents array — fetch // each project in parallel so FileDirectory can render the docs // when the user expands a folder. Promise.all([listStandaloneDocuments(), listProjects()]) .then(async ([docs, projs]) => { setStandaloneDocs( [...docs].sort((a, b) => (b.created_at ?? "").localeCompare(a.created_at ?? ""), ), ); const fullProjects = await Promise.all( projs.map((p) => getProject(p.id)), ); setDirectoryProjects(fullProjects); }) .catch(() => { setStandaloneDocs([]); setDirectoryProjects([]); }) .finally(() => setLoadingDirectory(false)); }, [open]); // eslint-disable-line react-hooks/exhaustive-deps if (!open) return null; function handleClose() { setTitle(""); setUnderProject(false); setSelectedProjectId(""); setProjectDropdownOpen(false); setProjectDocs([]); setStandaloneDocs([]); setDirectoryProjects([]); setSelectedDocIds(new Set()); setSelectedWorkflowId(null); setWorkflowDropdownOpen(false); onClose(); } function handleSubmit(e: React.FormEvent) { e.preventDefault(); if (!title.trim()) return; if (underProject && !selectedProjectId) return; const selectedWorkflow = workflows.find( (w) => w.id === selectedWorkflowId, ); onAdd( title.trim(), underProject ? selectedProjectId : undefined, selectedDocIds.size > 0 ? [...selectedDocIds] : undefined, selectedWorkflow?.columns_config ?? undefined, ); handleClose(); } async function handleSelectProject(projectId: string) { setSelectedProjectId(projectId); setProjectDropdownOpen(false); setProjectDocs([]); setSelectedDocIds(new Set()); setLoadingDocs(true); try { const proj = await getProject(projectId); const docs = (proj.documents ?? []).filter( (d) => d.status === "ready", ); setProjectDocs(docs); setSelectedDocIds(new Set(docs.map((d) => d.id))); } finally { setLoadingDocs(false); } } async function handleUpload(e: React.ChangeEvent) { const files = Array.from(e.target.files ?? []); if (!files.length) return; setUploading(true); try { const uploaded = await Promise.all( files.map((f) => underProject && selectedProjectId ? uploadProjectDocument(selectedProjectId, f) : uploadStandaloneDocument(f), ), ); if (underProject && selectedProjectId) { setProjectDocs((prev) => [...uploaded, ...prev]); } else { setStandaloneDocs((prev) => [...uploaded, ...prev]); } uploaded.forEach((d) => setSelectedDocIds((prev) => new Set([...prev, d.id])), ); } catch (err) { console.error("Upload failed:", err); } finally { setUploading(false); if (fileInputRef.current) fileInputRef.current.value = ""; } } const selectedProject = projects.find((p) => p.id === selectedProjectId); const selectedWorkflow = workflows.find((w) => w.id === selectedWorkflowId); // What to show in the directory depends on mode and toggle state const directoryStandalone = isProjectMode ? (fixedProjectDocs ?? []) : underProject ? [] : standaloneDocs; const directoryFolders = isProjectMode ? [] : underProject ? [] : directoryProjects; const flatProjectDocs: Document[] = !isProjectMode && underProject ? projectDocs : []; const directoryLoading = isProjectMode ? false : underProject ? loadingDocs : loadingDirectory; const showDirectory = isProjectMode || !underProject || !!selectedProjectId; const breadcrumbs = isProjectMode && projectName ? [ "Projects", `${projectName}${projectCmNumber ? ` (#${projectCmNumber})` : ""}`, "New Tabular Review", ] : ["Tabular Reviews", "New Tabular Review"]; return ( ) : ( ), onClick: () => fileInputRef.current?.click(), disabled: uploading, }} primaryAction={{ label: "Create", type: "submit", form: formId, disabled: !title.trim() || (underProject && !selectedProjectId), }} >
setTitle(e.target.value)} placeholder="Review name" className="w-full text-2xl font-serif text-gray-800 placeholder-gray-400 focus:outline-none bg-transparent" autoFocus /> {/* Workflow template */}

Workflow Template

{workflowDropdownOpen && !loadingWorkflows && (
{workflows.length > 0 && (
)} {workflows.map((wf) => ( ))}
)}
{/* Create under a project toggle */} {!isProjectMode &&
{underProject && (
{projectDropdownOpen && (
{projects.length === 0 ? (

No projects found

) : ( projects.map((p) => ( )) )}
)}
)}
} {/* File directory */} {showDirectory && (

Select Documents

)}
); }