diff --git a/app/javascript/components/ComboCommunesSearch.tsx b/app/javascript/components/ComboCommunesSearch.tsx deleted file mode 100644 index e2ac22731..000000000 --- a/app/javascript/components/ComboCommunesSearch.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import React from 'react'; -import { QueryClientProvider } from 'react-query'; -import { matchSorter } from 'match-sorter'; - -import ComboSearch, { ComboSearchProps } from './ComboSearch'; -import { queryClient } from './shared/queryClient'; -import { ComboDepartementsSearch } from './ComboDepartementsSearch'; -import { useHiddenField, groupId } from './shared/hooks'; - -type CommuneResult = { code: string; nom: string; codesPostaux: string[] }; - -// Avoid hiding similar matches for precise queries (like "Sainte Marie") -function searchResultsLimit(term: string) { - return term.length > 5 ? 10 : 5; -} - -function expandResultsWithMultiplePostalCodes(term: string, result: unknown) { - const results = result as CommuneResult[]; - // A single result may have several associated postal codes. - // To make the search results more precise, we want to generate - // an actual result for each postal code. - const expandedResults = results.flatMap((result) => - result.codesPostaux.map((codePostal) => ({ - ...result, - codesPostaux: [codePostal] - })) - ); - - // Some very large cities (like Paris) have A LOT of associated postal codes. - // As we generated one result per postal code, we now have a lot of results - // for the same city. If the number of results is above the threshold, we use - // local search to narrow the results. - const limit = searchResultsLimit(term); - if (expandedResults.length > limit) { - return matchSorter(expandedResults, term, { - keys: [(item) => `${item.nom} (${item.codesPostaux[0]})`, 'code'], - sorter: (rankedItems) => rankedItems - }).slice(0, limit + 1); - } - - return expandedResults; -} - -const placeholderDepartements = [ - ['63 – Puy-de-Dôme', 'Clermont-Ferrand'], - ['77 – Seine-et-Marne', 'Melun'], - ['22 – Côtes d’Armor', 'Saint-Brieuc'], - ['47 – Lot-et-Garonne', 'Agen'] -] as const; -const [placeholderDepartement, placeholderCommune] = - placeholderDepartements[ - Math.floor(Math.random() * (placeholderDepartements.length - 1)) - ]; - -export default function ComboCommunesSearch({ - id, - classNameDepartement, - ...props -}: ComboSearchProps & { - id: string; - classNameDepartement?: string; -}) { - const group = groupId(id); - const [departementValue, setDepartementValue] = useHiddenField( - group, - 'departement' - ); - const [codeDepartement, setCodeDepartement] = useHiddenField( - group, - 'code_departement' - ); - const departementDescribedBy = `${id}_departement_notice`; - const communeDescribedBy = `${id}_commune_notice`; - - return ( - -
-
-

- Choisissez le département dans lequel se situe la commune. Vous - pouvez entrer le nom ou le code. -

