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
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