fix: resolve permission fallback bug, remove debug code, and cleanup duplication

Logic Errors
------------
- Sidebar: fix permissions fallback so a user with no permissions gets
  zero access instead of falling back to the full nav list
  (user?.permissions ?? [] instead of ?? navSections.flatMap(...))
- carMaintanance.service / UseCarsMaintanance: add pagination to the
  maintenance records fetch instead of loading the entire list at once
- api.ts: redact sensitive fields (password, token) before logging the
  request body in console.debug, to avoid leaking credentials/PII

Code Flow Problems
-------------------
- OrderFormModal: remove leftover console.log/debug statements and the
  redundant onClick handler on the submit button
- auth: remove the unused src/service/auth.service.ts (axios) and keep
  only src/services/auth.service.ts (fetch); fix useAuth.ts import path
  from
This commit is contained in:
m7amedez5511
2026-07-19 14:57:48 +03:00
parent bbde177f4a
commit 538111d726
82 changed files with 1441 additions and 2261 deletions

View File

@@ -1,100 +0,0 @@
"use client";
import { useEffect } from "react";
import { Spinner } from "../UI";
import type { Driver } from "@/src/types/driver";
interface DriverDeleteModalProps {
driver: Driver;
deleting: boolean;
onCancel: () => void;
onConfirm: () => void;
}
export function DriverDeleteModal({ driver, deleting, onCancel, onConfirm }: DriverDeleteModalProps) {
useEffect(() => {
const h = (e: KeyboardEvent) => { if (e.key === "Escape") onCancel(); };
window.addEventListener("keydown", h);
return () => window.removeEventListener("keydown", h);
}, [onCancel]);
return (
<div
role="alertdialog" aria-modal="true" aria-labelledby="driver-del-title"
onClick={e => { if (e.target === e.currentTarget) onCancel(); }}
style={{
position: "fixed", inset: 0, zIndex: 60,
background: "rgba(15,23,42,0.55)", backdropFilter: "blur(4px)",
display: "flex", alignItems: "center", justifyContent: "center", padding: "1rem",
}}
>
<div
onClick={e => e.stopPropagation()}
style={{
width: "100%", maxWidth: 420,
background: "var(--color-surface)",
borderRadius: "var(--radius-xl)",
border: "1px solid #FECACA",
boxShadow: "0 20px 48px rgba(0,0,0,.18)",
padding: "2rem",
display: "flex", flexDirection: "column", gap: "1rem",
textAlign: "center",
}}
>
{/* Icon */}
<div style={{
width: 52, height: 52, margin: "0 auto", borderRadius: "50%",
background: "#FEF2F2", border: "1px solid #FECACA",
display: "flex", alignItems: "center", justifyContent: "center",
}}>
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#DC2626" strokeWidth="2">
<polyline points="3 6 5 6 21 6" />
<path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" />
<path d="M10 11v6M14 11v6" />
<path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2" />
</svg>
</div>
<div>
<h2 id="driver-del-title" style={{ fontSize: 17, fontWeight: 700, color: "var(--color-text-primary)", margin: 0 }}>
حذف السائق
</h2>
<p style={{ marginTop: 8, fontSize: 13, color: "var(--color-text-muted)", lineHeight: 1.6 }}>
هل أنت متأكد من حذف{" "}
<strong style={{ color: "var(--color-text-primary)" }}>{driver.name}</strong>
{" "}(
<span style={{ fontFamily: "var(--font-mono)", fontSize: 12 }}>
{driver.phone}
</span>
)؟ لا يمكن التراجع عن هذا الإجراء.
</p>
</div>
<div style={{ display: "flex", gap: "0.5rem" }}>
<button type="button" onClick={onCancel} disabled={deleting}
style={{
flex: 1, height: 40, borderRadius: "var(--radius-md)",
border: "1px solid var(--color-border)", background: "var(--color-surface)",
fontSize: 13, fontWeight: 600, color: "var(--color-text-secondary)",
cursor: deleting ? "not-allowed" : "pointer", fontFamily: "var(--font-sans)",
}}>
إلغاء
</button>
<button type="button" onClick={onConfirm} disabled={deleting}
style={{
flex: 1, height: 40, borderRadius: "var(--radius-md)",
border: "none", background: "#DC2626",
fontSize: 13, fontWeight: 700, color: "#FFF",
cursor: deleting ? "not-allowed" : "pointer",
display: "flex", alignItems: "center", justifyContent: "center", gap: 8,
fontFamily: "var(--font-sans)", opacity: deleting ? 0.7 : 1,
}}>
{deleting && <Spinner size="sm" className="text-white" />}
{deleting ? "جارٍ الحذف…" : "تأكيد الحذف"}
</button>
</div>
</div>
</div>
);
}

View File

