import React, { useState } from 'react'; import { useRegions, useSaveRegion, useDeleteRegion } from '@/hooks/useRegions'; import type { Province } from '@/types/address.types'; import type { Region } from '@/types/shipping.types'; interface RegionManagerProps { provinces: Province[]; } // ---- Region Form (create / edit) ------------------------------------------ // interface RegionFormProps { region: Partial | null; provinces: Province[]; onSave: (data: Partial) => void; onCancel: () => void; isSaving: boolean; } const RegionForm: React.FC = ({ region, provinces, onSave, onCancel, isSaving, }) => { const [name, setName] = useState(region?.region_name || ''); const [code, setCode] = useState(region?.region_code || ''); const [selected, setSelected] = useState(region?.province_codes || []); const toggleProvince = (pCode: string) => { setSelected((prev) => prev.includes(pCode) ? prev.filter((c) => c !== pCode) : [...prev, pCode] ); }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); onSave({ id: region?.id, region_name: name, region_code: code, province_codes: selected, }); }; const isEdit = !!region?.id; return (

{isEdit ? 'Edit region' : 'Add new region'}

setName(e.target.value)} required style={{ width: '300px' }} placeholder="e.g. Northern Vietnam" />
setCode(e.target.value.toLowerCase().replace(/[^a-z0-9_]/g, '_'))} required disabled={isEdit} style={{ width: '200px', fontFamily: 'monospace' }} placeholder="VD: mien_bac" /> {!isEdit && (

Use lowercase letters, numbers, and underscores only.

)}

{selected.length} selected

{provinces.map((p) => ( ))}
); }; // ---- Main RegionManager ---------------------------------------------------- // export const RegionManager: React.FC = ({ provinces }) => { const { data: regions = [], isLoading, refetch } = useRegions(); const { mutate: saveRegion, isPending: isSaving } = useSaveRegion(); const { mutate: deleteRegion, isPending: isDeleting } = useDeleteRegion(); const [showForm, setShowForm] = useState(false); const [editingRegion, setEditing] = useState | null>(null); const [expanded, setExpanded] = useState>(new Set()); const handleAdd = () => { setEditing(null); setShowForm(true); }; const handleEdit = (region: Region) => { setEditing(region); setShowForm(true); }; const handleDelete = (region: Region) => { if (!confirm(`Delete region "${region.region_name}"? This action cannot be undone.`)) return; deleteRegion(region.id!, { onSuccess: () => refetch() }); }; const handleSave = (data: Partial) => { saveRegion(data, { onSuccess: () => { setShowForm(false); setEditing(null); refetch(); }, }); }; const toggleExpand = (code: string) => { setExpanded((prev) => { const next = new Set(prev); next.has(code) ? next.delete(code) : next.add(code); return next; }); }; const provinceMap = React.useMemo(() => { const m: Record = {}; provinces.forEach((p) => (m[p.code] = p.name)); return m; }, [provinces]); return (

Group provinces/cities into regions to apply shared shipping rates. Predefined regions (Northern Vietnam, Central Vietnam, Southern Vietnam) are view-only.

{showForm && ( { setShowForm(false); setEditing(null); }} isSaving={isSaving} /> )} {isLoading &&

Loading...

} {!isLoading && regions.length === 0 && (

No regions yet.

)} {!isLoading && regions.length > 0 && ( {regions.map((region) => { const isOpen = expanded.has(region.region_code); return ( ); })}
Region name Region code Province/City Type Actions
{region.region_name} {region.region_code} {isOpen && (
{region.province_codes.map((code) => ( {provinceMap[code] || code} ))}
)}
{region.is_predefined ? ( Predefined ) : ( Custom )} {!region.is_predefined && ( <> )} {region.is_predefined && ( )}
)}
); };