"use client"; import { useCallback, useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import { useTrips } from "@/src/hooks/useTrip"; import { TripFormModal } from "@/src/Components/Trip/Tripformmodal"; import { TripDeleteModal } from "@/src/Components/Trip/Tripdeletemodal"; import { ArchivedTripList } from "@/src/Components/Trip/archive/ArchivedTripList"; import { Alert, Spinner, ArchiveButton } from "@/src/Components/UI"; import { Toast } from "@/src/Components/UI/Toast"; import type { Trip, TripStatus, CreateTripPayload, UpdateTripPayload, } from "@/src/types/trip"; import { TRIP_STATUS_MAP } from "@/src/types/trip"; // ── Status badge — same visual pattern as Driver's status badge ───────────── function StatusBadge({ status }: { status: TripStatus }) { const s = TRIP_STATUS_MAP[status]; return ( {s.label} ); } // ── Archived trips modal — unchanged wrapper, kept as-is ──────────────────── function ArchivedTripsModal({ onClose }: { onClose: () => void }) { const router = useRouter(); useEffect(() => { const h = (e: KeyboardEvent) => { if (e.key === "Escape") onClose(); }; window.addEventListener("keydown", h); return () => window.removeEventListener("keydown", h); }, [onClose]); return (
{ if (e.target === e.currentTarget) onClose(); }} style={{ position: "fixed", inset: 0, zIndex: 70, background: "rgba(15,23,42,0.6)", backdropFilter: "blur(4px)", display: "flex", alignItems: "flex-start", justifyContent: "center", padding: "2rem 1rem", overflowY: "auto", }} >
e.stopPropagation()} style={{ width: "100%", maxWidth: 920, background: "var(--color-surface-sunken)", borderRadius: "var(--radius-xl)", border: "1px solid var(--color-border)", boxShadow: "0 24px 64px rgba(0,0,0,.2)", overflow: "hidden", }} >

أرشيف الرحلات

{/* Was pointing at the normal trip page — send it to the archived route instead */} router.push(`/dashboard/trips/archived/${trip.id}`) } />
); } // ── Page ────────────────────────────────────────────────────────────────────── export default function TripsPage() { const router = useRouter(); // All list state + mutations now come from the hook, same as useDrivers // is used on the Driver page. No direct tripService calls in this file. const { trips, total, pages, loading, error, page, setPage, search, handleSearch, status, handleStatusFilter, createTrip, updateTrip, deleteTrip, notification, dismissNotification, clearError, } = useTrips(); const [showForm, setShowForm] = useState(false); const [editTrip, setEditTrip] = useState(null); const [deleteTarget, setDeleteTarget] = useState(null); const [deleting, setDeleting] = useState(false); const [archiveOpen, setArchiveOpen] = useState(false); // Debounced search input, same pattern as the Driver page's search box const [searchInput, setSearchInput] = useState(search); useEffect(() => { const t = setTimeout(() => handleSearch(searchInput), 400); return () => clearTimeout(t); // eslint-disable-next-line react-hooks/exhaustive-deps }, [searchInput]); const handleEdit = useCallback((trip: Trip) => { setEditTrip(trip); setShowForm(true); }, []); const handleDelete = useCallback((trip: Trip) => { setDeleteTarget(trip); }, []); // ── Create / update — delegates to the hook (hook fires the toast) ─────── const handleSubmit = async ( payload: CreateTripPayload | UpdateTripPayload, isNew: boolean, ): Promise => { if (isNew) { return createTrip(payload as CreateTripPayload); } return updateTrip(editTrip!.id, payload as UpdateTripPayload); }; // ── Delete confirm — delegates to the hook ──────────────────────────────── const handleConfirmDelete = async () => { if (!deleteTarget) return; setDeleting(true); const ok = await deleteTrip(deleteTarget.id); setDeleting(false); if (ok) setDeleteTarget(null); }; return (
{/* ── Header ── */}

إدارة العمليات

الرحلات

إجمالي{" "} {total} {" "} رحلة مسجلة

{/* Search */}
setSearchInput(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)", }} />
{/* Status filter */} {/* Archive button */} {/* Add button */}
{/* ── Error handling: Alert banner for list/API errors ── Same pattern as the Driver page: a persistent banner tied to the hook's `error` state, dismissible via `clearError`. */} {error && } {/* ── Table ── */}
رقم الرحلة العنوان السائق السيارة الحالة البدء الانتهاء إجراءات
{loading ? (
جارٍ التحميل…
) : trips.length === 0 ? (

لا توجد رحلات مطابقة {search && `لـ "${search}"`}

) : (
    {trips.map((trip, i) => (
  • router.push(`/dashboard/trips/${trip.id}`)} style={{ display: "grid", gridTemplateColumns: "1.5fr 2fr 1.3fr 1.3fr 1fr 1.1fr 1.1fr 0.8fr", 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") } > {trip.tripNumber} {trip.title} {trip.driver?.name ?? "—"} {trip.car ? `${trip.car.manufacturer} ${trip.car.model}` : "—"} {trip.startTime ? new Date(trip.startTime).toLocaleString("ar-SA", { dateStyle: "short", timeStyle: "short", }) : "—"} {trip.endTime ? new Date(trip.endTime).toLocaleString("ar-SA", { dateStyle: "short", timeStyle: "short", }) : "—"} {/* Inline row actions — stopPropagation so the click does not also trigger navigation to the detail page. */}
    e.stopPropagation()} >
  • ))}
)} {/* ── Pagination — same pattern as Driver page ── */} {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) => ( ))}
)}
{/* ── Form modal ── */} {showForm && ( setShowForm(false)} onSubmit={async (payload, isNew) => { const ok = await handleSubmit(payload, isNew); if (ok) setShowForm(false); return ok; }} /> )} {/* ── Delete modal ── */} {deleteTarget && ( setDeleteTarget(null)} onConfirm={handleConfirmDelete} /> )} {/* ── Archive browser modal ── */} {archiveOpen && ( setArchiveOpen(false)} /> )} {/* ── Floating archive button — same component Driver page uses ── */} setArchiveOpen(true)} label="الأرشيف" />
); }