"use client"; // hooks/useCars.ts // All custom hooks for the Car module. import { useCallback, useEffect, useState } from "react"; import { getStoredToken } from "../lib/auth"; import { carService } from "../services/car.service"; import { get } from "../services/api"; import type { Car, CarImage, CarListResponse, CreateCarPayload, ImageStage, ToastMsg, UpdateCarPayload, } from "../types/car"; // ── useCars ─────────────────────────────────────────────────────────────────── // Manages the paginated car list for the main page. export function useCars(page: number, search: string) { const [cars, setCars] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [total, setTotal] = useState(0); const [pages, setPages] = useState(1); const loadCars = useCallback(() => { const token = getStoredToken(); setLoading(true); setError(null); const query = `?page=${page}&limit=12${search ? `&search=${encodeURIComponent(search)}` : ""}`; get(`cars${query}`, token) .then((res) => { const payload = (res as unknown as { data: CarListResponse["data"] }).data ?? res; setCars((payload as CarListResponse["data"]).data ?? []); setTotal((payload as CarListResponse["data"]).meta?.total ?? 0); setPages((payload as CarListResponse["data"]).meta?.pages ?? 1); }) .catch((err: Error) => setError(err.message)) .finally(() => setLoading(false)); }, [page, search]); useEffect(() => { loadCars(); }, [loadCars]); // Optimistic removal after delete const removeCar = useCallback((id: string) => { setCars(prev => prev.filter(c => c.id !== id)); setTotal(prev => Math.max(0, prev - 1)); }, []); return { cars, loading, error, total, pages, loadCars, removeCar, setError }; } // ── useCarDetail ────────────────────────────────────────────────────────────── // Fetches a single car by ID — used in CarDetailPanel. export function useCarDetail(carId: string) { const [car, setCar] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const token = getStoredToken(); setLoading(true); setError(null); carService .getById(carId, token) .then(res => setCar((res as unknown as { data: Car }).data)) .catch((err: Error) => setError(err.message)) .finally(() => setLoading(false)); }, [carId]); return { car, loading, error }; } // ── useCarMutations ─────────────────────────────────────────────────────────── // Create, update, and delete operations — used in the main page. interface UseCarMutationsOptions { onSuccess: (msg: string) => void; onError: (msg: string) => void; onDeleted: (id: string) => void; getEditTarget: () => Car | null; } export function useCarMutations({ onSuccess, onError, onDeleted, getEditTarget, }: UseCarMutationsOptions) { const [deleting, setDeleting] = useState(false); const handleFormSubmit = useCallback(async ( payload: CreateCarPayload | UpdateCarPayload, isNew: boolean, ): Promise => { const token = getStoredToken(); try { if (isNew) { await carService.create(payload as CreateCarPayload, token); onSuccess("تم إضافة المركبة بنجاح."); } else { const editTarget = getEditTarget(); if (!editTarget) return false; await carService.update(editTarget.id, payload as UpdateCarPayload, token); onSuccess("تم تحديث بيانات المركبة."); } return true; } catch (err: unknown) { onError(err instanceof Error ? err.message : "فشلت العملية."); return false; } }, [onSuccess, onError, getEditTarget]); const handleDeleteConfirm = useCallback(async (target: Car) => { setDeleting(true); const token = getStoredToken(); try { await carService.delete(target.id, token); onDeleted(target.id); onSuccess(`تم حذف ${target.manufacturer} ${target.model} بنجاح.`); } catch (err: unknown) { onError(err instanceof Error ? err.message : "فشل الحذف."); } finally { setDeleting(false); } }, [onSuccess, onError, onDeleted]); return { deleting, handleFormSubmit, handleDeleteConfirm }; } // ── useToast ────────────────────────────────────────────────────────────────── // Simple toast notification state. export function useToast(duration = 3500) { const [toast, setToast] = useState(null); const notify = useCallback((t: ToastMsg) => { setToast(t); setTimeout(() => setToast(null), duration); }, [duration]); return { toast, notify }; } // ── useCarImages ────────────────────────────────────────────────────────────── // Manages gallery images — used in CarImageGallery. export function useCarImages(carId: string, sortBy: "asc" | "desc") { const [images, setImages] = useState([]); const [loading, setLoading] = useState(true); const [uploading, setUploading] = useState(false); const [deleting, setDeleting] = useState(null); const [error, setError] = useState(null); const fetchImages = useCallback(async () => { setLoading(true); setError(null); try { const token = getStoredToken(); const res = await carService.getImages(carId, token, { sortBy }); const raw = (res as unknown as { data: CarImage[] }).data ?? []; setImages(raw); } catch (err: unknown) { setError(err instanceof Error ? err.message : "تعذّر تحميل الصور"); } finally { setLoading(false); } }, [carId, sortBy]); useEffect(() => { fetchImages(); }, [fetchImages]); const uploadImages = useCallback(async (files: File[], stage: ImageStage) => { setUploading(true); setError(null); try { const token = getStoredToken(); await carService.uploadImages(carId, files, stage, token); await fetchImages(); } catch (err: unknown) { setError(err instanceof Error ? err.message : "فشل رفع الصور"); } finally { setUploading(false); } }, [carId, fetchImages]); const deleteImage = useCallback(async (imageId: string) => { setDeleting(imageId); setError(null); try { const token = getStoredToken(); await carService.deleteImage(imageId, token); setImages(prev => prev.filter(img => img.id !== imageId)); return true; } catch (err: unknown) { setError(err instanceof Error ? err.message : "فشل حذف الصورة"); return false; } finally { setDeleting(null); } }, []); return { images, loading, uploading, deleting, error, setError, fetchImages, uploadImages, deleteImage, }; }