Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UHF-10236: Accessibility fixes for search monitor #1016

Merged
merged 1 commit into from
Jun 25, 2024
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
2 changes: 1 addition & 1 deletion dist/js/job-search.min.js

Large diffs are not rendered by default.

52 changes: 42 additions & 10 deletions src/js/react/apps/job-search/containers/SearchMonitorContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { atom, useAtom, useAtomValue } from 'jotai';

import { Button, Checkbox, TextInput, Notification, IconAngleUp, IconAngleDown } from 'hds-react';
import React from 'react';
import React, { createRef, useEffect } from 'react';
import { Buffer } from 'buffer';
import URLParams from '../types/URLParams';
import useQueryString from '../hooks/useQueryString';
import { urlAtom } from '../store';
import useScrollToResults from '@/react/common/hooks/useScrollToResults';

// Define new atom for scroll state
const shouldScrollAtom = atom(false);

const SearchMonitorContainer = () => {
const urlParams: URLParams = useAtomValue(urlAtom);
Expand All @@ -18,6 +22,9 @@ const SearchMonitorContainer = () => {
const [errorMessage, seterrorMessage] = useAtom(errorAtom);
const [isFormVisible, setIsFormVisible] = useAtom(isFormVisibleAtom);

// Scroll state
const [shouldScroll, setShouldScroll] = useAtom(shouldScrollAtom);

// ElasticSearch query base64 encoded
const queryEncoded = Buffer.from(query).toString('base64');
const searchDescription = '-';
Expand All @@ -28,6 +35,8 @@ const SearchMonitorContainer = () => {
const currentParams = window.location.search;
const currentRelativeUrl = currentPath + currentParams;

const scrollTarget = createRef<HTMLDivElement>();

const requestBody = {
elastic_query: queryEncoded,
query: currentRelativeUrl,
Expand Down Expand Up @@ -112,20 +121,36 @@ const SearchMonitorContainer = () => {
if (submitButton) {
submitButton.removeAttribute('disabled');
}
// Move focus to error message.
setShouldScroll(true);
return;
}

// Release submit locks and show success page
setSubmitted(true);
seterrorMessage('');

// Move focus to successful message.
setShouldScroll(true);

if (submitButton) {
submitButton.removeAttribute('disabled');
}
};

// Scroll to results when they change.
useScrollToResults(scrollTarget, shouldScroll);

// This tackles the issue that focus moves constantly to the error message for example.
useEffect(() => {
if (shouldScroll) {
setShouldScroll(false); // Reset the scroll state after scrolling
}
}, [shouldScroll, setShouldScroll]);

const formHeader: string = Drupal.t('Receive search results by email', {}, { context: 'Search monitor header' });
const openLabel: string = Drupal.t('Open', {}, { context: 'Search monitor open label' });
const closeLabel: string = Drupal.t('Close', {}, { context: 'Search monitor close label' });
const openLabel: string = Drupal.t('Open the order form', {}, { context: 'Search monitor open label' });
const closeLabel: string = Drupal.t('Close the order form', {}, { context: 'Search monitor close label' });
const descriptionHeader: string = Drupal.t('Saved search', {}, { context: 'Search monitor content title' });
const descriptionFirstPart: string = Drupal.t('Save the search you make so that you can receive an email notification of new results matching your search criteria.', {}, { context: 'Search monitor content' });
const descriptionSecondPart: string = Drupal.t('You can save as many searches as you like. You can delete the saved search via the link in the email messages.', {}, { context: 'Search monitor content' });
Expand All @@ -139,12 +164,21 @@ const SearchMonitorContainer = () => {
const tosLinkUrl: string = window.drupalSettings.helfi_rekry_job_search.hakuvahti_tos_link_url;
const tosLinkSuffix: string = Drupal.t('The link opens in a new tab', {}, {context: 'Explanation for users that the link opens in a new tab instead of the expected current tab'});

const customEmailStyles = {
marginTop: 'var(--spacing-m)',
};

const customCheckboxStyles = {
'--background-unselected': 'var(--color-white)',
'--background-selected': 'var(--color-black)',
marginTop: 'var(--spacing-m)',
};

const customButtonStyles = {
'--border-color-focus': 'var(--color-black)',
backgroundColor: 'transparent',
};

return (
<form onSubmit={onSubmit} className="job-search-form__search-monitor">
{!submitted && (
Expand All @@ -153,16 +187,15 @@ const SearchMonitorContainer = () => {
<Button
type="button"
aria-controls='job-search-form__search-monitor__content'
aria-expanded={isFormVisible}
variant="supplementary"
theme="black"
iconLeft={isFormVisible ? <IconAngleUp /> : <IconAngleDown />}
onClick={(event: React.MouseEvent) => {
event.preventDefault();
setIsFormVisible(!isFormVisible);
}}
style={{
backgroundColor: 'transparent',
}}
style={customButtonStyles}
>
{isFormVisible ? closeLabel : openLabel}
</Button>
Expand All @@ -179,6 +212,7 @@ const SearchMonitorContainer = () => {
size='default'
label={errorLabel}
className='job-search-form__search-monitor__error'
ref={scrollTarget}
>
{errorMessage}
</Notification>
Expand All @@ -193,9 +227,7 @@ const SearchMonitorContainer = () => {
onChange={(event) => setEmail(event.target.value)}
value={email}
required
style={{
marginTop: 'var(--spacing-m)',
}}
style={customEmailStyles}
/>

<p><a href={tosLinkUrl} target='_blank' rel="noreferrer" className='job-search-form__search-monitor__terms-link'>{tosLinkLabel} ({tosLinkSuffix})</a></p>
Expand Down Expand Up @@ -227,7 +259,7 @@ const SearchMonitorContainer = () => {

{submitted &&
<>
<h3 className='job-search-form__search-monitor__heading'>{thankYouHeader}</h3>
<h3 className='job-search-form__search-monitor__heading' ref={scrollTarget}>{thankYouHeader}</h3>
<p>{thankYouMessage}</p>
</>
}
Expand Down
8 changes: 4 additions & 4 deletions translations/fi.po
Original file line number Diff line number Diff line change
Expand Up @@ -1223,12 +1223,12 @@ msgid "Receive search results by email"
msgstr "Tilaa hakuvahti sähköpostiisi"

msgctxt "Search monitor open label"
msgid "Open"
msgstr "Avaa"
msgid "Open the order form"
msgstr "Avaa hakuvahti"

msgctxt "Search monitor close label"
msgid "Close"
msgstr "Sulje"
msgid "Close the order form"
msgstr "Sulje hakuvahti"

msgctxt "Search monitor content title"
msgid "Saved search"
Expand Down
8 changes: 4 additions & 4 deletions translations/sv.po
Original file line number Diff line number Diff line change
Expand Up @@ -1225,12 +1225,12 @@ msgid "Receive search results by email"
msgstr "Beställ sökvakten till din e-post"

msgctxt "Search monitor open label"
msgid "Open"
msgstr "Öppna"
msgid "Open the order form"
msgstr "Öppna sökvakten"

msgctxt "Search monitor close label"
msgid "Close"
msgstr "Stäng"
msgid "Close the order form"
msgstr "Stäng sökvakten"

msgctxt "Search monitor content title"
msgid "Saved search"
Expand Down