add archive endpoint to user , driver , car ,order ,trip and update trip fails also update saidecar
This commit is contained in:
159
src/hooks/UseCarsMaintanance.ts
Normal file
159
src/hooks/UseCarsMaintanance.ts
Normal file
@@ -0,0 +1,159 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { getStoredToken } from "@/src/lib/auth";
|
||||
import { carMaintenanceService } from "@/src/services/carMaintanance.service";
|
||||
import type {
|
||||
CarMaintenance,
|
||||
CreateMaintenancePayload,
|
||||
MaintenanceToastMsg,
|
||||
UpdateMaintenancePayload,
|
||||
} from "../types/carMaintanance";
|
||||
|
||||
// ── useCarMaintenanceList ─────────────────────────────────────────────────────
|
||||
// Loads every maintenance record for one car — used in the detail panel.
|
||||
|
||||
export function useCarMaintenanceList(carId: string | null) {
|
||||
const [records, setRecords] = useState<CarMaintenance[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const loadRecords = useCallback(() => {
|
||||
if (!carId) return;
|
||||
const token = getStoredToken();
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
carMaintenanceService
|
||||
.getAll(carId, token)
|
||||
.then((res) => {
|
||||
const payload = (res as unknown as { data: { data: CarMaintenance[] } }).data ?? res;
|
||||
setRecords((payload as { data: CarMaintenance[] }).data ?? []);
|
||||
})
|
||||
.catch((err: Error) => setError(err.message))
|
||||
.finally(() => setLoading(false));
|
||||
}, [carId]);
|
||||
|
||||
useEffect(() => { loadRecords(); }, [loadRecords]);
|
||||
|
||||
// Remove a record from the list right away, instead of waiting on a refetch.
|
||||
const removeRecord = useCallback((id: string) => {
|
||||
setRecords((prev) => prev.filter((r) => r.id !== id));
|
||||
}, []);
|
||||
|
||||
return { records, loading, error, loadRecords, removeRecord, setError };
|
||||
}
|
||||
|
||||
// ── useCarMaintenanceDetail ───────────────────────────────────────────────────
|
||||
// Fetches a single maintenance record by id.
|
||||
|
||||
export function useCarMaintenanceDetail(carId: string | null, maintenanceId: string | null) {
|
||||
const [record, setRecord] = useState<CarMaintenance | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!carId || !maintenanceId) return;
|
||||
const token = getStoredToken();
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
carMaintenanceService
|
||||
.getById(carId, maintenanceId, token)
|
||||
.then((res) => setRecord((res as unknown as { data: CarMaintenance }).data))
|
||||
.catch((err: Error) => setError(err.message))
|
||||
.finally(() => setLoading(false));
|
||||
}, [carId, maintenanceId]);
|
||||
|
||||
return { record, loading, error };
|
||||
}
|
||||
|
||||
// ── useCarMaintenanceMutations ────────────────────────────────────────────────
|
||||
// Create, update, and soft-delete operations for maintenance records.
|
||||
|
||||
interface UseCarMaintenanceMutationsOptions {
|
||||
carId: string;
|
||||
onSuccess: (msg: string) => void;
|
||||
onError: (msg: string) => void;
|
||||
onDeleted: (id: string) => void;
|
||||
getEditTarget: () => CarMaintenance | null;
|
||||
}
|
||||
|
||||
export function useCarMaintenanceMutations({
|
||||
carId,
|
||||
onSuccess,
|
||||
onError,
|
||||
onDeleted,
|
||||
getEditTarget,
|
||||
}: UseCarMaintenanceMutationsOptions) {
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [deleting, setDeleting] = useState(false);
|
||||
|
||||
const handleFormSubmit = useCallback(
|
||||
async (
|
||||
payload: CreateMaintenancePayload | UpdateMaintenancePayload,
|
||||
isNew: boolean,
|
||||
): Promise<boolean> => {
|
||||
const token = getStoredToken();
|
||||
setSaving(true);
|
||||
try {
|
||||
if (isNew) {
|
||||
await carMaintenanceService.create(carId, payload as CreateMaintenancePayload, token);
|
||||
onSuccess("تم إضافة سجل الصيانة بنجاح.");
|
||||
} else {
|
||||
const editTarget = getEditTarget();
|
||||
if (!editTarget) return false;
|
||||
await carMaintenanceService.update(
|
||||
carId,
|
||||
editTarget.id,
|
||||
payload as UpdateMaintenancePayload,
|
||||
token,
|
||||
);
|
||||
onSuccess("تم تحديث سجل الصيانة.");
|
||||
}
|
||||
return true;
|
||||
} catch (err: unknown) {
|
||||
// Show the backend's own message when it has one, otherwise a generic fallback.
|
||||
onError(err instanceof Error ? err.message : "فشلت العملية.");
|
||||
return false;
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
},
|
||||
[carId, onSuccess, onError, getEditTarget],
|
||||
);
|
||||
|
||||
const handleDeleteConfirm = useCallback(
|
||||
async (target: CarMaintenance) => {
|
||||
setDeleting(true);
|
||||
const token = getStoredToken();
|
||||
try {
|
||||
await carMaintenanceService.delete(carId, target.id, token);
|
||||
onDeleted(target.id);
|
||||
onSuccess("تم حذف سجل الصيانة بنجاح.");
|
||||
} catch (err: unknown) {
|
||||
onError(err instanceof Error ? err.message : "فشل الحذف.");
|
||||
} finally {
|
||||
setDeleting(false);
|
||||
}
|
||||
},
|
||||
[carId, onSuccess, onError, onDeleted],
|
||||
);
|
||||
|
||||
return { saving, deleting, handleFormSubmit, handleDeleteConfirm };
|
||||
}
|
||||
|
||||
// ── useMaintenanceToast ────────────────────────────────────────────────────────
|
||||
// Simple toast notification state, same shape as useCars' useToast.
|
||||
|
||||
export function useMaintenanceToast(duration = 3500) {
|
||||
const [toast, setToast] = useState<MaintenanceToastMsg | null>(null);
|
||||
|
||||
const notify = useCallback(
|
||||
(t: MaintenanceToastMsg) => {
|
||||
setToast(t);
|
||||
setTimeout(() => setToast(null), duration);
|
||||
},
|
||||
[duration],
|
||||
);
|
||||
|
||||
return { toast, notify };
|
||||
}
|
||||
0
src/hooks/archive/UseArchivedCarsMaintanance.ts
Normal file
0
src/hooks/archive/UseArchivedCarsMaintanance.ts
Normal file
0
src/hooks/archive/useArchiveBranch.ts
Normal file
0
src/hooks/archive/useArchiveBranch.ts
Normal file
0
src/hooks/archive/useArchiveClient.ts
Normal file
0
src/hooks/archive/useArchiveClient.ts
Normal file
0
src/hooks/archive/useArchiveClientAdresses.ts
Normal file
0
src/hooks/archive/useArchiveClientAdresses.ts
Normal file
0
src/hooks/archive/useArchiveRole.ts
Normal file
0
src/hooks/archive/useArchiveRole.ts
Normal file
@@ -1,58 +1,112 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useReducer, useState } from "react";
|
||||
import { getStoredToken } from "@/src/lib/auth";
|
||||
import { archivedOrderService } from "@/src/services/archive/archivedOrder.service";
|
||||
import type { ArchivedOrder } from "@/src/types/order";
|
||||
|
||||
const PAGE_SIZE = 10;
|
||||
|
||||
// ── Table state / reducer ──────────────────────────────────────────────────
|
||||
// نفس شكل TableState/TableAction اللي في useOrder.ts عشان الهوكين يفضلوا متسقين
|
||||
interface TableState {
|
||||
orders: ArchivedOrder[];
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
}
|
||||
|
||||
type TableAction =
|
||||
| { type: "LOAD_START" }
|
||||
| { type: "LOAD_OK"; orders: ArchivedOrder[] }
|
||||
| { type: "LOAD_ERR"; error: string }
|
||||
| { type: "CLEAR_ERR" };
|
||||
|
||||
function reducer(s: TableState, a: TableAction): TableState {
|
||||
switch (a.type) {
|
||||
case "LOAD_START":
|
||||
return { ...s, loading: true, error: null };
|
||||
case "LOAD_OK":
|
||||
return { ...s, loading: false, orders: a.orders };
|
||||
case "LOAD_ERR":
|
||||
return { ...s, loading: false, error: a.error };
|
||||
case "CLEAR_ERR":
|
||||
return { ...s, error: null };
|
||||
default:
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
const initialState: TableState = {
|
||||
orders: [],
|
||||
loading: true,
|
||||
error: null,
|
||||
};
|
||||
|
||||
// ── Main hook ──────────────────────────────────────────────────────────────
|
||||
export function useArchivedOrders() {
|
||||
const [orders, setOrders] = useState<ArchivedOrder[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
const [page, setPage] = useState(1);
|
||||
const [search, setSearch] = useState("");
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
// ── Fetch archived orders ─────────────────────────────────────────────
|
||||
const load = useCallback(async () => {
|
||||
setLoading(true);
|
||||
dispatch({ type: "LOAD_START" });
|
||||
try {
|
||||
const token = getStoredToken();
|
||||
const res = await archivedOrderService.getAll(token);
|
||||
setOrders(res.data);
|
||||
setError(null);
|
||||
|
||||
// نفس الـ pattern بتاع useOrder.ts:
|
||||
// get() بترجع axios response كامل، فـ res.data هو الـ JSON body
|
||||
// {success, message, responseAt, data}. الـ "?? res" احتياطي لو
|
||||
// الـ interceptor بتاع axios بيرجّع الـ body مباشرة من غير .data
|
||||
const payload =
|
||||
(res as unknown as { data: { data: ArchivedOrder[] } }).data ?? res;
|
||||
|
||||
dispatch({ type: "LOAD_OK", orders: payload.data ?? [] });
|
||||
} catch {
|
||||
setError("تعذّر تحميل الطلبات المؤرشفة. يرجى المحاولة لاحقاً.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
dispatch({
|
||||
type: "LOAD_ERR",
|
||||
error: "تعذّر تحميل الطلبات المؤرشفة. يرجى المحاولة لاحقاً.",
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => { load(); }, [load]);
|
||||
useEffect(() => {
|
||||
load();
|
||||
}, [load]);
|
||||
|
||||
// Client-side search — endpoint has no `?search=` param in the sample payload
|
||||
const filtered = useMemo(() => {
|
||||
if (!search.trim()) return orders;
|
||||
const q = search.trim().toLowerCase();
|
||||
return orders.filter(
|
||||
o =>
|
||||
o.shipmentNumber.toLowerCase().includes(q) ||
|
||||
o.recipientName.toLowerCase().includes(q) ||
|
||||
o.recipientPhone.includes(q),
|
||||
);
|
||||
}, [orders, search]);
|
||||
// ── Client-side search — الـ endpoint معندوش ?search= param ────────────
|
||||
const filtered = !search.trim()
|
||||
? state.orders
|
||||
: state.orders.filter((o) => {
|
||||
const q = search.trim().toLowerCase();
|
||||
return (
|
||||
o.shipmentNumber.toLowerCase().includes(q) ||
|
||||
o.recipientName.toLowerCase().includes(q) ||
|
||||
o.recipientPhone.includes(q)
|
||||
);
|
||||
});
|
||||
|
||||
const pages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE));
|
||||
const paginated = filtered.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE);
|
||||
|
||||
const handleSearch = (value: string) => {
|
||||
// ── Search / page helpers ──────────────────────────────────────────────
|
||||
const handleSearch = useCallback((value: string) => {
|
||||
setSearch(value);
|
||||
setPage(1);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return {
|
||||
orders: paginated,
|
||||
total: filtered.length,
|
||||
loading, pages, page, search, error,
|
||||
setPage, handleSearch, clearError: () => setError(null),
|
||||
loading: state.loading,
|
||||
pages,
|
||||
page,
|
||||
search,
|
||||
error: state.error,
|
||||
setPage,
|
||||
handleSearch,
|
||||
clearError: () => dispatch({ type: "CLEAR_ERR" }),
|
||||
refresh: load,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user