"use client"; import { useState, useCallback } from "react"; import { Alert, Spinner, ArchiveButton } from "@/src/Components/UI"; import { DriverFormModal } from "@/src/Components/Driver/DriverFormModal"; import { DriverDeleteModal } from "@/src/Components/Driver/DriverDeleteModal"; import { ArchivedDrivers } from "@/src/Components/Driver/archive/ArchivedDrivers"; import { useDrivers } from "@/src/hooks/useDriver"; import { CreateDriverPayload, Driver, DRIVER_STATUS_MAP, UpdateDriverPayload } from "@/src/types/driver"; import { DriverDetailPanel } from "@/src/Components/Driver/DriverDetailPanel"; // ── Helpers ─────────────────────────────────────────────────────────────────── function fmtDate(iso?: string | null): string { if (!iso) return "—"; return new Date(iso).toLocaleDateString("ar-SA", { year: "numeric", month: "short", day: "numeric", }); } function expirySoon(iso?: string | null): boolean { if (!iso) return false; return (new Date(iso).getTime() - Date.now()) / 86_400_000 <= 90; } // ── Styles ──────────────────────────────────────────────────────────────────── const cardStyle: React.CSSProperties = { borderRadius: "var(--radius-xl)", border: "1px solid var(--color-border)", background: "var(--color-surface)", overflow: "hidden", boxShadow: "var(--shadow-card)", }; const thStyle: React.CSSProperties = { padding: "0.75rem 1.5rem", fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.2em", color: "var(--color-text-muted)", background: "var(--color-surface-muted)", borderBottom: "1px solid var(--color-border)", }; // Shared across header + rows — keep these in sync or columns will misalign. const ROW_GRID_COLUMNS = "2fr 1.2fr 1fr 1.1fr 1.1fr 1fr 0.8fr"; const iconBtnBase: React.CSSProperties = { width: 30, height: 30, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: "var(--radius-md)", cursor: "pointer", flexShrink: 0, }; // ── Page Component ──────────────────────────────────────────────────────────── export default function DriversPage() { const { drivers, loading, error, total, pages, page, search, setPage, handleSearch, clearError, createDriver, updateDriver, deleteDriver, notification, reload, } = useDrivers(); // ── Panel / modal state ─────────────────────────────────────────────────── const [selectedDriverId, setSelectedDriverId] = useState(null); const [formDriver, setFormDriver] = useState(null); const [deleteTarget, setDeleteTarget] = useState(null); const [deleting, setDeleting] = useState(false); // Bumped after a successful edit to force the detail panel to re-fetch const [panelRefreshKey, setPanelRefreshKey] = useState(0); // Archive browser modal open/closed const [archiveOpen, setArchiveOpen] = useState(false); // ── Handlers ────────────────────────────────────────────────────────────── const handleEdit = useCallback((driver: Driver) => { setSelectedDriverId(null); setFormDriver(driver); }, []); const handleDelete = useCallback((driver: Driver) => { setSelectedDriverId(null); setDeleteTarget(driver); }, []); const handleFormSubmit = useCallback( async ( payload: CreateDriverPayload | UpdateDriverPayload, isNew: boolean, ): Promise => { let ok: boolean; if (isNew) { ok = await createDriver( payload as CreateDriverPayload & { photo?: File; nationalPhoto?: File; driverCardPhoto?: File; }, ); } else { const id = (formDriver as Driver).id; ok = await updateDriver( id, payload as UpdateDriverPayload & { photo?: File; nationalPhoto?: File; driverCardPhoto?: File; }, ); // Re-fetch detail panel so updated status is visible immediately if (ok && selectedDriverId) setPanelRefreshKey((k) => k + 1); } return ok; }, [formDriver, createDriver, updateDriver, selectedDriverId], ); const handleConfirmDelete = useCallback(async () => { if (!deleteTarget) return; setDeleting(true); const ok = await deleteDriver(deleteTarget.id); setDeleting(false); if (ok) setDeleteTarget(null); }, [deleteTarget, deleteDriver]); // ── Render ──────────────────────────────────────────────────────────────── return ( <>
{/* ── Header ── */}

إدارة الكوادر

السائقون

إجمالي{" "} {total}{" "} سائق مسجل

{/* Search */}
handleSearch(e.target.value)} dir="rtl" style={{ width: "100%", height: 40, paddingRight: 36, paddingLeft: 12, borderRadius: "var(--radius-lg)", border: "1px solid var(--color-border)", background: "var(--color-surface)", fontSize: 13, color: "var(--color-text-primary)", outline: "none", fontFamily: "var(--font-sans)", }} />
{/* Add button */}
{/* ── Notifications ── */} {notification && ( )} {error && ( )} {/* ── Table ── */}
السائق الفرع الجنسية انتهاء الرخصة انتهاء الهوية الحالة إجراءات
{loading ? (
جارٍ التحميل…
) : drivers.length === 0 ? (

لا توجد نتائج {search && `لـ "${search}"`}

) : (
    {drivers.map((d, i) => { const statusCfg = DRIVER_STATUS_MAP[d.status] ?? DRIVER_STATUS_MAP.Inactive; const licWarn = expirySoon(d.licenseExpiry); const idWarn = expirySoon((d as Driver & { nationalIdExpiry?: string }).nationalIdExpiry); return (
  • setSelectedDriverId(d.id)} style={{ display: "grid", gridTemplateColumns: ROW_GRID_COLUMNS, alignItems: "center", gap: "0.5rem", padding: "0.875rem 1.5rem", borderBottom: "1px solid var(--color-border)", background: i % 2 !== 0 ? "var(--color-surface-muted)" : "transparent", fontSize: 13, cursor: "pointer", transition: "background 0.15s", }} onMouseEnter={(e) => (e.currentTarget.style.background = "var(--color-surface-hover, #F8FAFC)")} onMouseLeave={(e) => (e.currentTarget.style.background = i % 2 !== 0 ? "var(--color-surface-muted)" : "transparent")} >

    {d.name}

    {d.phone}

    {d.branch?.name ?? "—"} {d.nationality ?? "—"} {licWarn && "⚠ "}{fmtDate(d.licenseExpiry)} {idWarn && "⚠ "}{fmtDate((d as Driver & { nationalIdExpiry?: string }).nationalIdExpiry)} {statusCfg.label} {/* ── Inline row actions: edit / delete ── stopPropagation is required on both buttons so the click doesn't bubble up to the
  • onClick and open the detail panel as well. */}
  • ); })}
)} {/* ── Pagination ── */} {pages > 1 && (
صفحة{" "} {page}{" "} من{" "} {pages}
{[ { 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 => ( ))}
)}
{/* ── Detail panel — key forces re-fetch after successful edit ── */} {selectedDriverId && ( setSelectedDriverId(null)} onEdit={handleEdit} onDelete={handleDelete} /> )} {/* ── Form modal ── */} {formDriver !== null && ( setFormDriver(null)} onSubmit={handleFormSubmit} /> )} {/* ── Delete modal ── */} {deleteTarget && ( setDeleteTarget(null)} onConfirm={handleConfirmDelete} /> )} {/* ── Archive browser modal ── */} {archiveOpen && ( setArchiveOpen(false)} /> )} {/* ── Floating button to open the archive browser ── */} setArchiveOpen(true)} /> ); }