2025-09-17 18:43:43 +09:00
|
|
|
"use client";
|
|
|
|
|
|
2025-10-29 13:29:28 +09:00
|
|
|
import { useEffect, useState, useRef } from "react";
|
2025-10-22 10:58:16 +09:00
|
|
|
import { Skeleton } from "@/components/atoms/loading-skeleton";
|
2025-09-25 15:54:54 +09:00
|
|
|
import { AlertBanner } from "@/components/molecules/AlertBanner/AlertBanner";
|
2025-09-25 17:42:36 +09:00
|
|
|
import {
|
|
|
|
|
MapPinIcon,
|
|
|
|
|
PencilIcon,
|
|
|
|
|
CheckIcon,
|
|
|
|
|
XMarkIcon,
|
|
|
|
|
UserIcon,
|
|
|
|
|
} from "@heroicons/react/24/outline";
|
2025-09-17 18:43:43 +09:00
|
|
|
import { useAuthStore } from "@/features/auth/services/auth.store";
|
|
|
|
|
import { accountService } from "@/features/account/services/account.service";
|
|
|
|
|
import { useProfileEdit } from "@/features/account/hooks/useProfileEdit";
|
|
|
|
|
import { AddressForm } from "@/features/catalog/components/base/AddressForm";
|
2025-09-20 11:35:40 +09:00
|
|
|
import { Button } from "@/components/atoms/button";
|
2025-09-17 18:43:43 +09:00
|
|
|
import { useAddressEdit } from "@/features/account/hooks/useAddressEdit";
|
|
|
|
|
|
|
|
|
|
export default function ProfileContainer() {
|
|
|
|
|
const { user } = useAuthStore();
|
|
|
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
|
const [editingProfile, setEditingProfile] = useState(false);
|
|
|
|
|
const [editingAddress, setEditingAddress] = useState(false);
|
2025-10-29 13:29:28 +09:00
|
|
|
const hasLoadedRef = useRef(false);
|
2025-09-17 18:43:43 +09:00
|
|
|
|
|
|
|
|
const profile = useProfileEdit({
|
2025-10-09 10:49:03 +09:00
|
|
|
firstname: user?.firstname || "",
|
|
|
|
|
lastname: user?.lastname || "",
|
|
|
|
|
phonenumber: user?.phonenumber || "",
|
2025-09-17 18:43:43 +09:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const address = useAddressEdit({
|
2025-10-07 17:38:39 +09:00
|
|
|
address1: "",
|
|
|
|
|
address2: "",
|
2025-09-17 18:43:43 +09:00
|
|
|
city: "",
|
|
|
|
|
state: "",
|
2025-10-07 17:38:39 +09:00
|
|
|
postcode: "",
|
2025-09-17 18:43:43 +09:00
|
|
|
country: "",
|
2025-10-07 17:38:39 +09:00
|
|
|
countryCode: "",
|
|
|
|
|
phoneNumber: "",
|
|
|
|
|
phoneCountryCode: "",
|
2025-09-17 18:43:43 +09:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
2025-10-29 13:29:28 +09:00
|
|
|
// Only load data once on mount
|
|
|
|
|
if (hasLoadedRef.current) return;
|
|
|
|
|
hasLoadedRef.current = true;
|
|
|
|
|
|
2025-09-17 18:43:43 +09:00
|
|
|
void (async () => {
|
|
|
|
|
try {
|
|
|
|
|
setLoading(true);
|
|
|
|
|
const [addr, prof] = await Promise.all([
|
|
|
|
|
accountService.getAddress().catch(() => null),
|
|
|
|
|
accountService.getProfile().catch(() => null),
|
|
|
|
|
]);
|
|
|
|
|
if (addr) {
|
2025-10-07 17:38:39 +09:00
|
|
|
address.setValue("address1", addr.address1 ?? "");
|
|
|
|
|
address.setValue("address2", addr.address2 ?? "");
|
2025-09-19 17:37:46 +09:00
|
|
|
address.setValue("city", addr.city ?? "");
|
|
|
|
|
address.setValue("state", addr.state ?? "");
|
2025-10-07 17:38:39 +09:00
|
|
|
address.setValue("postcode", addr.postcode ?? "");
|
2025-09-19 17:37:46 +09:00
|
|
|
address.setValue("country", addr.country ?? "");
|
2025-10-07 17:38:39 +09:00
|
|
|
address.setValue("countryCode", addr.countryCode ?? "");
|
|
|
|
|
address.setValue("phoneNumber", addr.phoneNumber ?? "");
|
|
|
|
|
address.setValue("phoneCountryCode", addr.phoneCountryCode ?? "");
|
2025-09-17 18:43:43 +09:00
|
|
|
}
|
|
|
|
|
if (prof) {
|
2025-10-09 10:49:03 +09:00
|
|
|
profile.setValue("firstname", prof.firstname || "");
|
|
|
|
|
profile.setValue("lastname", prof.lastname || "");
|
|
|
|
|
profile.setValue("phonenumber", prof.phonenumber || "");
|
2025-09-17 18:43:43 +09:00
|
|
|
useAuthStore.setState(state => ({
|
|
|
|
|
...state,
|
|
|
|
|
user: state.user
|
|
|
|
|
? {
|
|
|
|
|
...state.user,
|
2025-10-09 10:49:03 +09:00
|
|
|
firstname: prof.firstname || state.user.firstname,
|
|
|
|
|
lastname: prof.lastname || state.user.lastname,
|
|
|
|
|
phonenumber: prof.phonenumber || state.user.phonenumber,
|
2025-09-17 18:43:43 +09:00
|
|
|
}
|
|
|
|
|
: (prof as unknown as typeof state.user),
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
setError(e instanceof Error ? e.message : "Failed to load profile data");
|
|
|
|
|
} finally {
|
|
|
|
|
setLoading(false);
|
|
|
|
|
}
|
|
|
|
|
})();
|
2025-10-29 13:29:28 +09:00
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
|
|
}, []);
|
2025-09-17 18:43:43 +09:00
|
|
|
|
|
|
|
|
if (loading) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="py-6">
|
|
|
|
|
<div className="max-w-4xl mx-auto px-4 sm:px-6 md:px-8 space-y-8">
|
|
|
|
|
<div className="bg-white shadow-sm rounded-xl border border-gray-200">
|
|
|
|
|
<div className="px-6 py-5 border-b border-gray-200">
|
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<div className="flex items-center space-x-3">
|
|
|
|
|
<div className="h-6 w-6 bg-blue-200 rounded" />
|
|
|
|
|
<div className="h-6 w-40 bg-gray-200 rounded" />
|
|
|
|
|
</div>
|
|
|
|
|
<div className="h-8 w-20 bg-gray-200 rounded" />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="p-6">
|
|
|
|
|
<div className="grid grid-cols-1 gap-8 sm:grid-cols-2">
|
|
|
|
|
{Array.from({ length: 4 }).map((_, i) => (
|
|
|
|
|
<div key={i} className="space-y-2">
|
|
|
|
|
<Skeleton className="h-4 w-24" />
|
|
|
|
|
<Skeleton className="h-10 w-full" />
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
<div className="sm:col-span-2">
|
|
|
|
|
<Skeleton className="h-4 w-28 mb-3" />
|
|
|
|
|
<div className="bg-gray-50 rounded-lg p-4 border border-gray-200">
|
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<Skeleton className="h-5 w-48" />
|
|
|
|
|
<Skeleton className="h-5 w-24" />
|
|
|
|
|
</div>
|
|
|
|
|
<Skeleton className="h-3 w-64 mt-2" />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex items-center justify-end space-x-3 pt-6 border-t border-gray-200 mt-6">
|
|
|
|
|
<Skeleton className="h-9 w-24" />
|
|
|
|
|
<Skeleton className="h-9 w-28" />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="bg-white shadow-sm rounded-xl border border-gray-200">
|
|
|
|
|
<div className="px-6 py-5 border-b border-gray-200">
|
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<div className="flex items-center space-x-3">
|
|
|
|
|
<div className="h-6 w-6 bg-blue-200 rounded" />
|
|
|
|
|
<div className="h-6 w-48 bg-gray-200 rounded" />
|
|
|
|
|
</div>
|
|
|
|
|
<div className="h-8 w-20 bg-gray-200 rounded" />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="p-6">
|
|
|
|
|
<div className="bg-gray-50 rounded-lg p-4 border border-gray-200">
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Skeleton className="h-4 w-60" />
|
|
|
|
|
<Skeleton className="h-4 w-48" />
|
|
|
|
|
<Skeleton className="h-4 w-52" />
|
|
|
|
|
<Skeleton className="h-4 w-32" />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex items-center justify-end space-x-3 pt-6">
|
|
|
|
|
<Skeleton className="h-9 w-24" />
|
|
|
|
|
<Skeleton className="h-9 w-28" />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="py-6">
|
|
|
|
|
<div className="max-w-4xl mx-auto px-4 sm:px-6 md:px-8">
|
|
|
|
|
{error && (
|
|
|
|
|
<AlertBanner variant="error" title="Error" className="mb-6">
|
|
|
|
|
{error}
|
|
|
|
|
</AlertBanner>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<div className="bg-white shadow-sm rounded-xl border border-gray-200">
|
|
|
|
|
<div className="px-6 py-5 border-b border-gray-200">
|
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<div className="flex items-center space-x-3">
|
|
|
|
|
<UserIcon className="h-6 w-6 text-blue-600" />
|
|
|
|
|
<h2 className="text-xl font-semibold text-gray-900">Personal Information</h2>
|
|
|
|
|
</div>
|
|
|
|
|
{!editingProfile && (
|
2025-11-04 11:14:26 +09:00
|
|
|
<Button
|
|
|
|
|
variant="outline"
|
|
|
|
|
size="sm"
|
2025-10-29 13:29:28 +09:00
|
|
|
onClick={() => setEditingProfile(true)}
|
|
|
|
|
leftIcon={<PencilIcon className="h-4 w-4" />}
|
|
|
|
|
>
|
2025-09-17 18:43:43 +09:00
|
|
|
Edit
|
|
|
|
|
</Button>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="p-6">
|
2025-10-29 13:29:28 +09:00
|
|
|
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
2025-09-17 18:43:43 +09:00
|
|
|
<div>
|
|
|
|
|
<label className="block text-sm font-medium text-gray-700 mb-2">First Name</label>
|
|
|
|
|
{editingProfile ? (
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
2025-10-09 10:49:03 +09:00
|
|
|
value={profile.values.firstname}
|
|
|
|
|
onChange={e => profile.setValue("firstname", e.target.value)}
|
2025-10-29 13:29:28 +09:00
|
|
|
className="block w-full px-4 py-2.5 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors"
|
2025-09-17 18:43:43 +09:00
|
|
|
/>
|
|
|
|
|
) : (
|
2025-10-29 13:29:28 +09:00
|
|
|
<p className="text-base text-gray-900 py-2">
|
2025-10-09 10:49:03 +09:00
|
|
|
{user?.firstname || <span className="text-gray-500 italic">Not provided</span>}
|
2025-09-17 18:43:43 +09:00
|
|
|
</p>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label className="block text-sm font-medium text-gray-700 mb-2">Last Name</label>
|
|
|
|
|
{editingProfile ? (
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
2025-10-09 10:49:03 +09:00
|
|
|
value={profile.values.lastname}
|
|
|
|
|
onChange={e => profile.setValue("lastname", e.target.value)}
|
2025-10-29 13:29:28 +09:00
|
|
|
className="block w-full px-4 py-2.5 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors"
|
2025-09-17 18:43:43 +09:00
|
|
|
/>
|
|
|
|
|
) : (
|
2025-10-29 13:29:28 +09:00
|
|
|
<p className="text-base text-gray-900 py-2">
|
2025-10-09 10:49:03 +09:00
|
|
|
{user?.lastname || <span className="text-gray-500 italic">Not provided</span>}
|
2025-09-17 18:43:43 +09:00
|
|
|
</p>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
<div className="sm:col-span-2">
|
2025-10-29 13:29:28 +09:00
|
|
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
2025-09-17 18:43:43 +09:00
|
|
|
Email Address
|
|
|
|
|
</label>
|
|
|
|
|
<div className="bg-gray-50 rounded-lg p-4 border border-gray-200">
|
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<p className="text-base text-gray-900 font-medium">{user?.email}</p>
|
|
|
|
|
</div>
|
|
|
|
|
<p className="text-xs text-gray-500 mt-2">
|
|
|
|
|
Email cannot be changed from the portal.
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label className="block text-sm font-medium text-gray-700 mb-2">Phone Number</label>
|
|
|
|
|
{editingProfile ? (
|
|
|
|
|
<input
|
|
|
|
|
type="tel"
|
2025-10-09 10:49:03 +09:00
|
|
|
value={profile.values.phonenumber}
|
|
|
|
|
onChange={e => profile.setValue("phonenumber", e.target.value)}
|
2025-09-17 18:43:43 +09:00
|
|
|
placeholder="+81 XX-XXXX-XXXX"
|
2025-10-29 13:29:28 +09:00
|
|
|
className="block w-full px-4 py-2.5 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors"
|
2025-09-17 18:43:43 +09:00
|
|
|
/>
|
|
|
|
|
) : (
|
2025-10-29 13:29:28 +09:00
|
|
|
<p className="text-base text-gray-900 py-2">
|
2025-10-22 10:58:16 +09:00
|
|
|
{user?.phonenumber || (
|
|
|
|
|
<span className="text-gray-500 italic">Not provided</span>
|
|
|
|
|
)}
|
2025-09-17 18:43:43 +09:00
|
|
|
</p>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{editingProfile && (
|
|
|
|
|
<div className="flex items-center justify-end space-x-3 pt-6 border-t border-gray-200 mt-6">
|
|
|
|
|
<Button
|
|
|
|
|
variant="outline"
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={() => setEditingProfile(false)}
|
2025-09-19 16:34:10 +09:00
|
|
|
disabled={profile.isSubmitting}
|
2025-10-29 13:29:28 +09:00
|
|
|
leftIcon={<XMarkIcon className="h-4 w-4" />}
|
2025-09-17 18:43:43 +09:00
|
|
|
>
|
|
|
|
|
Cancel
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={() => {
|
2025-09-25 17:42:36 +09:00
|
|
|
void profile
|
|
|
|
|
.handleSubmit()
|
|
|
|
|
.then(() => {
|
|
|
|
|
setEditingProfile(false);
|
|
|
|
|
})
|
|
|
|
|
.catch(() => {
|
|
|
|
|
// Error is handled by useZodForm
|
|
|
|
|
});
|
2025-09-17 18:43:43 +09:00
|
|
|
}}
|
2025-10-29 13:29:28 +09:00
|
|
|
isLoading={profile.isSubmitting}
|
|
|
|
|
leftIcon={!profile.isSubmitting ? <CheckIcon className="h-4 w-4" /> : undefined}
|
2025-09-17 18:43:43 +09:00
|
|
|
>
|
2025-10-29 13:29:28 +09:00
|
|
|
{profile.isSubmitting ? "Saving..." : "Save Changes"}
|
2025-09-17 18:43:43 +09:00
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="bg-white shadow-sm rounded-xl border border-gray-200 mt-8">
|
|
|
|
|
<div className="px-6 py-5 border-b border-gray-200">
|
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<div className="flex items-center space-x-3">
|
|
|
|
|
<MapPinIcon className="h-6 w-6 text-blue-600" />
|
|
|
|
|
<h2 className="text-xl font-semibold text-gray-900">Address Information</h2>
|
|
|
|
|
</div>
|
|
|
|
|
{!editingAddress && (
|
2025-11-04 11:14:26 +09:00
|
|
|
<Button
|
|
|
|
|
variant="outline"
|
|
|
|
|
size="sm"
|
2025-10-29 13:29:28 +09:00
|
|
|
onClick={() => setEditingAddress(true)}
|
|
|
|
|
leftIcon={<PencilIcon className="h-4 w-4" />}
|
|
|
|
|
>
|
2025-09-17 18:43:43 +09:00
|
|
|
Edit
|
|
|
|
|
</Button>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="p-6">
|
|
|
|
|
{editingAddress ? (
|
|
|
|
|
<div className="space-y-6">
|
|
|
|
|
<AddressForm
|
|
|
|
|
initialAddress={{
|
2025-10-07 17:38:39 +09:00
|
|
|
address1: address.values.address1,
|
|
|
|
|
address2: address.values.address2,
|
2025-09-19 16:34:10 +09:00
|
|
|
city: address.values.city,
|
|
|
|
|
state: address.values.state,
|
2025-10-07 17:38:39 +09:00
|
|
|
postcode: address.values.postcode,
|
2025-09-19 16:34:10 +09:00
|
|
|
country: address.values.country,
|
2025-10-07 17:38:39 +09:00
|
|
|
countryCode: address.values.countryCode,
|
|
|
|
|
phoneNumber: address.values.phoneNumber,
|
|
|
|
|
phoneCountryCode: address.values.phoneCountryCode,
|
2025-09-17 18:43:43 +09:00
|
|
|
}}
|
2025-09-19 17:37:46 +09:00
|
|
|
onChange={a => {
|
2025-10-07 17:38:39 +09:00
|
|
|
address.setValue("address1", a.address1 ?? "");
|
|
|
|
|
address.setValue("address2", a.address2 ?? "");
|
2025-09-25 17:42:36 +09:00
|
|
|
address.setValue("city", a.city ?? "");
|
|
|
|
|
address.setValue("state", a.state ?? "");
|
2025-10-07 17:38:39 +09:00
|
|
|
address.setValue("postcode", a.postcode ?? "");
|
2025-09-25 17:42:36 +09:00
|
|
|
address.setValue("country", a.country ?? "");
|
2025-10-07 17:38:39 +09:00
|
|
|
address.setValue("countryCode", a.countryCode ?? "");
|
|
|
|
|
address.setValue("phoneNumber", a.phoneNumber ?? "");
|
|
|
|
|
address.setValue("phoneCountryCode", a.phoneCountryCode ?? "");
|
2025-09-19 17:37:46 +09:00
|
|
|
}}
|
2025-09-17 18:43:43 +09:00
|
|
|
title="Mailing Address"
|
|
|
|
|
/>
|
|
|
|
|
<div className="flex items-center justify-end space-x-3 pt-2">
|
|
|
|
|
<Button
|
|
|
|
|
variant="outline"
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={() => setEditingAddress(false)}
|
2025-09-19 16:34:10 +09:00
|
|
|
disabled={address.isSubmitting}
|
2025-10-29 13:29:28 +09:00
|
|
|
leftIcon={<XMarkIcon className="h-4 w-4" />}
|
2025-09-17 18:43:43 +09:00
|
|
|
>
|
|
|
|
|
Cancel
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={() => {
|
2025-09-25 17:42:36 +09:00
|
|
|
void address
|
|
|
|
|
.handleSubmit()
|
|
|
|
|
.then(() => {
|
|
|
|
|
setEditingAddress(false);
|
|
|
|
|
})
|
|
|
|
|
.catch(() => {
|
|
|
|
|
// Error is handled by useZodForm
|
|
|
|
|
});
|
2025-09-17 18:43:43 +09:00
|
|
|
}}
|
2025-10-29 13:29:28 +09:00
|
|
|
isLoading={address.isSubmitting}
|
|
|
|
|
leftIcon={!address.isSubmitting ? <CheckIcon className="h-4 w-4" /> : undefined}
|
2025-09-17 18:43:43 +09:00
|
|
|
>
|
2025-10-29 13:29:28 +09:00
|
|
|
{address.isSubmitting ? "Saving..." : "Save Address"}
|
2025-09-17 18:43:43 +09:00
|
|
|
</Button>
|
|
|
|
|
</div>
|
2025-09-19 16:34:10 +09:00
|
|
|
{address.submitError && (
|
2025-09-17 18:43:43 +09:00
|
|
|
<AlertBanner variant="error" title="Address Error">
|
2025-09-19 16:34:10 +09:00
|
|
|
{address.submitError}
|
2025-09-17 18:43:43 +09:00
|
|
|
</AlertBanner>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<div>
|
2025-10-07 17:38:39 +09:00
|
|
|
{address.values.address1 || address.values.city ? (
|
2025-10-29 13:29:28 +09:00
|
|
|
<div className="bg-gray-50 rounded-lg p-5 border border-gray-200">
|
|
|
|
|
<div className="text-gray-900 space-y-1.5">
|
2025-10-07 17:38:39 +09:00
|
|
|
{address.values.address1 && (
|
2025-10-29 13:29:28 +09:00
|
|
|
<p className="font-medium text-base">{address.values.address1}</p>
|
2025-09-25 17:42:36 +09:00
|
|
|
)}
|
2025-11-04 11:14:26 +09:00
|
|
|
{address.values.address2 && (
|
|
|
|
|
<p className="text-gray-700">{address.values.address2}</p>
|
|
|
|
|
)}
|
2025-10-29 13:29:28 +09:00
|
|
|
<p className="text-gray-700">
|
2025-10-07 17:38:39 +09:00
|
|
|
{[address.values.city, address.values.state, address.values.postcode]
|
2025-09-17 18:43:43 +09:00
|
|
|
.filter(Boolean)
|
|
|
|
|
.join(", ")}
|
|
|
|
|
</p>
|
2025-10-29 13:29:28 +09:00
|
|
|
<p className="text-gray-700">{address.values.country}</p>
|
2025-09-17 18:43:43 +09:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
2025-10-29 13:29:28 +09:00
|
|
|
<div className="text-center py-12">
|
2025-09-17 18:43:43 +09:00
|
|
|
<MapPinIcon className="h-12 w-12 text-gray-400 mx-auto mb-4" />
|
|
|
|
|
<p className="text-gray-600 mb-4">No address on file</p>
|
2025-11-04 11:14:26 +09:00
|
|
|
<Button
|
2025-10-29 13:29:28 +09:00
|
|
|
onClick={() => setEditingAddress(true)}
|
|
|
|
|
leftIcon={<PencilIcon className="h-4 w-4" />}
|
|
|
|
|
>
|
|
|
|
|
Add Address
|
|
|
|
|
</Button>
|
2025-09-17 18:43:43 +09:00
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|