"use client"; import { useCallback, useEffect, useRef, useState } from "react"; import { useParams, useRouter } from "next/navigation"; import { Spinner } from "@/src/Components/UI"; import { TripFormModal } from "@/src/Components/Trip/Tripformmodal"; import { TripDeleteModal } from "@/src/Components/Trip/Tripdeletemodal"; import { TripReportPanel } from "@/src/Components/Trip_Report/Tripreportpanel"; import { tripService } from "@/src/services/trip.service"; import { getStoredToken } from "@/src/lib/auth"; import type { Trip, CreateTripPayload, UpdateTripPayload } from "@/src/types/trip"; import { TRIP_STATUS_MAP } from "@/src/types/trip"; import { Toast, type ToastNotification } from "@/src/Components/UI/Toast"; // ── API error extractor ──────────────────────────────────────────────────── // Same shape-walking logic as useTrip.ts — duplicated here on purpose so this // page no longer depends on the list hook for a single piece of UI feedback. function extractApiMessage(err: unknown, fallback: string): string { if (typeof err === "string" && err.trim()) return err.trim(); if (err && typeof err === "object") { const e = err as Record; const responseData = (e["response"] as Record | undefined)?.["data"]; if (responseData && typeof responseData === "object") { const rd = responseData as Record; if (typeof rd["message"] === "string" && rd["message"].trim()) return rd["message"]; if (Array.isArray(rd["message"])) return (rd["message"] as string[]).join(" — "); if (typeof rd["error"] === "string" && rd["error"].trim()) return rd["error"]; } if (typeof e["message"] === "string" && e["message"].trim()) return e["message"]; } return fallback; } // ── Helpers ─────────────────────────────────────────────────────────────────── function fmtDate(iso?: string | null): string { if (!iso) return "—"; return new Date(iso).toLocaleDateString("ar-SA", { year: "numeric", month: "long", day: "numeric", }); } function fmtDateTime(iso?: string | null): string { if (!iso) return "—"; return new Date(iso).toLocaleString("ar-SA", { dateStyle: "medium", timeStyle: "short", }); } // ── Sub-components ──────────────────────────────────────────────────────────── function SectionCard({ title, children, }: { title: string; children: React.ReactNode; }) { return (

{title}

{children}
); } function DetailRow({ label, value, mono = false, warn = false, }: { label: string; value: string; mono?: boolean; warn?: boolean; }) { return (
{label} {warn && value !== "—" ? "⚠ " : ""} {value}
); } function StatCard({ label, value, color, }: { label: string; value: number | string; color: string; }) { return (
{label} {value}
); } // ── Page ────────────────────────────────────────────────────────────────────── export default function TripDetailPage() { const params = useParams(); const router = useRouter(); const tripId = params?.tripId as string; const [trip, setTrip] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); // ── Modal state ─────────────────────────────────────────────────────────── const [editOpen, setEditOpen] = useState(false); const [deleteOpen, setDeleteOpen] = useState(false); const [deleting, setDeleting] = useState(false); // ── Notifications (standalone — no longer borrowed from the list hook) ─── const [notification, setNotification] = useState(null); const timerRef = useRef | null>(null); const notify = useCallback((n: ToastNotification) => { if (timerRef.current) clearTimeout(timerRef.current); setNotification(n); timerRef.current = setTimeout(() => setNotification(null), 4000); }, []); const dismissNotification = useCallback(() => { if (timerRef.current) clearTimeout(timerRef.current); setNotification(null); }, []); useEffect(() => () => { if (timerRef.current) clearTimeout(timerRef.current); }, []); // ── Load trip ───────────────────────────────────────────────────────────── const loadTrip = useCallback(async () => { if (!tripId) return; setLoading(true); setError(null); try { const token = getStoredToken(); const res = await tripService.getById(tripId, token); setTrip((res as unknown as { data: Trip }).data); } catch (err: unknown) { setError(err instanceof Error ? err.message : "تعذّر تحميل بيانات الرحلة."); } finally { setLoading(false); } }, [tripId]); useEffect(() => { loadTrip(); }, [loadTrip]); // ── Edit submit ─────────────────────────────────────────────────────────── const handleEditSubmit = useCallback( async ( payload: CreateTripPayload | UpdateTripPayload, _isNew: boolean, ): Promise => { if (!trip) return false; try { const token = getStoredToken(); const res = await tripService.update(trip.id, payload as UpdateTripPayload, token); const updated = (res as unknown as { data: Trip }).data; setTrip(updated); notify({ type: "success", message: "تم تحديث بيانات الرحلة بنجاح." }); return true; } catch (err) { notify({ type: "error", message: extractApiMessage(err, "تعذّر تحديث الرحلة.") }); return false; } }, [trip, notify], ); // ── Delete confirm ──────────────────────────────────────────────────────── const handleConfirmDelete = useCallback(async () => { if (!trip) return; setDeleting(true); try { const token = getStoredToken(); await tripService.delete(trip.id, token); router.push("/dashboard/trips"); } catch (err) { notify({ type: "error", message: extractApiMessage(err, "تعذّر حذف الرحلة.") }); setDeleting(false); } }, [trip, router, notify]); // ── Status config ───────────────────────────────────────────────────────── const statusConfig = trip ? TRIP_STATUS_MAP[trip.status] : null; // ── Render: Loading ─────────────────────────────────────────────────────── if (loading) { return (
جارٍ التحميل…
); } // ── Render: Error ───────────────────────────────────────────────────────── if (error || !trip) { return (

⚠ {error ?? "الرحلة غير موجودة"}

); } // ── Render: Trip detail ──────────────────────────────────────────────────── return ( <> {/* ── Toast notification ── */}
{/* ── Page header ── */}
{/* Back link */}
{/* Icon + title */}
{trip.title.charAt(0)}

ملف الرحلة

{trip.title}

#{trip.tripNumber} {statusConfig && ( {statusConfig.label} )}
{/* Actions */}
{/* ── Stats row ── */}
{/* ── Content grid ── */}
{/* Trip Info */} {trip.notes && } {trip.endReason && } {/* Driver */} {trip.driver && ( )} {/* Car */} {trip.car && ( )} {/* System Info */}
{/* ── Report section (full width) ── */}
{/* ── Edit modal ── */} {editOpen && ( setEditOpen(false)} onSubmit={handleEditSubmit} /> )} {/* ── Delete modal ── */} {deleteOpen && ( setDeleteOpen(false)} onConfirm={handleConfirmDelete} /> )} ); }