import React, { useState, useEffect, useCallback } from 'react';
import { listAddresses, deleteAddress, setDefaultAddress } from '../core/checkout-api';
import type { SavedAddress } from '../core/checkout-api';
import type { SavedAddressStepProps } from '../core/types';
// ─── Label icons ──────────────────────────────────────────────────────────────
const HomeIcon = () => (
);
const WorkIcon = () => (
);
const PinIcon = () => (
);
function LabelIcon({ label }: { label: string }) {
if (label === 'home') return ;
if (label === 'work') return ;
return ;
}
function formatAddressLabel(address: SavedAddress): string {
const custom = address.label_text?.trim();
if (address.label === 'other' && custom) return custom;
return address.label.charAt(0).toUpperCase() + address.label.slice(1);
}
// ─── Address card ─────────────────────────────────────────────────────────────
interface AddressCardProps {
address: SavedAddress;
onUse: () => void;
onDelete: () => void;
onSetDefault: () => void;
deleting: boolean;
}
function AddressCard({ address, onUse, onDelete, onSetDefault, deleting }: AddressCardProps) {
const parts = [
address.flat_number,
address.building_name,
address.street_name,
address.locality,
address.district,
address.state,
address.pincode,
].filter(Boolean);
const line1 = [address.flat_number, address.building_name, address.street_name].filter(Boolean).join(', ');
const line2 = [address.locality, address.district].filter(Boolean).join(', ');
const line3 = [address.state, address.pincode].filter(Boolean).join(' – ');
const summary = parts.length > 0 ? undefined : address.locality || address.district || address.state;
return (
{formatAddressLabel(address)}
{address.is_default && (
Default
)}
{!address.is_default && (
)}
{summary ? (
{summary}
) : (
<>
{line1 &&
{line1}
}
{line2 &&
{line2}
}
{line3 &&
{line3}
}
>
)}
{address.digipin ? (
DigiPin
{address.digipin}
) : (
Pin confirmation needed
)}
{address.saved_at_brand && (
{address.saved_at_brand}
)}
);
}
// ─── Main component ───────────────────────────────────────────────────────────
const SavedAddressStep: React.FC = ({
sessionToken,
functionBaseUrl,
merchantId,
onSelectAddress,
onAddNew,
}) => {
const [addresses, setAddresses] = useState([]);
const [loadingList, setLoadingList] = useState(true);
const [listError, setListError] = useState(null);
const [deletingId, setDeletingId] = useState(null);
const config = { functionBaseUrl, merchantId };
const load = useCallback(async () => {
setLoadingList(true);
setListError(null);
try {
const list = await listAddresses(config, sessionToken);
if (list.length === 0) {
// No saved addresses — go straight to map
onAddNew();
return;
}
setAddresses(list);
} catch (err: unknown) {
setListError(err instanceof Error ? err.message : 'Failed to load addresses.');
} finally {
setLoadingList(false);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [sessionToken]);
useEffect(() => { load(); }, [load]);
const handleDelete = useCallback(async (id: string) => {
setDeletingId(id);
try {
await deleteAddress(config, sessionToken, id);
setAddresses((prev) => {
const updated = prev.filter((a) => a.id !== id);
if (updated.length === 0) { onAddNew(); }
return updated;
});
} catch (err: unknown) {
setListError(err instanceof Error ? err.message : 'Failed to delete address.');
} finally {
setDeletingId(null);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [sessionToken, onAddNew]);
const handleSetDefault = useCallback(async (id: string) => {
try {
await setDefaultAddress(config, sessionToken, id);
setAddresses((prev) => prev.map((a) => ({ ...a, is_default: a.id === id })));
} catch (err: unknown) {
setListError(err instanceof Error ? err.message : 'Failed to set default.');
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [sessionToken]);
// ── Loading ──────────────────────────────────────────────────────────────────
if (loadingList) {
return (
);
}
// ── Error ────────────────────────────────────────────────────────────────────
if (listError && addresses.length === 0) {
return (
{listError}
);
}
return (
Saved Addresses
Pick one or add a new location
{listError && (
{listError}
)}
{addresses.map((addr) => (
onSelectAddress(addr)}
onDelete={() => handleDelete(addr.id)}
onSetDefault={() => handleSetDefault(addr.id)}
deleting={deletingId === addr.id}
/>
))}
);
};
export default SavedAddressStep;