Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/controllers/verify_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ def show
def app_data
{
base_path: idv_app_root_path,
app_name: APP_NAME,
initial_values: { 'personalKey' => '0000-0000-0000-0000' },
}
end
Expand Down
7 changes: 7 additions & 0 deletions app/javascript/packages/form-steps/form-steps.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ describe('FormSteps', () => {
const STEPS = [
{
name: 'first',
title: 'First Title',
form: () => (
<>
<PageHeading>First Title</PageHeading>
Expand Down Expand Up @@ -132,6 +133,12 @@ describe('FormSteps', () => {
expect(getByText('First')).to.be.ok();
});

it('sets the browser page title using titleFormat', () => {
render(<FormSteps steps={STEPS} titleFormat="%{step} - Example" />);

expect(document.title).to.equal('First Title - Example');
});

it('renders continue button at first step', () => {
const { getByText } = render(<FormSteps steps={STEPS} />);

Expand Down
27 changes: 27 additions & 0 deletions app/javascript/packages/form-steps/form-steps.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useEffect, useRef, useState } from 'react';
import type { RefCallback, FormEventHandler, FC } from 'react';
import { Alert } from '@18f/identity-components';
import { replaceVariables } from '@18f/identity-i18n';
import { useDidUpdateEffect, useIfStillMounted } from '@18f/identity-react-hooks';
import RequiredValueMissingError from './required-value-missing-error';
import FormStepsContext from './form-steps-context';
Expand Down Expand Up @@ -81,6 +82,11 @@ export interface FormStep {
* Step form component.
*/
form: FC<FormStepComponentProps<Record<string, any>>>;

/**
* Human-readable step label.
*/
title?: string;
}

interface FieldsRefEntry {
Expand Down Expand Up @@ -142,6 +148,25 @@ interface FormStepsProps {
* is appended.
*/
basePath?: string;

/**
* Format string for page title, interpolated with step title as `%{step}` parameter.
*/
titleFormat?: string;
}

/**
* React hook which sets page title for the current step.
*
* @param step Current step.
* @param titleFormat Format string for page title.
*/
function useStepTitle(step: FormStep, titleFormat?: string) {
useEffect(() => {
if (titleFormat && step.title) {
document.title = replaceVariables(titleFormat, { step: step.title });
}
}, [step]);
}

/**
Expand Down Expand Up @@ -183,6 +208,7 @@ function FormSteps({
autoFocus,
promptOnNavigate = true,
basePath,
titleFormat,
}: FormStepsProps) {
const [values, setValues] = useState(initialValues);
const [activeErrors, setActiveErrors] = useState(initialActiveErrors);
Expand Down Expand Up @@ -231,6 +257,7 @@ function FormSteps({
}
}, [stepErrors]);

useStepTitle(step, titleFormat);
useDidUpdateEffect(onStepChange, [step]);
useDidUpdateEffect(onPageTransition, [step]);

Expand Down
8 changes: 7 additions & 1 deletion app/javascript/packages/verify-flow/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@ interface VerifyFlowProps {
* The path to which the current step is appended to create the current step URL.
*/
basePath: string;

/**
* Application name, used in generating page titles for current step.
*/
appName: string;
}

export function VerifyFlow({ initialValues = {}, basePath }: VerifyFlowProps) {
export function VerifyFlow({ initialValues = {}, basePath, appName }: VerifyFlowProps) {
return (
<>
<StepIndicator className="margin-x-neg-2 margin-top-neg-4 tablet:margin-x-neg-6 tablet:margin-top-neg-4">
Expand All @@ -33,6 +38,7 @@ export function VerifyFlow({ initialValues = {}, basePath }: VerifyFlowProps) {
initialValues={initialValues}
promptOnNavigate={false}
basePath={basePath}
titleFormat={`%{step} - ${appName}`}
/>
</>
);
Expand Down
3 changes: 3 additions & 0 deletions app/javascript/packages/verify-flow/steps/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import type { FormStep } from '@18f/identity-form-steps';
import { t } from '@18f/identity-i18n';
import PersonalKeyStep from './personal-key/personal-key-step';
import PersonalKeyConfirmStep from './personal-key-confirm/personal-key-confirm-step';

export const STEPS: FormStep[] = [
{
name: 'personal_key',
form: PersonalKeyStep,
title: t('titles.idv.personal_key'),
},
{
name: 'personal_key_confirm',
form: PersonalKeyConfirmStep,
title: t('titles.idv.personal_key'),
},
];
12 changes: 10 additions & 2 deletions app/javascript/packs/verify-flow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,26 @@ interface AppRootValues {
* The path to which the current step is appended to create the current step URL.
*/
basePath: string;

/**
* Application name.
*/
appName: string;
}

interface AppRootElement extends HTMLElement {
dataset: DOMStringMap & AppRootValues;
}

const appRoot = document.getElementById('app-root') as AppRootElement;
const { initialValues, basePath } = appRoot.dataset;
const { initialValues, basePath, appName } = appRoot.dataset;

let parsedInitialValues;
try {
parsedInitialValues = JSON.parse(initialValues);
} catch {}

render(<VerifyFlow initialValues={parsedInitialValues} basePath={basePath} />, appRoot);
render(
<VerifyFlow initialValues={parsedInitialValues} basePath={basePath} appName={appName} />,
appRoot,
);