import { useEffect, useState } from 'react' import { createPortal } from 'react-dom' import { X } from 'lucide-react' import { getLocationOptionLabel, matchCityByName, matchProvinceByName, useLocale, useToast, } from '@meshkee/dashboard-ui' import { useT } from '../i18n/useT' import { ApiError } from '../lib/api' import { createAddress, updateAddress, type UserAddress, } from '../services/addressService' import { listCitiesByProvinceSlug, listIranProvinces, type CityOption, } from '../services/citiesService' import modalStyles from './VariationsModal.module.css' import panelStyles from './checkout/CheckoutAddAddressPanel.module.css' import styles from './AddressFormModal.module.css' interface AddressFormModalProps { open: boolean address: UserAddress | null onClose: () => void onSaved: (address: UserAddress) => void } const ANIMATION_MS = 220 export function AddressFormModal({ open, address, onClose, onSaved }: AddressFormModalProps) { const t = useT() const { locale, dir } = useLocale() const { showToast } = useToast() const [mounted, setMounted] = useState(open) const [closing, setClosing] = useState(false) const [formKey, setFormKey] = useState(0) useEffect(() => { if (open) { setMounted(true) setClosing(false) setFormKey((key) => key + 1) } else if (mounted) { setClosing(true) const timer = setTimeout(() => { setMounted(false) setClosing(false) }, ANIMATION_MS) return () => clearTimeout(timer) } }, [open, mounted]) useEffect(() => { if (!mounted || closing) return const prevOverflow = document.body.style.overflow document.body.style.overflow = 'hidden' const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() } document.addEventListener('keydown', onKey) return () => { document.body.style.overflow = prevOverflow document.removeEventListener('keydown', onKey) } }, [mounted, closing, onClose]) if (!mounted) return null const isEdit = Boolean(address?.id) return createPortal(
e.stopPropagation()} role="dialog" aria-modal="true" aria-labelledby="address-form-title" lang={locale} dir={dir} >

{isEdit ? t('addresses.modal.editTitle') : t('addresses.modal.addTitle')}

{t('addresses.modal.subtitle')}

{ showToast( isEdit ? t('addresses.toast.updated') : t('addresses.toast.created'), 'success', ) onSaved(saved) onClose() }} />
, document.body, ) } function AddressFormFields({ address, onCancel, onSaved, }: { address: UserAddress | null onCancel: () => void onSaved: (address: UserAddress) => void }) { const t = useT() const { locale } = useLocale() const [provinces, setProvinces] = useState([]) const [cities, setCities] = useState([]) const [loadingLocations, setLoadingLocations] = useState(true) const [saving, setSaving] = useState(false) const [error, setError] = useState('') const [label, setLabel] = useState(address?.label ?? '') const [provinceSlug, setProvinceSlug] = useState('') const [city, setCity] = useState('') const [street, setStreet] = useState(address?.address ?? '') const [postalCode, setPostalCode] = useState(address?.postalCode ?? '') const [landline, setLandline] = useState(address?.landline ?? '') useEffect(() => { const controller = new AbortController() async function load() { setLoadingLocations(true) try { const items = await listIranProvinces(controller.signal) if (controller.signal.aborted) return setProvinces(items) if (!address) return const province = matchProvinceByName(address.province, items) if (!province) return setProvinceSlug(province.slug) const cityItems = await listCitiesByProvinceSlug(province.slug, controller.signal) if (controller.signal.aborted) return setCities(cityItems) const matchedCity = matchCityByName(address.city, cityItems) setCity( matchedCity ? getLocationOptionLabel(matchedCity, locale) : address.city, ) } catch { if (!controller.signal.aborted) setError(t('addresses.error.loadLocations')) } finally { if (!controller.signal.aborted) setLoadingLocations(false) } } void load() return () => controller.abort() }, [address, locale, t]) async function handleProvinceChange(slug: string) { setProvinceSlug(slug) setCity('') setCities([]) if (!slug) return try { const items = await listCitiesByProvinceSlug(slug) setCities(items) } catch { setError(t('addresses.error.loadCities')) } } async function handleSubmit(e: React.FormEvent) { e.preventDefault() setError('') const province = provinces.find((item) => item.slug === provinceSlug) if (!label.trim() || !province || !city.trim() || !street.trim()) { setError(t('addresses.error.incompleteForm')) return } const payload = { label: label.trim(), province: getLocationOptionLabel(province, locale), city: city.trim(), address: street.trim(), postalCode: postalCode.trim() || undefined, landline: landline.trim() || undefined, } setSaving(true) try { const result = address?.id ? await updateAddress(address.id, payload) : await createAddress(payload) onSaved(result.address) } catch (err) { setError(err instanceof ApiError ? err.message : t('addresses.error.save')) } finally { setSaving(false) } } return (
void handleSubmit(e)} > {error && (
{error}
)}
setLabel(e.target.value)} placeholder={t('addresses.labelPlaceholder')} />
setStreet(e.target.value)} placeholder={t('addresses.streetPlaceholder')} />
setPostalCode(e.target.value)} placeholder={t('addresses.postalPlaceholder')} dir="ltr" />
setLandline(e.target.value)} placeholder={t('addresses.landlinePlaceholder')} dir="ltr" />
) }