import { useState } from "react"; import { motion, AnimatePresence } from "framer-motion"; import FormModal from "./FormModal"; import FormField from "./FormField"; import AdminDatePicker from "./AdminDatePicker"; import ConfirmModal from "./ConfirmModal"; import useReducedMotion from "../hooks/useReducedMotion"; import { ResolvedCell, PlanCategory, planCategoryLabel, cellProjectLabel, } from "../lib/queries/plan"; import { formatDate } from "../utils/formatters"; interface Project { id: number; name: string; project_number?: string; } export type PlanCellModalMode = | { kind: "closed" } | { kind: "create"; userId: number; date: string } | { kind: "edit-range"; entryId: number; userId: number; date: string; range: { date_from: string; date_to: string; project_id: number | null; category: string; note: string; }; } | { kind: "edit-override"; overrideId: number; userId: number; date: string; cell: ResolvedCell; } | { kind: "day-in-range"; entryId: number; userId: number; date: string; range: { date_from: string; date_to: string; project_id: number | null; category: string; note: string; }; } | { kind: "view"; userId: number; date: string; cell: ResolvedCell }; interface Props { open: boolean; mode: PlanCellModalMode; projects: Project[]; categories: PlanCategory[]; onClose: () => void; onSaveEntry: (body: any) => Promise; onUpdateEntry: (id: number, body: any) => Promise; onDeleteEntry: (id: number) => Promise; onSaveOverride: (body: any) => Promise; onUpdateOverride: (id: number, body: any) => Promise; onDeleteOverride: (id: number) => Promise; onCreateOverrideFromRange: ( entryId: number, userId: number, date: string, ) => Promise; onSwitchToEditRange: (entryId: number, userId: number, date: string) => void; } export default function PlanCellModal(props: Props) { const { open, mode, onClose } = props; if (!open || mode.kind === "closed") return null; if (mode.kind === "view") return ; if (mode.kind === "day-in-range") return ; return ; } function EditForm(props: Props) { const { mode, onClose, onSaveEntry, onUpdateEntry, onDeleteEntry, onSaveOverride, onUpdateOverride, onDeleteOverride, projects, } = props; const [submitting, setSubmitting] = useState(false); const [confirmDelete, setConfirmDelete] = useState(false); // Narrow mode to the kinds EditForm actually handles. The call site in // PlanCellModal only passes "create" | "edit-range" | "edit-override" but // the parameter type is the full union, so we narrow explicitly here. if ( mode.kind !== "create" && mode.kind !== "edit-range" && mode.kind !== "edit-override" ) { return null; } const isOverride = mode.kind === "edit-override"; const activeCategories = props.categories.filter((c) => c.is_active); const initial = (() => { if (mode.kind === "create") { return { date_from: mode.date, date_to: mode.date, is_range: false, project_id: null as number | null, // Default to "work" when it's active, otherwise the first active // category, so a new entry never starts on a retired key. category: activeCategories.some((c) => c.key === "work") ? "work" : (activeCategories[0]?.key ?? "work"), note: "", }; } if (mode.kind === "edit-range") { return { date_from: mode.range.date_from, date_to: mode.range.date_to, is_range: mode.range.date_from !== mode.range.date_to, project_id: mode.range.project_id, category: mode.range.category, note: mode.range.note, }; } // mode.kind === "edit-override" (narrowed above) return { date_from: mode.date, date_to: mode.date, is_range: false, project_id: mode.cell.project_id, category: mode.cell.category, note: mode.cell.note, }; })(); const [dateFrom, setDateFrom] = useState(initial.date_from); const [dateTo, setDateTo] = useState(initial.date_to); const [isRange, setIsRange] = useState(initial.is_range); const [projectId, setProjectId] = useState(initial.project_id); const [category, setCategory] = useState(initial.category); const [note, setNote] = useState(initial.note); const title = mode.kind === "create" ? "Nový záznam plánu" : mode.kind === "edit-range" ? "Upravit rozsah" : "Upravit přepsání dne"; const handleSubmit = async () => { setSubmitting(true); try { if (mode.kind === "create") { const userId = mode.userId; await onSaveEntry({ user_id: userId, date_from: dateFrom, date_to: isRange ? dateTo : dateFrom, project_id: projectId, category, note, }); } else if (mode.kind === "edit-range") { await onUpdateEntry(mode.entryId, { date_from: dateFrom, date_to: isRange ? dateTo : dateFrom, project_id: projectId, category, note, }); } else { await onUpdateOverride(mode.overrideId, { project_id: projectId, category, note, }); } onClose(); } finally { setSubmitting(false); } }; const handleDelete = async () => { setSubmitting(true); try { if (mode.kind === "edit-range") { await onDeleteEntry(mode.entryId); } else if (mode.kind === "edit-override") { await onDeleteOverride(mode.overrideId); } onClose(); } finally { setSubmitting(false); } }; return ( <> setConfirmDelete(true)} disabled={submitting} > Smazat ) : null } > {!isOverride && ( )} {!isOverride && isRange && ( )}