From 312bd6445a063c243f610c04342fa5fcc3d66dcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Bret=C3=A9cher?= Date: Wed, 29 Jan 2025 18:04:29 +0100 Subject: [PATCH 1/9] up --- admin/src/scenes/volontaires/list.jsx | 10 ++++---- admin/src/scenes/volontaires/utils/index.js | 26 ++++++++++----------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/admin/src/scenes/volontaires/list.jsx b/admin/src/scenes/volontaires/list.jsx index 9a66b7284b..7fa91c6c96 100644 --- a/admin/src/scenes/volontaires/list.jsx +++ b/admin/src/scenes/volontaires/list.jsx @@ -58,10 +58,10 @@ export default function VolontaireList() { filters: {}, exportFields: ["busId"], }); - const { data: classes } = await api.post(`/elasticsearch/cle/classe/export`, { - filters: {}, - exportFields: ["name", "uniqueKeyAndId"], - }); + // const { data: classes } = await api.post(`/elasticsearch/cle/classe/export`, { + // filters: {}, + // exportFields: ["name", "uniqueKeyAndId"], + // }); const { data: etablissements } = await api.post(`/elasticsearch/cle/etablissement/export`, { filters: {}, exportFields: ["name", "uai"], @@ -76,7 +76,7 @@ export default function VolontaireList() { })(); }, []); - if (!sessionsPhase1 || !bus || !classes || !etablissements) return ; + if (!sessionsPhase1 || !bus || !etablissements) return ; return ( <> diff --git a/admin/src/scenes/volontaires/utils/index.js b/admin/src/scenes/volontaires/utils/index.js index c179ff5d4d..53ce1b64cd 100644 --- a/admin/src/scenes/volontaires/utils/index.js +++ b/admin/src/scenes/volontaires/utils/index.js @@ -25,7 +25,7 @@ import { orderCohort } from "../../../components/filters-system-v2/components/fi import { formatPhoneE164 } from "../../../utils/formatPhoneE164"; import { youngCheckinField } from "@/utils"; -export const getFilterArray = (user, bus, session, classes, etablissements) => { +export const getFilterArray = (user, bus, session, etablissements) => { return [ { title: "Cohorte", name: "cohort", parentGroup: "Général", missingLabel: "Non renseigné", sort: (e) => orderCohort(e) }, { title: "Cohorte d'origine", name: "originalCohort", parentGroup: "Général", missingLabel: "Non renseigné", sort: orderCohort }, @@ -175,18 +175,18 @@ export const getFilterArray = (user, bus, session, classes, etablissements) => { missingLabel: "Non renseigné", translate: translatePhase1, }, - { - title: "Classe Engagée ID", - name: "classeId", - parentGroup: "Phase 1", - missingLabel: "Non renseigné", - translate: (item) => { - if (item === "N/A" || !classes.length) return item; - const res = classes.find((option) => option._id.toString() === item); - if (!res) return "N/A - Supprimé"; - return res?.uniqueKeyAndId; - }, - }, + // { + // title: "Classe Engagée ID", + // name: "classeId", + // parentGroup: "Phase 1", + // missingLabel: "Non renseigné", + // translate: (item) => { + // if (item === "N/A" || !classes.length) return item; + // const res = classes.find((option) => option._id.toString() === item); + // if (!res) return "N/A - Supprimé"; + // return res?.uniqueKeyAndId; + // }, + // }, { title: "Etablissement CLE", name: "etablissementId", From 5050e7bd57018d043b68838dcb08184316dc9183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Bret=C3=A9cher?= Date: Wed, 29 Jan 2025 18:21:14 +0100 Subject: [PATCH 2/9] fix --- admin/src/scenes/volontaires/list.jsx | 10 +++---- admin/src/scenes/volontaires/utils/index.js | 26 +++++++++---------- .../controllers/elasticsearch/cle/classe.js | 8 +++--- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/admin/src/scenes/volontaires/list.jsx b/admin/src/scenes/volontaires/list.jsx index 7fa91c6c96..9a66b7284b 100644 --- a/admin/src/scenes/volontaires/list.jsx +++ b/admin/src/scenes/volontaires/list.jsx @@ -58,10 +58,10 @@ export default function VolontaireList() { filters: {}, exportFields: ["busId"], }); - // const { data: classes } = await api.post(`/elasticsearch/cle/classe/export`, { - // filters: {}, - // exportFields: ["name", "uniqueKeyAndId"], - // }); + const { data: classes } = await api.post(`/elasticsearch/cle/classe/export`, { + filters: {}, + exportFields: ["name", "uniqueKeyAndId"], + }); const { data: etablissements } = await api.post(`/elasticsearch/cle/etablissement/export`, { filters: {}, exportFields: ["name", "uai"], @@ -76,7 +76,7 @@ export default function VolontaireList() { })(); }, []); - if (!sessionsPhase1 || !bus || !etablissements) return ; + if (!sessionsPhase1 || !bus || !classes || !etablissements) return ; return ( <> diff --git a/admin/src/scenes/volontaires/utils/index.js b/admin/src/scenes/volontaires/utils/index.js index 53ce1b64cd..c179ff5d4d 100644 --- a/admin/src/scenes/volontaires/utils/index.js +++ b/admin/src/scenes/volontaires/utils/index.js @@ -25,7 +25,7 @@ import { orderCohort } from "../../../components/filters-system-v2/components/fi import { formatPhoneE164 } from "../../../utils/formatPhoneE164"; import { youngCheckinField } from "@/utils"; -export const getFilterArray = (user, bus, session, etablissements) => { +export const getFilterArray = (user, bus, session, classes, etablissements) => { return [ { title: "Cohorte", name: "cohort", parentGroup: "Général", missingLabel: "Non renseigné", sort: (e) => orderCohort(e) }, { title: "Cohorte d'origine", name: "originalCohort", parentGroup: "Général", missingLabel: "Non renseigné", sort: orderCohort }, @@ -175,18 +175,18 @@ export const getFilterArray = (user, bus, session, etablissements) => { missingLabel: "Non renseigné", translate: translatePhase1, }, - // { - // title: "Classe Engagée ID", - // name: "classeId", - // parentGroup: "Phase 1", - // missingLabel: "Non renseigné", - // translate: (item) => { - // if (item === "N/A" || !classes.length) return item; - // const res = classes.find((option) => option._id.toString() === item); - // if (!res) return "N/A - Supprimé"; - // return res?.uniqueKeyAndId; - // }, - // }, + { + title: "Classe Engagée ID", + name: "classeId", + parentGroup: "Phase 1", + missingLabel: "Non renseigné", + translate: (item) => { + if (item === "N/A" || !classes.length) return item; + const res = classes.find((option) => option._id.toString() === item); + if (!res) return "N/A - Supprimé"; + return res?.uniqueKeyAndId; + }, + }, { title: "Etablissement CLE", name: "etablissementId", diff --git a/api/src/controllers/elasticsearch/cle/classe.js b/api/src/controllers/elasticsearch/cle/classe.js index 6acac1722c..5daf3adfa1 100644 --- a/api/src/controllers/elasticsearch/cle/classe.js +++ b/api/src/controllers/elasticsearch/cle/classe.js @@ -65,9 +65,11 @@ router.post("/:action(search|export)", passport.authenticate(["referent"], { ses if (req.params.action === "export") { let response = await allRecords("classe", hitsRequestBody.query, esClient, exportFields); - response = await populateWithEtablissementInfo(response); - response = await populateWithYoungsInfo(response); - response = await populateWithAllReferentsInfo(response); + if (req.query?.type === "export-des-classes") { + response = await populateWithEtablissementInfo(response); + response = await populateWithYoungsInfo(response); + response = await populateWithAllReferentsInfo(response); + } if (req.query?.type === "schema-de-repartition") { if (![ROLES.ADMIN, ROLES.REFERENT_REGION, ROLES.TRANSPORTER].includes(user.role)) return res.status(403).send({ ok: false, code: ERRORS.OPERATION_UNAUTHORIZED }); From 5048b49cfa3ccf7cd86548f58004b5c295f87b74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Bret=C3=A9cher?= Date: Thu, 30 Jan 2025 10:56:34 +0100 Subject: [PATCH 3/9] add filter label endpoint --- admin/src/scenes/volontaires/list.jsx | 44 +++---------------- .../src/scenes/volontaires/useFilterLabels.ts | 15 +++++++ api/src/controllers/filter-label.ts | 33 ++++++++++++++ api/src/routes.ts | 1 + 4 files changed, 56 insertions(+), 37 deletions(-) create mode 100644 admin/src/scenes/volontaires/useFilterLabels.ts create mode 100644 api/src/controllers/filter-label.ts diff --git a/admin/src/scenes/volontaires/list.jsx b/admin/src/scenes/volontaires/list.jsx index 9a66b7284b..352fb8fe03 100644 --- a/admin/src/scenes/volontaires/list.jsx +++ b/admin/src/scenes/volontaires/list.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useState } from "react"; import { useSelector } from "react-redux"; import { Link, useHistory } from "react-router-dom"; @@ -13,7 +13,7 @@ import Breadcrumbs from "../../components/Breadcrumbs"; import Loader from "../../components/Loader"; import { ExportComponent, Filters, ModalExport, ResultTable, Save, SelectedFilters, SortOption } from "../../components/filters-system-v2"; import { appURL } from "../../config"; -import api from "../../services/api"; +import useFilterLabels from "./useFilterLabels"; import plausibleEvent from "../../services/plausible"; import { ROLES, YOUNG_STATUS, YOUNG_STATUS_COLORS, getAge, translate, translatePhase1, translatePhase2 } from "../../utils"; import { Title } from "../pointDeRassemblement/components/common"; @@ -26,13 +26,11 @@ import { getCohortGroups } from "@/services/cohort.service"; export default function VolontaireList() { const user = useSelector((state) => state.Auth.user); const history = useHistory(); + const { data: filterLabels, isPending, isError } = useFilterLabels("volontaires"); + const { sessions, bus, classes, etablissements } = filterLabels || {}; if (user?.role === ROLES.ADMINISTRATEUR_CLE) return history.push("/mes-eleves"); const [volontaire, setVolontaire] = useState(null); - const [sessionsPhase1, setSessionsPhase1] = useState(null); - const [bus, setBus] = useState(null); - const [classes, setClasses] = useState(null); - const [etablissements, setEtablissements] = useState(null); const [isExportOpen, setIsExportOpen] = useState(false); const [size, setSize] = useState(10); @@ -45,38 +43,10 @@ export default function VolontaireList() { sort: { label: "Nom (A > Z)", field: "lastName.keyword", order: "asc" }, }); - const filterArray = getFilterArray(user, bus, sessionsPhase1, classes, etablissements); + if (isPending) return ; + if (isError) return
Erreur lors de la récupération des filtres
; - useEffect(() => { - (async () => { - try { - const { data: sessions } = await api.post(`/elasticsearch/sessionphase1/export`, { - filters: {}, - exportFields: ["codeCentre", "cohesionCenterId"], - }); - const { data: bus } = await api.post(`/elasticsearch/lignebus/export`, { - filters: {}, - exportFields: ["busId"], - }); - const { data: classes } = await api.post(`/elasticsearch/cle/classe/export`, { - filters: {}, - exportFields: ["name", "uniqueKeyAndId"], - }); - const { data: etablissements } = await api.post(`/elasticsearch/cle/etablissement/export`, { - filters: {}, - exportFields: ["name", "uai"], - }); - setSessionsPhase1(sessions); - setBus(bus); - setClasses(classes); - setEtablissements(etablissements); - } catch (e) { - toastr.error("Oups, une erreur est survenue lors de la récupération des données"); - } - })(); - }, []); - - if (!sessionsPhase1 || !bus || !classes || !etablissements) return ; + const filterArray = getFilterArray(user, bus, sessions, classes, etablissements); return ( <> diff --git a/admin/src/scenes/volontaires/useFilterLabels.ts b/admin/src/scenes/volontaires/useFilterLabels.ts new file mode 100644 index 0000000000..9eb2d0d46b --- /dev/null +++ b/admin/src/scenes/volontaires/useFilterLabels.ts @@ -0,0 +1,15 @@ +import API from "@/services/api"; +import { useQuery } from "@tanstack/react-query"; + +async function getFilterLabels(listType: string): Promise { + const { ok, data } = await API.get(`/filter-label/${listType}`); + if (!ok) throw new Error("Impossible de récupérer les labels de filtres."); + return data; +} + +export default function useFilterLabels(listType: string) { + return useQuery({ + queryKey: ["filter-label", listType], + queryFn: () => getFilterLabels(listType), + }); +} diff --git a/api/src/controllers/filter-label.ts b/api/src/controllers/filter-label.ts new file mode 100644 index 0000000000..66c0c92f64 --- /dev/null +++ b/api/src/controllers/filter-label.ts @@ -0,0 +1,33 @@ +import Joi from "joi"; +import { ERRORS } from "snu-lib"; +import passport from "passport"; +import express, { Response } from "express"; +import { ClasseModel, EtablissementModel, LigneBusModel, SessionPhase1Model } from "../models"; +import { capture } from "../sentry"; +import { UserRequest } from "./request"; + +const router = express.Router(); + +const listTypes = { INSCRIPTION: "inscription", VOLONTAIRES: "volontaires" }; + +const validator = Joi.string().valid(listTypes.INSCRIPTION, listTypes.VOLONTAIRES).required(); + +router.get("/:list", passport.authenticate("referent", { session: false, failWithError: true }), async (req: UserRequest, res: Response) => { + const { value, error } = validator.validate(req.params.list); + if (error) { + capture(error); + return res.status(400).send({ ok: false, code: ERRORS.INVALID_PARAMS }); + } + + if (value === listTypes.VOLONTAIRES) { + const sessions = await SessionPhase1Model.find({}, { codeCentre: 1 }); + const bus = await LigneBusModel.find({}, { busId: 1 }); + const classes = await ClasseModel.find({}, { uniqueKeyAndId: 1 }); + // console.log("🚀 ~ router.get ~ classes:", classes); + const etablissements = await EtablissementModel.find({}, { name: 1 }); + const data = { sessions, bus, classes, etablissements }; + return res.status(200).send({ ok: true, data }); + } +}); + +module.exports = router; diff --git a/api/src/routes.ts b/api/src/routes.ts index db9a2cbc76..11abe76fa0 100644 --- a/api/src/routes.ts +++ b/api/src/routes.ts @@ -40,6 +40,7 @@ export function injectRoutes(app) { app.use("/SNUpport", require("./controllers/SNUpport")); app.use("/cle", require("./cle").default); app.use("/preinscription", require("./preinscription/preinscriptionController")); + app.use("/filter-label", require("./controllers/filter-label")); //services app.use("/jeveuxaider", require("./services/jeveuxaider")); From 2ecd17ae613922a9b0af3e04b7c5100bf0106bc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Bret=C3=A9cher?= Date: Thu, 30 Jan 2025 11:53:21 +0100 Subject: [PATCH 4/9] up --- .../src/scenes/volontaires/useFilterLabels.ts | 14 ++++++--- admin/src/scenes/volontaires/utils/index.js | 16 ++++------ .../filterLabelController.ts} | 15 ++++------ api/src/filterLabel/filterLabelRepository.ts | 29 +++++++++++++++++++ api/src/filterLabel/filterLabelService.ts | 11 +++++++ api/src/routes.ts | 2 +- packages/lib/src/dto/filterLabelDto.ts | 1 + packages/lib/src/dto/index.ts | 1 + packages/lib/src/routes/filterLabel/index.ts | 13 +++++++++ packages/lib/src/routes/index.ts | 1 + 10 files changed, 78 insertions(+), 25 deletions(-) rename api/src/{controllers/filter-label.ts => filterLabel/filterLabelController.ts} (54%) create mode 100644 api/src/filterLabel/filterLabelRepository.ts create mode 100644 api/src/filterLabel/filterLabelService.ts create mode 100644 packages/lib/src/dto/filterLabelDto.ts create mode 100644 packages/lib/src/routes/filterLabel/index.ts diff --git a/admin/src/scenes/volontaires/useFilterLabels.ts b/admin/src/scenes/volontaires/useFilterLabels.ts index 9eb2d0d46b..f84b4a4f8e 100644 --- a/admin/src/scenes/volontaires/useFilterLabels.ts +++ b/admin/src/scenes/volontaires/useFilterLabels.ts @@ -1,9 +1,15 @@ -import API from "@/services/api"; +import { buildRequest } from "@/utils/buildRequest"; import { useQuery } from "@tanstack/react-query"; +import { FilterLabelDto, FilterLabelRoutes } from "snu-lib"; -async function getFilterLabels(listType: string): Promise { - const { ok, data } = await API.get(`/filter-label/${listType}`); - if (!ok) throw new Error("Impossible de récupérer les labels de filtres."); +async function getFilterLabels(listType: string): Promise { + const { ok, code, data } = await buildRequest({ + path: "/filter-label/{listType}", + method: "GET", + params: { listType }, + })(); + if (!ok) throw new Error(code); + if (!data) throw new Error("No data"); return data; } diff --git a/admin/src/scenes/volontaires/utils/index.js b/admin/src/scenes/volontaires/utils/index.js index c179ff5d4d..212415c8bd 100644 --- a/admin/src/scenes/volontaires/utils/index.js +++ b/admin/src/scenes/volontaires/utils/index.js @@ -26,6 +26,7 @@ import { formatPhoneE164 } from "../../../utils/formatPhoneE164"; import { youngCheckinField } from "@/utils"; export const getFilterArray = (user, bus, session, classes, etablissements) => { + console.log("🚀 ~ getFilterArray ~ classes:", classes); return [ { title: "Cohorte", name: "cohort", parentGroup: "Général", missingLabel: "Non renseigné", sort: (e) => orderCohort(e) }, { title: "Cohorte d'origine", name: "originalCohort", parentGroup: "Général", missingLabel: "Non renseigné", sort: orderCohort }, @@ -181,10 +182,9 @@ export const getFilterArray = (user, bus, session, classes, etablissements) => { parentGroup: "Phase 1", missingLabel: "Non renseigné", translate: (item) => { + console.log("🚀 ~ getFilterArray ~ item:", typeof item); if (item === "N/A" || !classes.length) return item; - const res = classes.find((option) => option._id.toString() === item); - if (!res) return "N/A - Supprimé"; - return res?.uniqueKeyAndId; + return classes[item] || "N/A - Supprimé"; }, }, { @@ -194,9 +194,7 @@ export const getFilterArray = (user, bus, session, classes, etablissements) => { missingLabel: "Non renseigné", translate: (item) => { if (item === "N/A" || !etablissements.length) return item; - const res = etablissements.find((option) => option._id.toString() === item); - if (!res) return "N/A - Supprimé"; - return res?.name; + return etablissements[item] || "N/A - Supprimé"; }, }, { @@ -206,9 +204,7 @@ export const getFilterArray = (user, bus, session, classes, etablissements) => { missingLabel: "Non renseigné", translate: (item) => { if (item === "N/A" || !session.length) return item; - const res = session.find((option) => option._id.toString() === item); - if (!res) return "N/A - Supprimé"; - return res?.codeCentre; + return session[item] || "N/A - Supprimé"; }, }, { @@ -274,7 +270,7 @@ export const getFilterArray = (user, bus, session, classes, etablissements) => { missingLabel: "Non renseigné", translate: (item) => { if (item === "N/A" || !bus?.length) return item; - return bus.find((option) => option._id.toString() === item)?.busId || item; + return bus[item] || item; }, }, { diff --git a/api/src/controllers/filter-label.ts b/api/src/filterLabel/filterLabelController.ts similarity index 54% rename from api/src/controllers/filter-label.ts rename to api/src/filterLabel/filterLabelController.ts index 66c0c92f64..613c8dc45b 100644 --- a/api/src/controllers/filter-label.ts +++ b/api/src/filterLabel/filterLabelController.ts @@ -2,14 +2,12 @@ import Joi from "joi"; import { ERRORS } from "snu-lib"; import passport from "passport"; import express, { Response } from "express"; -import { ClasseModel, EtablissementModel, LigneBusModel, SessionPhase1Model } from "../models"; import { capture } from "../sentry"; -import { UserRequest } from "./request"; +import { UserRequest } from "../controllers/request"; +import { getLabelVolontaires, listTypes } from "./filterLabelService"; const router = express.Router(); -const listTypes = { INSCRIPTION: "inscription", VOLONTAIRES: "volontaires" }; - const validator = Joi.string().valid(listTypes.INSCRIPTION, listTypes.VOLONTAIRES).required(); router.get("/:list", passport.authenticate("referent", { session: false, failWithError: true }), async (req: UserRequest, res: Response) => { @@ -20,14 +18,11 @@ router.get("/:list", passport.authenticate("referent", { session: false, failWit } if (value === listTypes.VOLONTAIRES) { - const sessions = await SessionPhase1Model.find({}, { codeCentre: 1 }); - const bus = await LigneBusModel.find({}, { busId: 1 }); - const classes = await ClasseModel.find({}, { uniqueKeyAndId: 1 }); - // console.log("🚀 ~ router.get ~ classes:", classes); - const etablissements = await EtablissementModel.find({}, { name: 1 }); - const data = { sessions, bus, classes, etablissements }; + const data = await getLabelVolontaires(); return res.status(200).send({ ok: true, data }); } + + // TODO: getLabelInscriptions }); module.exports = router; diff --git a/api/src/filterLabel/filterLabelRepository.ts b/api/src/filterLabel/filterLabelRepository.ts new file mode 100644 index 0000000000..d35638a581 --- /dev/null +++ b/api/src/filterLabel/filterLabelRepository.ts @@ -0,0 +1,29 @@ +import { ClasseModel, EtablissementModel, LigneBusModel, SessionPhase1Model } from "../models"; + +function formatLabel(data, key: string) { + return data.reduce((acc, cur) => { + acc[cur._id] = cur[key]; + return acc; + }, {}); +} + +export async function getBus() { + const data = await LigneBusModel.find({}, { busId: 1 }); + return formatLabel(data, "busId"); +} + +export async function getClasses() { + // Pourquoi ça renvoit les patches ça ? + const data = await ClasseModel.find({}, { uniqueKeyAndId: 1 }); + return formatLabel(data, "uniqueKeyAndId"); +} + +export async function getEtablissements() { + const data = await EtablissementModel.find({}, { name: 1 }); + return formatLabel(data, "name"); +} + +export async function getSessions() { + const data = await SessionPhase1Model.find({}, { codeCentre: 1 }); + return formatLabel(data, "codeCentre"); +} diff --git a/api/src/filterLabel/filterLabelService.ts b/api/src/filterLabel/filterLabelService.ts new file mode 100644 index 0000000000..c0a71fbd1c --- /dev/null +++ b/api/src/filterLabel/filterLabelService.ts @@ -0,0 +1,11 @@ +import { getBus, getClasses, getEtablissements, getSessions } from "./filterLabelRepository"; + +export const listTypes = { INSCRIPTION: "inscription", VOLONTAIRES: "volontaires" }; + +export async function getLabelVolontaires() { + const sessions = await getSessions(); + const bus = await getBus(); + const classes = await getClasses(); + const etablissements = await getEtablissements(); + return { sessions, bus, classes, etablissements }; +} diff --git a/api/src/routes.ts b/api/src/routes.ts index 11abe76fa0..3def966146 100644 --- a/api/src/routes.ts +++ b/api/src/routes.ts @@ -40,7 +40,7 @@ export function injectRoutes(app) { app.use("/SNUpport", require("./controllers/SNUpport")); app.use("/cle", require("./cle").default); app.use("/preinscription", require("./preinscription/preinscriptionController")); - app.use("/filter-label", require("./controllers/filter-label")); + app.use("/filter-label", require("./filterLabel/filterLabelController")); //services app.use("/jeveuxaider", require("./services/jeveuxaider")); diff --git a/packages/lib/src/dto/filterLabelDto.ts b/packages/lib/src/dto/filterLabelDto.ts new file mode 100644 index 0000000000..b3538c824a --- /dev/null +++ b/packages/lib/src/dto/filterLabelDto.ts @@ -0,0 +1 @@ +export type FilterLabelDto = Record; diff --git a/packages/lib/src/dto/index.ts b/packages/lib/src/dto/index.ts index e0bda87314..c7cdf00651 100644 --- a/packages/lib/src/dto/index.ts +++ b/packages/lib/src/dto/index.ts @@ -10,3 +10,4 @@ export * from "./contactDto"; export * from "./taskDto"; export * from "./phase1"; export * from "./referentiel/ReferentielTaskDto"; +export * from "./filterLabelDto"; diff --git a/packages/lib/src/routes/filterLabel/index.ts b/packages/lib/src/routes/filterLabel/index.ts new file mode 100644 index 0000000000..ce5f3da442 --- /dev/null +++ b/packages/lib/src/routes/filterLabel/index.ts @@ -0,0 +1,13 @@ +import { FilterLabelDto } from "src/dto/filterLabelDto"; +import { BasicRoute, RouteResponseBody } from ".."; + +interface GetFilterLabelRoute extends BasicRoute { + method: "GET"; + path: "/filter-label/{listType}"; + params: { listType: string }; + response: RouteResponseBody; +} + +export type FilterLabelRoutes = { + Get: GetFilterLabelRoute; +}; diff --git a/packages/lib/src/routes/index.ts b/packages/lib/src/routes/index.ts index 1f133b8cd4..ecefffe341 100644 --- a/packages/lib/src/routes/index.ts +++ b/packages/lib/src/routes/index.ts @@ -38,5 +38,6 @@ export type { PreinscriptionRoutes } from "./preinscription"; export type { AffectationRoutes } from "./phase1/affectation"; export type { ReferentielRoutes } from "./referentiel"; export type { ReferentRoutes } from "./iam/referent"; +export type { FilterLabelRoutes } from "./filterLabel"; export * from "./phase1"; From 923c9e985fa556c6870f89db505085f9fd85a848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Bret=C3=A9cher?= Date: Thu, 30 Jan 2025 11:55:42 +0100 Subject: [PATCH 5/9] fix --- admin/src/scenes/volontaires/utils/index.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/admin/src/scenes/volontaires/utils/index.js b/admin/src/scenes/volontaires/utils/index.js index 212415c8bd..b08f683327 100644 --- a/admin/src/scenes/volontaires/utils/index.js +++ b/admin/src/scenes/volontaires/utils/index.js @@ -26,7 +26,6 @@ import { formatPhoneE164 } from "../../../utils/formatPhoneE164"; import { youngCheckinField } from "@/utils"; export const getFilterArray = (user, bus, session, classes, etablissements) => { - console.log("🚀 ~ getFilterArray ~ classes:", classes); return [ { title: "Cohorte", name: "cohort", parentGroup: "Général", missingLabel: "Non renseigné", sort: (e) => orderCohort(e) }, { title: "Cohorte d'origine", name: "originalCohort", parentGroup: "Général", missingLabel: "Non renseigné", sort: orderCohort }, @@ -182,8 +181,7 @@ export const getFilterArray = (user, bus, session, classes, etablissements) => { parentGroup: "Phase 1", missingLabel: "Non renseigné", translate: (item) => { - console.log("🚀 ~ getFilterArray ~ item:", typeof item); - if (item === "N/A" || !classes.length) return item; + if (item === "N/A") return item; return classes[item] || "N/A - Supprimé"; }, }, @@ -193,7 +191,7 @@ export const getFilterArray = (user, bus, session, classes, etablissements) => { parentGroup: "Phase 1", missingLabel: "Non renseigné", translate: (item) => { - if (item === "N/A" || !etablissements.length) return item; + if (item === "N/A") return item; return etablissements[item] || "N/A - Supprimé"; }, }, @@ -203,7 +201,7 @@ export const getFilterArray = (user, bus, session, classes, etablissements) => { parentGroup: "Phase 1", missingLabel: "Non renseigné", translate: (item) => { - if (item === "N/A" || !session.length) return item; + if (item === "N/A") return item; return session[item] || "N/A - Supprimé"; }, }, @@ -269,7 +267,7 @@ export const getFilterArray = (user, bus, session, classes, etablissements) => { parentGroup: "Phase 1", missingLabel: "Non renseigné", translate: (item) => { - if (item === "N/A" || !bus?.length) return item; + if (item === "N/A") return item; return bus[item] || item; }, }, From 6bf15a21ae5381e5d15b539e61ccab3bab205e41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Bret=C3=A9cher?= Date: Thu, 30 Jan 2025 11:59:01 +0100 Subject: [PATCH 6/9] fix type --- packages/lib/src/routes/filterLabel/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lib/src/routes/filterLabel/index.ts b/packages/lib/src/routes/filterLabel/index.ts index ce5f3da442..f9d2150284 100644 --- a/packages/lib/src/routes/filterLabel/index.ts +++ b/packages/lib/src/routes/filterLabel/index.ts @@ -1,4 +1,4 @@ -import { FilterLabelDto } from "src/dto/filterLabelDto"; +import { FilterLabelDto } from "src/dto"; import { BasicRoute, RouteResponseBody } from ".."; interface GetFilterLabelRoute extends BasicRoute { From 69de437fad82478b5bfd0b57cdd21bfc1734c8a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Bret=C3=A9cher?= Date: Thu, 30 Jan 2025 12:07:17 +0100 Subject: [PATCH 7/9] fix import --- packages/lib/src/routes/filterLabel/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lib/src/routes/filterLabel/index.ts b/packages/lib/src/routes/filterLabel/index.ts index f9d2150284..2096f284b1 100644 --- a/packages/lib/src/routes/filterLabel/index.ts +++ b/packages/lib/src/routes/filterLabel/index.ts @@ -1,4 +1,4 @@ -import { FilterLabelDto } from "src/dto"; +import { FilterLabelDto } from "../../dto"; import { BasicRoute, RouteResponseBody } from ".."; interface GetFilterLabelRoute extends BasicRoute { From a1ea9f620c14e35adb91e3a6ecd87871a7ac87fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Bret=C3=A9cher?= Date: Thu, 30 Jan 2025 12:13:09 +0100 Subject: [PATCH 8/9] up --- api/src/controllers/elasticsearch/cle/classe.js | 8 +++----- api/src/filterLabel/filterLabelRepository.ts | 8 ++++---- api/src/filterLabel/filterLabelService.ts | 10 +++++----- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/api/src/controllers/elasticsearch/cle/classe.js b/api/src/controllers/elasticsearch/cle/classe.js index 5daf3adfa1..6acac1722c 100644 --- a/api/src/controllers/elasticsearch/cle/classe.js +++ b/api/src/controllers/elasticsearch/cle/classe.js @@ -65,11 +65,9 @@ router.post("/:action(search|export)", passport.authenticate(["referent"], { ses if (req.params.action === "export") { let response = await allRecords("classe", hitsRequestBody.query, esClient, exportFields); - if (req.query?.type === "export-des-classes") { - response = await populateWithEtablissementInfo(response); - response = await populateWithYoungsInfo(response); - response = await populateWithAllReferentsInfo(response); - } + response = await populateWithEtablissementInfo(response); + response = await populateWithYoungsInfo(response); + response = await populateWithAllReferentsInfo(response); if (req.query?.type === "schema-de-repartition") { if (![ROLES.ADMIN, ROLES.REFERENT_REGION, ROLES.TRANSPORTER].includes(user.role)) return res.status(403).send({ ok: false, code: ERRORS.OPERATION_UNAUTHORIZED }); diff --git a/api/src/filterLabel/filterLabelRepository.ts b/api/src/filterLabel/filterLabelRepository.ts index d35638a581..ff99e3ecb9 100644 --- a/api/src/filterLabel/filterLabelRepository.ts +++ b/api/src/filterLabel/filterLabelRepository.ts @@ -7,23 +7,23 @@ function formatLabel(data, key: string) { }, {}); } -export async function getBus() { +export async function getLigneLabel() { const data = await LigneBusModel.find({}, { busId: 1 }); return formatLabel(data, "busId"); } -export async function getClasses() { +export async function getClasseLabel() { // Pourquoi ça renvoit les patches ça ? const data = await ClasseModel.find({}, { uniqueKeyAndId: 1 }); return formatLabel(data, "uniqueKeyAndId"); } -export async function getEtablissements() { +export async function getEtablissementLabel() { const data = await EtablissementModel.find({}, { name: 1 }); return formatLabel(data, "name"); } -export async function getSessions() { +export async function getSessionLabel() { const data = await SessionPhase1Model.find({}, { codeCentre: 1 }); return formatLabel(data, "codeCentre"); } diff --git a/api/src/filterLabel/filterLabelService.ts b/api/src/filterLabel/filterLabelService.ts index c0a71fbd1c..fbb453a756 100644 --- a/api/src/filterLabel/filterLabelService.ts +++ b/api/src/filterLabel/filterLabelService.ts @@ -1,11 +1,11 @@ -import { getBus, getClasses, getEtablissements, getSessions } from "./filterLabelRepository"; +import { getClasseLabel, getEtablissementLabel, getLigneLabel, getSessionLabel } from "./filterLabelRepository"; export const listTypes = { INSCRIPTION: "inscription", VOLONTAIRES: "volontaires" }; export async function getLabelVolontaires() { - const sessions = await getSessions(); - const bus = await getBus(); - const classes = await getClasses(); - const etablissements = await getEtablissements(); + const sessions = await getSessionLabel(); + const bus = await getLigneLabel(); + const classes = await getClasseLabel(); + const etablissements = await getEtablissementLabel(); return { sessions, bus, classes, etablissements }; } From 4c55b567257103dbe08872229695b94b7f9c4ce3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Bret=C3=A9cher?= Date: Thu, 30 Jan 2025 15:45:10 +0100 Subject: [PATCH 9/9] up --- .../src/scenes/volontaires/useFilterLabels.ts | 1 + api/src/filterLabel/filterLabelController.ts | 31 +++++++------ api/src/filterLabel/filterLabelRepository.ts | 43 ++++++++++--------- api/src/filterLabel/filterLabelService.ts | 10 ++--- 4 files changed, 47 insertions(+), 38 deletions(-) diff --git a/admin/src/scenes/volontaires/useFilterLabels.ts b/admin/src/scenes/volontaires/useFilterLabels.ts index f84b4a4f8e..620a59bee7 100644 --- a/admin/src/scenes/volontaires/useFilterLabels.ts +++ b/admin/src/scenes/volontaires/useFilterLabels.ts @@ -17,5 +17,6 @@ export default function useFilterLabels(listType: string) { return useQuery({ queryKey: ["filter-label", listType], queryFn: () => getFilterLabels(listType), + refetchOnWindowFocus: false, }); } diff --git a/api/src/filterLabel/filterLabelController.ts b/api/src/filterLabel/filterLabelController.ts index 613c8dc45b..965f57a0f7 100644 --- a/api/src/filterLabel/filterLabelController.ts +++ b/api/src/filterLabel/filterLabelController.ts @@ -10,19 +10,26 @@ const router = express.Router(); const validator = Joi.string().valid(listTypes.INSCRIPTION, listTypes.VOLONTAIRES).required(); -router.get("/:list", passport.authenticate("referent", { session: false, failWithError: true }), async (req: UserRequest, res: Response) => { - const { value, error } = validator.validate(req.params.list); - if (error) { - capture(error); - return res.status(400).send({ ok: false, code: ERRORS.INVALID_PARAMS }); - } +router.get("/:list", passport.authenticate("referent", { session: false, failWithError: true }), GetFilterLabels); - if (value === listTypes.VOLONTAIRES) { - const data = await getLabelVolontaires(); - return res.status(200).send({ ok: true, data }); - } +async function GetFilterLabels(req: UserRequest, res: Response) { + try { + const { value, error } = validator.validate(req.params.list); + if (error) { + capture(error); + return res.status(400).send({ ok: false, code: ERRORS.INVALID_PARAMS }); + } - // TODO: getLabelInscriptions -}); + if (value === listTypes.VOLONTAIRES) { + const data = await getLabelVolontaires(); + return res.status(200).send({ ok: true, data }); + } + + // TODO: getLabelInscriptions + } catch (error) { + capture(error); + return res.status(500).send({ ok: false, code: ERRORS.SERVER_ERROR }); + } +} module.exports = router; diff --git a/api/src/filterLabel/filterLabelRepository.ts b/api/src/filterLabel/filterLabelRepository.ts index ff99e3ecb9..f5a1e4794c 100644 --- a/api/src/filterLabel/filterLabelRepository.ts +++ b/api/src/filterLabel/filterLabelRepository.ts @@ -1,29 +1,30 @@ import { ClasseModel, EtablissementModel, LigneBusModel, SessionPhase1Model } from "../models"; -function formatLabel(data, key: string) { - return data.reduce((acc, cur) => { - acc[cur._id] = cur[key]; - return acc; - }, {}); +function buildPipeline(key: string) { + return [ + { $project: { _id: 1, [key]: 1 } }, + { $group: { _id: null, keyValuePairs: { $push: { k: { $toString: "$_id" }, v: { $toString: `$${key}` } } } } }, + { $replaceRoot: { newRoot: { $arrayToObject: "$keyValuePairs" } } }, + ]; } -export async function getLigneLabel() { - const data = await LigneBusModel.find({}, { busId: 1 }); - return formatLabel(data, "busId"); +export async function getLigneLabelMap() { + const pipeline = buildPipeline("busId"); + const data = await LigneBusModel.aggregate(pipeline); + return data[0]; } - -export async function getClasseLabel() { - // Pourquoi ça renvoit les patches ça ? - const data = await ClasseModel.find({}, { uniqueKeyAndId: 1 }); - return formatLabel(data, "uniqueKeyAndId"); +export async function getClasseLabelMap() { + const pipeline = buildPipeline("uniqueKeyAndId"); + const data = await ClasseModel.aggregate(pipeline); + return data[0]; } - -export async function getEtablissementLabel() { - const data = await EtablissementModel.find({}, { name: 1 }); - return formatLabel(data, "name"); +export async function getEtablissementLabelMap() { + const pipeline = buildPipeline("name"); + const data = await EtablissementModel.aggregate(pipeline); + return data[0]; } - -export async function getSessionLabel() { - const data = await SessionPhase1Model.find({}, { codeCentre: 1 }); - return formatLabel(data, "codeCentre"); +export async function getSessionLabelMap() { + const pipeline = buildPipeline("codeCentre"); + const data = await SessionPhase1Model.aggregate(pipeline); + return data[0]; } diff --git a/api/src/filterLabel/filterLabelService.ts b/api/src/filterLabel/filterLabelService.ts index fbb453a756..15a650a7ff 100644 --- a/api/src/filterLabel/filterLabelService.ts +++ b/api/src/filterLabel/filterLabelService.ts @@ -1,11 +1,11 @@ -import { getClasseLabel, getEtablissementLabel, getLigneLabel, getSessionLabel } from "./filterLabelRepository"; +import { getClasseLabelMap, getEtablissementLabelMap, getLigneLabelMap, getSessionLabelMap } from "./filterLabelRepository"; export const listTypes = { INSCRIPTION: "inscription", VOLONTAIRES: "volontaires" }; export async function getLabelVolontaires() { - const sessions = await getSessionLabel(); - const bus = await getLigneLabel(); - const classes = await getClasseLabel(); - const etablissements = await getEtablissementLabel(); + const sessions = await getSessionLabelMap(); + const bus = await getLigneLabelMap(); + const classes = await getClasseLabelMap(); + const etablissements = await getEtablissementLabelMap(); return { sessions, bus, classes, etablissements }; }