import { api } from "@/services/api"; import type { ProfileResponse } from "@/types/profile"; import { Alert, Card, Center, Container, Group, Loader, Tabs, Text, Title, } from "@mantine/core"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { AlertCircle, Briefcase, Building2, FileCheck, User, UserCheck, } from "lucide-react"; import { useCallback, useEffect, useState } from "react"; import { useNavigate, useSearchParams } from "react-router-dom"; import TabCompanyProfile from "./settings/TabCompanyProfile"; import TabContactPerson from "./settings/TabContactPerson"; import TabDocuments from "./settings/TabDocuments"; import TabGeneralManager from "./settings/TabGeneralManager"; import TabPowerOfAttorney from "./settings/TabPowerOfAttorney"; type SettingsTab = "company" | "contact" | "gm" | "poa" | "documents"; function tabIncomplete(tabId: SettingsTab, profile?: ProfileResponse | null): boolean { if (!profile) return false; switch (tabId) { case "company": return !profile.companyEmail || !profile.companyPhone || !profile.companyAddress || !profile.fanNumber; case "contact": return !profile.contactPersonName || !profile.contactPersonPhone; case "gm": return !profile.generalManagerName || !profile.generalManagerEmail || !profile.generalManagerPhone; case "poa": return false; case "documents": return false; } } const TABS: { id: SettingsTab; label: string; icon: React.ReactNode }[] = [ { id: "company", label: "Company Profile", icon: }, { id: "contact", label: "Contact Person", icon: }, { id: "gm", label: "General Manager", icon: }, { id: "poa", label: "Power of Attorney", icon: }, { id: "documents", label: "Documents", icon: }, ]; const TAB_ORDER: SettingsTab[] = [ "company", "contact", "gm", "poa", "documents", ]; export default function SettingsPage() { const navigate = useNavigate(); const queryClient = useQueryClient(); const [searchParams, setSearchParams] = useSearchParams(); const tab = (searchParams.get("tab") as SettingsTab) || "company"; const setTab = useCallback( (t: SettingsTab) => { setSearchParams( (prev) => { const next = new URLSearchParams(prev); next.set("tab", t); return next; }, { replace: true }, ); }, [setSearchParams], ); const profileQuery = useQuery( api.companies.getProfile.queryOptions({ retry: false, refetchOnWindowFocus: false, }), ); const profile = profileQuery.data; useEffect(() => { if (profileQuery.dataUpdatedAt > 0) { queryClient.invalidateQueries({ queryKey: api.companies.getInfo.queryKey(), }); } }, [profileQuery.dataUpdatedAt, queryClient]); const [isOnboarding, setIsOnboarding] = useState(null); useEffect(() => { if (profileQuery.isFetched && isOnboarding === null) { setIsOnboarding(!profileQuery.data); } }, [profileQuery.isFetched, profileQuery.data, isOnboarding]); const handleOnboardingSuccess = useCallback(() => { setTab("contact"); }, [setTab]); const handleContactContinue = useCallback(() => { setTab("gm"); }, [setTab]); const handleGMContinue = useCallback(() => { setTab("poa"); }, [setTab]); const handlePOAContinue = useCallback(() => { setTab("documents"); }, [setTab]); const handleDocumentsContinue = useCallback(() => { navigate("/portal"); }, [navigate]); if (profileQuery.isPending) { return (
); } const onboarding = isOnboarding === true; const renderProfileContent = (children: React.ReactNode) => { if (onboarding && tab !== "company" && !profile) { return (
); } if (!profile) { return (
} color="gray" variant="light" > Please complete the company profile first.
); } return children; }; return (
{onboarding ? "Complete Your Profile" : "Account Settings"} {onboarding ? "Set up your company profile, personnel, and documents to get started" : "Manage your company profile, personnel, and documents"}
{ if (!value) return; // if (onboarding) return; setTab(value as SettingsTab); }} > {TABS.map((t) => ( ) : undefined } > {t.label} ))} {!profile ? ( ) : ( )} {renderProfileContent( , )} {renderProfileContent( , )} {renderProfileContent( , )} {renderProfileContent( , )}
); }