diff --git a/app/javascript/packages/verify-flow/verify-flow-step-indicator.spec.tsx b/app/javascript/packages/verify-flow/verify-flow-step-indicator.spec.tsx new file mode 100644 index 00000000000..7c2086a2257 --- /dev/null +++ b/app/javascript/packages/verify-flow/verify-flow-step-indicator.spec.tsx @@ -0,0 +1,35 @@ +import { render } from '@testing-library/react'; +import { StepStatus } from '@18f/identity-step-indicator'; +import VerifyFlowStepIndicator, { getStepStatus } from './verify-flow-step-indicator'; + +describe('getStepStatus', () => { + it('returns incomplete if step is after current step', () => { + const result = getStepStatus(1, 0); + + expect(result).to.equal(StepStatus.INCOMPLETE); + }); + + it('returns current if step is current step', () => { + const result = getStepStatus(1, 1); + + expect(result).to.equal(StepStatus.CURRENT); + }); + + it('returns complete if step is before current step', () => { + const result = getStepStatus(0, 1); + + expect(result).to.equal(StepStatus.COMPLETE); + }); +}); + +describe('VerifyFlowStepIndicator', () => { + it('renders step indicator for the current step', () => { + const { getByText } = render(); + + const current = getByText('step_indicator.flows.idv.secure_account'); + expect(current.closest('.step-indicator__step--current')).to.exist(); + + const previous = getByText('step_indicator.flows.idv.verify_phone_or_address'); + expect(previous.closest('.step-indicator__step--complete')).to.exist(); + }); +}); diff --git a/app/javascript/packages/verify-flow/verify-flow-step-indicator.tsx b/app/javascript/packages/verify-flow/verify-flow-step-indicator.tsx new file mode 100644 index 00000000000..8b134f51db5 --- /dev/null +++ b/app/javascript/packages/verify-flow/verify-flow-step-indicator.tsx @@ -0,0 +1,80 @@ +import { StepIndicator, StepIndicatorStep, StepStatus } from '@18f/identity-step-indicator'; +import { t } from '@18f/identity-i18n'; + +// i18n-tasks-use t('step_indicator.flows.idv.getting_started') +// i18n-tasks-use t('step_indicator.flows.idv.verify_id') +// i18n-tasks-use t('step_indicator.flows.idv.verify_info') +// i18n-tasks-use t('step_indicator.flows.idv.verify_phone_or_address') +// i18n-tasks-use t('step_indicator.flows.idv.secure_account') + +type VerifyFlowStepIndicatorStep = + | 'getting_started' + | 'verify_id' + | 'verify_info' + | 'verify_phone_or_address' + | 'secure_account'; + +/** + * Mapping of flow form steps to corresponding step indicator step. + */ +const FLOW_STEP_STEP_MAPPING: Record = { + personal_key: 'secure_account', + personal_key_confirm: 'secure_account', +}; + +/** + * Sequence of step indicator steps. + */ +const STEP_INDICATOR_STEPS: VerifyFlowStepIndicatorStep[] = [ + 'getting_started', + 'verify_id', + 'verify_info', + 'verify_phone_or_address', + 'secure_account', +]; + +interface VerifyFlowStepIndicatorProps { + /** + * Current step name. + */ + currentStep: string; +} + +/** + * Given an index of a step and the current step index, returns the status of the step relative to + * the current step. + * + * @param index Index of step against which to compare current step. + * @param currentStepIndex Index of current step. + * + * @return Step status. + */ +export function getStepStatus(index, currentStepIndex): StepStatus { + if (index === currentStepIndex) { + return StepStatus.CURRENT; + } + + if (index < currentStepIndex) { + return StepStatus.COMPLETE; + } + + return StepStatus.INCOMPLETE; +} + +function VerifyFlowStepIndicator({ currentStep }: VerifyFlowStepIndicatorProps) { + const currentStepIndex = STEP_INDICATOR_STEPS.indexOf(FLOW_STEP_STEP_MAPPING[currentStep]); + + return ( + + {STEP_INDICATOR_STEPS.map((step, index) => ( + + ))} + + ); +} + +export default VerifyFlowStepIndicator; diff --git a/app/javascript/packages/verify-flow/verify-flow.tsx b/app/javascript/packages/verify-flow/verify-flow.tsx index 6fce4686195..54623ebdde7 100644 --- a/app/javascript/packages/verify-flow/verify-flow.tsx +++ b/app/javascript/packages/verify-flow/verify-flow.tsx @@ -1,9 +1,9 @@ -import { useEffect } from 'react'; +import { useEffect, useState } from 'react'; import { FormSteps } from '@18f/identity-form-steps'; -import { StepIndicator, StepIndicatorStep, StepStatus } from '@18f/identity-step-indicator'; import { t } from '@18f/identity-i18n'; import { Alert } from '@18f/identity-components'; import { trackEvent } from '@18f/identity-analytics'; +import VerifyFlowStepIndicator from './verify-flow-step-indicator'; import { STEPS } from './steps'; export interface VerifyFlowValues { @@ -67,9 +67,11 @@ export function VerifyFlow({ appName, onComplete, }: VerifyFlowProps) { + const [currentStep, setCurrentStep] = useState(STEPS[0].name); + useEffect(() => { - logStepVisited(STEPS[0].name); - }, []); + logStepVisited(currentStep); + }, [currentStep]); let steps = STEPS; if (enabledStepNames) { @@ -78,13 +80,7 @@ export function VerifyFlow({ return ( <> - - - - - - - + {t('idv.messages.confirm')} @@ -95,7 +91,7 @@ export function VerifyFlow({ basePath={basePath} titleFormat={`%{step} - ${appName}`} onStepSubmit={logStepSubmitted} - onStepChange={logStepVisited} + onStepChange={setCurrentStep} onComplete={onComplete} />