feat: merge the role and nationality step

This commit is contained in:
Nathnael
2026-07-03 12:09:35 +00:00
parent 414c9610dc
commit d3707fe704

View File

@@ -10,10 +10,8 @@ import {
} from "@mantine/core"; } from "@mantine/core";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { import {
ArrowLeft,
ArrowRight, ArrowRight,
Building2, Building2,
CheckCircle2,
Clock, Clock,
FileText, FileText,
Globe2, Globe2,
@@ -42,42 +40,29 @@ import type { UpdateProfilePayload } from "@/types/profile";
import { extractApiError } from "@/utils/result"; import { extractApiError } from "@/utils/result";
/** Form steps rendered by CompanyProfileForm. */ /** Form steps rendered by CompanyProfileForm. */
type FormStep = type FormStep = "company" | "personnel" | "contact" | "poa" | "documents";
| "company"
| "personnel"
| "contact"
| "poa"
| "documents"
| "additional";
const FORM_STEPS: FormStep[] = [ const FORM_STEPS: FormStep[] = [
"company", "company",
"personnel", "personnel",
"contact", "contact",
"poa", "poa",
"documents", "documents",
"additional",
]; ];
/** The full onboarding journey: the two pre-form phases + the form steps. */ /** The full onboarding journey: the two pre-form phases + the form steps. */
type WizardStep = "nationality" | "role" | FormStep; type WizardStep = "nationality-role" | FormStep;
const WIZARD_STEPS: WizardStep[] = ["nationality", "role", ...FORM_STEPS]; const WIZARD_STEPS: WizardStep[] = ["nationality-role", ...FORM_STEPS];
/** Icon + title + description shown in the global dialog header per step. */ /** Icon + title + description shown in the global dialog header per step. */
const STEP_META: Record< const STEP_META: Record<
WizardStep, WizardStep,
{ icon: ReactNode; title: string; description: string } { icon: ReactNode; title: string; description: string }
> = { > = {
nationality: { "nationality-role": {
icon: <Globe2 size={20} />, icon: <Globe2 size={20} />,
title: "Where is your company registered?", title: "Tell us about your company",
description: "This determines the documents we'll ask you to provide.", description: "This determines the documents we'll ask you to provide.",
}, },
role: {
icon: <Building2 size={20} />,
title: "What does your company do?",
description:
"Pick any combination of Importer, Exporter and Freight Forwarder — each is set up with its own business license.",
},
company: { company: {
icon: <Building2 size={20} />, icon: <Building2 size={20} />,
title: "Company Information", title: "Company Information",
@@ -103,11 +88,6 @@ const STEP_META: Record<
title: "Upload Documents", title: "Upload Documents",
description: "Provide the required company documents.", description: "Provide the required company documents.",
}, },
additional: {
icon: <CheckCircle2 size={20} />,
title: "Business License",
description: "Upload a business license for each operational profile.",
},
}; };
interface OnboardingWizardDialogProps { interface OnboardingWizardDialogProps {
@@ -165,12 +145,8 @@ export default function OnboardingWizardDialog({
// Phases: nationality → role → form. If a draft already exists, resume // Phases: nationality → role → form. If a draft already exists, resume
// straight into the form with nationality + roles pre-selected. // straight into the form with nationality + roles pre-selected.
const [phase, setPhase] = useState<"nationality" | "role" | "form">( const [phase, setPhase] = useState<"nationality-role" | "form">(
companyAlreadyStarted companyAlreadyStarted ? "form" : "nationality-role",
? hasOperationalProfiles
? "form"
: "role"
: "nationality",
); );
const [nationality, setNationality] = useState<CompanyNationality | null>( const [nationality, setNationality] = useState<CompanyNationality | null>(
savedNationality, savedNationality,
@@ -295,16 +271,12 @@ export default function OnboardingWizardDialog({
setNationality(savedNationality); setNationality(savedNationality);
// Resume into the form only when profiles exist; otherwise send the user to // Resume into the form only when profiles exist; otherwise send the user to
// role selection so the missing operational profiles get created. // role selection so the missing operational profiles get created.
setPhase(hasOperationalProfiles ? "form" : "role"); setPhase(hasOperationalProfiles ? "form" : "nationality-role");
const idx = FORM_STEPS.indexOf(resumeFormStep); const idx = FORM_STEPS.indexOf(resumeFormStep);
if (idx > furthestIdxRef.current) furthestIdxRef.current = idx; if (idx > furthestIdxRef.current) furthestIdxRef.current = idx;
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [companyAlreadyStarted, resumeFormStep]); }, [companyAlreadyStarted, resumeFormStep]);
const handleNationalityContinue = useCallback(() => {
if (nationality) setPhase("role");
}, [nationality]);
const handleRolesContinue = useCallback(() => { const handleRolesContinue = useCallback(() => {
setStartError(null); setStartError(null);
startMutation.mutate({ startMutation.mutate({
@@ -387,6 +359,7 @@ export default function OnboardingWizardDialog({
// The active step across the whole journey, driving the header + progress pill. // The active step across the whole journey, driving the header + progress pill.
const activeStep: WizardStep = phase === "form" ? formStep : phase; const activeStep: WizardStep = phase === "form" ? formStep : phase;
const stepMeta = STEP_META[activeStep]; const stepMeta = STEP_META[activeStep];
console.log({ stepMeta, activeStep, STEP_META });
const activeIdx = WIZARD_STEPS.indexOf(activeStep); const activeIdx = WIZARD_STEPS.indexOf(activeStep);
// Closing from the congratulations panel also clears the completed flag so a // Closing from the congratulations panel also clears the completed flag so a
@@ -418,7 +391,7 @@ export default function OnboardingWizardDialog({
); );
const effectiveResumeStep: FormStep = const effectiveResumeStep: FormStep =
requiredDocsMissing && requiredDocsMissing &&
FORM_STEPS.indexOf(resumeFormStep) > FORM_STEPS.indexOf("documents") FORM_STEPS.indexOf(resumeFormStep) > FORM_STEPS.indexOf("documents")
? "documents" ? "documents"
: resumeFormStep; : resumeFormStep;
@@ -490,26 +463,19 @@ export default function OnboardingWizardDialog({
<OnboardingCompletePanel onClose={handleClose} /> <OnboardingCompletePanel onClose={handleClose} />
) : ( ) : (
<Stack gap="xl"> <Stack gap="xl">
{phase === "nationality" ? ( {phase === "nationality-role" ? (
<Stack gap="lg"> <Stack gap="lg">
<Text fw={600} size="lg" c="edr-text">
Where is your company registered?
</Text>
<NationalitySelect <NationalitySelect
value={nationality} value={nationality}
onChange={setNationality} onChange={setNationality}
embedded embedded
/> />
<Group justify="flex-end" pt="xs"> <Text fw={600} size="lg" c="edr-text">
<Button What does your company do?(multiple)
color="edr-green" </Text>
onClick={handleNationalityContinue}
disabled={!nationality}
rightSection={<ArrowRight size={16} />}
>
Continue
</Button>
</Group>
</Stack>
) : phase === "role" ? (
<Stack gap="lg">
<OnboardingRoleSelect <OnboardingRoleSelect
value={roles} value={roles}
onChange={setRoles} onChange={setRoles}
@@ -520,14 +486,7 @@ export default function OnboardingWizardDialog({
{startError} {startError}
</Text> </Text>
)} )}
<Group justify="space-between" pt="xs"> <Group justify="flex-end" pt="xs">
<Button
variant="default"
leftSection={<ArrowLeft size={16} />}
onClick={() => setPhase("nationality")}
>
Back
</Button>
<Button <Button
color="edr-green" color="edr-green"
onClick={handleRolesContinue} onClick={handleRolesContinue}
@@ -609,7 +568,7 @@ function OnboardingCompletePanel({ onClose }: { onClose: () => void }) {
</Stack> </Stack>
<Button color="edr-green" size="md" onClick={onClose} mt="xs"> <Button color="edr-green" size="md" onClick={onClose} mt="xs">
Go to my dashboard Continue to Dashboard
</Button> </Button>
</Stack> </Stack>
); );