"use client"; import { useCallback, useState } from "react"; import { Spinner, Alert, ArchiveButton, ConfirmDialog, Toast, EmptyState, Button } from "@/src/Components/UI"; import { CarFormModal,CarDetailPanel } from "@/src/Components/car"; import { ArchivedCarsModal } from "@/src/Components/car/archive/Archivedcarsmodal"; import { CarMaintenanceFormModal } from "@/src/Components/Car_Maintanance/CarMaintananceFormModal"; import { useCars, useCarMutations, useToast } from "@/src/hooks/useCars"; import { useCarMaintenanceMutations } from "@/src/hooks/UseCarsMaintanance"; import { fmtDateShort, isExpiringSoon, STATUS_MAP, INS_MAP } from "@/src/types/car"; import type { Car, CreateCarPayload, UpdateCarPayload } from "@/src/types/car"; import type { CreateMaintenancePayload, UpdateMaintenancePayload } from "@/src/types/carMaintanance"; import Header from "@/src/Components/UI/Header"; // ── CarCard ─────────────────────────────────────────────────────────────────── function CarCard({ car, onClick, onSendToMaintenance, }: { car: Car; onClick: () => void; onSendToMaintenance: (car: Car) => void; }) { const status = STATUS_MAP[car.currentStatus]; const ins = car.insuranceStatus ? INS_MAP[car.insuranceStatus] : null; const regWarn = isExpiringSoon(car.registrationExpiryDate); // Maintenance status can ONLY be set via this button's flow (POST // cars/:carId/maintenance flips it on the backend). Disable rather than // hide it once the car is already in maintenance or inactive, and explain why. const maintenanceDisabled = car.currentStatus === "InMaintenance" || car.currentStatus === "Inactive"; const maintenanceDisabledReason = car.currentStatus === "InMaintenance" ? "المركبة في الصيانة بالفعل" : car.currentStatus === "Inactive" ? "لا يمكن إرسال مركبة غير نشطة للصيانة" : undefined; return (
{ if (e.key === "Enter" || e.key === " ") onClick(); }} aria-label={`${car.manufacturer} ${car.model} — ${car.plateLetters} ${car.plateNumber}`} style={{ borderRadius: "var(--radius-xl)", border: "1px solid var(--color-border)", background: "var(--color-surface)", overflow: "hidden", boxShadow: "var(--shadow-card)", cursor: "pointer", transition: "box-shadow 200ms, transform 200ms", }} onMouseEnter={e => { (e.currentTarget as HTMLElement).style.boxShadow = "0 8px 24px rgba(37,99,235,.12)"; (e.currentTarget as HTMLElement).style.transform = "translateY(-2px)"; }} onMouseLeave={e => { (e.currentTarget as HTMLElement).style.boxShadow = "var(--shadow-card)"; (e.currentTarget as HTMLElement).style.transform = "translateY(0)"; }} > {/* Colour accent bar by status */}
{/* Manufacturer + model */}

{car.manufacturer} {car.model}

{car.year}{car.color ? ` · ${car.color}` : ""}

{/* Status badge */} {status.label}
{/* Plate number */}
رقم اللوحة {car.plateLetters} {car.plateNumber}
{/* Key attributes grid */}
الفرع {car.branch?.name ?? "—"}
التأمين {ins?.label ?? "—"}
انتهاء الاستمارة {regWarn && "⚠ "}{fmtDateShort(car.registrationExpiryDate)}
الطاقة {car.capacity != null ? car.capacity : "—"}
{/* Send to Maintenance quick action — kept custom (amber accent isn't one of Button's variants: primary/secondary/ghost/danger). Same rationale as IconBtn: forcing it into an existing variant would misrepresent this as a routine action rather than the maintenance-triggering one it is. */} {/* Footer CTA hint */}

