Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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/css/styles.min.css

Large diffs are not rendered by default.

54 changes: 27 additions & 27 deletions dist/js/district-and-project-search.min.js

Large diffs are not rendered by default.

54 changes: 27 additions & 27 deletions dist/js/health-station-search.min.js

Large diffs are not rendered by default.

131 changes: 63 additions & 68 deletions dist/js/job-search.min.js

Large diffs are not rendered by default.

56 changes: 28 additions & 28 deletions dist/js/linkedevents.min.js

Large diffs are not rendered by default.

54 changes: 27 additions & 27 deletions dist/js/maternity-and-child-health-clinic-search.min.js

Large diffs are not rendered by default.

78 changes: 39 additions & 39 deletions dist/js/news-archive.min.js

Large diffs are not rendered by default.

54 changes: 27 additions & 27 deletions dist/js/school-search.min.js

Large diffs are not rendered by default.

44 changes: 44 additions & 0 deletions src/js/react/apps/job-search/components/AreaFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { useAtomValue, useSetAtom } from 'jotai';
import { areaFilterAtom, getAreaAtom, setStateValueAtom } from '../store';
import SearchComponents from '../enum/SearchComponents';
import { Select } from 'hds-react';
import { defaultMultiSelectTheme } from '@/react/common/constants/selectTheme';

const areaFilterLabel: string = Drupal.t('Job location', {}, { context: 'Job search: Job location label' });

export const AreaFilter = () => {
const areaOptions = useAtomValue(areaFilterAtom);
const setStateValue = useSetAtom(setStateValueAtom);
const value = useAtomValue(getAreaAtom);

return (
<Select
className='job-search-form__dropdown'
clearable
id={SearchComponents.AREA_FILTER}
multiSelect
noTags
onChange={(selectedOptions) => {
setStateValue({ key: SearchComponents.AREA_FILTER, value: selectedOptions });
}}
options={areaOptions}
value={value}
texts={{
clearButtonAriaLabel_one: Drupal.t(
'Clear @label selection',
{ '@label': areaFilterLabel },
{ context: 'React search clear selection label' },
),
clearButtonAriaLabel_multiple: Drupal.t(
'Clear @label selection',
{ '@label': areaFilterLabel },
{ context: 'React search clear selection label' },
),
label: areaFilterLabel,
language: window.drupalSettings.path.currentLanguage,
placeholder: Drupal.t('All areas', {}, { context: 'Location placeholder' }),
}}
theme={defaultMultiSelectTheme}
/>
);
};
73 changes: 73 additions & 0 deletions src/js/react/apps/job-search/components/CheckBoxFilters.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { useAtomValue, useSetAtom } from 'jotai';
import { getCheckBoxValuesAtom, getEmploymentSearchIdMap, setStateValueAtom } from '../store';
import CustomIds from '../enum/CustomTermIds';
import { Checkbox } from 'hds-react';
import SearchComponents from '../enum/SearchComponents';
import { defaultCheckboxStyle } from '@/react/common/constants/checkboxStyle';

export const CheckBoxFilters = () => {
const [continuous, internship, summerJobs, youthSummerJobs] = useAtomValue(getCheckBoxValuesAtom);
const setStateValue = useSetAtom(setStateValueAtom);
const employmentSearchIdMap = useAtomValue(getEmploymentSearchIdMap);
const showContinuous = employmentSearchIdMap.get(CustomIds.CONTINUOUS);
const showInternships = employmentSearchIdMap.get(CustomIds.TRAINING);
const showSummerJobs = employmentSearchIdMap.get(CustomIds.SUMMER_JOBS);
const showYouthSummerJobs =
employmentSearchIdMap.get(CustomIds.YOUTH_SUMMER_JOBS) || employmentSearchIdMap.get(CustomIds.COOL_SUMMER_PROJECT);

return (
<fieldset className='job-search-form__checkboxes'>
<legend className='job-search-form__checkboxes-legend'>
{Drupal.t('Filters', {}, { context: 'Checkbox filters heading' })}
</legend>
{showContinuous && (
<Checkbox
checked={continuous}
className='job-search-form__checkbox'
id={SearchComponents.CONTINUOUS}
label={Drupal.t('Open-ended vacancies', {}, { context: 'Job search' })}
name={SearchComponents.CONTINUOUS}
onClick={() => setStateValue({ key: SearchComponents.CONTINUOUS, value: !continuous })}
value={continuous.toString()}
style={defaultCheckboxStyle}
/>
)}
{showInternships && (
<Checkbox
checked={internship}
className='job-search-form__checkbox'
id={SearchComponents.INTERNSHIPS}
label={Drupal.t('Practical training', {}, { context: 'Job search' })}
name={SearchComponents.INTERNSHIPS}
onClick={() => setStateValue({ key: SearchComponents.INTERNSHIPS, value: !internship })}
value={internship.toString()}
style={defaultCheckboxStyle}
/>
)}
{showSummerJobs && (
<Checkbox
checked={summerJobs}
className='job-search-form__checkbox'
id={SearchComponents.SUMMER_JOBS}
label={Drupal.t('Summer jobs', {}, { context: 'Job search' })}
name={SearchComponents.SUMMER_JOBS}
onClick={() => setStateValue({ key: SearchComponents.SUMMER_JOBS, value: !summerJobs })}
value={summerJobs.toString()}
style={defaultCheckboxStyle}
/>
)}
{showYouthSummerJobs && (
<Checkbox
checked={youthSummerJobs}
className='job-search-form__checkbox'
id={SearchComponents.YOUTH_SUMMER_JOBS}
label={Drupal.t('Summer jobs for young people', {}, { context: 'Job search' })}
name={SearchComponents.YOUTH_SUMMER_JOBS}
onClick={() => setStateValue({ key: SearchComponents.YOUTH_SUMMER_JOBS, value: !youthSummerJobs })}
value={youthSummerJobs.toString()}
style={defaultCheckboxStyle}
/>
)}
</fieldset>
);
};
42 changes: 42 additions & 0 deletions src/js/react/apps/job-search/components/EmploymentFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useAtomValue, useSetAtom } from 'jotai';
import { employmentAtom, getEmploymentAtom, setStateValueAtom } from '../store';
import { Select } from 'hds-react';
import SearchComponents from '../enum/SearchComponents';
import { defaultMultiSelectTheme } from '@/react/common/constants/selectTheme';

