157 lines
4.5 KiB
TypeScript
Raw Normal View History

"use client";
import { useEffect, useState, useCallback } from "react";
import { useAuthStore } from "@/features/auth/services/auth.store";
import { accountService } from "@/features/account/services/account.service";
import { logger } from "@customer-portal/logging";
// Use centralized profile types
import type { ProfileFormData } from "@customer-portal/domain";
export type { ProfileFormData };
// Address type moved to domain package
import type { Address } from "@customer-portal/domain";
export function useProfileData() {
const { user } = useAuthStore();
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [isSavingProfile, setIsSavingProfile] = useState(false);
const [isSavingAddress, setIsSavingAddress] = useState(false);
const [billingInfo, setBillingInfo] = useState<{ address: Address } | null>(null);
const [formData, setFormData] = useState<ProfileFormData>({
firstName: user?.firstName || "",
lastName: user?.lastName || "",
email: user?.email || "",
phone: user?.phone || "",
});
const [addressData, setAddress] = useState<Address>({
street: "",
streetLine2: "",
city: "",
state: "",
postalCode: "",
country: "",
});
const fetchBillingInfo = useCallback(async () => {
try {
setLoading(true);
const address = await accountService.getAddress().catch(() => null);
if (address)
setBillingInfo({
address: {
street: address.street || "",
streetLine2: address.streetLine2 || "",
city: address.city || "",
state: address.state || "",
postalCode: address.postalCode || "",
country: address.country || "",
},
});
if (address)
setAddress({
street: address.street || "",
streetLine2: address.streetLine2 || "",
city: address.city || "",
state: address.state || "",
postalCode: address.postalCode || "",
country: address.country || "",
});
} catch (err) {
setError(err instanceof Error ? err.message : "Failed to load address information");
} finally {
setLoading(false);
}
}, []);
useEffect(() => {
void fetchBillingInfo();
}, [fetchBillingInfo]);
useEffect(() => {
if (user) {
setFormData({
firstName: user.firstName || "",
lastName: user.lastName || "",
email: user.email || "",
phone: user.phone || "",
});
}
}, [user]);
const saveProfile = async (next: ProfileFormData) => {
setIsSavingProfile(true);
try {
const { tokens } = useAuthStore.getState();
if (!tokens?.accessToken) throw new Error("Authentication required");
const response = await fetch("/api/me", {
method: "PATCH",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${tokens.accessToken}`,
},
body: JSON.stringify({
firstName: next.firstName,
lastName: next.lastName,
phone: next.phone,
}),
});
if (!response.ok) throw new Error("Failed to update profile");
const updatedUser = (await response.json()) as Partial<typeof user>;
useAuthStore.setState(state => ({
...state,
user: state.user ? { ...state.user, ...updatedUser } : state.user,
}));
setFormData(next);
return true;
} catch (err) {
logger.error(err, "Error updating profile");
setError(err instanceof Error ? err.message : "Failed to update profile");
return false;
} finally {
setIsSavingProfile(false);
}
};
const saveAddress = async (next: Address) => {
setIsSavingAddress(true);
setError(null);
try {
await accountService.updateAddress({
street: next.street,
streetLine2: next.streetLine2,
city: next.city,
state: next.state,
postalCode: next.postalCode,
country: next.country,
});
setBillingInfo({ address: next });
setAddress(next);
return true;
} catch (err) {
logger.error(err, "Error updating address");
setError(err instanceof Error ? err.message : "Failed to update address");
return false;
} finally {
setIsSavingAddress(false);
}
};
return {
loading,
error,
billingInfo,
formData,
setFormData,
addressData,
setAddressData: setAddress,
saveProfile,
saveAddress,
isSavingProfile,
isSavingAddress,
} as const;
}