"use client"; import { useEffect, useState } from "react"; import { AppShell } from "../../../components/app-shell"; import { apiFetch } from "@/lib/api"; type ProfileData = { user: { id: string; email: string; fullName?: string | null; phone?: string | null; companyName?: string | null; addressLine1?: string | null; addressLine2?: string | null; city?: string | null; state?: string | null; postalCode?: string | null; country?: string | null; }; }; type PrivacySummary = { subject: { email: string; createdAt: string; emailVerified: boolean; twoFactorEnabled: boolean; }; dataCategories: Record; controls: { exportEndpoint: string; deletionEndpoint: string; excludedFromExport?: string[]; }; }; export default function ProfilePage() { const [status, setStatus] = useState(""); const [isError, setIsError] = useState(false); const [privacySummary, setPrivacySummary] = useState(null); const [privacyStatus, setPrivacyStatus] = useState(""); const [privacyError, setPrivacyError] = useState(false); const [fullName, setFullName] = useState(""); const [phone, setPhone] = useState(""); const [companyName, setCompanyName] = useState(""); const [addressLine1, setAddressLine1] = useState(""); const [addressLine2, setAddressLine2] = useState(""); const [city, setCity] = useState(""); const [state, setState] = useState(""); const [postalCode, setPostalCode] = useState(""); const [country, setCountry] = useState(""); useEffect(() => { apiFetch("/api/auth/me") .then((res) => { if (!res.error && res.data) { const u = (res.data as unknown as ProfileData).user; if (u) { setFullName(u.fullName ?? ""); setPhone(u.phone ?? ""); setCompanyName(u.companyName ?? ""); setAddressLine1(u.addressLine1 ?? ""); setAddressLine2(u.addressLine2 ?? ""); setCity(u.city ?? ""); setState(u.state ?? ""); setPostalCode(u.postalCode ?? ""); setCountry(u.country ?? ""); } } }) .catch(() => {}); apiFetch("/api/auth/me/privacy-summary") .then((res) => { if (!res.error && res.data) { setPrivacySummary(res.data as PrivacySummary); } }) .catch(() => {}); }, []); const onSubmit = async (event: React.FormEvent) => { event.preventDefault(); setStatus("Saving profile..."); setIsError(false); const res = await apiFetch("/api/auth/profile", { method: "PATCH", body: JSON.stringify({ fullName: fullName || undefined, phone: phone || undefined, companyName: companyName || undefined, addressLine1: addressLine1 || undefined, addressLine2: addressLine2 || undefined, city: city || undefined, state: state || undefined, postalCode: postalCode || undefined, country: country || undefined, }), }); if (res.error) { setStatus(res.error.message ?? "Profile update failed."); setIsError(true); return; } setStatus("Profile saved successfully."); }; const downloadPersonalData = async () => { setPrivacyStatus("Preparing personal data export..."); setPrivacyError(false); const res = await apiFetch>("/api/auth/me/data-export"); if (res.error || !res.data) { setPrivacyStatus(res.error?.message ?? "Personal data export failed."); setPrivacyError(true); return; } const blob = new Blob([JSON.stringify(res.data, null, 2)], { type: "application/json" }); const url = URL.createObjectURL(blob); const anchor = document.createElement("a"); anchor.href = url; anchor.download = `ledgerone-personal-data-${new Date().toISOString().slice(0, 10)}.json`; document.body.appendChild(anchor); anchor.click(); anchor.remove(); URL.revokeObjectURL(url); setPrivacyStatus("Personal data export downloaded."); }; const deleteAccount = async () => { const confirmed = window.confirm("Delete this LedgerOne account and associated personal data? This cannot be undone."); if (!confirmed) return; setPrivacyStatus("Deleting account..."); setPrivacyError(false); const res = await apiFetch<{ message: string }>("/api/auth/me", { method: "DELETE" }); if (res.error) { setPrivacyStatus(res.error.message ?? "Account deletion failed."); setPrivacyError(true); return; } setPrivacyStatus("Account deleted. Redirecting to sign in..."); window.location.href = "/login"; }; const inputCls = "w-full rounded-lg border border-border bg-background/50 px-3 py-2 text-sm focus:border-primary focus:outline-none focus:ring-primary transition-all"; const labelCls = "block text-xs font-medium text-muted-foreground mb-1 uppercase tracking-wide"; const dataCategoryEntries = privacySummary ? Object.entries(privacySummary.dataCategories) : []; return (

Personal & Business Details

These details appear on tax exports and CSV reports.

setFullName(e.target.value)} required />
setPhone(e.target.value)} />
setCompanyName(e.target.value)} />
setAddressLine1(e.target.value)} />
setAddressLine2(e.target.value)} />
setCity(e.target.value)} />
setState(e.target.value)} />
setPostalCode(e.target.value)} />
setCountry(e.target.value)} />
{status && (
{status}
)}

Data & Privacy

Review stored data categories, download a minimized personal data export, or erase your account.

{dataCategoryEntries.length ? dataCategoryEntries.map(([key, value]) => (
{key.replace(/([A-Z])/g, " $1")}
{value}
)) : (
Privacy inventory is not available yet.
)}
{privacySummary?.controls.excludedFromExport?.length ? (
Excluded from export

{privacySummary.controls.excludedFromExport.join(", ")}

) : null}
{privacyStatus && (
{privacyStatus}
)}
); }