From d6e0d83c5d36866fcc7facf7ab056e99517e719a Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Fri, 12 Jul 2024 17:31:38 +0200 Subject: [PATCH] fix(education): query annuaire education in the browser --- .../annuaire_education_component.rb | 3 +- app/javascript/components/ComboBox.tsx | 5 ++-- app/javascript/components/react-aria/hooks.ts | 30 ++++++++++++++++++- app/javascript/components/react-aria/props.ts | 3 +- 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/app/components/editable_champ/annuaire_education_component.rb b/app/components/editable_champ/annuaire_education_component.rb index fc7fd6bd5..10044eb61 100644 --- a/app/components/editable_champ/annuaire_education_component.rb +++ b/app/components/editable_champ/annuaire_education_component.rb @@ -9,7 +9,8 @@ class EditableChamp::AnnuaireEducationComponent < EditableChamp::EditableChampBa name: @form.field_name(:external_id), selected_key: @champ.external_id, items: @champ.selected_items, - loader: data_sources_data_source_education_path, + loader: 'https://data.education.gouv.fr/api/records/1.0/search?dataset=fr-en-annuaire-education&rows=5', + coerce: 'AnnuaireEducation', debounce: 500, minimum_input_length: 5) end diff --git a/app/javascript/components/ComboBox.tsx b/app/javascript/components/ComboBox.tsx index b51c2623a..5b2475fdd 100644 --- a/app/javascript/components/ComboBox.tsx +++ b/app/javascript/components/ComboBox.tsx @@ -232,6 +232,7 @@ export function RemoteComboBox({ minimumInputLength, limit, debounce, + coerce, formValue, name, form, @@ -245,9 +246,9 @@ export function RemoteComboBox({ const load = useMemo( () => typeof loader == 'string' - ? createLoader(loader, { minimumInputLength, limit }) + ? createLoader(loader, { minimumInputLength, limit, coerce }) : loader, - [loader, minimumInputLength, limit] + [loader, minimumInputLength, limit, coerce] ); const { selectedItem, onReset, ...comboBoxProps } = useRemoteList({ allowsCustomValue, diff --git a/app/javascript/components/react-aria/hooks.ts b/app/javascript/components/react-aria/hooks.ts index abd5a820b..ede4825b6 100644 --- a/app/javascript/components/react-aria/hooks.ts +++ b/app/javascript/components/react-aria/hooks.ts @@ -401,12 +401,39 @@ function getKey(item: Item) { return item.value; } +const AnnuaireEducationPayload = s.type({ + records: s.array( + s.type({ + fields: s.type({ + identifiant_de_l_etablissement: s.string(), + nom_etablissement: s.string(), + nom_commune: s.string() + }) + }) + ) +}); + +const Coerce = { + Default: s.array(Item), + AnnuaireEducation: s.coerce( + s.array(Item), + AnnuaireEducationPayload, + ({ records }) => + records.map((record) => ({ + label: `${record.fields.nom_etablissement}, ${record.fields.nom_commune} (${record.fields.identifiant_de_l_etablissement})`, + value: record.fields.identifiant_de_l_etablissement, + data: record + })) + ) +}; + export const createLoader: ( source: string, options?: { minimumInputLength?: number; limit?: number; param?: string; + coerce?: keyof typeof Coerce; } ) => Loader = (source, options) => @@ -427,7 +454,8 @@ export const createLoader: ( }); if (response.ok) { const json = await response.json(); - const [err, items] = s.validate(json, s.array(Item), { coerce: true }); + const struct = Coerce[options?.coerce ?? 'Default']; + const [err, items] = s.validate(json, struct, { coerce: true }); if (!err) { if (items.length > limit) { const filteredItems = matchSorter(items, filterText, { diff --git a/app/javascript/components/react-aria/props.ts b/app/javascript/components/react-aria/props.ts index 9000565a1..10d62859a 100644 --- a/app/javascript/components/react-aria/props.ts +++ b/app/javascript/components/react-aria/props.ts @@ -68,7 +68,8 @@ export const RemoteComboBoxProps = s.assign( minimumInputLength: s.number(), limit: s.number(), allowsCustomValue: s.boolean(), - debounce: s.number() + debounce: s.number(), + coerce: s.enums(['Default', 'AnnuaireEducation']) }) ) );