import { useState } from "react"; import type { FormEvent } from "react"; import { Database, FolderOpen, Settings2, SlidersHorizontal } from "lucide-react"; import type { Library } from "@/api/types"; import { Button } from "@/components/ui/button"; import { Dialog, DialogClose, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { cn } from "@/lib/utils"; import { AdvancedFields, FolderFields, GeneralFields, MetadataFields } from "./LibraryFormSections"; import { libraryTypeMeta } from "./libraryTypes"; import { LibraryPosterSection } from "./LibraryPosterSection"; import { useLibraryForm } from "./useLibraryForm"; import type { LibraryFormErrors } from "./useLibraryForm"; type SectionId = "general" | "folders" | "metadata" | "advanced"; const SECTIONS: Array<{ id: SectionId; label: string; icon: typeof Settings2; title: string; description: string; }> = [ { id: "general", label: "General", icon: Settings2, title: "General", description: "Name this library and choose the kind of media it holds.", }, { id: "folders", label: "Folders", icon: FolderOpen, title: "Folders", description: "Silo scans these folders for media and watches them for changes.", }, { id: "metadata", label: "Metadata", icon: Database, title: "Metadata", description: "Control where artwork and descriptions come from, and in which language.", }, { id: "advanced", label: "Advanced", icon: SlidersHorizontal, title: "Advanced", description: "Optional background processing for this library.", }, ]; function sectionForErrors(errors: LibraryFormErrors): SectionId | null { if (errors.name) return "general"; if (errors.paths) return "folders"; return null; } export interface LibraryEditorDialogProps { open: boolean; onOpenChange: (open: boolean) => void; library: Library | null; chapterThumbnailsSupported: boolean; } export function LibraryEditorDialog({ open, onOpenChange, library, chapterThumbnailsSupported, }: LibraryEditorDialogProps) { return ( onOpenChange(false)} /> ); } function LibraryEditorBody({ library, chapterThumbnailsSupported, onClose, }: { library: Library | null; chapterThumbnailsSupported: boolean; onClose: () => void; }) { const [section, setSection] = useState("general"); const form = useLibraryForm({ library, onClose }); const typeMeta = libraryTypeMeta(form.type); const folderCount = form.paths.filter((p) => p.trim()).length; const errorSections = new Set(); if (form.errors.name) errorSections.add("general"); if (form.errors.paths) errorSections.add("folders"); function handleSubmit(e: FormEvent) { e.preventDefault(); const result = form.submit(); if (!result.ok) { const target = sectionForErrors(result.errors); if (target) setSection(target); } } return ( {library ? "Edit Library" : "Add Library"} {library ? `Configure how “${library.name}” is scanned and matched.` : "Set up a new library from folders on your server."} setSection(value as SectionId)} orientation="vertical" className="min-h-0 flex-1 gap-0" > {SECTIONS.map(({ id, label, icon: Icon }) => ( {label} {errorSections.has(id) ? ( ) : id === "folders" && folderCount > 0 ? ( {folderCount} ) : null} ))} {SECTIONS.map(({ id, title, description }) => ( {title} {description} {id === "general" && ( : null} /> )} {id === "folders" && } {id === "metadata" && } {id === "advanced" && ( )} ))} {errorSections.size > 0 ? ( {[form.errors.name, form.errors.paths].filter(Boolean).join(" ")} ) : null} Cancel {form.isPending ? library ? "Saving…" : "Creating…" : library ? "Save Changes" : "Create Library"} ); }
{description}
{[form.errors.name, form.errors.paths].filter(Boolean).join(" ")}