From c1b77f89cdd94a8ff77a962ae7ccba82f65be787 Mon Sep 17 00:00:00 2001 From: m7amedez5511 Date: Thu, 18 Jun 2026 16:51:31 +0300 Subject: [PATCH] finsh user,car,driver pages also add validator layer to app build trip page --- Components/Driver/DriverDetailPanel.tsx | 461 ++++--------- Components/Driver/DriverFormModal.tsx | 216 ++++-- Components/Driver_Report/driverReport.tsx | 163 +++++ Components/Trip/Tripdeletemodal.tsx | 99 +++ Components/Trip/Tripformmodal.tsx | 497 ++++++++++++++ Components/Trip/tripe.tsx | 0 Components/Trip_Report/Tripreportpanel.tsx | 97 +++ Components/Trip_Report/tripe_report.tsx | 0 Components/User/UserFormModal.tsx | 77 ++- Components/car/CarDetailPanel.tsx | 94 +-- Components/car/CarFormModal.tsx | 175 ++--- Components/car/CarImageGallery.tsx | 247 ++----- app/NewOrder/page.tsx | 95 --- app/components/layout/Navbar.tsx | 4 +- app/components/layout/Sidebar.tsx | 19 +- app/{ => dashboard}/audit/page.tsx | 0 app/{ => dashboard}/branches/page.tsx | 0 app/{ => dashboard}/cars/page.tsx | 206 ++---- .../clients/[clientId]/addresses/page.tsx | 12 +- app/{ => dashboard}/clients/page.tsx | 10 +- app/dashboard/drivers/[driverId]/page.tsx | 624 ++++++++++++++++++ app/{ => dashboard}/drivers/page.tsx | 0 app/dashboard/layout.tsx | 5 +- app/{ => dashboard}/orders/page.tsx | 6 +- app/{ => dashboard}/roles/page.tsx | 0 app/dashboard/trips/[tripId]/page.tsx | 498 ++++++++++++++ app/{ => dashboard}/trips/page.tsx | 0 app/{ => dashboard}/users/page.tsx | 16 +- app/not_found/page.tsx | 7 + app/page.tsx | 246 +++++-- app/register/page.tsx | 146 ---- app/users/[userId]/page.tsx | 429 ------------ hooks/useCars.ts | 217 ++++++ package-lock.json | 45 +- package.json | 3 +- services/car.service.ts | 2 - services/driver.service.ts | 12 +- services/trip.service.ts | 114 ++++ types/car.ts | 86 ++- types/driver.ts | 3 + types/trip.ts | 160 +++++ validations/car.validator.ts | 236 +++++++ validations/driver.validator.ts | 207 ++++++ validations/trip.validator.ts | 194 ++++++ validations/user.validator.ts | 90 +++ 45 files changed, 4128 insertions(+), 1690 deletions(-) create mode 100644 Components/Trip/Tripdeletemodal.tsx create mode 100644 Components/Trip/Tripformmodal.tsx delete mode 100644 Components/Trip/tripe.tsx create mode 100644 Components/Trip_Report/Tripreportpanel.tsx delete mode 100644 Components/Trip_Report/tripe_report.tsx delete mode 100644 app/NewOrder/page.tsx rename app/{ => dashboard}/audit/page.tsx (100%) rename app/{ => dashboard}/branches/page.tsx (100%) rename app/{ => dashboard}/cars/page.tsx (66%) rename app/{ => dashboard}/clients/[clientId]/addresses/page.tsx (97%) rename app/{ => dashboard}/clients/page.tsx (96%) create mode 100644 app/dashboard/drivers/[driverId]/page.tsx rename app/{ => dashboard}/drivers/page.tsx (100%) rename app/{ => dashboard}/orders/page.tsx (98%) rename app/{ => dashboard}/roles/page.tsx (100%) create mode 100644 app/dashboard/trips/[tripId]/page.tsx rename app/{ => dashboard}/trips/page.tsx (100%) rename app/{ => dashboard}/users/page.tsx (93%) create mode 100644 app/not_found/page.tsx delete mode 100644 app/register/page.tsx delete mode 100644 app/users/[userId]/page.tsx create mode 100644 hooks/useCars.ts create mode 100644 services/trip.service.ts create mode 100644 types/trip.ts create mode 100644 validations/car.validator.ts create mode 100644 validations/driver.validator.ts create mode 100644 validations/trip.validator.ts create mode 100644 validations/user.validator.ts diff --git a/Components/Driver/DriverDetailPanel.tsx b/Components/Driver/DriverDetailPanel.tsx index f602da7..84f0db8 100644 --- a/Components/Driver/DriverDetailPanel.tsx +++ b/Components/Driver/DriverDetailPanel.tsx @@ -1,10 +1,10 @@ "use client"; - import { useCallback, useEffect, useState } from "react"; import { Spinner } from "../UI"; import { driverService } from "../../services/driver.service"; import { getStoredToken } from "../../lib/auth"; +import { DriverReportPanel } from "../Driver_Report/driverReport"; import type { Driver } from "../../types/driver"; import { DRIVER_STATUS_MAP, @@ -14,7 +14,6 @@ import { // ── Helpers ─────────────────────────────────────────────────────────────────── -/** Format an ISO date string to a readable Arabic date. */ function fmtDate(iso?: string | null): string { if (!iso) return "—"; return new Date(iso).toLocaleDateString("ar-SA", { @@ -24,19 +23,12 @@ function fmtDate(iso?: string | null): string { }); } -/** Returns true if the date is within 90 days in the future (or already past). */ function isExpiringSoon(iso?: string | null): boolean { if (!iso) return false; const diff = new Date(iso).getTime() - Date.now(); return diff <= 90 * 86_400_000; } -/** Build the full image URL via the proxy to avoid CORS issues. */ -function buildPhotoUrl(filename?: string | null): string | null { - if (!filename) return null; - return `/api/proxy/driver-photos/${filename}`; -} - // ── Sub-components ──────────────────────────────────────────────────────────── function DetailRow({ @@ -60,13 +52,7 @@ function DetailRow({ borderBottom: "1px solid var(--color-border)", }} > - + {label} (null); - const [reportUrl, setReportUrl] = useState(null); - - const handleGenerate = async () => { - setLoading(true); - setError(null); - setReportUrl(null); - try { - const token = getStoredToken(); - const res = await driverService.getDailyReport(driverId, date, token); - const url = ( - res as unknown as { data: { reportUrl: string } } - ).data?.reportUrl; - setReportUrl(url ?? null); - } catch (err: unknown) { - setError( - err instanceof Error ? err.message : "تعذّر إنشاء التقرير.", - ); - } finally { - setLoading(false); - } - }; +function PhotoCard({ + url, + label, +}: { + url?: string | null; + label: string; +}) { + const [imgError, setImgError] = useState(false); return ( -
-

+ + {label} + +

- إنشاء تقرير يومي -

- -
- {/* Date input */} -
- - { - setDate(e.target.value); - setReportUrl(null); - setError(null); - }} - style={{ - width: "100%", - height: 38, - padding: "0 0.625rem", - borderRadius: "var(--radius-md)", - border: "1px solid var(--color-border)", - background: "var(--color-surface)", - fontSize: 13, - color: "var(--color-text-primary)", - outline: "none", - fontFamily: "var(--font-sans)", - }} + {url && !imgError ? ( + // eslint-disable-next-line @next/next/no-img-element + {label} setImgError(true)} /> -
- - {/* Generate button */} - -
- - {/* Error */} - {error && ( -
- ⚠ {error} -
- )} - - {/* Success link */} - {reportUrl && ( -
- ✓ تم إنشاء التقرير بنجاح - - فتح التقرير ↗ - -
+ + + + + )} +
+ {url && !imgError && ( + + عرض الصورة ↗ + )}
); @@ -288,6 +166,7 @@ function ReportPanel({ driverId }: { driverId: string }) { interface DriverDetailPanelProps { driverId: string; onClose: () => void; + onEdit: (driver: Driver) => void; onDelete: (driver: Driver) => void; } @@ -296,12 +175,13 @@ interface DriverDetailPanelProps { export function DriverDetailPanel({ driverId, onClose, + onEdit, onDelete, }: DriverDetailPanelProps) { const [driver, setDriver] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); - const [imgError, setImgError] = useState(false); + const [avatarError, setAvatarError] = useState(false); // Fetch driver data const loadDriver = useCallback(async () => { @@ -312,9 +192,7 @@ export function DriverDetailPanel({ const res = await driverService.getById(driverId, token); setDriver((res as unknown as { data: Driver }).data); } catch (err: unknown) { - setError( - err instanceof Error ? err.message : "تعذّر تحميل بيانات السائق.", - ); + setError(err instanceof Error ? err.message : "تعذّر تحميل بيانات السائق."); } finally { setLoading(false); } @@ -326,14 +204,11 @@ export function DriverDetailPanel({ // Close on Escape key useEffect(() => { - const h = (e: KeyboardEvent) => { - if (e.key === "Escape") onClose(); - }; + const h = (e: KeyboardEvent) => { if (e.key === "Escape") onClose(); }; window.addEventListener("keydown", h); return () => window.removeEventListener("keydown", h); }, [onClose]); - const photoUrl = driver ? buildPhotoUrl(driver.photo) : null; const statusConfig = driver ? DRIVER_STATUS_MAP[driver.status] : null; return ( @@ -350,7 +225,7 @@ export function DriverDetailPanel({ }} /> - {/* Slide-in panel — from the left, mirroring CarDetailPanel */} + {/* Slide-in panel */}