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
This commit is contained in:
m7amedez5511
2026-06-23 15:54:07 +03:00
parent c1b77f89cd
commit db64b79fe3
140 changed files with 9266 additions and 2449 deletions

View File

@@ -3,9 +3,9 @@
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useEffect, useMemo } from "react";
import { useDashboardSummary } from "../../hooks/useDashboardSummary";
import { clearAuth, getStoredUser } from "../../lib/auth";
import { Spinner, Alert } from "../../Components/UI";
import { useDashboardSummary } from "@/src/hooks/useDashboardSummary";
import { clearAuth, getStoredUser } from "@/src/lib/auth";
import { Spinner, Alert } from "@/src/Components/UI";
export default function DashboardPage() {
const router = useRouter();
@@ -48,15 +48,15 @@ export default function DashboardPage() {
backdropFilter: "blur(16px)",
}}
>
<p style={{ fontSize: 11, letterSpacing: "0.35em", textTransform: "uppercase", color: "#67E8F9" }}>
<p style={{ fontSize: 11, letterSpacing: "0.35em", textTransform: "uppercase", color: "#67E8F9", textAlign: "start" }}>
لوحة العمليات
</p>
<div className="mt-4 flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between">
<div>
<h1 style={{ fontSize: "clamp(1.5rem,3vw,2rem)", fontWeight: 600, color: "var(--color-text-dark-primary)", margin: 0 }}>
<h1 style={{ fontSize: "clamp(1.5rem,3vw,2rem)", fontWeight: 600, color: "var(--color-text-dark-primary)", margin: 0, textAlign: "start" }}>
ذكاء الأسطول في لمحة سريعة
</h1>
<p style={{ marginTop: "0.75rem", maxWidth: 680, color: "var(--color-text-dark-muted)", fontSize: 14, lineHeight: 1.6 }}>
<p style={{ marginTop: "0.75rem", maxWidth: 680, color: "var(--color-text-dark-muted)", fontSize: 14, lineHeight: 1.6, textAlign: "start" }}>
عرض واضح لطلبات الأسطول وتنبيهات السلامة وتقدم الرحلات.
</p>
</div>
@@ -111,23 +111,28 @@ export default function DashboardPage() {
}}
>
<div style={{ height: 3, borderRadius: 999, background: item.accent, marginBottom: "1rem" }} />
<p style={{ fontSize: 11, letterSpacing: "0.25em", textTransform: "uppercase", color: "var(--color-text-dark-muted)" }}>
<p style={{ fontSize: 11, letterSpacing: "0.25em", textTransform: "uppercase", color: "var(--color-text-dark-muted)", textAlign: "start" }}>
{item.label}
</p>
<p style={{ fontSize: "2.25rem", fontWeight: 600, color: "var(--color-text-dark-primary)", marginTop: "0.5rem" }}>
<p style={{ fontSize: "2.25rem", fontWeight: 600, color: "var(--color-text-dark-primary)", marginTop: "0.5rem", textAlign: "start" }}>
{item.value}
</p>
</article>
))}
</div>
{/* ── Active trips + alerts ── */}
{/* ── Active trips + alerts ──
Column order in the template below stays [trips, alerts] —
same reading order as before. In RTL this now renders
trips on the right (read first) and alerts on the left,
which is the correct mirror; no class change needed (see
grid + RTL note in the project report). */}
<div className="grid gap-6 xl:grid-cols-[1.1fr_0.9fr]">
<article style={{ borderRadius: "var(--radius-2xl)", border: "1px solid var(--color-border-dark)", background: "var(--color-surface-dark-card)", padding: "1.5rem", boxShadow: "var(--shadow-card)" }}>
<div className="flex items-center justify-between">
<div>
<p style={{ fontSize: 11, letterSpacing: "0.25em", textTransform: "uppercase", color: "#67E8F9" }}>الرحلات النشطة</p>
<h2 style={{ fontSize: "1.25rem", fontWeight: 600, color: "var(--color-text-dark-primary)", marginTop: "0.5rem" }}>تقدم الرحلات</h2>
<p style={{ fontSize: 11, letterSpacing: "0.25em", textTransform: "uppercase", color: "#67E8F9", textAlign: "start" }}>الرحلات النشطة</p>
<h2 style={{ fontSize: "1.25rem", fontWeight: 600, color: "var(--color-text-dark-primary)", marginTop: "0.5rem", textAlign: "start" }}>تقدم الرحلات</h2>
</div>
<span style={{ borderRadius: "var(--radius-full)", background: "rgba(52,211,153,0.10)", padding: "0.25rem 0.75rem", fontSize: 11, color: "#A7F3D0" }}>
مباشر
@@ -138,44 +143,54 @@ export default function DashboardPage() {
<div key={trip.id} style={{ borderRadius: "var(--radius-xl)", border: "1px solid var(--color-border-dark)", background: "var(--color-surface-dark-raised)", padding: "1rem" }}>
<div className="flex items-center justify-between gap-3">
<div>
<p style={{ fontSize: 13, fontWeight: 600, color: "var(--color-text-dark-primary)" }}>{trip.tripNumber}</p>
<p style={{ fontSize: 13, color: "var(--color-text-dark-muted)" }}>{trip.title}</p>
<p style={{ fontSize: 13, fontWeight: 600, color: "var(--color-text-dark-primary)", textAlign: "start" }}>
<span className="ltr-embed">{trip.tripNumber}</span>
</p>
<p style={{ fontSize: 13, color: "var(--color-text-dark-muted)", textAlign: "start" }}>{trip.title}</p>
</div>
<span style={{ borderRadius: "var(--radius-full)", background: "rgba(103,232,249,0.10)", padding: "0.25rem 0.75rem", fontSize: 11, color: "#CFFAFE" }}>
{trip.progress}%
</span>
</div>
<div style={{ marginTop: "0.75rem", height: 6, borderRadius: 999, background: "rgba(255,255,255,0.08)" }}>
{/*
Progress fill: width % growing from the bar's
start edge is correct in both directions since
`width` itself is non-directional — the bar's
own inline-start (right, in RTL) is where the
fill begins, matching how the rest of the RTL
layout fills from the right. No change needed.
*/}
<div style={{ height: 6, borderRadius: 999, width: `${trip.progress}%`, background: "linear-gradient(90deg,#06B6D4,#34D399)" }} />
</div>
</div>
)) : (
<p style={{ fontSize: 13, color: "var(--color-text-dark-muted)" }}>لا توجد رحلات نشطة حالياً.</p>
<p style={{ fontSize: 13, color: "var(--color-text-dark-muted)", textAlign: "start" }}>لا توجد رحلات نشطة حالياً.</p>
)}
</div>
</article>
<article style={{ borderRadius: "var(--radius-2xl)", border: "1px solid var(--color-border-dark)", background: "var(--color-surface-dark-card)", padding: "1.5rem", boxShadow: "var(--shadow-card)" }}>
<p style={{ fontSize: 11, letterSpacing: "0.25em", textTransform: "uppercase", color: "#FCD34D" }}>تنبيهات الالتزام</p>
<h2 style={{ fontSize: "1.25rem", fontWeight: 600, color: "var(--color-text-dark-primary)", marginTop: "0.5rem" }}>التجديدات القادمة</h2>
<p style={{ fontSize: 11, letterSpacing: "0.25em", textTransform: "uppercase", color: "#FCD34D", textAlign: "start" }}>تنبيهات الالتزام</p>
<h2 style={{ fontSize: "1.25rem", fontWeight: 600, color: "var(--color-text-dark-primary)", marginTop: "0.5rem", textAlign: "start" }}>التجديدات القادمة</h2>
<div style={{ marginTop: "1.5rem", display: "flex", flexDirection: "column", gap: "0.75rem" }}>
{(alerts?.expiringCars || []).slice(0, 3).map((item, i) => (
<div key={`car-${i}`} style={{ borderRadius: "var(--radius-xl)", border: "1px solid rgba(251,191,36,0.20)", background: "rgba(251,191,36,0.06)", padding: "0.75rem 1rem", fontSize: 13, color: "var(--color-text-dark-primary)" }}>
<div key={`car-${i}`} style={{ borderRadius: "var(--radius-xl)", border: "1px solid rgba(251,191,36,0.20)", background: "rgba(251,191,36,0.06)", padding: "0.75rem 1rem", fontSize: 13, color: "var(--color-text-dark-primary)", textAlign: "start" }}>
{String((item as Record<string, unknown>).message || "Vehicle expiry alert")}
</div>
))}
{(alerts?.expiringDrivers || []).slice(0, 3).map((item, i) => (
<div key={`driver-${i}`} style={{ borderRadius: "var(--radius-xl)", border: "1px solid rgba(251,113,133,0.20)", background: "rgba(244,63,94,0.06)", padding: "0.75rem 1rem", fontSize: 13, color: "var(--color-text-dark-primary)" }}>
<div key={`driver-${i}`} style={{ borderRadius: "var(--radius-xl)", border: "1px solid rgba(251,113,133,0.20)", background: "rgba(244,63,94,0.06)", padding: "0.75rem 1rem", fontSize: 13, color: "var(--color-text-dark-primary)", textAlign: "start" }}>
{String((item as Record<string, unknown>).message || "Driver expiry alert")}
</div>
))}
{(alerts?.upcomingMaint || []).slice(0, 3).map((item, i) => (
<div key={`maint-${i}`} style={{ borderRadius: "var(--radius-xl)", border: "1px solid rgba(103,232,249,0.20)", background: "rgba(103,232,249,0.06)", padding: "0.75rem 1rem", fontSize: 13, color: "var(--color-text-dark-primary)" }}>
<div key={`maint-${i}`} style={{ borderRadius: "var(--radius-xl)", border: "1px solid rgba(103,232,249,0.20)", background: "rgba(103,232,249,0.06)", padding: "0.75rem 1rem", fontSize: 13, color: "var(--color-text-dark-primary)", textAlign: "start" }}>
{String((item as Record<string, unknown>).message || "Maintenance alert")}
</div>
))}
{!(alerts?.expiringCars?.length || alerts?.expiringDrivers?.length || alerts?.upcomingMaint?.length) && (
<p style={{ fontSize: 13, color: "var(--color-text-dark-muted)" }}>لا توجد تنبيهات حالياً.</p>
<p style={{ fontSize: 13, color: "var(--color-text-dark-muted)", textAlign: "start" }}>لا توجد تنبيهات حالياً.</p>
)}
</div>
</article>
@@ -184,21 +199,29 @@ export default function DashboardPage() {
{/* ── Security + endpoints ── */}
<div className="grid gap-6 lg:grid-cols-2">
<article style={{ borderRadius: "var(--radius-2xl)", border: "1px solid var(--color-border-dark)", background: "var(--color-surface-dark-card)", padding: "1.5rem", boxShadow: "var(--shadow-card)" }}>
<p style={{ fontSize: 11, letterSpacing: "0.25em", textTransform: "uppercase", color: "#C4B5FD" }}>الأمان</p>
<h2 style={{ fontSize: "1.25rem", fontWeight: 600, color: "var(--color-text-dark-primary)", marginTop: "0.5rem" }}>لمحة الحساب</h2>
<p style={{ fontSize: 11, letterSpacing: "0.25em", textTransform: "uppercase", color: "#C4B5FD", textAlign: "start" }}>الأمان</p>
<h2 style={{ fontSize: "1.25rem", fontWeight: 600, color: "var(--color-text-dark-primary)", marginTop: "0.5rem", textAlign: "start" }}>لمحة الحساب</h2>
<div style={{ marginTop: "1.5rem", display: "flex", flexDirection: "column", gap: "0.75rem" }}>
<div style={{ borderRadius: "var(--radius-xl)", border: "1px solid var(--color-border-dark)", background: "var(--color-surface-dark-raised)", padding: "0.875rem 1rem", fontSize: 13, color: "var(--color-text-dark-muted)" }}>
آخر تسجيل دخول: {data?.accountSecurity?.lastLogin || "—"}
<div style={{ borderRadius: "var(--radius-xl)", border: "1px solid var(--color-border-dark)", background: "var(--color-surface-dark-raised)", padding: "0.875rem 1rem", fontSize: 13, color: "var(--color-text-dark-muted)", textAlign: "start" }}>
آخر تسجيل دخول: <span className="ltr-embed">{data?.accountSecurity?.lastLogin || "—"}</span>
</div>
<div style={{ borderRadius: "var(--radius-xl)", border: "1px solid var(--color-border-dark)", background: "var(--color-surface-dark-raised)", padding: "0.875rem 1rem", fontSize: 13, color: "var(--color-text-dark-muted)" }}>
بيانات الجهاز: {data?.accountSecurity?.requestMeta ? JSON.stringify(data.accountSecurity.requestMeta) : "—"}
<div style={{ borderRadius: "var(--radius-xl)", border: "1px solid var(--color-border-dark)", background: "var(--color-surface-dark-raised)", padding: "0.875rem 1rem", fontSize: 13, color: "var(--color-text-dark-muted)", textAlign: "start" }}>
{/*
JSON.stringify output is structurally LTR (braces,
colons, commas read left-to-right regardless of
locale). Wrapping it in .ltr-embed prevents the
surrounding RTL paragraph from reordering the
punctuation — without this, nested objects can
render with their braces visually swapped.
*/}
بيانات الجهاز: <span className="ltr-embed">{data?.accountSecurity?.requestMeta ? JSON.stringify(data.accountSecurity.requestMeta) : "—"}</span>
</div>
</div>
</article>
<article style={{ borderRadius: "var(--radius-2xl)", border: "1px solid var(--color-border-dark)", background: "var(--color-surface-dark-card)", padding: "1.5rem", boxShadow: "var(--shadow-card)" }}>
<p style={{ fontSize: 11, letterSpacing: "0.25em", textTransform: "uppercase", color: "#6EE7B7" }}>خريطة الخلفية</p>
<h2 style={{ fontSize: "1.25rem", fontWeight: 600, color: "var(--color-text-dark-primary)", marginTop: "0.5rem" }}>النقاط النهائية</h2>
<p style={{ fontSize: 11, letterSpacing: "0.25em", textTransform: "uppercase", color: "#6EE7B7", textAlign: "start" }}>خريطة الخلفية</p>
<h2 style={{ fontSize: "1.25rem", fontWeight: 600, color: "var(--color-text-dark-primary)", marginTop: "0.5rem", textAlign: "start" }}>النقاط النهائية</h2>
<ul style={{ marginTop: "1.5rem", display: "flex", flexDirection: "column", gap: "0.75rem", listStyle: "none", padding: 0 }}>
{[
"/v1/dashboard/summary — نظرة عامة تشغيلية",
@@ -206,8 +229,18 @@ export default function DashboardPage() {
"/v1/orders — دورة شحن الطلبات",
"/v1/trip — تنظيم الرحلات",
].map((ep) => (
<li key={ep} style={{ borderRadius: "var(--radius-xl)", border: "1px solid var(--color-border-dark)", background: "var(--color-surface-dark-raised)", padding: "0.875rem 1rem", fontSize: 12, fontFamily: "var(--font-mono)", color: "var(--color-text-dark-muted)" }}>
{ep}
<li key={ep} style={{ borderRadius: "var(--radius-xl)", border: "1px solid var(--color-border-dark)", background: "var(--color-surface-dark-raised)", padding: "0.875rem 1rem", fontSize: 12, fontFamily: "var(--font-mono)", color: "var(--color-text-dark-muted)", textAlign: "start" }}>
{/*
Each entry mixes an LTR API path with an Arabic
description. Splitting on the em-dash and
isolating only the path keeps the route string
from reading backwards while letting the Arabic
half flow naturally in the paragraph's own
direction.
*/}
<span className="ltr-embed">{ep.split(" — ")[0]}</span>
{" — "}
{ep.split(" — ")[1]}
</li>
))}
</ul>