chore: phase 1 lint/type fixes — commit all changes

This commit is contained in:
m7amedez5511
2026-07-02 20:07:38 +03:00
parent d225291b70
commit 25f3468d74
37 changed files with 162 additions and 176 deletions

View File

@@ -12,7 +12,6 @@ import {
type UpdateClientFormValues,
} from "@/src/validations/client.validator";
import type { Client } from "@/src/types/client";
import { Schema } from "yup";
// ── Styles ─────────────────────────────────────────────────────────────────
const S = {
@@ -71,7 +70,7 @@ export function ClientFormModal({ editClient, onClose, onSubmit }: ClientFormMod
setError,
formState: { errors, isSubmitting },
} = useForm<CreateClientFormValues | UpdateClientFormValues>({
resolver: yupResolver(Schema) as never, // FIX 1 applied here
resolver: yupResolver(schema) as never,
defaultValues: {
name: editClient?.name ?? "",
email: editClient?.email ?? "",

View File

@@ -38,37 +38,6 @@ function AddressBadge({ count, onClick }: { count: number; onClick: () => void }
);
}
// ── Status badge ───────────────────────────────────────────────────────────
function StatusBadge({ active }: { active?: boolean }) {
const isActive = active !== false;
return (
<span
style={{
display: "inline-flex",
alignItems: "center",
gap: 5,
borderRadius: "var(--radius-full)",
border: isActive ? "1px solid #BBF7D0" : "1px solid #FECACA",
background: isActive ? "#DCFCE7" : "#FEF2F2",
padding: "0.2rem 0.625rem",
fontSize: 11,
fontWeight: 600,
color: isActive ? "#166534" : "#991B1B",
}}
>
<span
style={{
width: 6,
height: 6,
borderRadius: "50%",
background: isActive ? "#16A34A" : "#DC2626",
}}
/>
{isActive ? "نشط" : "غير نشط"}
</span>
);
}
// ── Icon button ────────────────────────────────────────────────────────────
function IconBtn({
onClick,

View File

@@ -106,9 +106,17 @@ export function AddressFormModal({ editAddress, onClose, onSubmit }: AddressForm
},
});
const detailsErr = (errors as any)?.details ?? {};
const contactErr = (errors as any)?.contactPerson ?? {};
const locationErr = (errors as any)?.location ?? {};
type AddressErrors = {
details?: Record<string, unknown>;
contactPerson?: Record<string, unknown>;
location?: Record<string, unknown>;
};
const {
details: detailsErr = {},
contactPerson: contactErr = {},
location: locationErr = {},
} = errors as AddressErrors;
useEffect(() => {
const handler = (e: KeyboardEvent) => { if (e.key === "Escape") onClose(); };

View File

@@ -97,7 +97,7 @@ function PhotoCard({ url, label }: { url?: string | null; label: string }) {
const [imgError, setImgError] = useState(false);
useEffect(() => {
setImgError(false);
queueMicrotask(() => setImgError(false));
}, [url]);
return (
@@ -196,7 +196,7 @@ export function DriverDetailPanel({
}
}, [driverId]);
useEffect(() => { loadDriver(); }, [loadDriver]);
useEffect(() => { queueMicrotask(loadDriver); }, [loadDriver]);
useEffect(() => {
const h = (e: KeyboardEvent) => { if (e.key === "Escape") onClose(); };

View File

@@ -16,6 +16,7 @@ import type {
DriverStatus,
} from "@/src/types/driver";
import type { Branch } from "@/src/types/branch";
import { FileInput } from "@/src/Components/Driver/DriverFormModalHelper";
// ── Shared input style ───────────────────────────────────────────────────────
@@ -97,7 +98,7 @@ export function DriverFormModal({
const [branches, setBranches] = useState<Branch[]>(branchesProp);
useEffect(() => {
if (branchesProp.length > 0) {
setBranches(branchesProp);
queueMicrotask(() => setBranches(branchesProp));
return;
}
const token = getStoredToken();
@@ -108,8 +109,7 @@ export function DriverFormModal({
setBranches(list);
})
.catch(() => { /* silently ignore */ });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [branchesProp]);
// ── Form state ────────────────────────────────────────────────────────────
const [name, setName] = useState(editDriver?.name ?? "");
@@ -172,7 +172,7 @@ export function DriverFormModal({
setErrors((p) => ({ ...p, [field]: undefined }));
// ── Submit with yup validation ────────────────────────────────────────────
const handleSubmit = async (e: React.FormEvent) => {
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
// Build the raw object to validate
@@ -211,7 +211,6 @@ export function DriverFormModal({
}
}
// ── Build clean payload to send to backend ────────────────────────────
const payload: Record<string, unknown> = { name, phone };
if (email) payload.email = email;
if (address) payload.address = address;
@@ -253,39 +252,6 @@ export function DriverFormModal({
}
};
// ── File input helper ──────────────────────────────────────────────────────
function FileInput({
label: lbl,
current,
onChange,
}: {
label: string;
current: File | null;
onChange: (f: File | null) => void;
}) {
return (
<label style={labelStyle}>
{lbl}
<input
type="file"
accept="image/*"
onChange={(e) => onChange(e.target.files?.[0] ?? null)}
style={{
...inputBase,
padding: "0.35rem 0.75rem",
height: "auto",
cursor: "pointer",
}}
/>
{current && (
<span style={{ fontSize: 11, color: "var(--color-text-muted)" }}>
{current.name}
</span>
)}
</label>
);
}
// ── Render ─────────────────────────────────────────────────────────────────
return (
<div
@@ -645,8 +611,8 @@ export function DriverFormModal({
</p>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: "0.75rem" }}>
<FileInput label="صورة السائق" current={photo} onChange={setPhoto} />
<FileInput label="صورة الهوية" current={nationalPhoto} onChange={setNationalPhoto} />
<FileInput label="صورة السائق" current={photo} onChange={setPhoto} />
<FileInput label="صورة الهوية" current={nationalPhoto} onChange={setNationalPhoto} />
<FileInput label="صورة البطاقة" current={driverCardPhoto} onChange={setDriverCardPhoto} />
</div>

View File

@@ -0,0 +1,55 @@
import React from "react";
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)",
};
export function FileInput({
label,
current,
onChange,
}: {
label: string;
current: File | null;
onChange: (f: File | null) => void;
}) {
return (
<label style={labelStyle}>
{label}
<input
type="file"
accept="image/*"
onChange={(e) => onChange(e.target.files?.[0] ?? null)}
style={{
...inputBase,
padding: "0.35rem 0.75rem",
height: "auto",
cursor: "pointer",
}}
/>
{current && (
<span style={{ fontSize: 11, color: "var(--color-text-muted)" }}>
{current.name}
</span>
)}
</label>
);
}

View File

@@ -11,7 +11,7 @@ export function PhotoCard({
// Reset error state when url changes so updated images get a fresh load attempt
useEffect(() => {
setImgError(false);
queueMicrotask(() => setImgError(false));
}, [url]);
return (

View File

@@ -162,7 +162,7 @@ export function OrderDetailPanel({
}
}, [orderId]);
useEffect(() => { loadOrder(); }, [loadOrder]);
useEffect(() => { queueMicrotask(loadOrder); }, [loadOrder]);
useEffect(() => {
const h = (e: KeyboardEvent) => { if (e.key === "Escape") onClose(); };

View File

@@ -218,16 +218,16 @@ export function OrderFormModal({
// Fetch first 100 clients (enough for a practical dropdown)
const clientRes = await clientService.getAll(1, "", token);
const clientPayload = (clientRes as any).data ?? clientRes;
const clientList: Client[] = clientPayload.data ?? [];
const clientPayload = (clientRes as unknown as { data?: { data?: Client[] } }).data ?? clientRes;
const clientList: Client[] = (clientPayload as { data?: Client[] }).data ?? [];
// Fetch first 100 trips (active ones the order can be assigned to)
const tripRes = await tripService.getAll(
{ page: 1, limit: 100 },
token,
);
const tripPayload = (tripRes as any).data ?? tripRes;
const tripList: Trip[] = tripPayload.data ?? [];
const tripPayload = (tripRes as unknown as { data?: { data?: Trip[] } }).data ?? tripRes;
const tripList: Trip[] = (tripPayload as { data?: Trip[] }).data ?? [];
if (!cancelled) {
setClients(clientList);

View File

@@ -1,6 +1,6 @@
"use client";
import { Spinner, Alert, EmptyState, Badge } from "@/src/Components/UI";
import { Spinner, Alert, EmptyState } from "@/src/Components/UI";
import { useArchivedTrips } from "@/src/hooks/archive/useArchivedTrips";
import { TRIP_STATUS_MAP } from "@/src/types/trip";
import type { Trip } from "@/src/types/trip";

View File

@@ -21,7 +21,7 @@ export function Toast({ notification, onDismiss }: ToastProps) {
useEffect(() => {
if (notification) {
if (exitTimer.current) clearTimeout(exitTimer.current);
setVisible(true);
queueMicrotask(() => setVisible(true));
} else {
exitTimer.current = setTimeout(() => setVisible(false), 300);
}

View File

@@ -1,6 +1,6 @@
"use client";
import { useEffect, useRef, useState } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import * as yup from "yup";
import { Alert, Spinner } from "../UI";
import { get } from "@/src/services/api";
@@ -101,9 +101,9 @@ export function CarFormModal({
// ── Local branches (auto-fetched if prop is empty) ─────────────────────────
const [branches, setBranches] = useState<Branch[]>(branchesProp);
useEffect(() => {
const loadBranches = useCallback(() => {
if (branchesProp.length > 0) {
setBranches(branchesProp);
queueMicrotask(() => setBranches(branchesProp));
return;
}
const token = getStoredToken();
@@ -111,13 +111,16 @@ export function CarFormModal({
.then((res) => {
const list =
(res as unknown as { data: { data: Branch[] } }).data?.data ?? [];
setBranches(list);
queueMicrotask(() => setBranches(list));
})
.catch(() => {
/* silently ignore */
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [branchesProp]);
useEffect(() => {
loadBranches();
}, [loadBranches]);
// ── Form state ─────────────────────────────────────────────────────────────
const [manufacturer, setManufacturer] = useState(editCar?.manufacturer ?? "");