2025-09-17 18:43:43 +09:00
|
|
|
"use client";
|
|
|
|
|
|
2025-09-25 15:12:06 +09:00
|
|
|
import { SubCard } from "@/components/molecules/SubCard/SubCard";
|
2025-09-17 18:43:43 +09:00
|
|
|
import { MapPinIcon, PencilIcon, CheckIcon, XMarkIcon } from "@heroicons/react/24/outline";
|
2025-12-25 13:20:45 +09:00
|
|
|
import { AddressForm, type AddressFormProps } from "@/features/services/components";
|
2025-10-09 10:49:03 +09:00
|
|
|
import type { Address } from "@customer-portal/domain/customer";
|
2025-12-29 18:19:27 +09:00
|
|
|
import { getCountryName } from "@/shared/constants";
|
2025-09-17 18:43:43 +09:00
|
|
|
|
|
|
|
|
interface AddressCardProps {
|
|
|
|
|
address: Address;
|
|
|
|
|
isEditing: boolean;
|
|
|
|
|
isSaving: boolean;
|
|
|
|
|
error?: string | null;
|
|
|
|
|
onEdit: () => void;
|
|
|
|
|
onCancel: () => void;
|
|
|
|
|
onSave: () => void;
|
|
|
|
|
onAddressChange: NonNullable<AddressFormProps["onChange"]>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function AddressCard({
|
|
|
|
|
address,
|
|
|
|
|
isEditing,
|
|
|
|
|
isSaving,
|
|
|
|
|
error,
|
|
|
|
|
onEdit,
|
|
|
|
|
onCancel,
|
|
|
|
|
onSave,
|
|
|
|
|
onAddressChange,
|
|
|
|
|
}: AddressCardProps) {
|
2025-10-22 10:58:16 +09:00
|
|
|
const countryLabel = address.country
|
|
|
|
|
? (getCountryName(address.country) ?? address.country)
|
|
|
|
|
: null;
|
2025-10-21 13:21:03 +09:00
|
|
|
|
2025-09-17 18:43:43 +09:00
|
|
|
return (
|
|
|
|
|
<SubCard>
|
2025-12-16 16:08:17 +09:00
|
|
|
<div className="pb-5 border-b border-border/60">
|
2025-09-17 18:43:43 +09:00
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<div className="flex items-center space-x-3">
|
2025-12-16 16:08:17 +09:00
|
|
|
<div className="h-10 w-10 rounded-xl bg-primary/10 flex items-center justify-center">
|
|
|
|
|
<MapPinIcon className="h-5 w-5 text-primary" />
|
|
|
|
|
</div>
|
|
|
|
|
<h2 className="text-lg font-semibold text-foreground">Address Information</h2>
|
2025-09-17 18:43:43 +09:00
|
|
|
</div>
|
|
|
|
|
{!isEditing && (
|
|
|
|
|
<button
|
|
|
|
|
onClick={onEdit}
|
2025-12-16 16:08:17 +09:00
|
|
|
className="inline-flex items-center px-4 py-2 border border-border text-sm font-medium rounded-lg text-foreground bg-background hover:bg-muted transition-colors"
|
2025-09-17 18:43:43 +09:00
|
|
|
>
|
|
|
|
|
<PencilIcon className="h-4 w-4 mr-2" />
|
|
|
|
|
Edit
|
|
|
|
|
</button>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="pt-5">
|
|
|
|
|
{isEditing ? (
|
|
|
|
|
<div className="space-y-6">
|
|
|
|
|
<AddressForm initialAddress={address} onChange={addr => onAddressChange(addr, true)} />
|
2025-12-16 18:12:12 +09:00
|
|
|
{error && <div className="text-sm text-danger">{error}</div>}
|
2025-12-16 16:08:17 +09:00
|
|
|
<div className="flex items-center justify-end space-x-3 pt-4 border-t border-border/60">
|
2025-09-17 18:43:43 +09:00
|
|
|
<button
|
|
|
|
|
onClick={onCancel}
|
|
|
|
|
disabled={isSaving}
|
2025-12-16 16:08:17 +09:00
|
|
|
className="inline-flex items-center px-4 py-2 border border-border text-sm font-medium rounded-lg text-foreground bg-background hover:bg-muted disabled:opacity-50 transition-colors"
|
2025-09-17 18:43:43 +09:00
|
|
|
>
|
|
|
|
|
<XMarkIcon className="h-4 w-4 mr-2" />
|
|
|
|
|
Cancel
|
|
|
|
|
</button>
|
|
|
|
|
<button
|
|
|
|
|
onClick={onSave}
|
|
|
|
|
disabled={isSaving}
|
2025-12-16 16:08:17 +09:00
|
|
|
className="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-lg text-primary-foreground bg-primary hover:bg-primary-hover disabled:opacity-50 transition-colors shadow-sm"
|
2025-09-17 18:43:43 +09:00
|
|
|
>
|
|
|
|
|
{isSaving ? (
|
|
|
|
|
<>
|
2025-12-16 16:08:17 +09:00
|
|
|
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-primary-foreground mr-2"></div>
|
2025-09-17 18:43:43 +09:00
|
|
|
Saving...
|
|
|
|
|
</>
|
|
|
|
|
) : (
|
|
|
|
|
<>
|
|
|
|
|
<CheckIcon className="h-4 w-4 mr-2" />
|
|
|
|
|
Save Address
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
2025-12-16 16:08:17 +09:00
|
|
|
<div className="space-y-1.5 text-foreground">
|
2026-01-06 16:13:59 +09:00
|
|
|
{(address.address2 || address.address1) && (
|
|
|
|
|
<p className="font-semibold text-base">{address.address2 || address.address1}</p>
|
|
|
|
|
)}
|
|
|
|
|
{address.address2 && address.address1 && (
|
|
|
|
|
<p className="text-muted-foreground">{address.address1}</p>
|
|
|
|
|
)}
|
2025-10-09 10:49:03 +09:00
|
|
|
{(address.city || address.state || address.postcode) && (
|
2025-12-16 16:08:17 +09:00
|
|
|
<p className="text-muted-foreground">
|
2025-10-09 10:49:03 +09:00
|
|
|
{[address.city, address.state, address.postcode].filter(Boolean).join(", ")}
|
2025-09-17 18:43:43 +09:00
|
|
|
</p>
|
|
|
|
|
)}
|
2025-12-16 16:08:17 +09:00
|
|
|
{countryLabel && <p className="text-muted-foreground font-medium">{countryLabel}</p>}
|
2025-09-17 18:43:43 +09:00
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</SubCard>
|
|
|
|
|
);
|
|
|
|
|
}
|