From 20f48aa269f018b7a8704e24b4563ea8e314078d Mon Sep 17 00:00:00 2001 From: otenav Date: Fri, 20 Sep 2024 10:18:21 +0200 Subject: [PATCH 1/3] Lager felles interface for SearchResult og Aggregations --- .../filters/DistanceOrLocation.tsx | 4 +- ...{FiltersDesktop.jsx => FiltersDesktop.tsx} | 46 +++++++------------ .../searchBox/buildSearchBoxOptions.ts | 14 +----- ...esultHeader.jsx => SearchResultHeader.tsx} | 29 ++++++------ src/app/(sok)/_types/Aggregations.ts | 13 ++++++ src/app/(sok)/_types/SearchResult.ts | 8 ++++ 6 files changed, 56 insertions(+), 58 deletions(-) rename src/app/(sok)/_components/filters/{FiltersDesktop.jsx => FiltersDesktop.tsx} (75%) rename src/app/(sok)/_components/searchResultHeader/{SearchResultHeader.jsx => SearchResultHeader.tsx} (82%) create mode 100644 src/app/(sok)/_types/Aggregations.ts create mode 100644 src/app/(sok)/_types/SearchResult.ts diff --git a/src/app/(sok)/_components/filters/DistanceOrLocation.tsx b/src/app/(sok)/_components/filters/DistanceOrLocation.tsx index 86f805b76..ae0bb30e7 100644 --- a/src/app/(sok)/_components/filters/DistanceOrLocation.tsx +++ b/src/app/(sok)/_components/filters/DistanceOrLocation.tsx @@ -5,6 +5,7 @@ import * as actions from "@/app/_common/actions"; import { CarIcon, LocationPinIcon } from "@navikt/aksel-icons"; import { Postcode } from "@/app/(sok)/_utils/fetchPostcodes"; import { UserPreferencesContext } from "@/app/_common/user/UserPreferenceProvider"; +import SearchResult from "@/app/(sok)/_types/SearchResult"; import Counties from "./Locations"; // TODO: Fix disable no-explicit-any when new search field branch is merged @@ -12,8 +13,7 @@ interface DistanceOrLocationProps { postcodes: Postcode[]; // eslint-disable-next-line @typescript-eslint/no-explicit-any locations: any; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - searchResult: any; + searchResult: SearchResult; } function DistanceOrLocation({ postcodes, locations, searchResult }: DistanceOrLocationProps): ReactElement { diff --git a/src/app/(sok)/_components/filters/FiltersDesktop.jsx b/src/app/(sok)/_components/filters/FiltersDesktop.tsx similarity index 75% rename from src/app/(sok)/_components/filters/FiltersDesktop.jsx rename to src/app/(sok)/_components/filters/FiltersDesktop.tsx index a0a94a6ef..c11523e68 100644 --- a/src/app/(sok)/_components/filters/FiltersDesktop.jsx +++ b/src/app/(sok)/_components/filters/FiltersDesktop.tsx @@ -1,5 +1,4 @@ -import React from "react"; -import PropTypes from "prop-types"; +import React, { ReactElement } from "react"; import { Accordion, Alert, Button } from "@navikt/ds-react"; import Remote from "@/app/(sok)/_components/filters/Remote"; import Education from "@/app/(sok)/_components/filters/Education"; @@ -7,6 +6,9 @@ import DriversLicense from "@/app/(sok)/_components/filters/DriversLicense"; import Experience from "@/app/(sok)/_components/filters/Experience"; import NewFiltersMessage from "@/app/(sok)/_components/filters/NewFiltersMessage"; import DistanceOrLocation from "@/app/(sok)/_components/filters/DistanceOrLocation"; +import Aggregations from "@/app/(sok)/_types/Aggregations"; +import SearchResult from "@/app/(sok)/_types/SearchResult"; +import { Postcode } from "@/app/(sok)/_utils/fetchPostcodes"; import FilterAccordionItem from "./FilterAccordionItem"; import Published from "./Published"; import Occupations from "./Occupations"; @@ -15,7 +17,19 @@ import Sector from "./Sector"; import EngagementType from "./Engagement"; import WorkLanguage from "./WorkLanguage"; -function FiltersDesktop({ aggregations, locations, postcodes, searchResult }) { +interface FiltersDesktopProps { + aggregations: Aggregations; + locations: []; + postcodes: Postcode[]; + searchResult: SearchResult; +} + +export default function FiltersDesktop({ + aggregations, + locations, + postcodes, + searchResult, +}: FiltersDesktopProps): ReactElement { return (
@@ -76,29 +90,3 @@ function FiltersDesktop({ aggregations, locations, postcodes, searchResult }) {
); } - -FiltersDesktop.propTypes = { - locations: PropTypes.arrayOf(PropTypes.shape({})), - aggregations: PropTypes.shape({ - needDriversLicense: PropTypes.arrayOf(PropTypes.shape({})), - engagementTypes: PropTypes.arrayOf(PropTypes.shape({})), - occupationFirstLevels: PropTypes.arrayOf(PropTypes.shape({})), - published: PropTypes.arrayOf(PropTypes.shape({})), - extent: PropTypes.arrayOf(PropTypes.shape({})), - sector: PropTypes.arrayOf(PropTypes.shape({})), - workLanguage: PropTypes.arrayOf(PropTypes.shape({})), - }), - searchResult: PropTypes.shape({ - aggregations: PropTypes.shape({ - needDriversLicense: PropTypes.arrayOf(PropTypes.shape({})), - engagementTypes: PropTypes.arrayOf(PropTypes.shape({})), - occupationFirstLevels: PropTypes.arrayOf(PropTypes.shape({})), - published: PropTypes.arrayOf(PropTypes.shape({})), - extent: PropTypes.arrayOf(PropTypes.shape({})), - sector: PropTypes.arrayOf(PropTypes.shape({})), - workLanguage: PropTypes.arrayOf(PropTypes.shape({})), - }), - }), -}; - -export default FiltersDesktop; diff --git a/src/app/(sok)/_components/searchBox/buildSearchBoxOptions.ts b/src/app/(sok)/_components/searchBox/buildSearchBoxOptions.ts index 47043f3ff..62ba21703 100644 --- a/src/app/(sok)/_components/searchBox/buildSearchBoxOptions.ts +++ b/src/app/(sok)/_components/searchBox/buildSearchBoxOptions.ts @@ -26,6 +26,7 @@ import { WORK_LANGUAGE, } from "@/app/(sok)/_components/searchParamNames"; import { PublishedLabels } from "@/app/(sok)/_utils/publishedLabels"; +import Aggregations from "@/app/(sok)/_types/Aggregations"; const promotedOptions: ComboboxOption[] = [ { label: "Butikkmedarbeider", value: `${OCCUPATION}-Butikkmedarbeider` }, @@ -298,19 +299,6 @@ export const findLabelForFilter = (value: string): string => { } }; -interface Aggregations { - occupationFirstLevels: { key: string; occupationSecondLevels: { key: string }[] }[]; - published: { key: string }[]; - sector: { key: string }[]; - engagementTypes: { key: string }[]; - extent: { key: string }[]; - education: { key: string }[]; - workLanguage: { key: string }[]; - remote: { key: string }[]; - needDriversLicense: { key: string }[]; - experience: { key: string }[]; -} - interface LocationList { type: string; key: string; diff --git a/src/app/(sok)/_components/searchResultHeader/SearchResultHeader.jsx b/src/app/(sok)/_components/searchResultHeader/SearchResultHeader.tsx similarity index 82% rename from src/app/(sok)/_components/searchResultHeader/SearchResultHeader.jsx rename to src/app/(sok)/_components/searchResultHeader/SearchResultHeader.tsx index 2ca4e08a9..2bb5e4063 100644 --- a/src/app/(sok)/_components/searchResultHeader/SearchResultHeader.jsx +++ b/src/app/(sok)/_components/searchResultHeader/SearchResultHeader.tsx @@ -1,12 +1,22 @@ -import React from "react"; +import React, { ReactElement } from "react"; import { BodyShort, Box, Button, Heading, HGrid, HStack, Show, Stack } from "@navikt/ds-react"; -import PropTypes from "prop-types"; import Sorting from "@/app/(sok)/_components/searchResult/Sorting"; import { formatNumber } from "@/app/_common/utils/utils"; import FilterIcon from "@/app/(sok)/_components/icons/FilterIcon"; +import SearchResult from "@/app/(sok)/_types/SearchResult"; -function SearchResultHeader({ searchResult, isFiltersVisible, setIsFiltersVisible }) { - const stillingerWord = searchResult.totalPositions === 1 ? "stilling" : "stillinger"; +interface SearchResultHeaderProps { + searchResult: SearchResult; + isFiltersVisible: boolean; + setIsFiltersVisible: (isFiltersVisible: boolean) => void; +} + +export default function SearchResultHeader({ + searchResult, + isFiltersVisible, + setIsFiltersVisible, +}: SearchResultHeaderProps): ReactElement { + const stillingerWord: string = searchResult.totalPositions === 1 ? "stilling" : "stillinger"; return ( @@ -19,7 +29,7 @@ function SearchResultHeader({ searchResult, isFiltersVisible, setIsFiltersVisibl @@ -60,12 +70,3 @@ function SearchResultHeader({ searchResult, isFiltersVisible, setIsFiltersVisibl ); } - -SearchResultHeader.propTypes = { - searchResult: PropTypes.shape({ - totalAds: PropTypes.number, - totalPositions: PropTypes.number, - }), -}; - -export default SearchResultHeader; diff --git a/src/app/(sok)/_types/Aggregations.ts b/src/app/(sok)/_types/Aggregations.ts new file mode 100644 index 000000000..d1609b078 --- /dev/null +++ b/src/app/(sok)/_types/Aggregations.ts @@ -0,0 +1,13 @@ +export default interface Aggregations { + occupationFirstLevels: { key: string; occupationSecondLevels: { key: string }[] }[]; + published: { key: string }[]; + sector: { key: string }[]; + engagementTypes: { key: string }[]; + extent: { key: string }[]; + education: { key: string }[]; + workLanguage: { key: string }[]; + remote: { key: string }[]; + needDriversLicense: { key: string }[]; + experience: { key: string }[]; + publishedTotalCount: number; +} diff --git a/src/app/(sok)/_types/SearchResult.ts b/src/app/(sok)/_types/SearchResult.ts new file mode 100644 index 000000000..e2f51ee3f --- /dev/null +++ b/src/app/(sok)/_types/SearchResult.ts @@ -0,0 +1,8 @@ +import Aggregations from "@/app/(sok)/_types/Aggregations"; + +export default interface SearchResult { + ads: []; + aggregations: Aggregations; + totalAds: number; + totalPositions: number; +} From ddac9721e286b8ec23941046c197e229c1ee6761 Mon Sep 17 00:00:00 2001 From: otenav Date: Fri, 20 Sep 2024 11:13:02 +0200 Subject: [PATCH 2/3] Rename to FilterAggregations --- .../filters/{Extent.jsx => Extent.tsx} | 30 ++++++++----------- .../_components/filters/FiltersDesktop.tsx | 4 +-- .../searchBox/buildSearchBoxOptions.ts | 28 ++++++++--------- src/app/(sok)/_types/Aggregations.ts | 13 -------- src/app/(sok)/_types/FilterAggregations.ts | 22 ++++++++++++++ src/app/(sok)/_types/SearchResult.ts | 4 +-- 6 files changed, 52 insertions(+), 49 deletions(-) rename src/app/(sok)/_components/filters/{Extent.jsx => Extent.tsx} (67%) delete mode 100644 src/app/(sok)/_types/Aggregations.ts create mode 100644 src/app/(sok)/_types/FilterAggregations.ts diff --git a/src/app/(sok)/_components/filters/Extent.jsx b/src/app/(sok)/_components/filters/Extent.tsx similarity index 67% rename from src/app/(sok)/_components/filters/Extent.jsx rename to src/app/(sok)/_components/filters/Extent.tsx index 1ab087ccf..f7f45b896 100644 --- a/src/app/(sok)/_components/filters/Extent.jsx +++ b/src/app/(sok)/_components/filters/Extent.tsx @@ -1,16 +1,22 @@ -import PropTypes from "prop-types"; -import React from "react"; +import React, { ReactElement } from "react"; import { BodyShort, Checkbox, CheckboxGroup } from "@navikt/ds-react"; import mergeCount from "@/app/(sok)/_components/utils/mergeCount"; import { logFilterChanged } from "@/app/_common/monitoring/amplitude"; import { EXTENT } from "@/app/(sok)/_components/searchParamNames"; import useSearchQuery from "@/app/(sok)/_components/SearchQueryProvider"; +import { FilterAggregation } from "@/app/(sok)/_types/FilterAggregations"; -function Extent({ initialValues, updatedValues }) { - const values = mergeCount(initialValues, updatedValues); +interface ExtentProps { + initialValues: FilterAggregation[]; + updatedValues: FilterAggregation[]; +} + +export default function Extent({ initialValues, updatedValues }: ExtentProps): ReactElement { + // @ts-expect-error mergeCount is expecting 3 arguments + const values: FilterAggregation[] = mergeCount(initialValues, updatedValues); const searchQuery = useSearchQuery(); - function handleClick(e) { + function handleClick(e: React.ChangeEvent): void { const { value, checked } = e.target; if (checked) { searchQuery.append(EXTENT, value); @@ -32,7 +38,7 @@ function Extent({ initialValues, updatedValues }) { } > - {values.map((item) => ( + {values.map((item: FilterAggregation) => ( {`${item.key} (${item.count})`} @@ -40,15 +46,3 @@ function Extent({ initialValues, updatedValues }) { ); } - -Extent.propTypes = { - initialValues: PropTypes.arrayOf( - PropTypes.shape({ - key: PropTypes.string, - count: PropTypes.number, - }), - ).isRequired, - updatedValues: PropTypes.arrayOf(PropTypes.shape({})), -}; - -export default Extent; diff --git a/src/app/(sok)/_components/filters/FiltersDesktop.tsx b/src/app/(sok)/_components/filters/FiltersDesktop.tsx index c11523e68..d1f8480bc 100644 --- a/src/app/(sok)/_components/filters/FiltersDesktop.tsx +++ b/src/app/(sok)/_components/filters/FiltersDesktop.tsx @@ -6,7 +6,7 @@ import DriversLicense from "@/app/(sok)/_components/filters/DriversLicense"; import Experience from "@/app/(sok)/_components/filters/Experience"; import NewFiltersMessage from "@/app/(sok)/_components/filters/NewFiltersMessage"; import DistanceOrLocation from "@/app/(sok)/_components/filters/DistanceOrLocation"; -import Aggregations from "@/app/(sok)/_types/Aggregations"; +import FilterAggregations from "@/app/(sok)/_types/FilterAggregations"; import SearchResult from "@/app/(sok)/_types/SearchResult"; import { Postcode } from "@/app/(sok)/_utils/fetchPostcodes"; import FilterAccordionItem from "./FilterAccordionItem"; @@ -18,7 +18,7 @@ import EngagementType from "./Engagement"; import WorkLanguage from "./WorkLanguage"; interface FiltersDesktopProps { - aggregations: Aggregations; + aggregations: FilterAggregations; locations: []; postcodes: Postcode[]; searchResult: SearchResult; diff --git a/src/app/(sok)/_components/searchBox/buildSearchBoxOptions.ts b/src/app/(sok)/_components/searchBox/buildSearchBoxOptions.ts index 62ba21703..92de52dcf 100644 --- a/src/app/(sok)/_components/searchBox/buildSearchBoxOptions.ts +++ b/src/app/(sok)/_components/searchBox/buildSearchBoxOptions.ts @@ -26,7 +26,7 @@ import { WORK_LANGUAGE, } from "@/app/(sok)/_components/searchParamNames"; import { PublishedLabels } from "@/app/(sok)/_utils/publishedLabels"; -import Aggregations from "@/app/(sok)/_types/Aggregations"; +import FilterAggregations from "@/app/(sok)/_types/FilterAggregations"; const promotedOptions: ComboboxOption[] = [ { label: "Butikkmedarbeider", value: `${OCCUPATION}-Butikkmedarbeider` }, @@ -87,7 +87,7 @@ function getCountryOptions(locationList: LocationList[]): ComboboxOption[] { } // eslint-disable-next-line @typescript-eslint/explicit-function-return-type -function withSortedSecondLevelOccupations(aggregations: Aggregations) { +function withSortedSecondLevelOccupations(aggregations: FilterAggregations) { return aggregations.occupationFirstLevels.map((item) => { const secondLevel = sortValuesByFirstLetter(item.occupationSecondLevels); return { @@ -97,7 +97,7 @@ function withSortedSecondLevelOccupations(aggregations: Aggregations) { }); } -function getFirstLevelOccupationsOptions(aggregations: Aggregations): ComboboxOption[] { +function getFirstLevelOccupationsOptions(aggregations: FilterAggregations): ComboboxOption[] { return sortValuesByFirstLetter(withSortedSecondLevelOccupations(aggregations)).map( (occupation: { key: string }): ComboboxOption => editedOccupation(occupation.key) === "Ikke oppgitt" @@ -109,7 +109,7 @@ function getFirstLevelOccupationsOptions(aggregations: Aggregations): ComboboxOp ); } -function getSecondLevelOccupationsOptions(aggregations: Aggregations): ComboboxOption[] { +function getSecondLevelOccupationsOptions(aggregations: FilterAggregations): ComboboxOption[] { return withSortedSecondLevelOccupations(aggregations) .map((item) => item.secondLevel) .flat() @@ -121,7 +121,7 @@ function getSecondLevelOccupationsOptions(aggregations: Aggregations): ComboboxO ); } -function getPublishedOptions(aggregations: Aggregations): ComboboxOption[] { +function getPublishedOptions(aggregations: FilterAggregations): ComboboxOption[] { return aggregations.published .map( (item): ComboboxOption => ({ @@ -132,7 +132,7 @@ function getPublishedOptions(aggregations: Aggregations): ComboboxOption[] { .filter((option) => !promotedValues.includes(option.value)); } -function getSectorOptions(aggregations: Aggregations): ComboboxOption[] { +function getSectorOptions(aggregations: FilterAggregations): ComboboxOption[] { return aggregations.sector.map( (item): ComboboxOption => item.key === "Ikke oppgitt" @@ -141,7 +141,7 @@ function getSectorOptions(aggregations: Aggregations): ComboboxOption[] { ); } -function getEngagementTypeOptions(aggregations: Aggregations): ComboboxOption[] { +function getEngagementTypeOptions(aggregations: FilterAggregations): ComboboxOption[] { return aggregations.engagementTypes.map( (item): ComboboxOption => editedItemKey(item.key) === "Ikke oppgitt" @@ -150,7 +150,7 @@ function getEngagementTypeOptions(aggregations: Aggregations): ComboboxOption[] ); } -function getExtentOptions(aggregations: Aggregations): ComboboxOption[] { +function getExtentOptions(aggregations: FilterAggregations): ComboboxOption[] { return aggregations.extent .map( (item): ComboboxOption => @@ -163,7 +163,7 @@ function getExtentOptions(aggregations: Aggregations): ComboboxOption[] { ) .filter((option) => !promotedValues.includes(option.value)); } -function getEducationOptions(aggregations: Aggregations): ComboboxOption[] { +function getEducationOptions(aggregations: FilterAggregations): ComboboxOption[] { return aggregations.education .map( (item): ComboboxOption => @@ -180,7 +180,7 @@ function getEducationOptions(aggregations: Aggregations): ComboboxOption[] { .filter((option) => !promotedValues.includes(option.value)); } -function getWorkLanguageOptions(aggregations: Aggregations): ComboboxOption[] { +function getWorkLanguageOptions(aggregations: FilterAggregations): ComboboxOption[] { return aggregations.workLanguage .map( (item): ComboboxOption => @@ -191,7 +191,7 @@ function getWorkLanguageOptions(aggregations: Aggregations): ComboboxOption[] { .filter((option) => !promotedValues.includes(option.value)); } -function getRemoteOptions(aggregations: Aggregations): ComboboxOption[] { +function getRemoteOptions(aggregations: FilterAggregations): ComboboxOption[] { return aggregations.remote.map( (item): ComboboxOption => item.key === "Ikke oppgitt" @@ -211,7 +211,7 @@ function getOccupationSuggestionOptions(allSuggestions: string[]): ComboboxOptio .filter((option) => !promotedValues.includes(option.value)); } -function getDriversLicenseOptions(aggregations: Aggregations): ComboboxOption[] { +function getDriversLicenseOptions(aggregations: FilterAggregations): ComboboxOption[] { return aggregations.needDriversLicense .map( (licence): ComboboxOption => @@ -225,7 +225,7 @@ function getDriversLicenseOptions(aggregations: Aggregations): ComboboxOption[] .filter((option) => !promotedValues.includes(option.value)); } -function getExperienceOptions(aggregations: Aggregations): ComboboxOption[] { +function getExperienceOptions(aggregations: FilterAggregations): ComboboxOption[] { return aggregations.experience .map( (experience): ComboboxOption => @@ -240,7 +240,7 @@ function getExperienceOptions(aggregations: Aggregations): ComboboxOption[] { } export function getSearchBoxOptions( - aggregations: Aggregations, + aggregations: FilterAggregations, locations: LocationList[], allSuggestions: string[], ): ComboboxOption[] { diff --git a/src/app/(sok)/_types/Aggregations.ts b/src/app/(sok)/_types/Aggregations.ts deleted file mode 100644 index d1609b078..000000000 --- a/src/app/(sok)/_types/Aggregations.ts +++ /dev/null @@ -1,13 +0,0 @@ -export default interface Aggregations { - occupationFirstLevels: { key: string; occupationSecondLevels: { key: string }[] }[]; - published: { key: string }[]; - sector: { key: string }[]; - engagementTypes: { key: string }[]; - extent: { key: string }[]; - education: { key: string }[]; - workLanguage: { key: string }[]; - remote: { key: string }[]; - needDriversLicense: { key: string }[]; - experience: { key: string }[]; - publishedTotalCount: number; -} diff --git a/src/app/(sok)/_types/FilterAggregations.ts b/src/app/(sok)/_types/FilterAggregations.ts new file mode 100644 index 000000000..6d119a31b --- /dev/null +++ b/src/app/(sok)/_types/FilterAggregations.ts @@ -0,0 +1,22 @@ +export interface FilterAggregation { + key: string; + count: number; +} + +export interface OccupationFilterAggregation extends FilterAggregation { + occupationSecondLevels: FilterAggregation[]; +} + +export default interface FilterAggregations { + occupationFirstLevels: OccupationFilterAggregation[]; + published: FilterAggregation[]; + sector: FilterAggregation[]; + engagementTypes: FilterAggregation[]; + extent: FilterAggregation[]; + education: FilterAggregation[]; + workLanguage: FilterAggregation[]; + remote: FilterAggregation[]; + needDriversLicense: FilterAggregation[]; + experience: FilterAggregation[]; + publishedTotalCount: number; +} diff --git a/src/app/(sok)/_types/SearchResult.ts b/src/app/(sok)/_types/SearchResult.ts index e2f51ee3f..46c9f3b25 100644 --- a/src/app/(sok)/_types/SearchResult.ts +++ b/src/app/(sok)/_types/SearchResult.ts @@ -1,8 +1,8 @@ -import Aggregations from "@/app/(sok)/_types/Aggregations"; +import FilterAggregations from "@/app/(sok)/_types/FilterAggregations"; export default interface SearchResult { ads: []; - aggregations: Aggregations; + aggregations: FilterAggregations; totalAds: number; totalPositions: number; } From f6f936f4c89e4edbf9193fc55e6157296c926368 Mon Sep 17 00:00:00 2001 From: otenav Date: Tue, 24 Sep 2024 09:53:25 +0200 Subject: [PATCH 3/3] =?UTF-8?q?Gj=C3=B8r=20om=20alle=20filtre=20til=20type?= =?UTF-8?q?script?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filters/DistanceOrLocation.tsx | 4 +- ...{DriversLicense.jsx => DriversLicense.tsx} | 33 +++++------- .../filters/{Education.jsx => Education.tsx} | 29 ++++------ .../{Engagement.jsx => Engagement.tsx} | 34 ++++++------ .../{Experience.jsx => Experience.tsx} | 33 +++++------- src/app/(sok)/_components/filters/Extent.tsx | 9 ++-- .../filters/{Locations.jsx => Locations.tsx} | 53 +++++++++++-------- ...ltersMessage.jsx => NewFiltersMessage.tsx} | 4 +- .../{Occupations.jsx => Occupations.tsx} | 46 ++++++---------- .../filters/{Published.jsx => Published.tsx} | 33 ++++-------- .../filters/{Remote.jsx => Remote.tsx} | 18 ++++--- .../filters/{Sector.jsx => Sector.tsx} | 22 ++++---- .../{WorkLanguage.jsx => WorkLanguage.tsx} | 32 ++++++----- .../utils/{mergeCount.js => mergeCount.ts} | 35 +++++++----- src/app/(sok)/_types/FilterAggregations.ts | 7 ++- 15 files changed, 185 insertions(+), 207 deletions(-) rename src/app/(sok)/_components/filters/{DriversLicense.jsx => DriversLicense.tsx} (74%) rename src/app/(sok)/_components/filters/{Education.jsx => Education.tsx} (81%) rename src/app/(sok)/_components/filters/{Engagement.jsx => Engagement.tsx} (76%) rename src/app/(sok)/_components/filters/{Experience.jsx => Experience.tsx} (76%) rename src/app/(sok)/_components/filters/{Locations.jsx => Locations.tsx} (86%) rename src/app/(sok)/_components/filters/{NewFiltersMessage.jsx => NewFiltersMessage.tsx} (81%) rename src/app/(sok)/_components/filters/{Occupations.jsx => Occupations.tsx} (83%) rename src/app/(sok)/_components/filters/{Published.jsx => Published.tsx} (70%) rename src/app/(sok)/_components/filters/{Remote.jsx => Remote.tsx} (78%) rename src/app/(sok)/_components/filters/{Sector.jsx => Sector.tsx} (79%) rename src/app/(sok)/_components/filters/{WorkLanguage.jsx => WorkLanguage.tsx} (73%) rename src/app/(sok)/_components/utils/{mergeCount.js => mergeCount.ts} (52%) diff --git a/src/app/(sok)/_components/filters/DistanceOrLocation.tsx b/src/app/(sok)/_components/filters/DistanceOrLocation.tsx index ae0bb30e7..395950522 100644 --- a/src/app/(sok)/_components/filters/DistanceOrLocation.tsx +++ b/src/app/(sok)/_components/filters/DistanceOrLocation.tsx @@ -42,7 +42,9 @@ function DistanceOrLocation({ postcodes, locations, searchResult }: DistanceOrLo /> {selectedOption === "distance" && } - {selectedOption === "location" && } + {selectedOption === "location" && ( + + )} ); } diff --git a/src/app/(sok)/_components/filters/DriversLicense.jsx b/src/app/(sok)/_components/filters/DriversLicense.tsx similarity index 74% rename from src/app/(sok)/_components/filters/DriversLicense.jsx rename to src/app/(sok)/_components/filters/DriversLicense.tsx index 240313074..ed7df52ec 100644 --- a/src/app/(sok)/_components/filters/DriversLicense.jsx +++ b/src/app/(sok)/_components/filters/DriversLicense.tsx @@ -1,17 +1,22 @@ -import PropTypes from "prop-types"; -import React from "react"; +import React, { ReactElement } from "react"; import { BodyShort, Checkbox, CheckboxGroup } from "@navikt/ds-react"; import mergeCount from "@/app/(sok)/_components/utils/mergeCount"; import { logFilterChanged } from "@/app/_common/monitoring/amplitude"; import { NEED_DRIVERS_LICENSE } from "@/app/(sok)/_components/searchParamNames"; import useSearchQuery from "@/app/(sok)/_components/SearchQueryProvider"; +import { FilterAggregation } from "@/app/(sok)/_types/FilterAggregations"; -function DriversLicense({ initialValues, updatedValues }) { +interface DriversLicenseProps { + initialValues: FilterAggregation[]; + updatedValues: FilterAggregation[]; +} + +export default function DriversLicense({ initialValues, updatedValues }: DriversLicenseProps): ReactElement { const sortedValues = sortDriverLicenseValues(initialValues); const values = mergeCount(sortedValues, updatedValues); const searchQuery = useSearchQuery(); - function handleClick(e) { + function handleChange(e: React.ChangeEvent): void { const { value, checked } = e.target; if (checked) { searchQuery.append(NEED_DRIVERS_LICENSE, value); @@ -34,7 +39,7 @@ function DriversLicense({ initialValues, updatedValues }) { } > {values.map((item) => ( - + {`${labelForNeedDriversLicense(item.key)} (${item.count})`} ))} @@ -42,17 +47,7 @@ function DriversLicense({ initialValues, updatedValues }) { ); } -DriversLicense.propTypes = { - initialValues: PropTypes.arrayOf( - PropTypes.shape({ - key: PropTypes.string, - count: PropTypes.number, - }), - ).isRequired, - updatedValues: PropTypes.arrayOf(PropTypes.shape({})), -}; - -export const labelForNeedDriversLicense = (key) => { +export const labelForNeedDriversLicense = (key: string): string => { switch (key) { case "true": return "Må ha førerkort"; @@ -63,12 +58,10 @@ export const labelForNeedDriversLicense = (key) => { } }; -function sortDriverLicenseValues(facets) { +function sortDriverLicenseValues(facets: FilterAggregation[]): FilterAggregation[] { if (!facets) { - return undefined; + return []; } const sortedPublishedValues = ["false", "true", "Ikke oppgitt"]; return facets.sort((a, b) => sortedPublishedValues.indexOf(a.key) - sortedPublishedValues.indexOf(b.key)); } - -export default DriversLicense; diff --git a/src/app/(sok)/_components/filters/Education.jsx b/src/app/(sok)/_components/filters/Education.tsx similarity index 81% rename from src/app/(sok)/_components/filters/Education.jsx rename to src/app/(sok)/_components/filters/Education.tsx index 0ea7e324d..78771f626 100644 --- a/src/app/(sok)/_components/filters/Education.jsx +++ b/src/app/(sok)/_components/filters/Education.tsx @@ -1,5 +1,4 @@ -import PropTypes from "prop-types"; -import React from "react"; +import React, { ReactElement } from "react"; import { BodyShort, Checkbox, CheckboxGroup } from "@navikt/ds-react"; import mergeCount from "@/app/(sok)/_components/utils/mergeCount"; import { logFilterChanged } from "@/app/_common/monitoring/amplitude"; @@ -7,14 +6,20 @@ import moveCriteriaToBottom from "@/app/(sok)/_components/utils/moveFacetToBotto import sortEducationValues from "@/app/(sok)/_components/utils/sortEducationValues"; import { EDUCATION } from "@/app/(sok)/_components/searchParamNames"; import useSearchQuery from "@/app/(sok)/_components/SearchQueryProvider"; +import { FilterAggregation } from "@/app/(sok)/_types/FilterAggregations"; -function Education({ initialValues, updatedValues }) { +interface EducationProps { + initialValues: FilterAggregation[]; + updatedValues: FilterAggregation[]; +} + +export default function Education({ initialValues, updatedValues }: EducationProps): ReactElement { const sortedValuesByEducation = sortEducationValues(initialValues); const sortedValues = moveCriteriaToBottom(sortedValuesByEducation, "Ikke oppgitt"); const values = mergeCount(sortedValues, updatedValues); const searchQuery = useSearchQuery(); - function handleClick(e) { + function handleChange(e: React.ChangeEvent): void { const { value, checked } = e.target; if (checked) { searchQuery.append(EDUCATION, value); @@ -38,7 +43,7 @@ function Education({ initialValues, updatedValues }) { } > {values.map((item) => ( - + {`${labelForEducation(item.key)} (${item.count})`} ))} @@ -46,7 +51,7 @@ function Education({ initialValues, updatedValues }) { ); } -export const labelForEducation = (key) => { +export const labelForEducation = (key: string): string => { switch (key) { case "Ingen krav": return "Ingen krav til utdanning"; @@ -64,15 +69,3 @@ export const labelForEducation = (key) => { return key; } }; - -Education.propTypes = { - initialValues: PropTypes.arrayOf( - PropTypes.shape({ - key: PropTypes.string, - count: PropTypes.number, - }), - ).isRequired, - updatedValues: PropTypes.arrayOf(PropTypes.shape({})), -}; - -export default Education; diff --git a/src/app/(sok)/_components/filters/Engagement.jsx b/src/app/(sok)/_components/filters/Engagement.tsx similarity index 76% rename from src/app/(sok)/_components/filters/Engagement.jsx rename to src/app/(sok)/_components/filters/Engagement.tsx index c825e927c..b86d7eca2 100644 --- a/src/app/(sok)/_components/filters/Engagement.jsx +++ b/src/app/(sok)/_components/filters/Engagement.tsx @@ -1,5 +1,4 @@ -import PropTypes from "prop-types"; -import React from "react"; +import React, { ReactElement } from "react"; import { BodyShort, Checkbox, CheckboxGroup } from "@navikt/ds-react"; import moveCriteriaToBottom from "@/app/(sok)/_components/utils/moveFacetToBottom"; import mergeCount from "@/app/(sok)/_components/utils/mergeCount"; @@ -7,6 +6,7 @@ import sortValuesByFirstLetter from "@/app/(sok)/_components/utils/sortValuesByF import { logFilterChanged } from "@/app/_common/monitoring/amplitude"; import { ENGAGEMENT_TYPE } from "@/app/(sok)/_components/searchParamNames"; import useSearchQuery from "@/app/(sok)/_components/SearchQueryProvider"; +import { FilterAggregation } from "@/app/(sok)/_types/FilterAggregations"; /** * This ensures that 'Annet' is displayed as 'Ikke oppgitt' in the search filters. @@ -17,17 +17,22 @@ import useSearchQuery from "@/app/(sok)/_components/SearchQueryProvider"; * @param key * @returns {string|*} */ -export function editedItemKey(key) { +export function editedItemKey(key: string): string { return key === "Annet" ? "Ikke oppgitt" : key; } -function Engagement({ initialValues, updatedValues }) { +interface EngagementProps { + initialValues: FilterAggregation[]; + updatedValues: FilterAggregation[]; +} + +export default function Engagement({ initialValues, updatedValues }: EngagementProps): ReactElement { const sortedValuesByFirstLetter = sortValuesByFirstLetter(initialValues); const sortedValues = moveCriteriaToBottom(sortedValuesByFirstLetter, "Annet"); const values = mergeCount(sortedValues, updatedValues); const searchQuery = useSearchQuery(); - function handleClick(e) { + function handleChange(e: React.ChangeEvent): void { const { value, checked } = e.target; if (checked) { searchQuery.append(ENGAGEMENT_TYPE, value); @@ -51,22 +56,15 @@ function Engagement({ initialValues, updatedValues }) { } > {values.map((item) => ( - + {`${editedItemKey(item.key)} (${item.count})`} ))} ); } - -Engagement.propTypes = { - initialValues: PropTypes.arrayOf( - PropTypes.shape({ - key: PropTypes.string, - count: PropTypes.number, - }), - ).isRequired, - updatedValues: PropTypes.arrayOf(PropTypes.shape({})), -}; - -export default Engagement; diff --git a/src/app/(sok)/_components/filters/Experience.jsx b/src/app/(sok)/_components/filters/Experience.tsx similarity index 76% rename from src/app/(sok)/_components/filters/Experience.jsx rename to src/app/(sok)/_components/filters/Experience.tsx index 5df96ee30..ac124f1ae 100644 --- a/src/app/(sok)/_components/filters/Experience.jsx +++ b/src/app/(sok)/_components/filters/Experience.tsx @@ -1,17 +1,22 @@ -import PropTypes from "prop-types"; -import React from "react"; +import React, { ReactElement } from "react"; import { BodyShort, Checkbox, CheckboxGroup } from "@navikt/ds-react"; import mergeCount from "@/app/(sok)/_components/utils/mergeCount"; import { logFilterChanged } from "@/app/_common/monitoring/amplitude"; import { EXPERIENCE } from "@/app/(sok)/_components/searchParamNames"; import useSearchQuery from "@/app/(sok)/_components/SearchQueryProvider"; +import { FilterAggregation } from "@/app/(sok)/_types/FilterAggregations"; -function Experience({ initialValues, updatedValues }) { +interface ExperienceProps { + initialValues: FilterAggregation[]; + updatedValues: FilterAggregation[]; +} + +export default function Experience({ initialValues, updatedValues }: ExperienceProps): ReactElement { const sortedValues = sortExperienceValues(initialValues); const values = mergeCount(sortedValues, updatedValues); const searchQuery = useSearchQuery(); - function handleClick(e) { + function handleChange(e: React.ChangeEvent): void { const { value, checked } = e.target; if (checked) { searchQuery.append(EXPERIENCE, value); @@ -35,7 +40,7 @@ function Experience({ initialValues, updatedValues }) { } > {values.map((item) => ( - + {`${labelForExperience(item.key)} (${item.count})`} ))} @@ -43,7 +48,7 @@ function Experience({ initialValues, updatedValues }) { ); } -export const labelForExperience = (key) => { +export const labelForExperience = (key: string): string => { switch (key) { case "Ingen": return "Ingen krav til arbeidserfaring"; @@ -56,22 +61,10 @@ export const labelForExperience = (key) => { } }; -function sortExperienceValues(facets) { +function sortExperienceValues(facets: FilterAggregation[]): FilterAggregation[] { if (!facets) { - return undefined; + return []; } const sortedPublishedValues = ["Ingen", "Noe", "Mye", "Ikke oppgitt"]; return facets.sort((a, b) => sortedPublishedValues.indexOf(a.key) - sortedPublishedValues.indexOf(b.key)); } - -Experience.propTypes = { - initialValues: PropTypes.arrayOf( - PropTypes.shape({ - key: PropTypes.string, - count: PropTypes.number, - }), - ).isRequired, - updatedValues: PropTypes.arrayOf(PropTypes.shape({})), -}; - -export default Experience; diff --git a/src/app/(sok)/_components/filters/Extent.tsx b/src/app/(sok)/_components/filters/Extent.tsx index f7f45b896..16836548a 100644 --- a/src/app/(sok)/_components/filters/Extent.tsx +++ b/src/app/(sok)/_components/filters/Extent.tsx @@ -12,11 +12,10 @@ interface ExtentProps { } export default function Extent({ initialValues, updatedValues }: ExtentProps): ReactElement { - // @ts-expect-error mergeCount is expecting 3 arguments - const values: FilterAggregation[] = mergeCount(initialValues, updatedValues); + const values = mergeCount(initialValues, updatedValues); const searchQuery = useSearchQuery(); - function handleClick(e: React.ChangeEvent): void { + function handleChange(e: React.ChangeEvent): void { const { value, checked } = e.target; if (checked) { searchQuery.append(EXTENT, value); @@ -38,8 +37,8 @@ export default function Extent({ initialValues, updatedValues }: ExtentProps): R } > - {values.map((item: FilterAggregation) => ( - + {values.map((item) => ( + {`${item.key} (${item.count})`} ))} diff --git a/src/app/(sok)/_components/filters/Locations.jsx b/src/app/(sok)/_components/filters/Locations.tsx similarity index 86% rename from src/app/(sok)/_components/filters/Locations.jsx rename to src/app/(sok)/_components/filters/Locations.tsx index 02f61024d..5fd427b37 100644 --- a/src/app/(sok)/_components/filters/Locations.jsx +++ b/src/app/(sok)/_components/filters/Locations.tsx @@ -1,17 +1,34 @@ -import React from "react"; -import PropTypes from "prop-types"; +import React, { ReactElement } from "react"; import { BodyShort, Box, Checkbox, Fieldset } from "@navikt/ds-react"; import fixLocationName from "@/app/_common/utils/fixLocationName"; import buildLocations from "@/app/(sok)/_components/utils/buildLocations"; import { logFilterChanged } from "@/app/_common/monitoring/amplitude"; import { COUNTRY, COUNTY, INTERNATIONAL, MUNICIPAL } from "@/app/(sok)/_components/searchParamNames"; import useSearchQuery from "@/app/(sok)/_components/SearchQueryProvider"; +import FilterAggregations, { FilterAggregation } from "@/app/(sok)/_types/FilterAggregations"; -function Locations({ locations, updatedValues }) { - const locationValues = buildLocations(updatedValues.aggregations, locations); +interface SubLocation { + type: string; + key: string; + count: number; +} + +interface Location { + type: string; + key: string; + count: number; + subLocations: SubLocation[]; +} + +interface LocationsProps { + locations: []; + updatedValues: FilterAggregations; +} +export default function Locations({ locations, updatedValues }: LocationsProps): ReactElement { + const locationValues: Location[] = buildLocations(updatedValues, locations); const searchQuery = useSearchQuery(); - function handleLocationClick(value, type, checked) { + function handleLocationClick(value: string, type: string, checked: boolean): void { if (type === "county") { if (checked) { searchQuery.append(COUNTY, value); @@ -48,9 +65,11 @@ function Locations({ locations, updatedValues }) { } } - const handleCheckboxClick = (key, type) => (e) => { - handleLocationClick(key, type, e.target.checked); - }; + const handleCheckboxClick = + (key: string, type: string) => + (e: React.ChangeEvent): void => { + handleLocationClick(key, type, e.target.checked); + }; return (
- Utland ({updatedValues.aggregations.totalInternational}) + Utland ({updatedValues.totalInternational}) ) : ( {location.subLocations && location.subLocations - .sort((a, b) => a.key.localeCompare(b.key, "no")) + .sort((a: FilterAggregation, b: FilterAggregation) => + a.key.localeCompare(b.key, "no"), + ) .map((subLocation) => ( ); } - -Locations.propTypes = { - updatedValues: PropTypes.shape({ - aggregations: PropTypes.shape({ - internationalCountMap: PropTypes.object, - nationalCountMap: PropTypes.object, - }), - }), - locations: PropTypes.arrayOf(PropTypes.object), -}; - -export default Locations; diff --git a/src/app/(sok)/_components/filters/NewFiltersMessage.jsx b/src/app/(sok)/_components/filters/NewFiltersMessage.tsx similarity index 81% rename from src/app/(sok)/_components/filters/NewFiltersMessage.jsx rename to src/app/(sok)/_components/filters/NewFiltersMessage.tsx index da5d48c80..58f177ede 100644 --- a/src/app/(sok)/_components/filters/NewFiltersMessage.jsx +++ b/src/app/(sok)/_components/filters/NewFiltersMessage.tsx @@ -1,7 +1,7 @@ -import React from "react"; +import React, { ReactElement } from "react"; import { Link as AkselLink } from "@navikt/ds-react"; -export default function NewFiltersMessage() { +export default function NewFiltersMessage(): ReactElement { return ( <> Vi tester ut nye filtre og jobber med å gjøre dem mer nøyaktige. Vi bruker kunstig intelligens (KI) til å diff --git a/src/app/(sok)/_components/filters/Occupations.jsx b/src/app/(sok)/_components/filters/Occupations.tsx similarity index 83% rename from src/app/(sok)/_components/filters/Occupations.jsx rename to src/app/(sok)/_components/filters/Occupations.tsx index 25890bf17..225d4ca64 100644 --- a/src/app/(sok)/_components/filters/Occupations.jsx +++ b/src/app/(sok)/_components/filters/Occupations.tsx @@ -1,20 +1,25 @@ -import PropTypes from "prop-types"; -import React from "react"; +import React, { ReactElement } from "react"; import { BodyShort, Box, Checkbox, CheckboxGroup, ReadMore } from "@navikt/ds-react"; import moveCriteriaToBottom from "@/app/(sok)/_components/utils/moveFacetToBottom"; -import mergeCount from "@/app/(sok)/_components/utils/mergeCount"; +import { mergeCountOccupations } from "@/app/(sok)/_components/utils/mergeCount"; import sortValuesByFirstLetter from "@/app/(sok)/_components/utils/sortValuesByFirstLetter"; import { logFilterChanged } from "@/app/_common/monitoring/amplitude"; import { OCCUPATION_FIRST_LEVEL, OCCUPATION_SECOND_LEVEL } from "@/app/(sok)/_components/searchParamNames"; import useSearchQuery from "@/app/(sok)/_components/SearchQueryProvider"; +import { OccupationFilterAggregation } from "@/app/(sok)/_types/FilterAggregations"; -export function editedItemKey(key) { +export function editedItemKey(key: string): string { return key === "Uoppgitt/ ikke identifiserbare" ? "Ikke oppgitt" : key; } const OCCUPATION_LEVEL_OTHER = "Uoppgitt/ ikke identifiserbare"; -function Occupations({ initialValues, updatedValues }) { +interface OccupationsProps { + initialValues: OccupationFilterAggregation[]; + updatedValues: OccupationFilterAggregation[]; +} + +export default function Occupations({ initialValues, updatedValues }: OccupationsProps): ReactElement { const withSortedSecondLevelOccupations = initialValues.map((item) => { const secondLevel = sortValuesByFirstLetter(item.occupationSecondLevels); return { @@ -25,10 +30,10 @@ function Occupations({ initialValues, updatedValues }) { const sortedByLetterFirstLevelOccupations = sortValuesByFirstLetter(withSortedSecondLevelOccupations); const sortedValues = moveCriteriaToBottom(sortedByLetterFirstLevelOccupations, OCCUPATION_LEVEL_OTHER); - const values = mergeCount(sortedValues, updatedValues, "occupationSecondLevels"); + const values = mergeCountOccupations(sortedValues, updatedValues); const searchQuery = useSearchQuery(); - function handleFirstLevelClick(e) { + function handleFirstLevelChange(e: React.ChangeEvent): void { const { value, checked } = e.target; if (checked) { searchQuery.append(OCCUPATION_FIRST_LEVEL, value); @@ -43,7 +48,7 @@ function Occupations({ initialValues, updatedValues }) { logFilterChanged({ name: "Yrkeskategori", value, checked, level: "Yrkesnivå 1" }); } - function handleSecondLevelClick(e) { + function handleSecondLevelChange(e: React.ChangeEvent): void { const { value, checked } = e.target; if (checked) { searchQuery.append(OCCUPATION_SECOND_LEVEL, value); @@ -66,7 +71,7 @@ function Occupations({ initialValues, updatedValues }) { * @param key * @returns {string|*} */ - function editedSecondLevelItemKey(key) { + function editedSecondLevelItemKey(key: string): string { return key === "Tannhelse/-pleie" ? "Tannlege og tannpleier" : key; } @@ -94,9 +99,8 @@ function Occupations({ initialValues, updatedValues }) { {`${editedItemKey(firstLevel.key)} (${firstLevel.count})`} @@ -114,7 +118,7 @@ function Occupations({ initialValues, updatedValues }) { name="occupationSecondLevels[]" key={editedSecondLevelItemKey(secondLevel.key)} value={secondLevel.key} - onChange={handleSecondLevelClick} + onChange={handleSecondLevelChange} > {`${editedSecondLevelItemKey(secondLevel.label)} (${ secondLevel.count @@ -129,21 +133,3 @@ function Occupations({ initialValues, updatedValues }) { ); } - -Occupations.propTypes = { - initialValues: PropTypes.arrayOf( - PropTypes.shape({ - key: PropTypes.string, - count: PropTypes.number, - occupationSecondLevels: PropTypes.arrayOf( - PropTypes.shape({ - key: PropTypes.string, - count: PropTypes.number, - }), - ), - }), - ).isRequired, - updatedValues: PropTypes.arrayOf(PropTypes.shape({})), -}; - -export default Occupations; diff --git a/src/app/(sok)/_components/filters/Published.jsx b/src/app/(sok)/_components/filters/Published.tsx similarity index 70% rename from src/app/(sok)/_components/filters/Published.jsx rename to src/app/(sok)/_components/filters/Published.tsx index 2aaa60315..c607eb1c1 100644 --- a/src/app/(sok)/_components/filters/Published.jsx +++ b/src/app/(sok)/_components/filters/Published.tsx @@ -1,5 +1,4 @@ -import PropTypes from "prop-types"; -import React from "react"; +import React, { ReactElement } from "react"; import { Radio, RadioGroup } from "@navikt/ds-react"; import mergeCount from "@/app/(sok)/_components/utils/mergeCount"; import sortPublishedValues from "@/app/(sok)/_components/utils/sortPublishedValues"; @@ -7,13 +6,20 @@ import { logFilterChanged } from "@/app/_common/monitoring/amplitude"; import { PUBLISHED } from "@/app/(sok)/_components/searchParamNames"; import useSearchQuery from "@/app/(sok)/_components/SearchQueryProvider"; import { PublishedLabels } from "@/app/(sok)/_utils/publishedLabels"; +import { FilterAggregation } from "@/app/(sok)/_types/FilterAggregations"; -function Published({ initialValues, updatedValues, publishedTotalCount }) { +interface PublishedProps { + initialValues: FilterAggregation[]; + updatedValues: FilterAggregation[]; + publishedTotalCount: number; +} + +export default function Published({ initialValues, updatedValues, publishedTotalCount }: PublishedProps): ReactElement { const sortedValues = sortPublishedValues(initialValues); const values = mergeCount(sortedValues, updatedValues); const searchQuery = useSearchQuery(); - function handleClick(value) { + function handleChange(value: string): void { if (value) { searchQuery.set(PUBLISHED, value); } else { @@ -24,7 +30,7 @@ function Published({ initialValues, updatedValues, publishedTotalCount }) { return ( ); } - -Published.propTypes = { - initialValues: PropTypes.arrayOf( - PropTypes.shape({ - key: PropTypes.string, - count: PropTypes.number, - }), - ).isRequired, - updatedValues: PropTypes.arrayOf( - PropTypes.shape({ - key: PropTypes.string, - count: PropTypes.number, - }), - ), -}; - -export default Published; diff --git a/src/app/(sok)/_components/filters/Remote.jsx b/src/app/(sok)/_components/filters/Remote.tsx similarity index 78% rename from src/app/(sok)/_components/filters/Remote.jsx rename to src/app/(sok)/_components/filters/Remote.tsx index 3bd41d7a8..9c03f1676 100644 --- a/src/app/(sok)/_components/filters/Remote.jsx +++ b/src/app/(sok)/_components/filters/Remote.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { ReactElement } from "react"; import { BodyShort, Checkbox, CheckboxGroup } from "@navikt/ds-react"; import moveCriteriaToBottom from "@/app/(sok)/_components/utils/moveFacetToBottom"; import mergeCount from "@/app/(sok)/_components/utils/mergeCount"; @@ -6,14 +6,20 @@ import sortRemoteValues from "@/app/(sok)/_components/utils/sortRemoteValues"; import { logFilterChanged } from "@/app/_common/monitoring/amplitude"; import { REMOTE } from "@/app/(sok)/_components/searchParamNames"; import useSearchQuery from "@/app/(sok)/_components/SearchQueryProvider"; +import { FilterAggregation } from "@/app/(sok)/_types/FilterAggregations"; -function Remote({ initialValues, updatedValues }) { +interface RemoteProps { + initialValues: FilterAggregation[]; + updatedValues: FilterAggregation[]; +} + +export default function Remote({ initialValues, updatedValues }: RemoteProps): ReactElement { const sortedValuesByFirstLetter = sortRemoteValues(initialValues); const sortedValues = moveCriteriaToBottom(sortedValuesByFirstLetter, "Ikke oppgitt"); const values = mergeCount(sortedValues, updatedValues); const searchQuery = useSearchQuery(); - function labelForRemote(label) { + function labelForRemote(label: string): string { switch (label) { case "Hybridkontor": return "Hybridkontor"; @@ -24,7 +30,7 @@ function Remote({ initialValues, updatedValues }) { } } - function handleClick(e) { + function handleChange(e: React.ChangeEvent): void { const { value, checked } = e.target; if (checked) { searchQuery.append(REMOTE, value); @@ -44,12 +50,10 @@ function Remote({ initialValues, updatedValues }) { } > {values.map((item) => ( - + {`${labelForRemote(item.key)} (${item.count})`} ))} ); } - -export default Remote; diff --git a/src/app/(sok)/_components/filters/Sector.jsx b/src/app/(sok)/_components/filters/Sector.tsx similarity index 79% rename from src/app/(sok)/_components/filters/Sector.jsx rename to src/app/(sok)/_components/filters/Sector.tsx index 9741b28ef..c3b6ab403 100644 --- a/src/app/(sok)/_components/filters/Sector.jsx +++ b/src/app/(sok)/_components/filters/Sector.tsx @@ -1,5 +1,4 @@ -import PropTypes from "prop-types"; -import React from "react"; +import React, { ReactElement } from "react"; import { BodyShort, Checkbox, CheckboxGroup } from "@navikt/ds-react"; import moveCriteriaToBottom from "@/app/(sok)/_components/utils/moveFacetToBottom"; import mergeCount from "@/app/(sok)/_components/utils/mergeCount"; @@ -7,14 +6,20 @@ import sortValuesByFirstLetter from "@/app/(sok)/_components/utils/sortValuesByF import { logFilterChanged } from "@/app/_common/monitoring/amplitude"; import { SECTOR } from "@/app/(sok)/_components/searchParamNames"; import useSearchQuery from "@/app/(sok)/_components/SearchQueryProvider"; +import { FilterAggregation } from "@/app/(sok)/_types/FilterAggregations"; -function Sector({ initialValues, updatedValues }) { +interface SectorProps { + initialValues: FilterAggregation[]; + updatedValues: FilterAggregation[]; +} + +export default function Sector({ initialValues, updatedValues }: SectorProps): ReactElement { const sortedValuesByFirstLetter = sortValuesByFirstLetter(initialValues); const sortedValues = moveCriteriaToBottom(sortedValuesByFirstLetter, "Ikke oppgitt"); const values = mergeCount(sortedValues, updatedValues); const searchQuery = useSearchQuery(); - function handleClick(e) { + function handleChange(e: React.ChangeEvent): void { const { value, checked } = e.target; if (checked) { searchQuery.append(SECTOR, value); @@ -38,17 +43,10 @@ function Sector({ initialValues, updatedValues }) { } > {values.map((item) => ( - + {`${item.key} (${item.count})`} ))} ); } - -Sector.propTypes = { - initialValues: PropTypes.arrayOf(PropTypes.shape({})), - updatedValues: PropTypes.arrayOf(PropTypes.shape({})), -}; - -export default Sector; diff --git a/src/app/(sok)/_components/filters/WorkLanguage.jsx b/src/app/(sok)/_components/filters/WorkLanguage.tsx similarity index 73% rename from src/app/(sok)/_components/filters/WorkLanguage.jsx rename to src/app/(sok)/_components/filters/WorkLanguage.tsx index dd7d3c83c..bb0b61f8d 100644 --- a/src/app/(sok)/_components/filters/WorkLanguage.jsx +++ b/src/app/(sok)/_components/filters/WorkLanguage.tsx @@ -1,18 +1,28 @@ -import PropTypes from "prop-types"; -import React from "react"; +import React, { ReactElement } from "react"; import { BodyShort, Checkbox, CheckboxGroup } from "@navikt/ds-react"; import mergeCount from "@/app/(sok)/_components/utils/mergeCount"; import { logFilterChanged } from "@/app/_common/monitoring/amplitude"; import moveCriteriaToBottom from "@/app/(sok)/_components/utils/moveFacetToBottom"; import { WORK_LANGUAGE } from "@/app/(sok)/_components/searchParamNames"; import useSearchQuery from "@/app/(sok)/_components/SearchQueryProvider"; +import { FilterAggregation } from "@/app/(sok)/_types/FilterAggregations"; -function WorkLanguage({ initialValues, updatedValues, hideLegend = false }) { +interface WorkLanguageProps { + initialValues: FilterAggregation[]; + updatedValues: FilterAggregation[]; + hideLegend?: boolean; +} + +export default function WorkLanguage({ + initialValues, + updatedValues, + hideLegend = false, +}: WorkLanguageProps): ReactElement { const sortedValues = moveCriteriaToBottom(initialValues, "Ikke oppgitt"); const values = mergeCount(sortedValues, updatedValues); const searchQuery = useSearchQuery(); - function handleClick(e) { + function handleChange(e: React.ChangeEvent): void { const { value, checked } = e.target; if (checked) { searchQuery.append(WORK_LANGUAGE, value); @@ -33,22 +43,10 @@ function WorkLanguage({ initialValues, updatedValues, hideLegend = false }) { } > {values.map((item) => ( - + {`${item.key} (${item.count})`} ))} ); } - -WorkLanguage.propTypes = { - initialValues: PropTypes.arrayOf( - PropTypes.shape({ - key: PropTypes.string, - count: PropTypes.number, - }), - ).isRequired, - updatedValues: PropTypes.arrayOf(PropTypes.shape({})), -}; - -export default WorkLanguage; diff --git a/src/app/(sok)/_components/utils/mergeCount.js b/src/app/(sok)/_components/utils/mergeCount.ts similarity index 52% rename from src/app/(sok)/_components/utils/mergeCount.js rename to src/app/(sok)/_components/utils/mergeCount.ts index cf0272d7b..dde8bfab8 100644 --- a/src/app/(sok)/_components/utils/mergeCount.js +++ b/src/app/(sok)/_components/utils/mergeCount.ts @@ -1,3 +1,5 @@ +import { FilterAggregation, OccupationFilterAggregation } from "@/app/(sok)/_types/FilterAggregations"; + /** * Når det er utført et søk, oppdateres antall treff per fasett, f.eks "Oslo (25)" * @@ -6,25 +8,34 @@ * @param nestedKey (Optional): Navn på evt. underkategori som også skal oppdateres, f. eks municipal * @returns Returnerer en ny liste, hvor antall treff per fasett er oppdatert */ -export default function mergeCount(initialValues, newValues, nestedKey) { - if (nestedKey === undefined) { - return initialValues.map((item) => { - const found = newValues.find((e) => e.key === item.key); - return { - ...item, - count: found ? found.count : 0, - }; - }); - } +export default function mergeCount( + initialValues: FilterAggregation[], + newValues: FilterAggregation[], +): FilterAggregation[] { + return initialValues.map((item) => { + const found = newValues.find((e) => e.key === item.key); + return { + ...item, + count: found ? found.count : 0, + }; + }); +} + +export function mergeCountOccupations( + initialValues: OccupationFilterAggregation[], + newValues: OccupationFilterAggregation[], +): OccupationFilterAggregation[] { return initialValues.map((firstLevel) => { const foundFirstLevel = newValues.find((c) => c.key === firstLevel.key); return { ...firstLevel, count: foundFirstLevel ? foundFirstLevel.count : 0, - [nestedKey]: firstLevel[nestedKey].map((secondLevel) => { + occupationSecondLevels: firstLevel.occupationSecondLevels.map((secondLevel) => { let newSecondLevelCount = 0; if (foundFirstLevel) { - const foundSecondLevel = foundFirstLevel[nestedKey].find((m) => m.key === secondLevel.key); + const foundSecondLevel = foundFirstLevel.occupationSecondLevels.find( + (m) => m.key === secondLevel.key, + ); newSecondLevelCount = foundSecondLevel ? foundSecondLevel.count : 0; } return { diff --git a/src/app/(sok)/_types/FilterAggregations.ts b/src/app/(sok)/_types/FilterAggregations.ts index 6d119a31b..82a77ce7d 100644 --- a/src/app/(sok)/_types/FilterAggregations.ts +++ b/src/app/(sok)/_types/FilterAggregations.ts @@ -3,8 +3,12 @@ export interface FilterAggregation { count: number; } +interface OccupationSecondLevelFilterAggregation extends FilterAggregation { + label: string; +} + export interface OccupationFilterAggregation extends FilterAggregation { - occupationSecondLevels: FilterAggregation[]; + occupationSecondLevels: OccupationSecondLevelFilterAggregation[]; } export default interface FilterAggregations { @@ -19,4 +23,5 @@ export default interface FilterAggregations { needDriversLicense: FilterAggregation[]; experience: FilterAggregation[]; publishedTotalCount: number; + totalInternational: number; }