import { useState } from "react"; import { useAlert } from "../context/AlertContext"; import { useAuth } from "../context/AuthContext"; import { Link } from "react-router-dom"; import Forbidden from "../components/Forbidden"; import { Skeleton } from "boneyard-js/react"; import ProjectsFixture from "../fixtures/ProjectsFixture"; import { motion } from "framer-motion"; import ConfirmModal from "../components/ConfirmModal"; import apiFetch from "../utils/api"; import { formatDate, czechPlural } from "../utils/formatters"; import SortIcon from "../components/SortIcon"; import useTableSort from "../hooks/useTableSort"; import { useQueryClient } from "@tanstack/react-query"; import { usePaginatedQuery } from "../hooks/usePaginatedQuery"; import { projectListOptions } from "../lib/queries/projects"; import Pagination from "../components/Pagination"; const API_BASE = "/api/admin"; const STATUS_LABELS: Record = { aktivni: "Aktivní", dokonceny: "Dokončený", zruseny: "Zrušený", }; const STATUS_CLASSES: Record = { aktivni: "admin-badge-project-aktivni", dokonceny: "admin-badge-project-dokonceny", zruseny: "admin-badge-project-zruseny", }; interface Project { id: number; project_number: string; name: string; customer_name: string; responsible_user_name: string; status: string; start_date: string; end_date: string; order_id?: number; order_number?: string; } export default function Projects() { const alert = useAlert(); const { hasPermission } = useAuth(); const { sort, order, handleSort, activeSort } = useTableSort("project_number"); const [search, setSearch] = useState(""); const [page, setPage] = useState(1); const [deletingId, setDeletingId] = useState(null); const [deleteTarget, setDeleteTarget] = useState(null); const [deleteFiles, setDeleteFiles] = useState(false); const queryClient = useQueryClient(); const { items: projects, pagination, isPending, isFetching, } = usePaginatedQuery( projectListOptions({ search, sort, order, page }), ); if (!hasPermission("projects.view")) return ; const handleDelete = async () => { if (!deleteTarget) return; setDeletingId(deleteTarget.id); try { const res = await apiFetch(`${API_BASE}/projects/${deleteTarget.id}`, { method: "DELETE", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ delete_files: deleteFiles }), }); const data = await res.json(); if (data.success) { alert.success(data.message || "Projekt byl smazán"); queryClient.invalidateQueries({ queryKey: ["projects"] }); queryClient.invalidateQueries({ queryKey: ["orders"] }); queryClient.invalidateQueries({ queryKey: ["offers"] }); } else { alert.error(data.error || "Nepodařilo se smazat projekt"); } } catch { alert.error("Chyba připojení"); } finally { setDeletingId(null); setDeleteTarget(null); setDeleteFiles(false); } }; return ( }>

Projekty

{pagination?.total ?? projects.length}{" "} {czechPlural( pagination?.total ?? projects.length, "projekt", "projekty", "projektů", )}

{ setSearch(e.target.value); setPage(1); }} className="admin-form-input" placeholder="Hledat podle čísla, názvu nebo zákazníka..." />
{projects.length === 0 ? (

Zatím nejsou žádné projekty.

Vytvořte první projekt tlačítkem výše nebo automaticky při vytvoření objednávky.

) : (
{(projects as Project[]).map((p) => ( ))}
handleSort("project_number")} > Číslo{" "} handleSort("name")} > Název{" "} Zákazník Zodpovědná osoba handleSort("status")} > Stav{" "} handleSort("start_date")} > Začátek{" "} handleSort("end_date")} > Konec{" "} Objednávka Akce
{p.project_number} {p.name || "—"} {p.customer_name || "—"} {p.responsible_user_name || "—"} {STATUS_LABELS[p.status] || p.status} {formatDate(p.start_date)} {formatDate(p.end_date)} {p.order_id ? ( {p.order_number} ) : ( "—" )}
{!p.order_id && hasPermission("projects.create") && ( )}
)}
{ setDeleteTarget(null); setDeleteFiles(false); }} onConfirm={handleDelete} title="Smazat projekt" message={ <> Opravdu chcete smazat projekt {deleteTarget?.project_number}? } confirmText="Smazat" type="danger" loading={!!deletingId} />
); }