'use client'; import { useState } from 'react'; import { useLocale, useTranslations } from 'next-intl'; import { useSnackbar } from 'notistack'; import { Box, Skeleton, Stack, Typography } from '@mui/material'; import { AppButton, ConfirmDialog, EmptyState, ErrorState, FormDialogShell } from '@/components'; import { AddressCard, AddressForm } from '@/components/geography'; import { useAddresses, useCreateAddress, useUpdateAddress, useDeleteAddress, useSetPrimaryAddress, } from '@/services/addresses'; import type { CreateAddressInput, CustomerAddress } from '@/services/addresses/types'; /** * The customer address book — a cached, invalidate-on-mutation list of the customer's saved * addresses with add/edit (the cascading dropdowns + map pin in a full-screen-on-mobile dialog), * soft-delete (confirm), and set-primary (exactly one badge). Loading skeleton, error (with * retry), and empty states are all handled. The chosen address later feeds the f7 booking request. */ export default function AddressesPage() { const t = useTranslations('address'); const tc = useTranslations('common'); const locale = useLocale(); const { enqueueSnackbar } = useSnackbar(); const { data, isLoading, isError, refetch } = useAddresses(); const createAddress = useCreateAddress(); const updateAddress = useUpdateAddress(); const deleteAddress = useDeleteAddress(); const setPrimary = useSetPrimaryAddress(); const [formOpen, setFormOpen] = useState(false); const [formDirty, setFormDirty] = useState(false); const [editing, setEditing] = useState(null); const [deleteTarget, setDeleteTarget] = useState(null); const openAdd = () => { setEditing(null); setFormOpen(true); }; const openEdit = (address: CustomerAddress) => { setEditing(address); setFormOpen(true); }; const closeForm = () => setFormOpen(false); // Address district is optional granularity: show "city · district" when set, else just the city. const regionLabel = (address: CustomerAddress) => { const city = locale === 'en' ? address.cityNameEn : address.cityNameFa; if (address.districtId == null) return city; const district = locale === 'en' ? address.districtNameEn : address.districtNameFa; return `${city} · ${district}`; }; const handleSubmit = (input: CreateAddressInput) => { const onSuccess = () => { closeForm(); enqueueSnackbar(t('saved'), { variant: 'success' }); }; const onError = () => enqueueSnackbar(t('save_error'), { variant: 'error' }); if (editing) { updateAddress.mutate({ id: editing.id, input }, { onSuccess, onError }); } else { createAddress.mutate(input, { onSuccess, onError }); } }; const confirmDelete = () => { if (!deleteTarget) return; const id = deleteTarget.id; setDeleteTarget(null); deleteAddress.mutate(id, { onSuccess: () => enqueueSnackbar(t('deleted'), { variant: 'success' }), onError: () => enqueueSnackbar(t('unavailable'), { variant: 'error' }), }); }; const addresses = data?.items ?? []; const isEmpty = !isLoading && !isError && addresses.length === 0; return ( {t('title')} {t('subtitle')} {!isEmpty && !isError ? ( {t('add')} ) : null} {isLoading ? ( {[0, 1].map((key) => ( ))} ) : isError ? ( refetch()} /> ) : isEmpty ? ( {t('add')} } /> ) : ( {addresses.map((address) => ( openEdit(address)} onDelete={() => setDeleteTarget(address)} onSetPrimary={() => setPrimary.mutate(address.id, { onSuccess: () => enqueueSnackbar(t('primary_set'), { variant: 'success' }), onError: () => enqueueSnackbar(t('unavailable'), { variant: 'error' }), }) } settingPrimary={setPrimary.isPending} editLabel={t('edit')} deleteLabel={t('delete')} setPrimaryLabel={t('set_primary')} /> ))} )} setDeleteTarget(null)} onConfirm={confirmDelete} /> ); }