اضغط لعرض التفاصيل ←

); } // ── Page ────────────────────────────────────────────────────────────────────── export default function CarsPage() { const [search, setSearch] = useState(""); const [page, setPage] = useState(1); // Modal state const [detailId, setDetailId] = useState(null); const [formTarget, setFormTarget] = useState(false); // false = closed const [deleteTarget, setDeleteTarget] = useState(null); const [archiveOpen, setArchiveOpen] = useState(false); const [maintenanceTarget, setMaintenanceTarget] = useState(null); const { toast, notify } = useToast(); const { cars, loading, error, total, pages, loadCars, removeCar, setError } = useCars(page, search); // Need a stable ref to the current edit target for the mutation hook const getEditTarget = useCallback(() => formTarget instanceof Object && formTarget !== null ? formTarget as Car : null, [formTarget]); const { deleting, handleFormSubmit, handleDeleteConfirm } = useCarMutations({ onSuccess: (msg) => { notify({ type: "success", message: msg }); loadCars(); }, onError: (msg) => notify({ type: "error", message: msg }), onDeleted: (id) => { removeCar(id); setDeleteTarget(null); }, getEditTarget, }); const handleDelete = async () => { if (!deleteTarget) return; await handleDeleteConfirm(deleteTarget); }; // "Send to Maintenance" mutation — carId is bound to whichever car the // person just clicked. Errors surface inline inside the modal's own // apiError state (its default behavior), not through the outer toast — // onError is intentionally a no-op here. const { handleFormSubmit: handleMaintenanceSubmit } = useCarMaintenanceMutations({ carId: maintenanceTarget?.id ?? "", onSuccess: (msg) => { notify({ type: "success", message: msg }); loadCars(); }, onError: () => {}, onDeleted: () => {}, getEditTarget: () => null, }); // ── Render ────────────────────────────────────────────────────────────────── return ( <> {detailId && ( setDetailId(null)} onEdit={(car) => { setDetailId(null); setFormTarget(car); }} onDelete={(car) => { setDetailId(null); setDeleteTarget(car); }} /> )} {formTarget !== false && ( setFormTarget(false)} onSubmit={(payload: CreateCarPayload | UpdateCarPayload, isNew: boolean) => handleFormSubmit(payload, isNew).then((ok) => { if (ok) setFormTarget(false); return ok; }) } /> )} setDeleteTarget(null)} onConfirm={handleDelete} title="حذف المركبة" description={`هل أنت متأكد من حذف ${deleteTarget?.manufacturer ?? ""} ${deleteTarget?.model ?? ""} (${deleteTarget?.plateLetters ?? ""} ${deleteTarget?.plateNumber ?? ""})؟ لا يمكن التراجع عن هذا الإجراء.`} /> {maintenanceTarget && ( setMaintenanceTarget(null)} onSubmit={(payload: CreateMaintenancePayload | UpdateMaintenancePayload, isNew: boolean) => handleMaintenanceSubmit(payload, isNew) } /> )} {archiveOpen && ( setArchiveOpen(false)} /> )}
{/* ── Header ── */}
{}} setPage={setPage} title="المركبات" mainTitle="إدارة المركبات" name="مركبة" isAudit={false} onAdd={() => setFormTarget(null)}/> {/* Error alert */} {error && setError(null)} />} {/* ── Loading ── */} {loading ? (
جارٍ تحميل المركبات…
) : cars.length === 0 ? ( setFormTarget(null)}> إضافة مركبة )} /> ) : ( /* ── Card grid ── */
{cars.map((car) => ( setDetailId(car.id)} onSendToMaintenance={(c) => setMaintenanceTarget(c)} /> ))}
)} {/* ── Pagination ── */} {pages > 1 && (
صفحة {page} من{" "} {pages} {" · "} {total} مركبة
{[ { label: "← السابق", action: () => setPage(p => Math.max(1, p - 1)), disabled: page === 1 }, { label: "التالي →", action: () => setPage(p => Math.min(pages, p + 1)), disabled: page === pages }, ].map((btn) => ( ))}
)}
{/* Floating button to open the archive browser */} setArchiveOpen(true)} /> ); }