Skip to content

Commit

Permalink
YKI:VKT:AKR(Frontend): Improve stepper accessibility [deploy]
Browse files Browse the repository at this point in the history
  • Loading branch information
lket committed Sep 17, 2024
1 parent 1fe0973 commit e60a2ad
Show file tree
Hide file tree
Showing 14 changed files with 207 additions and 80 deletions.
2 changes: 2 additions & 0 deletions frontend/packages/akr/public/i18n/en-GB/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@
"steps": {
"active": "Active",
"completed": "Completed",
"ariaLabel": "Contact request steps",
"phaseNumber": "{{current}} of {{total}}",
"Done": "Complete!",
"FillContactDetails": "Fill in contact details",
"PreviewAndSend": "Preview and send",
Expand Down
2 changes: 2 additions & 0 deletions frontend/packages/akr/public/i18n/fi-FI/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@
"recipients": "Vastaanottajat",
"steps": {
"active": "Aktiivinen",
"ariaLabel": "Yhteydenottopyynnön vaiheet",
"phaseNumber": "{{current}} kautta {{total}}",
"completed": "Suoritettu",
"Done": "Valmis!",
"FillContactDetails": "Täytä yhteystietosi",
Expand Down
2 changes: 2 additions & 0 deletions frontend/packages/akr/public/i18n/sv-SE/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@
"steps": {
"active": "Aktiv",
"completed": "Utfört",
"ariaLabel": "Kontaktförfrågans faser",
"phaseNumber": "{{current}} av {{total}}",
"Done": "Klart!",
"FillContactDetails": "Fyll i kontaktuppgifter",
"PreviewAndSend": "Förhandsgranska och sänd",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Step, StepLabel, Stepper } from '@mui/material';
import { Step, StepLabel, Stepper, Typography } from '@mui/material';
import { visuallyHidden } from '@mui/utils';
import { CircularStepper } from 'shared/components';
import { useWindowProperties } from 'shared/hooks';

Expand All @@ -22,48 +23,57 @@ export const ContactRequestStepper = () => {
const value = activeStep * (100 / maxStep);
const stepAriaLabel = (step: number) => {
const phaseDescription = t(ContactRequestFormStep[step]);
const phaseNumberPart = `${step}/${maxStep}`;
const phaseNumberPart = t('phaseNumber', {
current: step,
total: maxStep,
});
if (step < activeStep) {
return `${phasePrefix} ${phaseNumberPart}, ${t(
'completed',
)}: ${phaseDescription}`;
} else if (step == activeStep) {
return `${phasePrefix} ${phaseNumberPart}, ${t(
'active',
)}: ${phaseDescription}`;
} else {
return `${phasePrefix} ${phaseNumberPart}: ${phaseDescription}`;
}
};

const text = `${activeStep}/${maxStep}`;
const ariaText = t('phaseNumber', {
current: activeStep,
total: maxStep,
});

const ariaLabel = `${translateCommon('phase')} ${text}: ${t(
ContactRequestFormStep[activeStep],
)}`;
const ariaLabel = `${translateCommon('phase')} ${ariaText}`;

return isPhone ? (
<CircularStepper
value={value}
ariaLabel={ariaLabel}
phaseText={text}
size={90}
/>
<div aria-label={t('ariaLabel')} role="group">
<CircularStepper
value={value}
aria-hidden={true}
ariaLabel={ariaLabel}
phaseText={text}
size={90}
/>
<Typography sx={visuallyHidden}>{ariaLabel}</Typography>
</div>
) : (
<Stepper
aria-label={t('ariaLabel')}
role="group"
className="contact-request-page__stepper"
activeStep={activeStep - 1}
>
{stepNumbers.map((v) => (
<Step key={v}>
<StepLabel
aria-current={activeStep === v && 'step'}
aria-label={stepAriaLabel(v)}
className={
activeStep < v
? 'contact-request-page__stepper__step--disabled'
: undefined
}
>
{t(ContactRequestFormStep[v])}
<span aria-hidden={true}>{t(ContactRequestFormStep[v])}</span>
</StepLabel>
</Step>
))}
Expand Down
6 changes: 4 additions & 2 deletions frontend/packages/akr/src/pages/ContactRequestPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Grid, Paper } from '@mui/material';
import { Grid, Paper, Typography } from '@mui/material';
import { useEffect, useState } from 'react';
import { H1, HeaderSeparator, Text } from 'shared/components';
import { useWindowProperties } from 'shared/hooks';
Expand Down Expand Up @@ -64,7 +64,9 @@ export const ContactRequestPage = () => {
<div className="contact-request-page__grid__stepper-container columns gapped">
<ContactRequestStepper />
<div className="rows">
<H1>{t(`steps.${ContactRequestFormStep[activeStep]}`)}</H1>
<Typography component="p" variant="h2">
{t(`steps.${ContactRequestFormStep[activeStep]}`)}
</Typography>
{ContactRequestFormStep[nextStep] && (
<Text>
{translateCommon('next')}:{' '}
Expand Down
1 change: 1 addition & 0 deletions frontend/packages/vkt/public/i18n/fi-FI/public.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
"stepper": {
"active": "Aktiivinen",
"completed": "Suoritettu",
"label": "Ilmoittautumisen vaiheet",
"phase": "Vaihe",
"phaseNumber": "{{current}} kautta {{total}}",
"phases": "Ilmoittautumisen vaiheet",
Expand Down
1 change: 1 addition & 0 deletions frontend/packages/vkt/public/i18n/sv-SE/public.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
"stepper": {
"active": "Aktiv",
"completed": "Utfört",
"label": "Anmälningens faser",
"phase": "Fas",
"phaseNumber": "{{current}} av {{total}}",
"phases": "Anmälningens faser",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export const PublicEnrollmentPhoneGrid = ({

const getMobileStepperHeading = () => {
const heading = (
<Typography component="h1" variant="h2">
<Typography component="p" variant="h2">
{t(`stepHeading.common.${PublicEnrollmentFormStep[activeStep]}`)}
</Typography>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Step, StepLabel, Stepper } from '@mui/material';
import { Step, StepLabel, Stepper, Typography } from '@mui/material';
import { visuallyHidden } from '@mui/utils';
import { useEffect } from 'react';
import { CircularStepper } from 'shared/components';
import { Color } from 'shared/enums';
import { useWindowProperties } from 'shared/hooks';
Expand Down Expand Up @@ -28,11 +30,12 @@ export const PublicEnrollmentStepper = ({
return t(`step.${PublicEnrollmentFormStep[step]}`);
};

const getStepAriaLabel = (stepNumber: number, stepIndex: number) => {
const getPhaseDescription = (stepNumber: number) => {
const part = t('phaseNumber', {
current: stepIndex + 1,
total: steps.length,
current: stepNumber,
total: doneStepNumber,
});

const statusText = isStepCompleted(stepNumber) ? t('completed') : '';
const partStatus = statusText ? `${part}, ${statusText}` : part;

Expand Down Expand Up @@ -63,49 +66,62 @@ export const PublicEnrollmentStepper = ({

const stepValue = Math.min(activeStep, doneStepNumber);

const currentStep = `${t('currentStep')}: ${getDescription(stepValue)}.`;
const nextStep =
stepValue + 1 <= doneStepNumber
? `${t('nextStep')}: ${getDescription(stepValue + 1)}.`
: '';

const mobileStepValue = stepValue * (100 / doneStepNumber);
const mobilePhaseText = `${stepValue}/${doneStepNumber}`;
const mobileAriaLabel = `${t('phase')} ${mobilePhaseText}: ${t(
`step.${PublicEnrollmentFormStep[activeStep]}`,
)}`;
const mobileAriaLabel = `${getPhaseDescription(stepValue)}
${currentStep}
${nextStep}`;

return isPhone ? (
<CircularStepper
value={mobileStepValue}
ariaLabel={mobileAriaLabel}
phaseText={mobilePhaseText}
color={
activeStep === PublicEnrollmentFormStep.Payment
? Color.Error
: Color.Secondary
}
size={90}
/>
<div role="group" aria-label={t('phases')}>
<CircularStepper
value={mobileStepValue}
aria-hidden={true}
ariaLabel={mobileAriaLabel}
phaseText={mobilePhaseText}
color={
activeStep === PublicEnrollmentFormStep.Payment
? Color.Error
: Color.Secondary
}
size={90}
/>
<Typography sx={visuallyHidden}>
{getPhaseDescription(stepValue)}
</Typography>
</div>
) : (
<Stepper
className="public-enrollment__grid__stepper"
activeStep={getDesktopActiveStep()}
aria-label={t('phases')}
role="group"
>
{steps.map((step, index) => (
<Step
data-testid={`enrollment-step-${index}`}
key={step}
completed={isStepCompleted(step)}
>
{/* eslint-disable jsx-a11y/aria-role */}
<StepLabel
error={hasError(step)}
aria-label={getStepAriaLabel(step, index)}
role="text"
aria-current={getDesktopActiveStep() === step - 1 && 'step'}
className={
activeStep < step
? 'public-enrollment__grid__stepper__step-disabled'
: undefined
}
>
{/* eslint-enable */}
{getDescription(step)}
<Typography sx={visuallyHidden}>
{getPhaseDescription(step)}
</Typography>
<span aria-hidden={true}>{getDescription(step)}</span>
</StepLabel>
</Step>
))}
Expand Down
2 changes: 2 additions & 0 deletions frontend/packages/yki/public/i18n/en-GB/public.json
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,10 @@
"stepper": {
"active": "Active",
"completed": "Completed",
"label": "Registration steps",
"paymentAborted": "Payment was cancelled",
"phase": "Phase",
"phaseNumber": "{{current}} of {{total}}",
"step": {
"Done": "Done",
"Identify": "Identify",
Expand Down
2 changes: 2 additions & 0 deletions frontend/packages/yki/public/i18n/fi-FI/public.json
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,10 @@
"stepper": {
"active": "Aktiivinen",
"completed": "Suoritettu",
"label": "Ilmoittautumisen vaiheet",
"paymentAborted": "Maksu keskeytyi",
"phase": "Vaihe",
"phaseNumber": "{{current}} kautta {{total}}",
"step": {
"Done": "Valmis",
"Identify": "Tunnistaudu",
Expand Down
2 changes: 2 additions & 0 deletions frontend/packages/yki/public/i18n/sv-SE/public.json
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,10 @@
"stepper": {
"active": "Aktiv",
"completed": "Genomförd",
"label": "Anmälningens faser",
"paymentAborted": "Betalningen kunde inte genomföras",
"phase": "Skede",
"phaseNumber": "{{current}} av {{total}}",
"step": {
"Done": "Färdig",
"Identify": "Identifiera dig",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Step, StepLabel, Stepper } from '@mui/material';
import { Step, StepLabel, Stepper, Typography } from '@mui/material';
import { visuallyHidden } from '@mui/utils';
import { useSearchParams } from 'react-router-dom';
import { CircularStepper, H2, Text } from 'shared/components';
import { CircularStepper, Text } from 'shared/components';
import { APIResponseStatus, Color } from 'shared/enums';
import { useWindowProperties } from 'shared/hooks';

Expand Down Expand Up @@ -38,14 +39,6 @@ export const PublicRegistrationStepper = () => {
.map(Number)
.filter((i) => i <= doneStepNumber);

const getStatusText = (stepNumber: number) => {
if (stepNumber < activeStep) {
return t('completed');
} else if (stepNumber === activeStep) {
return t('active');
}
};

const getDescription = (stepNumber: number) => {
return t(`step.${PublicRegistrationFormStep[stepNumber]}`);
};
Expand All @@ -60,9 +53,16 @@ export const PublicRegistrationStepper = () => {
}
};

const getStepAriaLabel = (stepNumber: number) => {
const part = `${stepNumber}/${stepNumbers.length}`;
const statusText = getStatusText(stepNumber);
const isStepCompleted = (step: number) => {
return step < activeStep;
};

const getPhaseDescription = (stepNumber: number) => {
const part = t('phaseNumber', {
current: stepNumber,
total: stepNumbers.length,
});
const statusText = isStepCompleted(stepNumber) ? t('completed') : '';
const partStatus = statusText ? `${part}, ${statusText}` : part;

return `${t('phase')} ${partStatus}: ${getDescription(stepNumber)}`;
Expand All @@ -74,23 +74,29 @@ export const PublicRegistrationStepper = () => {
: Math.min(activeStep, doneStepNumber);

const mobileStepValue = stepValue * (100 / doneStepNumber);
const mobilePhaseText = `${stepValue}/${doneStepNumber}`;
const mobileAriaLabel = `${t('phase')} ${mobilePhaseText}: ${getDescription(
stepValue,
)}`;
const phaseText = `${stepValue}/${doneStepNumber}`;
const mobileAriaLabel = `${getPhaseDescription(stepValue)}`;

if (isPhone) {
return (
<div className="columns gapped-xxl public-registration__grid__circular-stepper-container">
<div
className="columns gapped-xxl public-registration__grid__circular-stepper-container"
aria-label={t('label')}
role="group"
>
<CircularStepper
value={mobileStepValue}
aria-hidden={true}
ariaLabel={mobileAriaLabel}
phaseText={mobilePhaseText}
phaseText={phaseText}
color={isError ? Color.Error : Color.Secondary}
size={90}
/>
<Text sx={visuallyHidden}>{mobileAriaLabel}</Text>
<div className="rows">
<H2>{getDescription(stepValue)}</H2>
<Typography component="p" variant="h2">
{getDescription(stepValue)}
</Typography>
{!isError && <Text>{getNextInformation(stepValue)}</Text>}
</div>
</div>
Expand All @@ -99,13 +105,15 @@ export const PublicRegistrationStepper = () => {
return (
<Stepper
className="public-registration__grid__stepper"
aria-label={t('label')}
activeStep={stepValue - 1}
role="group"
>
{stepNumbers.map((i) => (
<Step key={i}>
<StepLabel
aria-label={getStepAriaLabel(i)}
error={isError && stepValue === i}
aria-current={stepValue === i && 'step'}
className={
stepValue === i && isError
? 'public-registration__grid__stepper__step-error'
Expand All @@ -114,7 +122,8 @@ export const PublicRegistrationStepper = () => {
: undefined
}
>
{getDescription(i)}
<Text sx={visuallyHidden}>{getPhaseDescription(i)}</Text>
<span aria-hidden={true}>{getDescription(i)}</span>
</StepLabel>
</Step>
))}
Expand Down
Loading

0 comments on commit e60a2ad

Please sign in to comment.