@@ -12,8 +12,6 @@ import {
NATIONAL_ID_TYPE_MAP,
} from "@/src/types/driver";
// ── Helpers ───────────────────────────────────────────────────────────────────
function fmtDate(iso?: string | null): string {
if (!iso) return "—";
return new Date(iso).toLocaleDateString("ar-SA", {
@@ -28,8 +26,6 @@ function isExpiringSoon(iso?: string | null): boolean {
return new Date(iso).getTime() - Date.now() <= 90 * 86_400_000;
}
// ── Sub-components ────────────────────────────────────────────────────────────
function DetailRow({
label,
value,
@@ -89,10 +85,6 @@ function SectionHeading({ title }: { title: string }) {
);
}
// ── PhotoCard ─────────────────────────────────────────────────────────────────
// key={url} on the <img> forces a full remount whenever the URL changes,
// which clears any stale onError state from a previously failed load.
function PhotoCard({ url, label }: { url?: string | null; label: string }) {
const [imgError, setImgError] = useState(false);
@@ -161,8 +153,6 @@ function PhotoCard({ url, label }: { url?: string | null; label: string }) {
);
}
// ── Props ─────────────────────────────────────────────────────────────────────
interface DriverDetailPanelProps {
driverId: string;
onClose: () => void;
@@ -170,8 +160,6 @@ interface DriverDetailPanelProps {
onDelete: (driver: Driver) => void;
}
// ── Component ─────────────────────────────────────────────────────────────────
export function DriverDetailPanel({
driverId,
onClose,
@@ -187,8 +175,8 @@ export function DriverDetailPanel({
setError(null);
try {
const token = getStoredToken();
const res = await driverService.getById(driverId, token);
setDriver((res as unknown as { data: Driver }).data);
const data = await driverService.getById(driverId, token);
setDriver(data);
} catch (err: unknown) {
setError(err instanceof Error ? err.message : "تعذّر تحميل بيانات السائق.");
} finally {
@@ -208,7 +196,6 @@ export function DriverDetailPanel({
return (
<>
{/* Backdrop */}
<div
onClick={onClose}
style={{
@@ -220,7 +207,6 @@ export function DriverDetailPanel({
}}
/>
{/* Slide-in panel */}
<aside
aria-label="تفاصيل السائق"
style={{
@@ -238,7 +224,6 @@ export function DriverDetailPanel({
overflowY: "hidden",
}}
>
{/* ── Header ── */}
<div
style={{
padding: "1.25rem 1.5rem",
@@ -249,7 +234,6 @@ export function DriverDetailPanel({
>
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 12 }}>
<div style={{ display: "flex", alignItems: "center", gap: 12 }}>
{/* Avatar — key={photoUrl} forces remount on photo change */}
<div
style={{
width: 56,
@@ -314,7 +298,6 @@ export function DriverDetailPanel({
</div>
</div>
{/* ── Scrollable content ── */}
<div style={{ flex: 1, overflowY: "auto", padding: "1.25rem 1.5rem" }}>
{loading && (
<div style={{ display: "flex", alignItems: "center", gap: 12, padding: "2rem 0" }}>
@@ -338,7 +321,6 @@ export function DriverDetailPanel({
{driver && !loading && (
<>
{/* Status badges */}
<div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: "1rem" }}>
{statusConfig && (
<span style={{
@@ -469,7 +451,6 @@ export function DriverDetailPanel({
)}
</div>
{/* ── Footer actions ── */}
{driver && (
<div
style={{
@@ -537,10 +518,6 @@ export function DriverDetailPanel({
);
}
// ── AvatarImg ─────────────────────────────────────────────────────────────────
// Separate component so key={src} forces a full remount on photo change,
// avoiding stale onError state from a previously failed load.
function AvatarImg({ src, name }: { src: string; name: string }) {
const [error, setError] = useState(false);

View File

@@ -72,27 +72,27 @@ export function ArchivedDriverDetailModal({ driverId, onClose }: ArchivedDriverD
}, [onClose]);
// fetch archived driver details + status history on mount
useEffect(() => {
let cancelled = false;
(async () => {
try {
const token = getStoredToken();
const [driverRes, historyRes] = await Promise.all([
archivedDriverService.getById(driverId, token),
archivedDriverService.getStatusHistory(driverId, token),
]);
if (!cancelled) {
setDriver(driverRes.data);
setHistory(historyRes.data ?? []);
}
} catch {
if (!cancelled) setError("تعذّر تحميل بيانات السائق المؤرشف. يرجى المحاولة لاحقاً.");
} finally {
if (!cancelled) setLoading(false);
useEffect(() => {
let cancelled = false;
(async () => {
try {
const token = getStoredToken();
const [driverData, historyList] = await Promise.all([
archivedDriverService.getByIdUnwrapped(driverId, token),
archivedDriverService.getStatusHistoryUnwrapped(driverId, token),
]);
if (!cancelled) {
setDriver(driverData);
setHistory(historyList ?? []);
}
})();
return () => { cancelled = true; };
}, [driverId]);
} catch {
if (!cancelled) setError("تعذّر تحميل بيانات السائق المؤرشف. يرجى المحاولة لاحقاً.");
} finally {
if (!cancelled) setLoading(false);
}
})();
return () => { cancelled = true; };
}, [driverId]);
// ── helpers ───────────────────────────────────────────────────────────────
const fmt = (iso?: string | null) =>