const employmentRelationshipLabel: string = Drupal.t('Employment type', {}, { context: 'Employment filter label' });

export const EmploymentFilter = () => {
const employmentOptions = useAtomValue(employmentAtom);
const value = useAtomValue(getEmploymentAtom);
const setStateValue = useSetAtom(setStateValueAtom);

return (
<Select
className='job-search-form__dropdown'
clearable
id={SearchComponents.EMPLOYMENT}
multiSelect
noTags
onChange={(selectedOptions) => setStateValue({ key: SearchComponents.EMPLOYMENT, value: selectedOptions })}
options={employmentOptions}
texts={{
clearButtonAriaLabel_one: Drupal.t(
'Clear @label selection',
{ '@label': employmentRelationshipLabel },
{ context: 'React search clear selection label' },
),
clearButtonAriaLabel_multiple: Drupal.t(
'Clear @label selection',
{ '@label': employmentRelationshipLabel },
{ context: 'React search clear selection label' },
),
label: employmentRelationshipLabel,
language: window.drupalSettings.path.currentLanguage,
placeholder: Drupal.t('All types of employment', {}, { context: 'Employment filter placeholder' }),
}}
value={value}
theme={defaultMultiSelectTheme}
/>
);
};
43 changes: 43 additions & 0 deletions src/js/react/apps/job-search/components/LanguageFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useAtomValue, useSetAtom } from 'jotai';
import { getLanguageAtom, languagesAtom, setStateValueAtom } from '../store';
import { Select } from 'hds-react';
import SearchComponents from '../enum/SearchComponents';
import { defaultSelectTheme } from '@/react/common/constants/selectTheme';

const languageLabel: string = Drupal.t('Language', {}, { context: 'Language filter label' });

export const LanguageFilter = () => {
const languageOptions = useAtomValue(languagesAtom);
const setStateValue = useSetAtom(setStateValueAtom);
const value = useAtomValue(getLanguageAtom);

return (
<Select
className='job-search-form__dropdown'
clearable
id={SearchComponents.LANGUAGE}
noTags
onChange={(selectedOptions) => {
setStateValue({ key: SearchComponents.LANGUAGE, value: selectedOptions });
}}
options={languageOptions}
texts={{
clearButtonAriaLabel_one: Drupal.t(
'Clear @label selection',
{ '@label': languageLabel },
{ context: 'React search clear selection label' },
),
clearButtonAriaLabel_multiple: Drupal.t(
'Clear @label selection',
{ '@label': languageLabel },
{ context: 'React search clear selection label' },
),
label: languageLabel,
language: window.drupalSettings.path.currentLanguage,
placeholder: Drupal.t('All languages', {}, { context: 'Language placeholder' }),
}}
value={value}
theme={defaultSelectTheme}
/>
);
};
33 changes: 33 additions & 0 deletions src/js/react/apps/job-search/components/SearchBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useAtomValue, useSetAtom } from 'jotai';
import { getKeywordAtom, setStateValueAtom } from '../store';
import { TextInput } from 'hds-react';
import { defaultTextInputStyle } from '@/react/common/constants/textInputStyle';
import SearchComponents from '../enum/SearchComponents';

export const SearchBar = () => {
const keyword = useAtomValue(getKeywordAtom);
const setStateValue = useSetAtom(setStateValueAtom);

const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setStateValue({ key: SearchComponents.KEYWORD, value: event.target.value.replace(/\s+/g, ' ') });
};

