168 lines
4.4 KiB
TypeScript
Raw Normal View History

"use client";
import { useState } from "react";
import { UserIcon } from "@heroicons/react/24/outline";
import { AlertBanner } from "@/components/molecules/AlertBanner/AlertBanner";
import { PageLayout } from "@/components/templates";
import { useAuthStore, type AuthState } from "@/features/auth/stores/auth.store";
import { useProfileDataLoading } from "@/features/account/hooks";
import {
useResidenceCardVerification,
useVerificationFileUpload,
} from "@/features/verification/hooks";
import {
PersonalInfoCard,
AddressCard,
VerificationCard,
ProfileLoadingSkeleton,
} from "@/features/account/components";
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(() => {});
}}
/>
);
}
export default function ProfileContainer() {
const { user } = useAuthStore();
const [editingProfile, setEditingProfile] = useState(false);
const [editingAddress, setEditingAddress] = useState(false);
const { isLoading, error, reload, profile, address } = useProfileDataLoading({
email: user?.email || "",
phonenumber: user?.phonenumber || "",
});
const verificationQuery = useResidenceCardVerification();
const fileUpload = useVerificationFileUpload({
verificationStatus: verificationQuery.data?.status,
});
if (isLoading) {
return (
<PageLayout
icon={<UserIcon />}
title="Profile"
description="Manage your account information"
loading
>
<ProfileLoadingSkeleton />
</PageLayout>
);
}
return (
<PageLayout
icon={<UserIcon />}
title="Profile"
description="Manage your account information"
error={error}
onRetry={reload}
>
{error && (
<AlertBanner variant="error" title="Unable to load profile" className="mb-6" elevated>
{error}
</AlertBanner>
)}
<PersonalInfoSection
user={user}
profile={profile}
editingProfile={editingProfile}
setEditingProfile={setEditingProfile}
/>
<AddressSection
address={address}
editingAddress={editingAddress}
setEditingAddress={setEditingAddress}
/>
<VerificationCard verificationQuery={verificationQuery} fileUpload={fileUpload} />
</PageLayout>
);
}