import { useCallback, useEffect, useRef, useState } from "react"; import { api, type Folder } from "./api"; /** * Dropdown checklist of the project's folders. Ticking folders restricts the videos * shown/counted to those folders (admins verify only some folders; the rest are * backup/misc). None ticked = consider all folders. Admin only. */ export function FoldersPicker({ projectId, onChange }: { projectId: number; onChange: () => void }) { const [open, setOpen] = useState(false); const [folders, setFolders] = useState([]); const [busy, setBusy] = useState(false); const [err, setErr] = useState(null); const ref = useRef(null); const load = useCallback(async () => { try { setFolders(await api.folders(projectId)); } catch (e) { setErr(String(e)); } }, [projectId]); useEffect(() => { if (open) void load(); }, [open, load]); useEffect(() => { if (!open) return; const h = (e: MouseEvent) => { if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false); }; document.addEventListener("mousedown", h); return () => document.removeEventListener("mousedown", h); }, [open]); const includedCount = folders.filter((f) => f.included).length; const commit = async (next: Folder[]) => { setFolders(next); setBusy(true); setErr(null); try { await api.setFolders(projectId, next.filter((f) => f.included).map((f) => f.folder)); onChange(); } catch (e) { setErr(String(e)); await load(); } finally { setBusy(false); } }; const toggle = (folder: string) => commit(folders.map((f) => (f.folder === folder ? { ...f, included: !f.included } : f))); const considerAll = () => commit(folders.map((f) => ({ ...f, included: false }))); const label = includedCount === 0 ? "Folders: all ▾" : `Folders: ${includedCount}/${folders.length} ▾`; return (
{open && (
Tick folders to verify. None ticked = all folders shown.
{folders.map((f) => ( ))} {folders.length === 0 &&
no folders — sync the project first
}
{err &&
⚠ {err}
}
{includedCount === 0 ? "all folders shown" : `${includedCount} selected`}
)}
); }