'use client'; import { useLingui } from '@lingui/react'; import { styled } from '@linaria/react'; import { type FormEvent, useCallback, useEffect } from 'react'; import { color, fontFamily, fontSize, radius, semanticColor, spacing, } from '@/tokens'; import { Body, Button, Heading, StepIndicator } from '@/ui'; import { buildPartnerApplicationRequestBody } from '../build-partner-application-request-body'; import { PARTNER_APPLICATION_STEP_IDS } from '../data/partner-application-step-ids'; import { getCurrentStepId } from '../get-current-step-id'; import { PARTNER_APPLICATION_COPY } from '../partner-application-copy'; import { type PartnerApplicationController, usePartnerApplicationState, } from '../use-partner-application-state'; import { validatePartnerApplicationStep } from '../validate-partner-application-step'; import { PartnerApplicationSuccess } from './PartnerApplicationSuccess'; import { CommercialsStep } from './steps/CommercialsStep'; import { ExpertiseStep } from './steps/ExpertiseStep'; import { IdentityStep } from './steps/IdentityStep'; import { ProfileStep } from './steps/ProfileStep'; const COPY = PARTNER_APPLICATION_COPY; const STEPS = PARTNER_APPLICATION_STEP_IDS; const WizardRoot = styled.div` display: flex; flex-direction: column; & > * + * { margin-top: ${spacing(4)}; } `; const TitleBlock = styled.div` display: flex; flex-direction: column; & > * + * { margin-top: ${spacing(6)}; } `; const IntroGroup = styled.div` display: flex; flex-direction: column; & > * + * { margin-top: ${spacing(3)}; } `; const HeaderStrip = styled.div` align-items: center; display: flex; gap: ${spacing(3)}; justify-content: space-between; `; const HeaderLabel = styled.span` color: ${semanticColor.inkMuted}; font-family: ${fontFamily('mono')}; font-size: ${fontSize(3)}; text-transform: uppercase; `; const FieldsStack = styled.div` display: flex; flex-direction: column; & > * + * { margin-top: ${spacing(4)}; } `; const Footer = styled.div` display: flex; flex-direction: column; & > * + * { margin-top: ${spacing(2)}; } `; const SecondaryButton = styled.button` background: none; border: 1px solid ${semanticColor.lineStrong}; border-radius: ${radius(2)}; color: ${semanticColor.ink}; cursor: pointer; font-family: ${fontFamily('mono')}; font-size: ${fontSize(3)}; height: ${spacing(10)}; padding: 0 ${spacing(4)}; text-transform: uppercase; `; const FooterControls = styled.div` align-items: center; display: flex; justify-content: space-between; width: 100%; `; const ErrorBanner = styled.p` color: ${color('error')}; font-family: ${fontFamily('sans')}; font-size: ${fontSize(3)}; `; function StepRenderer({ controller, }: { controller: PartnerApplicationController; }) { switch (getCurrentStepId(controller.state)) { case 'identity': return ; case 'profile': return ; case 'expertise': return ; case 'commercials': return ; } } export function PartnerApplicationWizard({ onSubmitted, onSuccess, resetSignal, }: { onSubmitted?: () => void; onSuccess: () => void; resetSignal: number; }) { const { i18n } = useLingui(); const controller = usePartnerApplicationState(); const { goBack, goNext, reset, setSubmitError, setSubmitted, setSubmitting, state, } = controller; useEffect(() => { reset(); }, [resetSignal, reset]); const stepId = getCurrentStepId(state); const stepIndex = state.stepIndex; const isLastStep = stepIndex === STEPS.length - 1; const errorValues = Object.values(state.fieldErrors); const hasFieldErrors = errorValues.length > 0; const fieldErrorMessage = errorValues.includes('invalid_email') ? COPY.validation.invalidEmail : errorValues.includes('invalid_url') ? COPY.validation.invalidUrl : errorValues.includes('invalid_amount') ? COPY.validation.invalidAmount : COPY.validation.incompleteForm; const handleSubmit = useCallback( async (event: FormEvent) => { event.preventDefault(); if (!isLastStep) { goNext(); return; } if (state.isSubmitting) return; setSubmitError(null); if (Object.keys(validatePartnerApplicationStep(state)).length > 0) { goNext(); return; } const payload = buildPartnerApplicationRequestBody(state); setSubmitting(true); try { const response = await fetch('/api/partner-application', { body: JSON.stringify(payload), headers: { 'Content-Type': 'application/json' }, method: 'POST', }); if (!response.ok) { setSubmitError(i18n._(COPY.validation.submitFailed)); return; } setSubmitted(); onSubmitted?.(); } catch { setSubmitError(i18n._(COPY.validation.submitFailed)); } finally { setSubmitting(false); } }, [ goNext, i18n, isLastStep, onSubmitted, setSubmitError, setSubmitted, setSubmitting, state, ], ); if (state.isSubmitted) { return ( ); } const stepLabel = `${i18n._( COPY.stepProgressLabel(stepIndex + 1, STEPS.length), )} ยท ${i18n._(COPY.stepHeaders[stepId])}`; return ( {stepIndex === 0 ? ( {i18n._(COPY.title)} {i18n._(COPY.subtitle)} ) : null} {stepLabel}
); }