-
- { - setDepartementValue(result?.nom ?? ''); - setCodeDepartement(result?.code ?? ''); - }} - /> -
- {codeDepartement ? ( -
-
-

- Choisissez la commune. Vous pouvez entrer le nom ou le code - postal. -

-
- [ - code, - `${nom} (${codesPostaux[0]})` - ]} - transformResults={expandResultsWithMultiplePostalCodes} - /> -
- ) : null} -
- ); -} diff --git a/app/javascript/components/ComboDepartementsSearch.tsx b/app/javascript/components/ComboDepartementsSearch.tsx deleted file mode 100644 index a614f1e44..000000000 --- a/app/javascript/components/ComboDepartementsSearch.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import { matchSorter } from 'match-sorter'; - -import ComboSearch, { ComboSearchProps } from './ComboSearch'; - -type DepartementResult = { code: string; nom: string }; - -const extraTerms = [{ code: '99', nom: 'Etranger' }]; - -function expandResultsWithForeignDepartement(term: string, result: unknown) { - const results = result as DepartementResult[]; - return [ - ...results, - ...matchSorter(extraTerms, term, { - keys: ['nom', 'code'] - }) - ]; -} - -type ComboDepartementsSearchProps = Omit< - ComboSearchProps & { - addForeignDepartement: boolean; - }, - 'transformResult' | 'transformResults' ->; - -export function ComboDepartementsSearch({ - addForeignDepartement = true, - ...props -}: ComboDepartementsSearchProps) { - return ( - [code, `${code} - ${nom}`]} - transformResults={ - addForeignDepartement ? expandResultsWithForeignDepartement : undefined - } - /> - ); -} diff --git a/app/javascript/components/shared/queryClient.ts b/app/javascript/components/shared/queryClient.ts index af7a90116..700dc595d 100644 --- a/app/javascript/components/shared/queryClient.ts +++ b/app/javascript/components/shared/queryClient.ts @@ -1,22 +1,11 @@ import { QueryClient, QueryFunction } from 'react-query'; -import { httpRequest, isNumeric, getConfig } from '@utils'; -import { matchSorter } from 'match-sorter'; +import { httpRequest, getConfig } from '@utils'; const API_EDUCATION_QUERY_LIMIT = 5; -const API_GEO_QUERY_LIMIT = 5; const API_ADRESSE_QUERY_LIMIT = 5; -// When searching for short strings like "mer", le exact match shows up quite far in -// the ordering (~50). -// -// That's why we deliberately fetch a lot of results, and then let the local matching -// (match-sorter) do the work. -// -// NB: 60 is arbitrary, we may add more if needed. -const API_GEO_COMMUNES_QUERY_LIMIT = 60; - const { - autocomplete: { api_geo_url, api_adresse_url, api_education_url } + autocomplete: { api_adresse_url, api_education_url } } = getConfig(); type QueryKey = readonly [ @@ -25,10 +14,10 @@ type QueryKey = readonly [ extra: string | undefined ]; -function buildURL(scope: string, term: string, extra?: string) { +function buildURL(scope: string, term: string) { term = term.replace(/\(|\)/g, ''); const params = new URLSearchParams(); - let path = `${api_geo_url}/${scope}`; + let path = ''; if (scope == 'adresse') { path = `${api_adresse_url}/search`; @@ -39,40 +28,15 @@ function buildURL(scope: string, term: string, extra?: string) { params.set('q', term); params.set('rows', `${API_EDUCATION_QUERY_LIMIT}`); params.set('dataset', 'fr-en-annuaire-education'); - } else if (scope == 'communes') { - if (extra) { - params.set('codeDepartement', extra); - } - if (isNumeric(term)) { - params.set('codePostal', term); - } else { - params.set('nom', term); - params.set('boost', 'population'); - } - params.set('limit', `${API_GEO_COMMUNES_QUERY_LIMIT}`); - } else { - if (isNumeric(term)) { - params.set('code', term.padStart(2, '0')); - } else { - params.set('nom', term); - } - if (scope == 'departements') { - params.set('zone', 'metro,drom,com'); - } - params.set('limit', `${API_GEO_QUERY_LIMIT}`); } return `${path}?${params}`; } const defaultQueryFn: QueryFunction = async ({ - queryKey: [scope, term, extra], + queryKey: [scope, term], signal }) => { - if (scope == 'pays') { - return matchSorter(await getPays(signal), term, { keys: ['label'] }); - } - // BAN will error with queries less then 3 chars long if (scope == 'adresse' && term.length < 3) { return { @@ -83,23 +47,10 @@ const defaultQueryFn: QueryFunction = async ({ }; } - const url = buildURL(scope, term, extra); + const url = buildURL(scope, term); return httpRequest(url, { csrf: false, signal }).json(); }; -let paysCache: { label: string }[]; -async function getPays(signal?: AbortSignal): Promise<{ label: string }[]> { - if (!paysCache) { - const data = await httpRequest('/api/pays', { signal }).json< - typeof paysCache - >(); - if (data) { - paysCache = data; - } - } - return paysCache; -} - export const queryClient = new QueryClient({ defaultOptions: { queries: {