2025-09-17 18:43:43 +09:00
|
|
|
"use client";
|
|
|
|
|
|
2026-01-19 15:47:43 +09:00
|
|
|
import { useState } from "react";
|
|
|
|
|
import { UserIcon } from "@heroicons/react/24/outline";
|
2025-09-25 15:54:54 +09:00
|
|
|
import { AlertBanner } from "@/components/molecules/AlertBanner/AlertBanner";
|
2026-01-19 15:47:43 +09:00
|
|
|
import { PageLayout } from "@/components/templates";
|
2026-03-05 15:31:47 +09:00
|
|
|
import { useAuthStore, type AuthState } from "@/features/auth/stores/auth.store";
|
2026-01-19 15:47:43 +09:00
|
|
|
import { useProfileDataLoading } from "@/features/account/hooks";
|
2025-12-23 15:19:20 +09:00
|
|
|
import {
|
|
|
|
|
useResidenceCardVerification,
|
2026-01-19 15:47:43 +09:00
|
|
|
useVerificationFileUpload,
|
|
|
|
|
} from "@/features/verification/hooks";
|
|
|
|
|
import {
|
|
|
|
|
PersonalInfoCard,
|
|
|
|
|
AddressCard,
|
|
|
|
|
VerificationCard,
|
|
|
|
|
ProfileLoadingSkeleton,
|
|
|
|
|
} from "@/features/account/components";
|
2025-09-17 18:43:43 +09:00
|
|
|
|
2026-03-05 15:31:47 +09:00
|
|
|
const ADDRESS_FIELDS = [
|
|
|
|
|
"address1",
|
|
|
|
|
"address2",
|
|
|
|
|
"city",
|
|
|
|
|
"state",
|
|
|
|
|
"postcode",
|
|
|
|
|
"country",
|
|
|
|
|
"countryCode",
|
|
|
|
|
"phoneNumber",
|
|
|
|
|
"phoneCountryCode",
|
|
|
|
|
] as const;
|
|
|
|
|
|
|
|
|
|
function buildPersonalInfoData(user: AuthState["user"]) {
|
|
|
|
|
return {
|
|
|
|
|
firstname: user?.firstname ?? null,
|
|
|
|
|
lastname: user?.lastname ?? null,
|
|
|
|
|
email: user?.email ?? "",
|
|
|
|
|
phonenumber: user?.phonenumber ?? null,
|
|
|
|
|
sfNumber: user?.sfNumber ?? null,
|
|
|
|
|
dateOfBirth: user?.dateOfBirth ?? null,
|
|
|
|
|
gender: user?.gender ?? null,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function PersonalInfoSection({
|
|
|
|
|
user,
|
|
|
|
|
profile,
|
|
|
|
|
editingProfile,
|
|
|
|
|
setEditingProfile,
|
|
|
|
|
}: {
|
|
|
|
|
user: AuthState["user"];
|
|
|
|
|
profile: ReturnType<typeof useProfileDataLoading>["profile"];
|
|
|
|
|
editingProfile: boolean;
|
|
|
|
|
setEditingProfile: (v: boolean) => void;
|
|
|
|
|
}) {
|
|
|
|
|
return (
|
|
|
|
|
<PersonalInfoCard
|
|
|
|
|
data={buildPersonalInfoData(user)}
|
|
|
|
|
editEmail={profile.values.email ?? ""}
|
|
|
|
|
editPhoneNumber={profile.values.phonenumber ?? ""}
|
|
|
|
|
isEditing={editingProfile}
|
|
|
|
|
isSaving={profile.isSubmitting}
|
|
|
|
|
onEdit={() => setEditingProfile(true)}
|
|
|
|
|
onCancel={() => setEditingProfile(false)}
|
|
|
|
|
onChange={(field, value) => profile.setValue(field, value)}
|
|
|
|
|
onSave={() => {
|
|
|
|
|
void profile
|
|
|
|
|
.handleSubmit()
|
|
|
|
|
.then(() => setEditingProfile(false))
|
|
|
|
|
.catch(() => {});
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function AddressSection({
|
|
|
|
|
address,
|
|
|
|
|
editingAddress,
|
|
|
|
|
setEditingAddress,
|
|
|
|
|
}: {
|
|
|
|
|
address: ReturnType<typeof useProfileDataLoading>["address"];
|
|
|
|
|
editingAddress: boolean;
|
|
|
|
|
setEditingAddress: (v: boolean) => void;
|
|
|
|
|
}) {
|
|
|
|
|
return (
|
|
|
|
|
<AddressCard
|
|
|
|
|
address={
|
|
|
|
|
Object.fromEntries(ADDRESS_FIELDS.map(f => [f, address.values[f]])) as Record<
|
|
|
|
|
(typeof ADDRESS_FIELDS)[number],
|
|
|
|
|
string
|
|
|
|
|
>
|
|
|
|
|
}
|
|
|
|
|
isEditing={editingAddress}
|
|
|
|
|
isSaving={address.isSubmitting}
|
|
|
|
|
error={address.submitError}
|
|
|
|
|
onEdit={() => setEditingAddress(true)}
|
|
|
|
|
onCancel={() => setEditingAddress(false)}
|
|
|
|
|
onAddressChange={a => {
|
|
|
|
|
for (const f of ADDRESS_FIELDS) address.setValue(f, (a as Record<string, string>)[f] ?? "");
|
|
|
|
|
}}
|
|
|
|
|
onSave={() => {
|
|
|
|
|
void address
|
|
|
|
|
.handleSubmit()
|
|
|
|
|
.then(() => setEditingAddress(false))
|
|
|
|
|
.catch(() => {});
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-17 18:43:43 +09:00
|
|
|
export default function ProfileContainer() {
|
|
|
|
|
const { user } = useAuthStore();
|
|
|
|
|
const [editingProfile, setEditingProfile] = useState(false);
|
|
|
|
|
const [editingAddress, setEditingAddress] = useState(false);
|
|
|
|
|
|
2026-01-19 15:47:43 +09:00
|
|
|
const { isLoading, error, reload, profile, address } = useProfileDataLoading({
|
2025-12-15 17:29:28 +09:00
|
|
|
email: user?.email || "",
|
2025-10-09 10:49:03 +09:00
|
|
|
phonenumber: user?.phonenumber || "",
|
2025-09-17 18:43:43 +09:00
|
|
|
});
|
|
|
|
|
|
2025-12-23 15:19:20 +09:00
|
|
|
const verificationQuery = useResidenceCardVerification();
|
2026-01-19 15:47:43 +09:00
|
|
|
const fileUpload = useVerificationFileUpload({
|
|
|
|
|
verificationStatus: verificationQuery.data?.status,
|
|
|
|
|
});
|
2025-09-17 18:43:43 +09:00
|
|
|
|
2026-01-19 15:47:43 +09:00
|
|
|
if (isLoading) {
|
2025-09-17 18:43:43 +09:00
|
|
|
return (
|
2025-12-16 13:54:31 +09:00
|
|
|
<PageLayout
|
|
|
|
|
icon={<UserIcon />}
|
|
|
|
|
title="Profile"
|
|
|
|
|
description="Manage your account information"
|
|
|
|
|
loading
|
|
|
|
|
>
|
2026-01-19 15:47:43 +09:00
|
|
|
<ProfileLoadingSkeleton />
|
2025-12-16 13:54:31 +09:00
|
|
|
</PageLayout>
|
2025-09-17 18:43:43 +09:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
2025-12-16 13:54:31 +09:00
|
|
|
<PageLayout
|
|
|
|
|
icon={<UserIcon />}
|
|
|
|
|
title="Profile"
|
|
|
|
|
description="Manage your account information"
|
|
|
|
|
error={error}
|
2026-01-19 15:47:43 +09:00
|
|
|
onRetry={reload}
|
2025-12-16 13:54:31 +09:00
|
|
|
>
|
|
|
|
|
{error && (
|
|
|
|
|
<AlertBanner variant="error" title="Unable to load profile" className="mb-6" elevated>
|
|
|
|
|
{error}
|
|
|
|
|
</AlertBanner>
|
|
|
|
|
)}
|
2025-09-17 18:43:43 +09:00
|
|
|
|
2026-03-05 15:31:47 +09:00
|
|
|
<PersonalInfoSection
|
|
|
|
|
user={user}
|
|
|
|
|
profile={profile}
|
|
|
|
|
editingProfile={editingProfile}
|
|
|
|
|
setEditingProfile={setEditingProfile}
|
2026-01-19 15:47:43 +09:00
|
|
|
/>
|
2026-03-05 15:31:47 +09:00
|
|
|
<AddressSection
|
|
|
|
|
address={address}
|
|
|
|
|
editingAddress={editingAddress}
|
|
|
|
|
setEditingAddress={setEditingAddress}
|
2026-01-19 15:47:43 +09:00
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<VerificationCard verificationQuery={verificationQuery} fileUpload={fileUpload} />
|
2025-12-16 13:54:31 +09:00
|
|
|
</PageLayout>
|
2025-09-17 18:43:43 +09:00
|
|
|
);
|
|
|
|
|
}
|