return (
<TextInput
className='job-search-form__filter'
id={SearchComponents.KEYWORD}
label={Drupal.t('Search term', {}, { context: 'Search keyword label' })}
name={SearchComponents.KEYWORD}
onChange={handleChange}
placeholder={Drupal.t(
'Eg. title, location, department',
{},
{ context: 'HELfi Rekry job search keyword placeholder' },
)}
type='search'
value={keyword}
clearButtonAriaLabel={Drupal.t('Clear', {}, { context: 'React search' })}
style={defaultTextInputStyle}
/>
);
};
45 changes: 45 additions & 0 deletions src/js/react/apps/job-search/components/TaskAreaFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { useAtomValue, useSetAtom } from 'jotai';
import { getTaskAreasAtom, setStateValueAtom, taskAreasAtom } from '../store';
import { Select } from 'hds-react';
import SearchComponents from '../enum/SearchComponents';
import type { OptionType } from '../types/OptionType';
import { defaultMultiSelectTheme } from '@/react/common/constants/selectTheme';

const taskAreasLabel: string = Drupal.t('Task area', {}, { context: 'Task areas filter label' });

export const TaskAreaFilter = () => {
const taskAreaOptions = useAtomValue(taskAreasAtom);
const value = useAtomValue(getTaskAreasAtom);
const setStateValue = useSetAtom(setStateValueAtom);

return (
<Select
className='job-search-form__dropdown'
clearable
id={SearchComponents.TASK_AREAS}
multiSelect
noTags
onChange={(selectedOptions) => {
setStateValue({ key: SearchComponents.TASK_AREAS, value: selectedOptions as OptionType[] });
}}
options={taskAreaOptions}
texts={{
clearButtonAriaLabel_one: Drupal.t(
'Clear @label selection',
{ '@label': taskAreasLabel },
{ context: 'React search clear selection label' },
),
clearButtonAriaLabel_multiple: Drupal.t(
'Clear @label selection',
{ '@label': taskAreasLabel },
{ context: 'React search clear selection label' },
),
label: taskAreasLabel,
language: window.drupalSettings.path.currentLanguage,
placeholder: Drupal.t('All fields', {}, { context: 'Task areas filter placeholder' }),
}}
value={value}
theme={defaultMultiSelectTheme}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import { useAtomValue } from 'jotai';
import CardItem from '@/react/common/Card';
import type Result from '@/types/Result';
import { currentLanguage } from '../../query/queries';
import { urlAtom } from '../../store';
import type Job from '../../types/Job';
import { submittedStateAtom } from '../../store';
import SearchComponents from '../../enum/SearchComponents';
import type { OptionType } from '../../types/OptionType';

const getResultCard = ({
title,
Expand Down Expand Up @@ -79,14 +81,14 @@ const getResultCard = ({
type ResultCardProps = { job: Job; innerHits: Result<Job>[] };

const ResultCard = ({ job, innerHits }: ResultCardProps) => {
const submittedState = useAtomValue(submittedStateAtom);
const { _language, title } = job;

if (!title || !title.length) {
return null;
}

// biome-ignore lint/correctness/useHookAtTopLevel: @todo UHF-12501
const languageFilterActive = useAtomValue(urlAtom)?.language;
const languageFilterActive = (submittedState[SearchComponents.LANGUAGE] as OptionType[])?.length > 0;
// If no filtering by language, prefer showing current language translation
if (!languageFilterActive && innerHits.length > 1 && !_language.includes(currentLanguage)) {
for (const hit of innerHits) {
Expand Down
23 changes: 5 additions & 18 deletions src/js/react/apps/job-search/components/results/ResultsSort.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Select } from 'hds-react';
import { useAtomValue, useSetAtom } from 'jotai';
import { useEffect, useState } from 'react';
import { defaultSelectTheme } from '@/react/common/constants/selectTheme';
import { getCurrentLanguage } from '@/react/common/helpers/GetCurrentLanguage';
import Global from '../../enum/Global';
import { urlAtom, urlUpdateAtom } from '../../store';
import type OptionType from '../../types/OptionType';
import { setSortAtom, submittedStateAtom } from '../../store';

const { sortOptions } = Global;
const options: OptionType[] = [
Expand All @@ -14,34 +13,22 @@ const options: OptionType[] = [
];

const ResultsSort = () => {
const urlParams = useAtomValue(urlAtom);
const setUrlParams = useSetAtom(urlUpdateAtom);
const [sort, setSort] = useState<OptionType>(options[0]);
const submittedState = useAtomValue(submittedStateAtom);
const setSort = useSetAtom(setSortAtom);

// biome-ignore lint/correctness/useExhaustiveDependencies: @todo UHF-12501
useEffect(() => {
if (urlParams.sort) {
const matchedSort = options.find((option: OptionType) => option.value === urlParams.sort);

if (matchedSort) {
setSort(matchedSort);
}
}
}, []);
return (
<Select
className='job-listing-search__sort'
clearable={false}
onChange={(_selectedOptions, clickedOption) => {
setSort(clickedOption);
setUrlParams({ ...urlParams, sort: clickedOption.value });
setSort(clickedOption?.value || sortOptions.newestFirst);
}}
options={options}
texts={{
label: Drupal.t('Sort search results', {}, { context: 'HELfi Rekry job search' }),
language: getCurrentLanguage(window.drupalSettings.path.currentLanguage),
}}
value={[sort]}
value={[options.find((option) => option.value === submittedState.sort) || options[0]]}
theme={defaultSelectTheme}
/>
);
Expand Down
Loading