From db64b79fe338fe485d8cbfb8705e0a290a7d951b Mon Sep 17 00:00:00 2001 From: m7amedez5511 Date: Tue, 23 Jun 2026 15:54:07 +0300 Subject: [PATCH] first action update user pages . 2-update driver pages [fixed image display and notyfi] 3-update car pages [fixed image] 4-build tripe pages crud 5-build some role pages 6-build audit page 7-update ui compounants 8-update saidebar and topbar 9-cheange view to be ar view 10-cheange stractcher to be app,src 11-add validation layer by yup 12-add api image-proxy to broke image corse bloken --- Components/Trip/Tripformmodal.tsx | 497 ---- Components/Trip_Report/Tripreportpanel.tsx | 97 - Components/UI/ModalProps.tsx | 54 - Components/UI/PageHeader.tsx | 29 - Components/UI/Select.tsx | 52 - Components/UI/Textarea.tsx | 41 - app/api/clear-cookie/route.ts | 2 +- app/api/proxy-image/[...imagePath]/route.ts | 35 + app/api/proxy/[...path]/route.ts | 46 +- app/components/layout/Navbar.tsx | 21 +- app/components/layout/Sidebar.tsx | 184 +- app/components/layout/Topbar.tsx | 23 +- app/dashboard/audit/page.tsx | 223 +- app/dashboard/branches/page.tsx | 494 +++- app/dashboard/cars/page.tsx | 14 +- .../clients/[clientId]/addresses/page.tsx | 16 +- app/dashboard/clients/page.tsx | 14 +- app/dashboard/drivers/[driverId]/page.tsx | 565 ++-- app/dashboard/drivers/page.tsx | 151 +- app/dashboard/layout.tsx | 17 +- app/dashboard/orders/page.tsx | 6 +- app/dashboard/page.tsx | 93 +- app/dashboard/role-permission/page.tsx | 238 ++ app/dashboard/roles/page.tsx | 144 +- app/dashboard/trips/[tripId]/page.tsx | 650 ++--- app/dashboard/trips/page.tsx | 376 ++- app/dashboard/users/page.tsx | 19 +- app/forbidden/page.tsx | 65 +- app/globals.css | 18 +- app/layout.tsx | 57 +- app/login/page.tsx | 10 +- app/not_found/page.tsx | 85 +- app/page.tsx | 2 +- hooks/useDriver.ts | 152 -- lib/formatters.ts | 20 - lib/order-status.ts | 28 - next.config.ts | 12 +- package-lock.json | 2301 ++++++++++++++++- package.json | 1 + services/driver.service.ts | 154 -- services/index.ts | 7 - .../Components}/Admen/admen.tsx | 0 .../Components}/Client/Addressformmodal.tsx | 2 +- .../Components}/Client/ClientAddressForm.tsx | 2 +- .../Components}/Client/ClientForm.tsx | 2 +- .../Components}/Client/Clientformmodal.tsx | 2 +- .../Components}/Client/Clienttable.tsx | 2 +- .../Components}/Client/Deleteconfirmmodal.tsx | 2 +- .../Components}/Client/Toast.tsx | 2 +- src/Components/Client/index.ts | 5 + .../Client_Adress/clientAdress.tsx | 0 .../Components}/Driver/DriverDeleteModal.tsx | 2 +- .../Components}/Driver/DriverDetailPanel.tsx | 208 +- .../Components}/Driver/DriverFormModal.tsx | 38 +- src/Components/Driver/DriverPhotos.tsx | 84 + src/Components/Driver/index.ts | 4 + .../Driver_Report/driverReport.tsx | 4 +- {Components => src/Components}/Home/home.tsx | 0 .../Components}/Order/order.tsx | 12 +- .../Components}/Trip/Tripdeletemodal.tsx | 2 +- src/Components/Trip/Tripformmodal.tsx | 732 ++++++ src/Components/Trip/index.ts | 2 + .../Trip_Report/Tripreportpanel.tsx | 120 + {Components => src/Components}/UI/Alert.tsx | 2 +- {Components => src/Components}/UI/Badge.tsx | 0 {Components => src/Components}/UI/Button.tsx | 2 +- .../Components}/UI/ConfirmDialog.tsx | 14 +- .../Components}/UI/EmptyState.tsx | 0 {Components => src/Components}/UI/Input.tsx | 2 +- src/Components/UI/ModalProps.tsx | 130 + src/Components/UI/PageHeader.tsx | 60 + src/Components/UI/Select.tsx | 54 + {Components => src/Components}/UI/Spinner.tsx | 2 +- src/Components/UI/Textarea.tsx | 64 + src/Components/UI/Toast.tsx | 101 + {Components => src/Components}/UI/index.ts | 10 +- .../Components}/User/DeleteConfirmModal.tsx | 2 +- {Components => src/Components}/User/Toast.tsx | 2 +- .../Components}/User/UserDetailModal.tsx | 6 +- .../Components}/User/UserFormModal.tsx | 8 +- .../Components}/User/UserTable.tsx | 2 +- src/Components/User/index.ts | 5 + .../Components}/car/CarDeleteModal.tsx | 5 +- .../Components}/car/CarDetailPanel.tsx | 8 +- .../Components}/car/CarFormModal.tsx | 11 +- .../Components}/car/CarImageGallery.tsx | 6 +- src/Components/car/index.ts | 4 + src/Components/role/DeleteRoleModal.tsx | 130 + src/Components/role/RoleDetailModal.tsx | 375 +++ src/Components/role/RoleFormModal.tsx | 510 ++++ src/Components/role/RoleTable.tsx | 300 +++ src/Components/role/RoleToast.tsx | 57 + src/Components/role/index.ts | 5 + {hooks => src/hooks}/useCars.ts | 9 +- {hooks => src/hooks}/useClientAddresses.ts | 6 +- src/hooks/useClientOrders.ts | 45 + {hooks => src/hooks}/useClients.ts | 6 +- {hooks => src/hooks}/useDashboardSummary.ts | 6 +- src/hooks/useDriver.ts | 211 ++ {hooks => src/hooks}/useOrder.ts | 4 +- src/hooks/useRole.ts | 284 ++ src/hooks/useTrip.ts | 227 ++ {hooks => src/hooks}/useUser.ts | 21 +- {lib => src/lib}/api.ts | 0 {lib => src/lib}/auth.ts | 44 +- src/lib/formatters.ts | 41 + src/lib/order-status.ts | 42 + {lib => src/lib}/session.ts | 4 +- {lib => src/lib}/utils.ts | 0 {middleware => src/middleware}/middleware.ts | 0 {services => src/services}/api.ts | 2 +- {services => src/services}/auth.service.ts | 2 +- {services => src/services}/car.service.ts | 2 +- {services => src/services}/client.service.ts | 4 +- .../services}/clientAddress.service.ts | 3 +- .../services}/dashboard.service.ts | 2 +- src/services/driver.service.ts | 273 ++ src/services/index.ts | 11 + {services => src/services}/order.service.ts | 2 +- src/services/role.service.ts | 95 + {services => src/services}/trip.service.ts | 43 +- {services => src/services}/user.service.ts | 6 +- {styles => src/styles}/tokens.css | 54 +- {types => src/types}/auth.ts | 0 {types => src/types}/branch.ts | 0 {types => src/types}/car.ts | 2 +- {types => src/types}/client.ts | 0 {types => src/types}/dashboard.ts | 0 {types => src/types}/driver.ts | 0 {types => src/types}/order.ts | 0 {types => src/types}/role.ts | 0 {types => src/types}/trip.ts | 4 - {types => src/types}/user.ts | 0 src/utils/helperFun.ts | 51 + {utils => src/utils}/logo.tsx | 0 .../validations}/car.validator.ts | 0 .../validations}/driver.validator.ts | 2 +- .../validations}/trip.validator.ts | 6 +- .../validations}/user.validator.ts | 0 utils/helperFun.ts | 84 - 140 files changed, 9266 insertions(+), 2449 deletions(-) delete mode 100644 Components/Trip/Tripformmodal.tsx delete mode 100644 Components/Trip_Report/Tripreportpanel.tsx delete mode 100644 Components/UI/ModalProps.tsx delete mode 100644 Components/UI/PageHeader.tsx delete mode 100644 Components/UI/Select.tsx delete mode 100644 Components/UI/Textarea.tsx create mode 100644 app/api/proxy-image/[...imagePath]/route.ts create mode 100644 app/dashboard/role-permission/page.tsx delete mode 100644 hooks/useDriver.ts delete mode 100644 lib/formatters.ts delete mode 100644 lib/order-status.ts delete mode 100644 services/driver.service.ts delete mode 100644 services/index.ts rename {Components => src/Components}/Admen/admen.tsx (100%) rename {Components => src/Components}/Client/Addressformmodal.tsx (99%) rename {Components => src/Components}/Client/ClientAddressForm.tsx (98%) rename {Components => src/Components}/Client/ClientForm.tsx (98%) rename {Components => src/Components}/Client/Clientformmodal.tsx (99%) rename {Components => src/Components}/Client/Clienttable.tsx (99%) rename {Components => src/Components}/Client/Deleteconfirmmodal.tsx (98%) rename {Components => src/Components}/Client/Toast.tsx (96%) create mode 100644 src/Components/Client/index.ts rename {Components => src/Components}/Client_Adress/clientAdress.tsx (100%) rename {Components => src/Components}/Driver/DriverDeleteModal.tsx (98%) rename {Components => src/Components}/Driver/DriverDetailPanel.tsx (77%) rename {Components => src/Components}/Driver/DriverFormModal.tsx (95%) create mode 100644 src/Components/Driver/DriverPhotos.tsx create mode 100644 src/Components/Driver/index.ts rename {Components => src/Components}/Driver_Report/driverReport.tsx (97%) rename {Components => src/Components}/Home/home.tsx (100%) rename {Components => src/Components}/Order/order.tsx (95%) rename {Components => src/Components}/Trip/Tripdeletemodal.tsx (98%) create mode 100644 src/Components/Trip/Tripformmodal.tsx create mode 100644 src/Components/Trip/index.ts create mode 100644 src/Components/Trip_Report/Tripreportpanel.tsx rename {Components => src/Components}/UI/Alert.tsx (98%) rename {Components => src/Components}/UI/Badge.tsx (100%) rename {Components => src/Components}/UI/Button.tsx (98%) rename {Components => src/Components}/UI/ConfirmDialog.tsx (70%) rename {Components => src/Components}/UI/EmptyState.tsx (100%) rename {Components => src/Components}/UI/Input.tsx (98%) create mode 100644 src/Components/UI/ModalProps.tsx create mode 100644 src/Components/UI/PageHeader.tsx create mode 100644 src/Components/UI/Select.tsx rename {Components => src/Components}/UI/Spinner.tsx (98%) create mode 100644 src/Components/UI/Textarea.tsx create mode 100644 src/Components/UI/Toast.tsx rename {Components => src/Components}/UI/index.ts (59%) rename {Components => src/Components}/User/DeleteConfirmModal.tsx (98%) rename {Components => src/Components}/User/Toast.tsx (96%) rename {Components => src/Components}/User/UserDetailModal.tsx (98%) rename {Components => src/Components}/User/UserFormModal.tsx (97%) rename {Components => src/Components}/User/UserTable.tsx (99%) create mode 100644 src/Components/User/index.ts rename {Components => src/Components}/car/CarDeleteModal.tsx (96%) rename {Components => src/Components}/car/CarDetailPanel.tsx (97%) rename {Components => src/Components}/car/CarFormModal.tsx (98%) rename {Components => src/Components}/car/CarImageGallery.tsx (98%) create mode 100644 src/Components/car/index.ts create mode 100644 src/Components/role/DeleteRoleModal.tsx create mode 100644 src/Components/role/RoleDetailModal.tsx create mode 100644 src/Components/role/RoleFormModal.tsx create mode 100644 src/Components/role/RoleTable.tsx create mode 100644 src/Components/role/RoleToast.tsx create mode 100644 src/Components/role/index.ts rename {hooks => src/hooks}/useCars.ts (97%) rename {hooks => src/hooks}/useClientAddresses.ts (97%) create mode 100644 src/hooks/useClientOrders.ts rename {hooks => src/hooks}/useClients.ts (97%) rename {hooks => src/hooks}/useDashboardSummary.ts (85%) create mode 100644 src/hooks/useDriver.ts rename {hooks => src/hooks}/useOrder.ts (98%) create mode 100644 src/hooks/useRole.ts create mode 100644 src/hooks/useTrip.ts rename {hooks => src/hooks}/useUser.ts (90%) rename {lib => src/lib}/api.ts (100%) rename {lib => src/lib}/auth.ts (58%) create mode 100644 src/lib/formatters.ts create mode 100644 src/lib/order-status.ts rename {lib => src/lib}/session.ts (90%) rename {lib => src/lib}/utils.ts (100%) rename {middleware => src/middleware}/middleware.ts (100%) rename {services => src/services}/api.ts (98%) rename {services => src/services}/auth.service.ts (92%) rename {services => src/services}/car.service.ts (99%) rename {services => src/services}/client.service.ts (93%) rename {services => src/services}/clientAddress.service.ts (93%) rename {services => src/services}/dashboard.service.ts (69%) create mode 100644 src/services/driver.service.ts create mode 100644 src/services/index.ts rename {services => src/services}/order.service.ts (97%) create mode 100644 src/services/role.service.ts rename {services => src/services}/trip.service.ts (73%) rename {services => src/services}/user.service.ts (93%) rename {styles => src/styles}/tokens.css (60%) rename {types => src/types}/auth.ts (100%) rename {types => src/types}/branch.ts (100%) rename {types => src/types}/car.ts (99%) rename {types => src/types}/client.ts (100%) rename {types => src/types}/dashboard.ts (100%) rename {types => src/types}/driver.ts (100%) rename {types => src/types}/order.ts (100%) rename {types => src/types}/role.ts (100%) rename {types => src/types}/trip.ts (97%) rename {types => src/types}/user.ts (100%) create mode 100644 src/utils/helperFun.ts rename {utils => src/utils}/logo.tsx (100%) rename {validations => src/validations}/car.validator.ts (100%) rename {validations => src/validations}/driver.validator.ts (98%) rename {validations => src/validations}/trip.validator.ts (97%) rename {validations => src/validations}/user.validator.ts (100%) delete mode 100644 utils/helperFun.ts diff --git a/Components/Trip/Tripformmodal.tsx b/Components/Trip/Tripformmodal.tsx deleted file mode 100644 index 7f45026..0000000 --- a/Components/Trip/Tripformmodal.tsx +++ /dev/null @@ -1,497 +0,0 @@ -"use client"; - -import { useEffect, useRef, useState } from "react"; -import * as yup from "yup"; -import { Alert, Spinner } from "../UI"; -import { get } from "@/services/api"; -import { getStoredToken } from "@/lib/auth"; -import { createTripSchema, updateTripSchema } from "@/validations/trip.validator"; -import type { TripSchemaErrors } from "@/validations/trip.validator"; -import type { - Trip, - TripStatus, - CreateTripPayload, - UpdateTripPayload, -} from "@/types/trip"; - -// ── Shared styles ──────────────────────────────────────────────────────────── - -const inputBase: React.CSSProperties = { - width: "100%", - height: 40, - padding: "0 0.75rem", - 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)", -}; - -const labelStyle: React.CSSProperties = { - display: "flex", - flexDirection: "column", - gap: 6, - fontSize: 12, - fontWeight: 600, - color: "var(--color-text-secondary)", -}; - -const errorTextStyle: React.CSSProperties = { - fontSize: 11, - color: "var(--color-danger)", - fontWeight: 500, -}; - -const sectionHeadingStyle: React.CSSProperties = { - fontSize: 11, - letterSpacing: "0.25em", - textTransform: "uppercase", - color: "var(--color-text-hint)", - fontWeight: 700, - margin: "0.5rem 0 0", -}; - -const optionalLabelStyle: React.CSSProperties = { - fontSize: 10, - fontWeight: 500, - color: "var(--color-text-hint)", - marginRight: 4, -}; - -// ── Driver / Car / Branch minimal types ───────────────────────────────────── - -interface DriverOption { id: string; name: string; phone: string; status: string; } -interface CarOption { id: string; manufacturer: string; model: string; plateNumber: string; status?: string; } -interface BranchOption { id: string; name: string; } - -// ── Props ──────────────────────────────────────────────────────────────────── - -interface TripFormModalProps { - editTrip: Trip | null; - onClose: () => void; - onSubmit: ( - payload: CreateTripPayload | UpdateTripPayload, - isNew: boolean, - ) => Promise; -} - -// ── Component ──────────────────────────────────────────────────────────────── - -export function TripFormModal({ editTrip, onClose, onSubmit }: TripFormModalProps) { - const isNew = editTrip === null; - - // ── Dropdown options ────────────────────────────────────────────────────── - const [drivers, setDrivers] = useState([]); - const [cars, setCars] = useState([]); - const [branches, setBranches] = useState([]); - - useEffect(() => { - const token = getStoredToken(); - // Fetch active drivers - get<{ data: { data: DriverOption[] } }>("driver?limit=100&status=Active", token) - .then(res => setDrivers((res as unknown as { data: { data: DriverOption[] } }).data?.data ?? [])) - .catch(() => {}); - // Fetch active cars - get<{ data: { data: CarOption[] } }>("cars?limit=100&status=Active", token) - .then(res => setCars((res as unknown as { data: { data: CarOption[] } }).data?.data ?? [])) - .catch(() => {}); - // Fetch branches - get<{ data: { data: BranchOption[] } }>("branches?limit=100", token) - .then(res => setBranches((res as unknown as { data: { data: BranchOption[] } }).data?.data ?? [])) - .catch(() => {}); - }, []); - - // ── Form state ──────────────────────────────────────────────────────────── - const [title, setTitle] = useState(editTrip?.title ?? ""); - const [driverId, setDriverId] = useState(editTrip?.driverId ?? ""); - const [carId, setCarId] = useState(editTrip?.carId ?? ""); - const [branchId, setBranchId] = useState(editTrip?.branchId ?? ""); - const [status, setStatus] = useState(editTrip?.status ?? "Scheduled"); - const [startTime, setStartTime] = useState(editTrip?.startTime?.slice(0, 16) ?? ""); - const [endTime, setEndTime] = useState(editTrip?.endTime?.slice(0, 16) ?? ""); - const [collectedCount, setCollectedCount] = useState( - editTrip?.collectedCount != null ? String(editTrip.collectedCount) : "", - ); - const [deliveredCount, setDeliveredCount] = useState( - editTrip?.deliveredCount != null ? String(editTrip.deliveredCount) : "", - ); - const [returnedCount, setReturnedCount] = useState( - editTrip?.returnedCount != null ? String(editTrip.returnedCount) : "", - ); - const [totalCashCollected, setTotalCashCollected] = useState( - editTrip?.totalCashCollected != null ? String(editTrip.totalCashCollected) : "", - ); - const [notes, setNotes] = useState(editTrip?.notes ?? ""); - const [endReason, setEndReason] = useState(editTrip?.endReason ?? ""); - const [reason, setReason] = useState(""); // update-only - - const [errors, setErrors] = useState({}); - const [saving, setSaving] = useState(false); - const [apiError, setApiError] = useState(""); - const firstRef = useRef(null); - - useEffect(() => { firstRef.current?.focus(); }, []); - useEffect(() => { - const h = (e: KeyboardEvent) => { if (e.key === "Escape") onClose(); }; - window.addEventListener("keydown", h); - return () => window.removeEventListener("keydown", h); - }, [onClose]); - - // ── Error style helper ──────────────────────────────────────────────────── - const inputStyle = (field: keyof TripSchemaErrors): React.CSSProperties => ({ - ...inputBase, - ...(errors[field] ? { borderColor: "var(--color-danger)", background: "#FEF2F2" } : {}), - }); - - const clearErr = (field: keyof TripSchemaErrors) => - setErrors(p => ({ ...p, [field]: undefined })); - - // ── Submit ──────────────────────────────────────────────────────────────── - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - - const raw: Record = { - title: title || undefined, - driverId: driverId || undefined, - carId: carId || undefined, - branchId: branchId || undefined, - status: status || undefined, - startTime: startTime ? `${startTime}:00.000Z` : undefined, - endTime: endTime ? `${endTime}:00.000Z` : undefined, - collectedCount: collectedCount !== "" ? Number(collectedCount) : undefined, - deliveredCount: deliveredCount !== "" ? Number(deliveredCount) : undefined, - returnedCount: returnedCount !== "" ? Number(returnedCount) : undefined, - totalCashCollected: totalCashCollected !== "" ? Number(totalCashCollected) : undefined, - notes: notes || undefined, - endReason: endReason || undefined, - ...(!isNew && reason ? { reason } : {}), - }; - - try { - const schema = isNew ? createTripSchema : updateTripSchema; - await schema.validate(raw, { abortEarly: false }); - } catch (err) { - if (err instanceof yup.ValidationError) { - const map: TripSchemaErrors = {}; - err.inner.forEach(e => { - if (e.path) (map as Record)[e.path] = e.message; - }); - setErrors(map); - } - return; - } - - setSaving(true); - setApiError(""); - try { - const ok = await onSubmit(raw as CreateTripPayload | UpdateTripPayload, isNew); - if (ok) onClose(); - else setApiError("حدث خطأ أثناء الحفظ. يرجى المحاولة مرة أخرى."); - } catch (err) { - setApiError(err instanceof Error ? err.message : "حدث خطأ غير متوقع."); - } finally { - setSaving(false); - } - }; - - return ( -
{ if (e.target === e.currentTarget) onClose(); }} - style={{ - position: "fixed", inset: 0, zIndex: 60, - background: "rgba(15,23,42,0.55)", backdropFilter: "blur(4px)", - display: "flex", alignItems: "flex-start", justifyContent: "center", - padding: "2rem 1rem", overflowY: "auto", - }} - > -
e.stopPropagation()} - style={{ - width: "100%", maxWidth: 700, - background: "var(--color-surface)", - borderRadius: "var(--radius-xl)", - border: "1px solid var(--color-border)", - boxShadow: "0 24px 56px rgba(0,0,0,.2)", - overflow: "hidden", - }} - > - {/* Header */} -
-

- {isNew ? "إضافة رحلة جديدة" : "تعديل بيانات الرحلة"} -

- -
- - {/* Form */} -
- - {apiError && ( - {apiError} - )} - - {/* ── Section: أساسيات الرحلة ── */} -

أساسيات الرحلة

- - {/* Title */} - - -
- {/* Driver */} - - - {/* Car */} - -
- -
- {/* Branch */} - - - {/* Status */} - -
- - {/* ── Section: التوقيت ── */} -

التوقيت

- -
- - - -
- - {/* ── Section: الأعداد والمبالغ ── */} -

الأعداد والمبالغ

- -
- - - - - - - -
- - {/* ── Section: ملاحظات ── */} -

ملاحظات

- -
-