"use client"; import { useCallback, useEffect, useState } from "react"; import { useParams, useRouter } from "next/navigation"; import { Alert, ConfirmDialog, Toast, ArchiveButton, Button, EmptyState, PageLoader, InlineLoader, } from "@/src/Components/UI"; import { useClientAddresses } from "@/src/hooks/useClientAddresses"; import { clientService } from "@/src/services/client.service"; import { getStoredToken } from "@/src/lib/auth"; import type { Client, ClientFormData } from "@/src/types/client"; import type { ClientAddress } from "@/src/types/client_adresses"; import { AddressFormModal, ClientFormModal } from "@/src/Components/Client"; import { AddressDetailModal } from "@/src/Components/Client_Adress/AddressDetailModal"; import { ArchivedClientsAddressesModal } from "@/src/Components/Client_Adress/archive/ArchivedClientsAddressesModal"; import type { CreateAddressFormValues, UpdateAddressFormValues, } from "@/src/validations/client_address.validator"; // ─── Helpers ─────────────────────────────────────────────────────────────── function labelIcon(label: string): string { const map: Record = { "فوترة": "💳", "شحن": "📦", "المقر الرئيسي": "🏢", "فرع": "🏬", "مستودع": "🏭", billing: "💳", shipping: "📦", "head office": "🏢", branch: "🏬", warehouse: "🏭", }; return map[label.toLowerCase()] ?? "📍"; } // ─── AddressCard ─────────────────────────────────────────────────────────── // CHANGE: clicking the card now opens AddressDetailModal — same pattern as // UserTable → UserDetailModal (viewUserId). Action buttons stop propagation // so they don't trigger the modal. `ActionBtn` (custom component) removed in // favor of the shared {!address.isPrimary && ( )} ); } // ─── Page ────────────────────────────────────────────────────────────────── export default function ClientAddressesPage() { const params = useParams(); const router = useRouter(); const clientId = (params?.clientId ?? params?.id) as string | undefined; useEffect(() => { if (!clientId) { console.warn("ClientAddressesPage: clientId missing from route params."); } }, [clientId]); // ── Parent client ──────────────────────────────────────────────────────── const [client, setClient] = useState(null); const [clientLoading, setClientLoading] = useState(true); const loadClient = useCallback(() => { if (!clientId) return; queueMicrotask(() => { setClientLoading(true); clientService .getById(clientId, getStoredToken()) .then((res) => setClient(res)) .catch(() => router.replace("/dashboard/clients")) .finally(() => setClientLoading(false)); }); }, [clientId, router]); useEffect(() => { loadClient(); }, [loadClient]); // ── Address hook ───────────────────────────────────────────────────────── const { addresses, loading: addrLoading, error, notification, clearError, createAddress, updateAddress, deleteAddress, setPrimaryAddress, settingPrimaryId, } = useClientAddresses(clientId ?? ""); // ── Modal state ────────────────────────────────────────────────────────── const [addrFormTarget, setAddrFormTarget] = useState(false); const [deleteTarget, setDeleteTarget] = useState(null); const [deleting, setDeleting] = useState(false); const [editingClient, setEditingClient] = useState(false); // Archive browser modal open/closed — scoped to this client's addresses const [archiveOpen, setArchiveOpen] = useState(false); // Address whose detail modal is open — same pattern as viewUserId/UserDetailModal const [viewAddress, setViewAddress] = useState(null); // ── Address form handler ───────────────────────────────────────────────── const handleAddressSubmit = async ( data: CreateAddressFormValues | UpdateAddressFormValues ): Promise => { if (addrFormTarget === null) return createAddress(data as CreateAddressFormValues); if (addrFormTarget === false) return false; return updateAddress(addrFormTarget.id, data as UpdateAddressFormValues); }; // ── Delete handler ─────────────────────────────────────────────────────── const handleDeleteConfirm = async () => { if (!deleteTarget || deleting) return; setDeleting(true); const ok = await deleteAddress(deleteTarget.id); setDeleting(false); if (ok) setDeleteTarget(null); }; // ── Set primary handler ────────────────────────────────────────────────── const handleSetPrimary = async (address: ClientAddress) => { await setPrimaryAddress(address.id); }; // ── Client edit handler ────────────────────────────────────────────────── const handleClientEditSubmit = async ( data: ClientFormData, ): Promise => { if (!client) return false; try { const res = await clientService.update(client.id, data, getStoredToken()); setClient(res); return true; } catch { return false; } }; // ── Loading guard ──────────────────────────────────────────────────────── // CHANGE: swapped the hand-rolled spinning
for the template's PageLoader. if (!clientId || clientLoading) { return ; } // ── Render ──────────────────────────────────────────────────────────────── return ( <> {/* Address detail modal — same pattern as viewUserId → UserDetailModal */} {viewAddress && ( setViewAddress(null)} /> )} {/* Address create / edit modal */} {addrFormTarget !== false && ( setAddrFormTarget(false)} onSubmit={handleAddressSubmit} /> )} {/* Delete confirmation */} { if (!deleting) setDeleteTarget(null); }} onConfirm={handleDeleteConfirm} title="حذف العنوان" description={`هل أنت متأكد من حذف ${deleteTarget?.label ?? ""}؟ لا يمكن التراجع عن هذا الإجراء.`} /> {/* Client edit modal CHANGE: removed the custom `ClientEditModal` wrapper that built its own fixed-position backdrop by hand. `ClientFormModal` already renders the shared internally, so wrapping it in another backdrop produced two stacked overlays. We now render it directly. */} {editingClient && client && ( setEditingClient(false)} onSubmit={handleClientEditSubmit} /> )} {/* Archived addresses browser — scoped to this client */} {archiveOpen && ( setArchiveOpen(false)} /> )}
{/* ── Header ── */}
{/* CHANGE: custom

إدارة العناوين

{client ? `${client.name} — العناوين` : "العناوين"}

إجمالي{" "} {addresses.length}{" "} عنوان

{/* CHANGE: custom )} {/* CHANGE: custom
{/* Client info strip */} {client && (
{client.name} {client.email} {client.phone} {client.taxId && ( {client.taxId} )}
)}
{error && } {/* ── Address grid ── */} {addrLoading ? ( // CHANGE: hand-rolled spinning
→ InlineLoader ) : addresses.length === 0 ? ( // CHANGE: custom empty-state
→ EmptyState setAddrFormTarget(null)}> أضف أول عنوان } /> ) : (
{addresses.map((addr) => ( setViewAddress(addr)} onEdit={() => setAddrFormTarget(addr)} onDelete={() => setDeleteTarget(addr)} onSetPrimary={() => handleSetPrimary(addr)} settingPrimary={settingPrimaryId === addr.id} /> ))}
)}
{/* Floating button to open the address archive for this client */} setArchiveOpen(true)} label="أرشيف العناوين" /> ); }