From 86521f3207f94d590d539bb9729183e7d9a131a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20D=C3=A9tr=C3=A9?= Date: Thu, 9 Nov 2023 16:08:48 +0100 Subject: [PATCH 01/28] feat: quadrant remplace cadran --- .../getEtablissement.query.ts | 6 +- ...{positionCadran.ts => positionQuadrant.ts} | 12 ++-- .../getDataForPanorama/dependencies.ts | 6 +- .../getEtablissements/dependencies.ts | 6 +- .../usecases/getFormations/dependencies.ts | 16 ++--- .../getFormations/getFormations.usecase.ts | 58 +++++++++---------- .../getFormationsStatsQuery.dep.ts | 6 +- .../dependencies.ts | 10 ++-- .../etablissements/etablissements.schema.ts | 2 +- shared/client/formations/formation.schema.ts | 4 +- .../pilotageTransfo/pilotageTransfo.schema.ts | 2 +- .../restitutionIntentions.schema.ts | 4 +- .../formations/components/LineContent.tsx | 2 +- ui/app/(wrapped)/console/formations/page.tsx | 4 +- ...{CadranSection.tsx => QuadrantSection.tsx} | 26 +++++---- ui/app/(wrapped)/intentions/pilotage/page.tsx | 4 +- .../ConsoleSection/ConsoleSection.tsx | 2 +- .../ConsoleSection/LineContent.tsx | 2 +- .../restitution/STATS_DEMANDES_COLUMN.ts | 2 +- ...{CadranSection.tsx => QuadrantSection.tsx} | 36 ++++++------ .../panorama/components/TopFlopSection.tsx | 10 ++-- .../departement/[codeDepartement]/page.tsx | 8 +-- ...{CadranSection.tsx => QuadrantSection.tsx} | 30 +++++----- .../panorama/etablissement/[uai]/page.tsx | 6 +- .../panorama/region/[codeRegion]/page.tsx | 8 +-- ui/components/{Cadran.tsx => Quadrant.tsx} | 32 +++++----- .../{TableCadran.tsx => TableQuadrant.tsx} | 6 +- 27 files changed, 158 insertions(+), 152 deletions(-) rename server/src/modules/data/queries/utils/{positionCadran.ts => positionQuadrant.ts} (94%) rename ui/app/(wrapped)/intentions/pilotage/components/{CadranSection.tsx => QuadrantSection.tsx} (95%) rename ui/app/(wrapped)/panorama/components/{CadranSection.tsx => QuadrantSection.tsx} (95%) rename ui/app/(wrapped)/panorama/etablissement/[uai]/{CadranSection.tsx => QuadrantSection.tsx} (86%) rename ui/components/{Cadran.tsx => Quadrant.tsx} (90%) rename ui/components/{TableCadran.tsx => TableQuadrant.tsx} (98%) diff --git a/server/src/modules/data/queries/getEtablissement/getEtablissement.query.ts b/server/src/modules/data/queries/getEtablissement/getEtablissement.query.ts index 380ec4d9f..a276ae615 100644 --- a/server/src/modules/data/queries/getEtablissement/getEtablissement.query.ts +++ b/server/src/modules/data/queries/getEtablissement/getEtablissement.query.ts @@ -5,7 +5,7 @@ import { kdb } from "../../../../db/db"; import { cleanNull } from "../../../../utils/noNull"; import { hasContinuum } from "../utils/hasContinuum"; import { notHistorique } from "../utils/notHistorique"; -import { withPositionCadran } from "../utils/positionCadran"; +import { withPositionQuadrant } from "../utils/positionQuadrant"; import { withInsertionReg } from "../utils/tauxInsertion6mois"; import { withPoursuiteReg } from "../utils/tauxPoursuite"; import { selectTauxPression } from "../utils/tauxPression"; @@ -107,13 +107,13 @@ export const getEtablissement = async ({ dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", }).as("tauxPoursuiteEtudes"), - withPositionCadran({ + withPositionQuadrant({ eb, millesimeSortie, cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", - }).as("positionCadran"), + }).as("positionQuadrant"), ]) .where(notHistorique) .whereRef("formationEtablissement.UAI", "=", "etablissement.UAI") diff --git a/server/src/modules/data/queries/utils/positionCadran.ts b/server/src/modules/data/queries/utils/positionQuadrant.ts similarity index 94% rename from server/src/modules/data/queries/utils/positionCadran.ts rename to server/src/modules/data/queries/utils/positionQuadrant.ts index bd5ee3c6e..a1a0d66d5 100644 --- a/server/src/modules/data/queries/utils/positionCadran.ts +++ b/server/src/modules/data/queries/utils/positionQuadrant.ts @@ -13,7 +13,7 @@ import { withPoursuiteReg, } from "./tauxPoursuite"; -export const getPositionCadran = ( +export const getPositionQuadrant = ( indicateurRegionSortieAlias: string, indicateurRegionSortieRegAlias: string ) => { @@ -36,14 +36,14 @@ export const getPositionCadran = ( WHEN (${tauxInsertion} >= ${tauxInsertionReg} AND ${tauxPoursuite} < ${tauxPoursuiteReg}) THEN 'Q2' WHEN (${tauxInsertion} < ${tauxInsertionReg} AND ${tauxPoursuite} >= ${tauxPoursuiteReg}) THEN 'Q3' WHEN (${tauxInsertion} < ${tauxInsertionReg} AND ${tauxPoursuite} < ${tauxPoursuiteReg}) THEN 'Q4' - ELSE 'Hors cadran' + ELSE 'Hors quadrant' END `; -}; +} type EbRef> = Parameters[0]; -export function withPositionCadran>({ +export function withPositionQuadrant>({ eb, cfdRef, dispositifIdRef, @@ -128,7 +128,7 @@ export function withPositionCadran>({ "indicateurRegionSortie" )}) THEN 'Q4' - ELSE 'Hors cadran' - END`.as("positionCadran"), + ELSE 'Hors quadrant' + END`.as("positionQuadrant"), ]); } diff --git a/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts b/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts index d8acef126..8eadd41c3 100644 --- a/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts +++ b/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts @@ -4,7 +4,7 @@ import { kdb } from "../../../../db/db"; import { cleanNull } from "../../../../utils/noNull"; import { effectifAnnee } from "../../queries/utils/effectifAnnee"; import { hasContinuum } from "../../queries/utils/hasContinuum"; -import { withPositionCadran } from "../../queries/utils/positionCadran"; +import { withPositionQuadrant } from "../../queries/utils/positionQuadrant"; import { withTauxDevenirFavorableReg } from "../../queries/utils/tauxDevenirFavorable"; import { withInsertionReg } from "../../queries/utils/tauxInsertion6mois"; import { withPoursuiteReg } from "../../queries/utils/tauxPoursuite"; @@ -128,13 +128,13 @@ const queryFormations = ({ codeRegionRef: "etablissement.codeRegion", }).as("tauxDevenirFavorable"), (eb) => - withPositionCadran({ + withPositionQuadrant({ eb, millesimeSortie, cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", - }).as("positionCadran"), + }).as("positionQuadrant"), ]) .$narrowType<{ tauxInsertion6mois: number; diff --git a/server/src/modules/data/usecases/getEtablissements/dependencies.ts b/server/src/modules/data/usecases/getEtablissements/dependencies.ts index 8c73f7791..1d1d4a6f8 100644 --- a/server/src/modules/data/usecases/getEtablissements/dependencies.ts +++ b/server/src/modules/data/usecases/getEtablissements/dependencies.ts @@ -7,7 +7,7 @@ import { capaciteAnnee } from "../../queries/utils/capaciteAnnee"; import { effectifAnnee } from "../../queries/utils/effectifAnnee"; import { hasContinuum } from "../../queries/utils/hasContinuum"; import { notHistorique } from "../../queries/utils/notHistorique"; -import { withPositionCadran } from "../../queries/utils/positionCadran"; +import { withPositionQuadrant } from "../../queries/utils/positionQuadrant"; import { withTauxDevenirFavorableReg } from "../../queries/utils/tauxDevenirFavorable"; import { withInsertionReg } from "../../queries/utils/tauxInsertion6mois"; import { withPoursuiteReg } from "../../queries/utils/tauxPoursuite"; @@ -171,13 +171,13 @@ const findEtablissementsInDb = async ({ codeRegionRef: "etablissement.codeRegion", }).as("tauxDevenirFavorable"), (eb) => - withPositionCadran({ + withPositionQuadrant({ eb, millesimeSortie, cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", - }).as("positionCadran"), + }).as("positionQuadrant"), ]) .$call((q) => { if (!codeRegion) return q; diff --git a/server/src/modules/data/usecases/getFormations/dependencies.ts b/server/src/modules/data/usecases/getFormations/dependencies.ts index 032fa9486..3ae8b0f6f 100644 --- a/server/src/modules/data/usecases/getFormations/dependencies.ts +++ b/server/src/modules/data/usecases/getFormations/dependencies.ts @@ -6,7 +6,7 @@ import { cleanNull } from "../../../../utils/noNull"; import { capaciteAnnee } from "../../queries/utils/capaciteAnnee"; import { effectifAnnee } from "../../queries/utils/effectifAnnee"; import { hasContinuum } from "../../queries/utils/hasContinuum"; -import { withPositionCadran } from "../../queries/utils/positionCadran"; +import { withPositionQuadrant } from "../../queries/utils/positionQuadrant"; import { withTauxDevenirFavorableReg } from "../../queries/utils/tauxDevenirFavorable"; import { withInsertionReg } from "../../queries/utils/tauxInsertion6mois"; import { withPoursuiteReg } from "../../queries/utils/tauxPoursuite"; @@ -32,7 +32,7 @@ const findFormationsInDb = async ({ CPCSecteur, CPCSousSecteur, libelleFiliere, - positionCadran, + positionQuadrant, }: { offset?: number; limit?: number; @@ -52,7 +52,7 @@ const findFormationsInDb = async ({ CPCSecteur?: string[]; CPCSousSecteur?: string[]; libelleFiliere?: string[]; - positionCadran?: string; + positionQuadrant?: string; } = {}) => { const query = kdb .selectFrom("formation") @@ -170,14 +170,14 @@ const findFormationsInDb = async ({ dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", }).as("tauxDevenirFavorable"), - withPositionCadran({ + withPositionQuadrant({ eb, millesimeSortie, cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", codeNiveauDiplomeRef: "formation.codeNiveauDiplome", - }).as("positionCadran"), + }).as("positionQuadrant"), ]) .where( "codeFormationDiplome", @@ -221,10 +221,10 @@ const findFormationsInDb = async ({ "niveauDiplome.libelleNiveauDiplome", ]) .having((h) => { - if (!positionCadran) return h.val(true); + if (!positionQuadrant) return h.val(true); return h( (eb) => - withPositionCadran({ + withPositionQuadrant({ eb, millesimeSortie, cfdRef: "formationEtablissement.cfd", @@ -232,7 +232,7 @@ const findFormationsInDb = async ({ codeRegionRef: "etablissement.codeRegion", }), "=", - positionCadran + positionQuadrant ); }) .$call((q) => { diff --git a/server/src/modules/data/usecases/getFormations/getFormations.usecase.ts b/server/src/modules/data/usecases/getFormations/getFormations.usecase.ts index 96e113b30..8c07d039b 100644 --- a/server/src/modules/data/usecases/getFormations/getFormations.usecase.ts +++ b/server/src/modules/data/usecases/getFormations/getFormations.usecase.ts @@ -7,36 +7,36 @@ const getFormationsFactory = findFiltersInDb: dependencies.findFiltersInDb, } ) => - async (activeFilters: { - offset?: number; - limit?: number; - codeRegion?: string[]; - codeAcademie?: string[]; - codeDepartement?: string[]; - codeDiplome?: string[]; - codeDispositif?: string[]; - commune?: string[]; - cfd?: string[]; - rentreeScolaire?: string[]; - cfdFamille?: string[]; - CPC?: string[]; - CPCSecteur?: string[]; - CPCSousSecteur?: string[]; - libelleFiliere?: string[]; - orderBy?: { order: "asc" | "desc"; column: string }; - withEmptyFormations?: boolean; - positionCadran?: string; - }) => { - const [{ formations, count }, filters] = await Promise.all([ - deps.findFormationsInDb(activeFilters), - deps.findFiltersInDb(activeFilters), - ]); + async (activeFilters: { + offset?: number; + limit?: number; + codeRegion?: string[]; + codeAcademie?: string[]; + codeDepartement?: string[]; + codeDiplome?: string[]; + codeDispositif?: string[]; + commune?: string[]; + cfd?: string[]; + rentreeScolaire?: string[]; + cfdFamille?: string[]; + CPC?: string[]; + CPCSecteur?: string[]; + CPCSousSecteur?: string[]; + libelleFiliere?: string[]; + orderBy?: { order: "asc" | "desc"; column: string }; + withEmptyFormations?: boolean; + positionQuadrant?: string; + }) => { + const [{ formations, count }, filters] = await Promise.all([ + deps.findFormationsInDb(activeFilters), + deps.findFiltersInDb(activeFilters), + ]); - return { - count, - filters, - formations, + return { + count, + filters, + formations, + }; }; - }; export const getFormations = getFormationsFactory(); diff --git a/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsStatsQuery.dep.ts b/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsStatsQuery.dep.ts index ee2f7f63f..022d93489 100644 --- a/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsStatsQuery.dep.ts +++ b/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsStatsQuery.dep.ts @@ -4,7 +4,7 @@ import { kdb } from "../../../../db/db"; import { DB } from "../../../../db/schema"; import { cleanNull } from "../../../../utils/noNull"; import { hasContinuum } from "../../queries/utils/hasContinuum"; -import { withPositionCadran } from "../../queries/utils/positionCadran"; +import { withPositionQuadrant } from "../../queries/utils/positionQuadrant"; import { withTauxDevenirFavorableReg } from "../../queries/utils/tauxDevenirFavorable"; import { withInsertionReg } from "../../queries/utils/tauxInsertion6mois"; import { withPoursuiteReg } from "../../queries/utils/tauxPoursuite"; @@ -138,14 +138,14 @@ export const getFormationsTransformationStatsQuery = ({ dispositifIdRef: "demande.dispositifId", codeRegionRef: "dataEtablissement.codeRegion", }).as("tauxDevenirFavorable"), - withPositionCadran({ + withPositionQuadrant({ eb, millesimeSortie: "2020_2021", cfdRef: "demande.cfd", dispositifIdRef: "demande.dispositifId", codeRegionRef: "dataEtablissement.codeRegion", codeNiveauDiplomeRef: codeNiveauDiplome ? "dataFormation.codeNiveauDiplome" : undefined, - }).as("positionCadran"), + }).as("positionQuadrant"), selectNbDemandes(eb).as("nbDemandes"), selectNbEtablissements(eb).as("nbEtablissements"), sql`ABS(${eb.fn.sum(selectDifferencePlaces(eb, type))})`.as( diff --git a/server/src/modules/data/usecases/getRestitutionIntentionsStats/dependencies.ts b/server/src/modules/data/usecases/getRestitutionIntentionsStats/dependencies.ts index 48278110e..496ac09fc 100644 --- a/server/src/modules/data/usecases/getRestitutionIntentionsStats/dependencies.ts +++ b/server/src/modules/data/usecases/getRestitutionIntentionsStats/dependencies.ts @@ -25,7 +25,7 @@ import { isRegionVisible, } from "../../../utils/isIntentionVisible"; import { notHistoriqueIndicateurRegionSortie } from "../../queries/utils/notHistorique"; -import { getPositionCadran } from "../../queries/utils/positionCadran"; +import { getPositionQuadrant } from "../../queries/utils/positionQuadrant"; const findRestitutionIntentionsStatsInDB = async ({ status, @@ -172,8 +172,8 @@ const findRestitutionIntentionsStatsInDB = async ({ .select([ selectTauxInsertion6moisAgg("subIRS").as("tauxInsertion"), selectTauxPoursuiteAgg("subIRS").as("tauxPoursuite"), - getPositionCadran("indicateurRegionSortie", "subIRS").as( - "positionCadran" + getPositionQuadrant("indicateurRegionSortie", "subIRS").as( + "positionQuadrant" ), ]) ).as("statsSortieMoyennes"), @@ -315,8 +315,8 @@ const findRestitutionIntentionsStatsInDB = async ({ demande.statsSortieMoyennes?.tauxInsertion ?? undefined, tauxPoursuiteMoyen: demande.statsSortieMoyennes?.tauxPoursuite ?? undefined, - positionCadran: - demande.statsSortieMoyennes?.positionCadran ?? "Hors cadran", + positionQuadrant: + demande.statsSortieMoyennes?.positionQuadrant ?? "Hors quadrant", }) ), count: parseInt(demandes[0]?.count) || 0, diff --git a/shared/client/etablissements/etablissements.schema.ts b/shared/client/etablissements/etablissements.schema.ts index ceb9edb66..ac65c299c 100644 --- a/shared/client/etablissements/etablissements.schema.ts +++ b/shared/client/etablissements/etablissements.schema.ts @@ -117,7 +117,7 @@ export const etablissementSchemas = { tauxInsertion6mois: Type.Optional(Type.Number()), tauxPoursuiteEtudes: Type.Optional(Type.Number()), tauxDevenirFavorable: Type.Optional(Type.Number()), - positionCadran: Type.Optional(Type.String()), + positionQuadrant: Type.Optional(Type.String()), CPC: Type.Optional(Type.String()), CPCSecteur: Type.Optional(Type.String()), CPCSousSecteur: Type.Optional(Type.String()), diff --git a/shared/client/formations/formation.schema.ts b/shared/client/formations/formation.schema.ts index 252ffaf76..5d3d9914a 100644 --- a/shared/client/formations/formation.schema.ts +++ b/shared/client/formations/formation.schema.ts @@ -35,7 +35,7 @@ const FormationLineSchema = Type.Object({ libelle: Type.Optional(Type.String()), }) ), - positionCadran: Type.Optional(Type.String()), + positionQuadrant: Type.Optional(Type.String()), }); const FiltersSchema = Type.Object({ @@ -74,7 +74,7 @@ const FormationSchema = Type.Object({ tauxPoursuiteEtudes: Type.Number(), tauxPoursuiteEtudesPrecedent: Type.Optional(Type.Number()), tauxDevenirFavorable: Type.Number(), - positionCadran: Type.Optional(Type.String()), + positionQuadrant: Type.Optional(Type.String()), CPC: Type.Optional(Type.String()), CPCSecteur: Type.Optional(Type.String()), CPCSousSecteur: Type.Optional(Type.String()), diff --git a/shared/client/pilotageTransfo/pilotageTransfo.schema.ts b/shared/client/pilotageTransfo/pilotageTransfo.schema.ts index afe5be353..f4a2dbdf5 100644 --- a/shared/client/pilotageTransfo/pilotageTransfo.schema.ts +++ b/shared/client/pilotageTransfo/pilotageTransfo.schema.ts @@ -69,7 +69,7 @@ const FormationTransformationStatsSchema = Type.Object({ placesOuvertes: Type.Number(), placesFermees: Type.Number(), placesTransformees: Type.Number(), - positionCadran: Type.Optional(Type.String()), + positionQuadrant: Type.Optional(Type.String()), continuum: Type.Optional( Type.Object({ cfd: Type.String(), diff --git a/shared/client/restitutionIntentions/restitutionIntentions.schema.ts b/shared/client/restitutionIntentions/restitutionIntentions.schema.ts index 5732f09a5..fc509eb1c 100644 --- a/shared/client/restitutionIntentions/restitutionIntentions.schema.ts +++ b/shared/client/restitutionIntentions/restitutionIntentions.schema.ts @@ -49,7 +49,7 @@ const StatsDemandesItem = Type.Object({ devenirFavorable: Type.Optional(Type.Number()), pression: Type.Optional(Type.Number()), nbEtablissement: Type.Optional(Type.Number()), - positionCadran: Type.Optional(Type.String()), + positionQuadrant: Type.Optional(Type.String()), tauxInsertionMoyen: Type.Optional(Type.Number()), tauxPoursuiteMoyen: Type.Optional(Type.Number()), }); @@ -79,7 +79,7 @@ const StatsFiltersSchema = Type.Object({ amiCMA: Type.Optional(Type.String()), secteur: Type.Optional(Type.String()), compensation: Type.Optional(Type.String()), - positionCadran: Type.Optional(Type.String()), + positionQuadrant: Type.Optional(Type.String()), order: Type.Optional(Type.Union([Type.Literal("asc"), Type.Literal("desc")])), orderBy: Type.Optional(Type.KeyOf(Type.Omit(StatsDemandesItem, []))), }); diff --git a/ui/app/(wrapped)/console/formations/components/LineContent.tsx b/ui/app/(wrapped)/console/formations/components/LineContent.tsx index 32121d578..f5444d18d 100644 --- a/ui/app/(wrapped)/console/formations/components/LineContent.tsx +++ b/ui/app/(wrapped)/console/formations/components/LineContent.tsx @@ -107,7 +107,7 @@ export const FormationLineContent = ({ {line.CPCSecteur ?? "-"} {line.CPCSousSecteur ?? "-"} {line.libelleFiliere ?? "-"} - {line.positionCadran} + {line.positionQuadrant} ); }; diff --git a/ui/app/(wrapped)/console/formations/page.tsx b/ui/app/(wrapped)/console/formations/page.tsx index 2ca94ed29..54842ad4d 100644 --- a/ui/app/(wrapped)/console/formations/page.tsx +++ b/ui/app/(wrapped)/console/formations/page.tsx @@ -61,7 +61,7 @@ const FORMATIONS_COLUMNS = { libelleFiliere: "Secteur d’activité", "continuum.libelle": "Diplôme historique", "continuum.cfd": "Code diplôme historique", - positionCadran: "Position dans le cadran", + positionQuadrant: "Position dans le quadrant", } satisfies ExportColumns< ApiType["formations"][number] >; @@ -495,7 +495,7 @@ export default function Formations() { {FORMATIONS_COLUMNS.libelleFiliere} - {FORMATIONS_COLUMNS.positionCadran} + {FORMATIONS_COLUMNS.positionQuadrant} diff --git a/ui/app/(wrapped)/intentions/pilotage/components/CadranSection.tsx b/ui/app/(wrapped)/intentions/pilotage/components/QuadrantSection.tsx similarity index 95% rename from ui/app/(wrapped)/intentions/pilotage/components/CadranSection.tsx rename to ui/app/(wrapped)/intentions/pilotage/components/QuadrantSection.tsx index eb82081af..56f38b283 100644 --- a/ui/app/(wrapped)/intentions/pilotage/components/CadranSection.tsx +++ b/ui/app/(wrapped)/intentions/pilotage/components/QuadrantSection.tsx @@ -27,8 +27,8 @@ import { GraphWrapper } from "@/components/GraphWrapper"; import { InfoBlock } from "@/components/InfoBlock"; import { api } from "../../../../../api.client"; -import { Cadran } from "../../../../../components/Cadran"; -import { TableCadran } from "../../../../../components/TableCadran"; +import { Quadrant } from "../../../../../components/Quadrant"; +import { TableQuadrant } from "../../../../../components/TableQuadrant"; import { createParametrizedUrl } from "../../../../../utils/createParametrizedUrl"; import { downloadCsv } from "../../../../../utils/downloadCsv"; import { useStateParams } from "../../../../../utils/useFilters"; @@ -39,7 +39,7 @@ import { Scope, } from "../types"; -export const CadranSection = ({ +export const QuadrantSection = ({ scope, parentFilters, scopeFilters, @@ -52,11 +52,11 @@ export const CadranSection = ({ scopeFilters?: PilotageTransformationStats["filters"]; }) => { const trackEvent = usePlausible(); - const [typeVue, setTypeVue] = useState<"cadran" | "tableau">("cadran"); + const [typeVue, setTypeVue] = useState<"quadrant" | "tableau">("quadrant"); const toggleTypeVue = () => { - if (typeVue === "cadran") setTypeVue("tableau"); - else setTypeVue("cadran"); + if (typeVue === "quadrant") setTypeVue("tableau"); + else setTypeVue("quadrant"); }; const [filters, setFilters] = useStateParams({ @@ -118,7 +118,7 @@ export const CadranSection = ({ const handleOrder = ( column: OrderFormationsTransformationStats["orderBy"] ) => { - trackEvent("tableau-cadran-intentions:ordre", { + trackEvent("tableau-quadrant-intentions:ordre", { props: { colonne: column }, }); if (order?.orderBy !== column) { @@ -150,7 +150,9 @@ export const CadranSection = ({ @@ -363,8 +365,8 @@ export const CadranSection = ({ <> {filteredFormations && - (typeVue === "cadran" ? ( - ({ @@ -380,7 +382,7 @@ export const CadranSection = ({ effectifSizes={effectifSizes} /> ) : ( - ({ ...formation, tauxInsertion: formation.tauxInsertion6mois, diff --git a/ui/app/(wrapped)/panorama/components/TopFlopSection.tsx b/ui/app/(wrapped)/panorama/components/TopFlopSection.tsx index 537a715c1..2290f73f2 100644 --- a/ui/app/(wrapped)/panorama/components/TopFlopSection.tsx +++ b/ui/app/(wrapped)/panorama/components/TopFlopSection.tsx @@ -18,19 +18,19 @@ import { PanoramaFormation, PanoramaFormations } from "../types"; import { FormationTooltipContent } from "./FormationTooltipContent"; export const TopFlopSection = ({ - cadranFormations, + quadrantFormations, codeNiveauDiplome, libelleFiliere, }: { - cadranFormations?: PanoramaFormations; + quadrantFormations?: PanoramaFormations; meanPoursuite?: number; meanInsertion?: number; codeNiveauDiplome?: string[]; libelleFiliere?: string[]; }) => { const topFlopFormations = useMemo(() => { - if (!cadranFormations) return; - const filtered = cadranFormations.filter((item) => { + if (!quadrantFormations) return; + const filtered = quadrantFormations.filter((item) => { if ( libelleFiliere?.length && (!item.libelleFiliere || !libelleFiliere.includes(item.libelleFiliere)) @@ -54,7 +54,7 @@ export const TopFlopSection = ({ const flop = sorted.slice().reverse().slice(0, Math.floor(nbTopFlop)); return { top, flop }; - }, [cadranFormations, codeNiveauDiplome, libelleFiliere]); + }, [quadrantFormations, codeNiveauDiplome, libelleFiliere]); return ( diff --git a/ui/app/(wrapped)/panorama/departement/[codeDepartement]/page.tsx b/ui/app/(wrapped)/panorama/departement/[codeDepartement]/page.tsx index 3b556713c..30889bd10 100644 --- a/ui/app/(wrapped)/panorama/departement/[codeDepartement]/page.tsx +++ b/ui/app/(wrapped)/panorama/departement/[codeDepartement]/page.tsx @@ -5,10 +5,10 @@ import { useRouter } from "next/navigation"; import { useState } from "react"; import { api } from "../../../../../api.client"; -import { CadranSection } from "../../components/CadranSection"; import { FiltersSection } from "../../components/FiltersSection"; import { IndicateursSection } from "../../components/IndicateursSection"; import { InfoSection } from "../../components/InfoSection"; +import { QuadrantSection } from "../../components/QuadrantSection"; import { TopFlopSection } from "../../components/TopFlopSection"; export default function Panorama({ @@ -72,17 +72,17 @@ export default function Panorama({ libelleFiliere={libelleFiliere} onLibelleFiliereChanged={setLibelleFiliere} /> - = T & Required>; @@ -27,28 +27,28 @@ const effectifSizes = [ { max: 100, size: 40 }, ]; -export const CadranSection = ({ - cadranFormations, +export const QuadrantSection = ({ + quadrantFormations, meanPoursuite, meanInsertion, codeNiveauDiplome, rentreeScolaire, }: { - cadranFormations?: ApiType["formations"]; + quadrantFormations?: ApiType["formations"]; meanPoursuite?: number; meanInsertion?: number; codeNiveauDiplome?: string[]; rentreeScolaire?: string; }) => { - const [typeVue, setTypeVue] = useState<"cadran" | "tableau">("cadran"); + const [typeVue, setTypeVue] = useState<"quadrant" | "tableau">("quadrant"); const toggleTypeVue = () => { - if (typeVue === "cadran") setTypeVue("tableau"); - else setTypeVue("cadran"); + if (typeVue === "quadrant") setTypeVue("tableau"); + else setTypeVue("quadrant"); }; const filteredFormations = useMemo( () => - cadranFormations?.filter( + quadrantFormations?.filter( ( item ): item is RequiredFields< @@ -60,7 +60,7 @@ export const CadranSection = ({ (!codeNiveauDiplome?.length || codeNiveauDiplome.includes(item.codeNiveauDiplome)) ), - [codeNiveauDiplome, cadranFormations] + [codeNiveauDiplome, quadrantFormations] ); return ( @@ -78,7 +78,9 @@ export const CadranSection = ({ @@ -97,8 +99,8 @@ export const CadranSection = ({ <> {filteredFormations && - (typeVue === "cadran" ? ( - ) : ( - ({ ...formation, tauxInsertion: formation.tauxInsertion6mois, diff --git a/ui/app/(wrapped)/panorama/etablissement/[uai]/page.tsx b/ui/app/(wrapped)/panorama/etablissement/[uai]/page.tsx index b4820157d..e5e394271 100644 --- a/ui/app/(wrapped)/panorama/etablissement/[uai]/page.tsx +++ b/ui/app/(wrapped)/panorama/etablissement/[uai]/page.tsx @@ -8,10 +8,10 @@ import { api } from "../../../../../api.client"; import { UaiFilterContext } from "../../../../layoutClient"; import { InfoSection } from "../../components/InfoSection"; import { PanoramaSelection } from "../PanoramaSelection"; -import { CadranSection } from "./CadranSection"; import { EtablissementSection } from "./EtablissementSection"; import { FiltersSection } from "./FiltersSection"; import { FormationsSection } from "./FormationsSection"; +import { QuadrantSection } from "./QuadrantSection"; import { RegionSection } from "./RegionSection"; export default function Panorama({ @@ -84,12 +84,12 @@ export default function Panorama({ codeDiplome={codeNiveauDiplome} /> - - diff --git a/ui/components/Cadran.tsx b/ui/components/Quadrant.tsx similarity index 90% rename from ui/components/Cadran.tsx rename to ui/components/Quadrant.tsx index cbe31dfac..e34e21760 100644 --- a/ui/components/Cadran.tsx +++ b/ui/components/Quadrant.tsx @@ -23,7 +23,7 @@ import { useState, } from "react"; -const cadranLabelStyle = { +const quadrantLabelStyle = { show: true, distance: 14, fontSize: 14, @@ -31,12 +31,12 @@ const cadranLabelStyle = { fontWeight: "bold", } as const; -export const Cadran = function < +export const Quadrant = function < F extends { effectif?: number; tauxPoursuite: number; tauxInsertion: number; - positionCadran?: string; + positionQuadrant?: string; }, >({ className, @@ -104,13 +104,13 @@ export const Cadran = function < })); }, [data]); - const repartitionCadrans = useMemo(() => { + const repartitionsQuadrants = useMemo(() => { if (!meanInsertion || !meanPoursuite) return; return { - q1: data.filter((item) => item.positionCadran === "Q1").length, - q2: data.filter((item) => item.positionCadran === "Q2").length, - q3: data.filter((item) => item.positionCadran === "Q3").length, - q4: data.filter((item) => item.positionCadran === "Q4").length, + q1: data.filter((item) => item.positionQuadrant === "Q1").length, + q2: data.filter((item) => item.positionQuadrant === "Q2").length, + q3: data.filter((item) => item.positionQuadrant === "Q3").length, + q4: data.filter((item) => item.positionQuadrant === "Q4").length, }; }, [data, meanInsertion, meanPoursuite]); @@ -217,9 +217,9 @@ export const Cadran = function < { coord: [0, 0], itemStyle: { color: "#ffe2e1" }, - name: `Q4 - ${repartitionCadrans?.q4} formations`, + name: `Q4 - ${repartitionsQuadrants?.q4} formations`, label: { - ...cadranLabelStyle, + ...quadrantLabelStyle, position: "insideBottomLeft", }, }, @@ -229,9 +229,9 @@ export const Cadran = function < { coord: [meanPoursuite, meanInsertion], itemStyle: { color: "#C8F6D6" }, - name: `Q1 - ${repartitionCadrans?.q1} formations`, + name: `Q1 - ${repartitionsQuadrants?.q1} formations`, label: { - ...cadranLabelStyle, + ...quadrantLabelStyle, position: "insideTopRight", }, }, @@ -241,9 +241,9 @@ export const Cadran = function < { coord: [0, meanInsertion], itemStyle: { color: "rgba(0,0,0,0.04)" }, - name: `Q2 - ${repartitionCadrans?.q2} formations`, + name: `Q2 - ${repartitionsQuadrants?.q2} formations`, label: { - ...cadranLabelStyle, + ...quadrantLabelStyle, position: "insideTopLeft", }, }, @@ -253,9 +253,9 @@ export const Cadran = function < { coord: [meanPoursuite, 0], itemStyle: { color: "rgba(0,0,0,0.04)" }, - name: `Q3 - ${repartitionCadrans?.q3} formations`, + name: `Q3 - ${repartitionsQuadrants?.q3} formations`, label: { - ...cadranLabelStyle, + ...quadrantLabelStyle, position: "insideBottomRight", }, }, diff --git a/ui/components/TableCadran.tsx b/ui/components/TableQuadrant.tsx similarity index 98% rename from ui/components/TableCadran.tsx rename to ui/components/TableQuadrant.tsx index 276c4b66b..1bc1b77a4 100644 --- a/ui/components/TableCadran.tsx +++ b/ui/components/TableQuadrant.tsx @@ -22,11 +22,11 @@ type Formation = { tauxPoursuite?: number; tauxInsertion?: number; tauxPression?: number; - positionCadran?: string; + positionQuadrant?: string; cfd?: string; }; -export const TableCadran = ({ +export const TableQuadrant = ({ formations, handleOrder, handleClick, @@ -50,7 +50,7 @@ export const TableCadran = ({ const getTrBgColor = (formation: Formation) => { if (currentCfd && formation.cfd === currentCfd) return "blue.main !important"; - switch (formation.positionCadran) { + switch (formation.positionQuadrant) { case "Q1": return "#C8F6D6"; case "Q4": From 4fc1ef365b3356684f60fc4054b954c9ce39e02d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20D=C3=A9tr=C3=A9?= Date: Thu, 9 Nov 2023 16:17:12 +0100 Subject: [PATCH 02/28] =?UTF-8?q?fix:=20affichage=20d=C3=A9tail=20formatio?= =?UTF-8?q?n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/components/Quadrant.tsx | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/ui/components/Quadrant.tsx b/ui/components/Quadrant.tsx index e34e21760..ce7ec0c81 100644 --- a/ui/components/Quadrant.tsx +++ b/ui/components/Quadrant.tsx @@ -312,25 +312,25 @@ export const Quadrant = function < bottom="0" > - - {InfoTootipContent && ( + {InfoTootipContent && ( + - )} + + )} - {displayedDetail && TooltipContent && ( - setDisplayedDetail(undefined)} - {...popperInstance.getPopperProps()} - > - {TooltipContent && displayedDetail && ( - - )} - - )} - + {displayedDetail && TooltipContent && ( + setDisplayedDetail(undefined)} + {...popperInstance.getPopperProps()} + > + {TooltipContent && displayedDetail && ( + + )} + + )} ); }; From 3fd52954b5a706d0b1c09d8069fa2b45178e7c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20D=C3=A9tr=C3=A9?= Date: Thu, 9 Nov 2023 17:42:41 +0100 Subject: [PATCH 03/28] feat: ajout tri tableau quadrant et refacto nommage --- .../getDepartementsStats.query.ts | 4 +- .../getEtablissement.query.ts | 4 +- .../getRegionStats/getRegionStats.query.ts | 4 +- .../data/queries/utils/positionQuadrant.ts | 2 - .../modules/data/routes/panorama.routes.ts | 17 +++-- .../getDataForPanorama/dependencies.ts | 36 ++++++++--- .../getDataForPanorama.usecase.ts | 23 ++++++- .../getEtablissements/dependencies.ts | 4 +- .../usecases/getFormations/dependencies.ts | 4 +- .../etablissements/etablissements.schema.ts | 16 ++--- shared/client/formations/formation.schema.ts | 16 +++-- .../etablissements/components/LineContent.tsx | 10 +-- .../(wrapped)/console/etablissements/page.tsx | 16 ++--- .../formations/components/LineContent.tsx | 10 +-- ui/app/(wrapped)/console/formations/page.tsx | 16 ++--- .../pilotage/components/QuadrantSection.tsx | 2 - .../components/FormationTooltipContent.tsx | 4 +- .../components/IndicateursSection.tsx | 8 +-- .../panorama/components/QuadrantSection.tsx | 62 ++++++++++++++----- .../departement/[codeDepartement]/page.tsx | 43 +++++++++++-- .../[uai]/FormationTooltipContent.tsx | 4 +- .../etablissement/[uai]/QuadrantSection.tsx | 14 ++--- .../etablissement/[uai]/RegionSection.tsx | 4 +- .../panorama/etablissement/[uai]/page.tsx | 4 +- .../panorama/region/[codeRegion]/page.tsx | 43 +++++++++++-- ui/app/(wrapped)/panorama/types.ts | 6 ++ .../components/VueRegionAcademieSection.tsx | 8 +-- ui/components/TableQuadrant.tsx | 4 +- 28 files changed, 254 insertions(+), 134 deletions(-) diff --git a/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts b/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts index e2ee64b56..785911790 100644 --- a/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts +++ b/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts @@ -46,10 +46,10 @@ export const getDepartementsStats = async ({ ) .select([ selectTauxInsertion6moisAgg("indicateurRegionSortie").as( - "tauxInsertion6mois" + "tauxInsertion" ), selectTauxPoursuiteAgg("indicateurRegionSortie").as( - "tauxPoursuiteEtudes" + "tauxPoursuite" ), ]) .executeTakeFirstOrThrow(); diff --git a/server/src/modules/data/queries/getEtablissement/getEtablissement.query.ts b/server/src/modules/data/queries/getEtablissement/getEtablissement.query.ts index a276ae615..94be14db4 100644 --- a/server/src/modules/data/queries/getEtablissement/getEtablissement.query.ts +++ b/server/src/modules/data/queries/getEtablissement/getEtablissement.query.ts @@ -99,14 +99,14 @@ export const getEtablissement = async ({ cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", - }).as("tauxInsertion6mois"), + }).as("tauxInsertion"), withPoursuiteReg({ eb, millesimeSortie, cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", - }).as("tauxPoursuiteEtudes"), + }).as("tauxPoursuite"), withPositionQuadrant({ eb, millesimeSortie, diff --git a/server/src/modules/data/queries/getRegionStats/getRegionStats.query.ts b/server/src/modules/data/queries/getRegionStats/getRegionStats.query.ts index 63ce22dab..158f89285 100644 --- a/server/src/modules/data/queries/getRegionStats/getRegionStats.query.ts +++ b/server/src/modules/data/queries/getRegionStats/getRegionStats.query.ts @@ -38,10 +38,10 @@ export const getRegionStats = async ({ .where(notHistoriqueIndicateurRegionSortie) .select([ selectTauxInsertion6moisAgg("indicateurRegionSortie").as( - "tauxInsertion6mois" + "tauxInsertion" ), selectTauxPoursuiteAgg("indicateurRegionSortie").as( - "tauxPoursuiteEtudes" + "tauxPoursuite" ), ]) .executeTakeFirstOrThrow(); diff --git a/server/src/modules/data/queries/utils/positionQuadrant.ts b/server/src/modules/data/queries/utils/positionQuadrant.ts index a1a0d66d5..5214a5e98 100644 --- a/server/src/modules/data/queries/utils/positionQuadrant.ts +++ b/server/src/modules/data/queries/utils/positionQuadrant.ts @@ -1,7 +1,6 @@ import { ExpressionBuilder, sql } from "kysely"; import { DB } from "../../../../db/schema"; -import { notHistoriqueIndicateurRegionSortie } from "./notHistorique"; import { selectTauxInsertion6mois, selectTauxInsertion6moisAgg, @@ -82,7 +81,6 @@ export function withPositionQuadrant>({ sql`ANY(array_agg(${eb.ref(codeRegionRef)}))` ) .where("indicateurRegionSortie.millesimeSortie", "=", millesimeSortie) - .where(notHistoriqueIndicateurRegionSortie) .innerJoin( "formation", "formation.codeFormationDiplome", diff --git a/server/src/modules/data/routes/panorama.routes.ts b/server/src/modules/data/routes/panorama.routes.ts index 20cc9c1e3..3ae2d6a5c 100644 --- a/server/src/modules/data/routes/panorama.routes.ts +++ b/server/src/modules/data/routes/panorama.routes.ts @@ -10,12 +10,11 @@ export const panoramaRoutes = ({ server }: { server: Server }) => { "/panorama/stats/region", { schema: ROUTES_CONFIG.getDataForPanoramaRegion }, async (request, response) => { - const q = request.query; - if (!("codeRegion" in q)) { - q; - } + const { order, orderBy, ...filters } = request.query; + console.log(request.query) const stats = await getDataForPanoramaRegion({ - ...request.query, + ...filters, + orderBy: order && orderBy ? { order, column: orderBy } : undefined, }); response.status(200).send(stats); } @@ -24,12 +23,10 @@ export const panoramaRoutes = ({ server }: { server: Server }) => { "/panorama/stats/departement", { schema: ROUTES_CONFIG.getDataForPanoramaDepartement }, async (request, response) => { - const q = request.query; - if (!("codeDepartement" in q)) { - q; - } + const { order, orderBy, ...filters } = request.query; const stats = await getDataForPanoramaDepartement({ - ...request.query, + ...filters, + orderBy: order && orderBy ? { order, column: orderBy } : undefined, }); response.status(200).send(stats); } diff --git a/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts b/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts index 8eadd41c3..05cc17ecc 100644 --- a/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts +++ b/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts @@ -14,9 +14,11 @@ import { selectTauxRemplissageAgg } from "../../queries/utils/tauxRemplissage"; const queryFormations = ({ rentreeScolaire = "2022", millesimeSortie = "2020_2021", + orderBy, }: { rentreeScolaire?: string; millesimeSortie?: string; + orderBy?: { column: string; order: "asc" | "desc" }; }) => kdb .selectFrom("formation") @@ -59,9 +61,8 @@ const queryFormations = ({ .onRef("formationEtablissement.id", "=", "iep.formationEtablissementId") .on("iep.rentreeScolaire", "=", "2021") ) - .select([ + .select((eb) => [ "codeFormationDiplome", - "libelleDiplome", "formationEtablissement.dispositifId", "libelleDispositif", "libelleNiveauDiplome", @@ -78,6 +79,7 @@ const queryFormations = ({ sql`SUM(${effectifAnnee({ alias: "iep" })})`.as( "effectifPrecedent" ), + sql`CONCAT(${eb.ref("formation.libelleDiplome")},' (',${eb.ref("niveauDiplome.libelleNiveauDiplome")}, ')')`.as("libelleDiplome"), selectTauxPressionAgg("indicateurEntree").as("tauxPression"), (eb) => withInsertionReg({ @@ -86,7 +88,7 @@ const queryFormations = ({ cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", - }).as("tauxInsertion6moisPrecedent"), + }).as("tauxInsertionPrecedent"), (eb) => withPoursuiteReg({ eb, @@ -94,7 +96,7 @@ const queryFormations = ({ cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", - }).as("tauxPoursuiteEtudesPrecedent"), + }).as("tauxPoursuitePrecedent"), (eb) => withInsertionReg({ eb, @@ -102,7 +104,7 @@ const queryFormations = ({ cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", - }).as("tauxInsertion6mois"), + }).as("tauxInsertion"), (eb) => withPoursuiteReg({ eb, @@ -110,7 +112,7 @@ const queryFormations = ({ cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", - }).as("tauxPoursuiteEtudes"), + }).as("tauxPoursuite"), (eb) => hasContinuum({ eb, @@ -137,8 +139,8 @@ const queryFormations = ({ }).as("positionQuadrant"), ]) .$narrowType<{ - tauxInsertion6mois: number; - tauxPoursuiteEtudes: number; + tauxInsertion: number; + tauxPoursuite: number; tauxDevenirFavorable: number; }>() .having( @@ -173,17 +175,29 @@ const queryFormations = ({ "dispositif.codeDispositif", "niveauDiplome.libelleNiveauDiplome", ]) + .$call((q) => { + if (!orderBy) return q; + return q.orderBy( + sql.ref(orderBy.column), + sql`${sql.raw(orderBy.order)} NULLS LAST` + ); + }) + .orderBy("tauxDevenirFavorable", "desc") export const queryFormationsRegion = async ({ codeRegion, rentreeScolaire = "2022", millesimeSortie = "2020_2021", + orderBy }: { codeRegion: string; rentreeScolaire?: string; millesimeSortie?: string; + orderBy?: { column: string; order: "asc" | "desc" }; }) => { - const formations = await queryFormations({ rentreeScolaire, millesimeSortie }) + + console.log(orderBy) + const formations = await queryFormations({ rentreeScolaire, millesimeSortie, orderBy }) .where("etablissement.codeRegion", "=", codeRegion) .execute(); @@ -194,12 +208,14 @@ export const queryFormationsDepartement = async ({ codeDepartement, rentreeScolaire = "2022", millesimeSortie = "2020_2021", + orderBy }: { codeDepartement: string; rentreeScolaire?: string; millesimeSortie?: string; + orderBy?: { column: string; order: "asc" | "desc" }; }) => { - const formations = await queryFormations({ rentreeScolaire, millesimeSortie }) + const formations = await queryFormations({ rentreeScolaire, millesimeSortie, orderBy }) .where("etablissement.codeDepartement", "=", codeDepartement) .execute(); diff --git a/server/src/modules/data/usecases/getDataForPanorama/getDataForPanorama.usecase.ts b/server/src/modules/data/usecases/getDataForPanorama/getDataForPanorama.usecase.ts index 3dc37bd89..2a2cc9ebb 100644 --- a/server/src/modules/data/usecases/getDataForPanorama/getDataForPanorama.usecase.ts +++ b/server/src/modules/data/usecases/getDataForPanorama/getDataForPanorama.usecase.ts @@ -8,8 +8,17 @@ import { export const [getDataForPanoramaRegion] = inject( { queryFormationsRegion }, (deps) => - async ({ codeRegion }: { codeRegion: string }) => { - const formations = await deps.queryFormationsRegion({ codeRegion }); + async ( + { + codeRegion, + orderBy + }: { + codeRegion: string; + orderBy?: { column: string; order: "asc" | "desc" }; + }) => { + console.log("codeRegion", codeRegion) + console.log("orderBy", orderBy) + const formations = await deps.queryFormationsRegion({ codeRegion, orderBy }); return { formations, @@ -20,9 +29,17 @@ export const [getDataForPanoramaRegion] = inject( export const [getDataForPanoramaDepartement] = inject( { queryFormationsDepartement }, (deps) => - async ({ codeDepartement }: { codeDepartement: string }) => { + async ( + { + codeDepartement, + orderBy + }: { + codeDepartement: string; + orderBy?: { column: string; order: "asc" | "desc" }; + }) => { const formations = await deps.queryFormationsDepartement({ codeDepartement, + orderBy }); return { diff --git a/server/src/modules/data/usecases/getEtablissements/dependencies.ts b/server/src/modules/data/usecases/getEtablissements/dependencies.ts index 1d1d4a6f8..2623b48bf 100644 --- a/server/src/modules/data/usecases/getEtablissements/dependencies.ts +++ b/server/src/modules/data/usecases/getEtablissements/dependencies.ts @@ -153,7 +153,7 @@ const findEtablissementsInDb = async ({ cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", - }).as("tauxPoursuiteEtudes"), + }).as("tauxPoursuite"), (eb) => withInsertionReg({ eb, @@ -161,7 +161,7 @@ const findEtablissementsInDb = async ({ cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", - }).as("tauxInsertion6mois"), + }).as("tauxInsertion"), (eb) => withTauxDevenirFavorableReg({ eb, diff --git a/server/src/modules/data/usecases/getFormations/dependencies.ts b/server/src/modules/data/usecases/getFormations/dependencies.ts index 3ae8b0f6f..c0166fbfd 100644 --- a/server/src/modules/data/usecases/getFormations/dependencies.ts +++ b/server/src/modules/data/usecases/getFormations/dependencies.ts @@ -155,14 +155,14 @@ const findFormationsInDb = async ({ cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", - }).as("tauxPoursuiteEtudes"), + }).as("tauxPoursuite"), withInsertionReg({ eb, millesimeSortie, cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", - }).as("tauxInsertion6mois"), + }).as("tauxInsertion"), withTauxDevenirFavorableReg({ eb, millesimeSortie, diff --git a/shared/client/etablissements/etablissements.schema.ts b/shared/client/etablissements/etablissements.schema.ts index ac65c299c..2ccb9eee0 100644 --- a/shared/client/etablissements/etablissements.schema.ts +++ b/shared/client/etablissements/etablissements.schema.ts @@ -27,8 +27,8 @@ const EtablissementLineSchema = Type.Object({ effectif3: Type.Optional(Type.Number()), tauxPression: Type.Optional(Type.Number()), tauxRemplissage: Type.Optional(Type.Number()), - tauxPoursuiteEtudes: Type.Optional(Type.Number()), - tauxInsertion6mois: Type.Optional(Type.Number()), + tauxPoursuite: Type.Optional(Type.Number()), + tauxInsertion: Type.Optional(Type.Number()), tauxDevenirFavorable: Type.Optional(Type.Number()), valeurAjoutee: Type.Optional(Type.Number()), CPC: Type.Optional(Type.String()), @@ -114,8 +114,8 @@ export const etablissementSchemas = { libelleNiveauDiplome: Type.Optional(Type.String()), effectif: Type.Optional(Type.Number()), tauxPression: Type.Optional(Type.Number()), - tauxInsertion6mois: Type.Optional(Type.Number()), - tauxPoursuiteEtudes: Type.Optional(Type.Number()), + tauxInsertion: Type.Optional(Type.Number()), + tauxPoursuite: Type.Optional(Type.Number()), tauxDevenirFavorable: Type.Optional(Type.Number()), positionQuadrant: Type.Optional(Type.String()), CPC: Type.Optional(Type.String()), @@ -147,8 +147,8 @@ export const etablissementSchemas = { nbFormations: Type.Number(), tauxPression: Type.Optional(Type.Number()), tauxRemplissage: Type.Optional(Type.Number()), - tauxPoursuiteEtudes: Type.Optional(Type.Number()), - tauxInsertion6mois: Type.Optional(Type.Number()), + tauxPoursuite: Type.Optional(Type.Number()), + tauxInsertion: Type.Optional(Type.Number()), }), }, }, @@ -167,8 +167,8 @@ export const etablissementSchemas = { nbFormations: Type.Number(), tauxPression: Type.Optional(Type.Number()), tauxRemplissage: Type.Optional(Type.Number()), - tauxPoursuiteEtudes: Type.Optional(Type.Number()), - tauxInsertion6mois: Type.Optional(Type.Number()), + tauxPoursuite: Type.Optional(Type.Number()), + tauxInsertion: Type.Optional(Type.Number()), }), }, }, diff --git a/shared/client/formations/formation.schema.ts b/shared/client/formations/formation.schema.ts index 5d3d9914a..dde1883c0 100644 --- a/shared/client/formations/formation.schema.ts +++ b/shared/client/formations/formation.schema.ts @@ -22,8 +22,8 @@ const FormationLineSchema = Type.Object({ effectif3: Type.Optional(Type.Number()), tauxRemplissage: Type.Optional(Type.Number()), tauxPression: Type.Optional(Type.Number()), - tauxInsertion6mois: Type.Optional(Type.Number()), - tauxPoursuiteEtudes: Type.Optional(Type.Number()), + tauxInsertion: Type.Optional(Type.Number()), + tauxPoursuite: Type.Optional(Type.Number()), tauxDevenirFavorable: Type.Optional(Type.Number()), CPC: Type.Optional(Type.String()), CPCSecteur: Type.Optional(Type.String()), @@ -69,10 +69,10 @@ const FormationSchema = Type.Object({ effectifPrecedent: Type.Optional(Type.Number()), tauxRemplissage: Type.Optional(Type.Number()), tauxPression: Type.Optional(Type.Number()), - tauxInsertion6mois: Type.Number(), - tauxInsertion6moisPrecedent: Type.Optional(Type.Number()), - tauxPoursuiteEtudes: Type.Number(), - tauxPoursuiteEtudesPrecedent: Type.Optional(Type.Number()), + tauxInsertion: Type.Number(), + tauxInsertionPrecedent: Type.Optional(Type.Number()), + tauxPoursuite: Type.Number(), + tauxPoursuitePrecedent: Type.Optional(Type.Number()), tauxDevenirFavorable: Type.Number(), positionQuadrant: Type.Optional(Type.String()), CPC: Type.Optional(Type.String()), @@ -120,6 +120,8 @@ export const formationSchemas = { getDataForPanoramaRegion: { querystring: Type.Object({ codeRegion: Type.String(), + order: Type.Optional(Type.Union([Type.Literal("asc"), Type.Literal("desc")])), + orderBy: Type.Optional(Type.KeyOf(FormationSchema)), }), response: { 200: Type.Object({ @@ -130,6 +132,8 @@ export const formationSchemas = { getDataForPanoramaDepartement: { querystring: Type.Object({ codeDepartement: Type.String(), + order: Type.Optional(Type.Union([Type.Literal("asc"), Type.Literal("desc")])), + orderBy: Type.Optional(Type.KeyOf(FormationSchema)), }), response: { 200: Type.Object({ diff --git a/ui/app/(wrapped)/console/etablissements/components/LineContent.tsx b/ui/app/(wrapped)/console/etablissements/components/LineContent.tsx index 93b037857..c691ac9f9 100644 --- a/ui/app/(wrapped)/console/etablissements/components/LineContent.tsx +++ b/ui/app/(wrapped)/console/etablissements/components/LineContent.tsx @@ -72,16 +72,10 @@ export const EtablissementLineContent = ({ - + - + handleOrder("tauxInsertion6mois")} + onClick={() => handleOrder("tauxInsertion")} > - - {ETABLISSEMENTS_COLUMNS.tauxInsertion6mois} + + {ETABLISSEMENTS_COLUMNS.tauxInsertion} handleOrder("tauxPoursuiteEtudes")} + onClick={() => handleOrder("tauxPoursuite")} > - - {ETABLISSEMENTS_COLUMNS.tauxPoursuiteEtudes} + + {ETABLISSEMENTS_COLUMNS.tauxPoursuite} - + - + handleOrder("tauxInsertion6mois")} + onClick={() => handleOrder("tauxInsertion")} > - - {FORMATIONS_COLUMNS.tauxInsertion6mois} + + {FORMATIONS_COLUMNS.tauxInsertion} handleOrder("tauxPoursuiteEtudes")} + onClick={() => handleOrder("tauxPoursuite")} > - - {FORMATIONS_COLUMNS.tauxPoursuiteEtudes} + + {FORMATIONS_COLUMNS.tauxPoursuite} item.cfd + item.dispositifId} data={formations?.map((item) => ({ ...item, - tauxInsertion6mois: item.tauxInsertion, - tauxPoursuiteEtudes: item.tauxPoursuite, effectif: item.differencePlaces, }))} itemColor={(item) => diff --git a/ui/app/(wrapped)/panorama/components/FormationTooltipContent.tsx b/ui/app/(wrapped)/panorama/components/FormationTooltipContent.tsx index aad3c6419..d813d3159 100644 --- a/ui/app/(wrapped)/panorama/components/FormationTooltipContent.tsx +++ b/ui/app/(wrapped)/panorama/components/FormationTooltipContent.tsx @@ -42,7 +42,7 @@ export const FormationTooltipContent = ({ mb="2" w="100%" continuum={formation.continuum} - value={formation.tauxInsertion6mois} + value={formation.tauxInsertion} /> Taux de pousuite d'études régional : @@ -50,7 +50,7 @@ export const FormationTooltipContent = ({ ); diff --git a/ui/app/(wrapped)/panorama/components/IndicateursSection.tsx b/ui/app/(wrapped)/panorama/components/IndicateursSection.tsx index 088540810..ca78adb96 100644 --- a/ui/app/(wrapped)/panorama/components/IndicateursSection.tsx +++ b/ui/app/(wrapped)/panorama/components/IndicateursSection.tsx @@ -135,9 +135,7 @@ export const IndicateursSection = ({ item.tauxInsertion6moisPrecedent; + item.tauxInsertionPrecedent !== undefined && + item.tauxInsertion > item.tauxInsertionPrecedent; } if (tendances["insertion_baisse"] === true) { mustBeReturned = mustBeReturned && - item.tauxInsertion6moisPrecedent !== undefined && - item.tauxInsertion6mois < item.tauxInsertion6moisPrecedent; + item.tauxInsertionPrecedent !== undefined && + item.tauxInsertion < item.tauxInsertionPrecedent; } if (tendances["poursuite_hausse"] === true) { mustBeReturned = mustBeReturned && - item.tauxPoursuiteEtudesPrecedent !== undefined && - item.tauxPoursuiteEtudes > item.tauxPoursuiteEtudesPrecedent; + item.tauxPoursuitePrecedent !== undefined && + item.tauxPoursuite > item.tauxPoursuitePrecedent; } if (tendances["poursuite_baisse"] === true) { mustBeReturned = mustBeReturned && - item.tauxPoursuiteEtudesPrecedent !== undefined && - item.tauxPoursuiteEtudes < item.tauxPoursuiteEtudesPrecedent; + item.tauxPoursuitePrecedent !== undefined && + item.tauxPoursuite < item.tauxPoursuitePrecedent; } if (tendances["effectif_hausse"] === true) { mustBeReturned = @@ -142,12 +143,16 @@ export const QuadrantSection = ({ meanInsertion, codeNiveauDiplome, libelleFiliere, + order, + handleOrder, }: { quadrantFormations?: PanoramaFormations; meanPoursuite?: number; meanInsertion?: number; codeNiveauDiplome?: string[]; libelleFiliere?: string[]; + order?: Partial; + handleOrder: (column: Order["orderBy"]) => void; }) => { const [effectifMin, setEffectifMin] = useState(0); const tendancesDefaultValue = { @@ -348,6 +353,31 @@ export const QuadrantSection = ({ typeVue === "quadrant" ? "tableau" : "quadrant" }`} + @@ -371,8 +401,8 @@ export const QuadrantSection = ({ meanInsertion={meanInsertion} data={filteredFormations.map((formation) => ({ ...formation, - tauxInsertion: formation.tauxInsertion6mois, - tauxPoursuite: formation.tauxPoursuiteEtudes, + tauxInsertion: formation.tauxInsertion, + tauxPoursuite: formation.tauxPoursuite, }))} TooltipContent={FormationTooltipContent} itemId={(item) => @@ -385,9 +415,13 @@ export const QuadrantSection = ({ ({ ...formation, - tauxInsertion: formation.tauxInsertion6mois, - tauxPoursuite: formation.tauxPoursuiteEtudes, + tauxInsertion: formation.tauxInsertion, + tauxPoursuite: formation.tauxPoursuite, }))} + order={order} + handleOrder={(column?: string) => + handleOrder(column as Order["orderBy"]) + } /> ))} {!filteredFormations && } diff --git a/ui/app/(wrapped)/panorama/departement/[codeDepartement]/page.tsx b/ui/app/(wrapped)/panorama/departement/[codeDepartement]/page.tsx index 30889bd10..5becece62 100644 --- a/ui/app/(wrapped)/panorama/departement/[codeDepartement]/page.tsx +++ b/ui/app/(wrapped)/panorama/departement/[codeDepartement]/page.tsx @@ -1,15 +1,18 @@ "use client"; import { useQuery } from "@tanstack/react-query"; -import { useRouter } from "next/navigation"; +import { useRouter, useSearchParams } from "next/navigation"; +import qs from "qs"; import { useState } from "react"; import { api } from "../../../../../api.client"; +import { createParametrizedUrl } from "../../../../../utils/createParametrizedUrl"; import { FiltersSection } from "../../components/FiltersSection"; import { IndicateursSection } from "../../components/IndicateursSection"; import { InfoSection } from "../../components/InfoSection"; import { QuadrantSection } from "../../components/QuadrantSection"; import { TopFlopSection } from "../../components/TopFlopSection"; +import { Order } from "../../types"; export default function Panorama({ params: { codeDepartement }, @@ -19,6 +22,31 @@ export default function Panorama({ }; }) { const router = useRouter(); + const queryParams = useSearchParams(); + const searchParams: { + order?: Partial; + } = qs.parse(queryParams.toString()); + + const setSearchParams = (params: { order?: typeof order }) => { + router.replace( + createParametrizedUrl(location.pathname, { ...searchParams, ...params }) + ); + }; + + const handleOrder = (column: Order["orderBy"]) => { + if (order?.orderBy !== column) { + setSearchParams({ order: { order: "desc", orderBy: column } }); + return; + } + setSearchParams({ + order: { + order: order?.order === "asc" ? "desc" : "asc", + orderBy: column, + }, + }); + }; + + const order = searchParams.order ?? { order: "asc" }; const onCodeDepartementChanged = (codeDepartement: string) => { router.push(`/panorama/departement/${codeDepartement}`); @@ -48,9 +76,12 @@ export default function Panorama({ ); const { data } = useQuery( - ["formationForPanorama", { codeDepartement }], + ["formationForPanorama", codeDepartement, order], api.getDataForPanoramaDepartement({ - query: { codeDepartement }, + query: { + codeDepartement, + ...order, + }, }).call, { keepPreviousData: true, staleTime: 10000000 } ); @@ -75,9 +106,11 @@ export default function Panorama({ Taux de pousuite d'études régional : @@ -48,7 +48,7 @@ export const FormationTooltipContent = ({ ); diff --git a/ui/app/(wrapped)/panorama/etablissement/[uai]/QuadrantSection.tsx b/ui/app/(wrapped)/panorama/etablissement/[uai]/QuadrantSection.tsx index e6c186c78..db209cb4f 100644 --- a/ui/app/(wrapped)/panorama/etablissement/[uai]/QuadrantSection.tsx +++ b/ui/app/(wrapped)/panorama/etablissement/[uai]/QuadrantSection.tsx @@ -53,10 +53,10 @@ export const QuadrantSection = ({ item ): item is RequiredFields< ApiType["formations"][number], - "tauxInsertion6mois" | "tauxPoursuiteEtudes" + "tauxInsertion" | "tauxPoursuite" > => - item.tauxInsertion6mois !== undefined && - item.tauxPoursuiteEtudes !== undefined && + item.tauxInsertion !== undefined && + item.tauxPoursuite !== undefined && (!codeNiveauDiplome?.length || codeNiveauDiplome.includes(item.codeNiveauDiplome)) ), @@ -107,8 +107,8 @@ export const QuadrantSection = ({ InfoTootipContent={InfoTooltipContent} data={filteredFormations.map((formation) => ({ ...formation, - tauxInsertion: formation.tauxInsertion6mois, - tauxPoursuite: formation.tauxPoursuiteEtudes, + tauxInsertion: formation.tauxInsertion, + tauxPoursuite: formation.tauxPoursuite, }))} itemId={(item) => item.cfd + item.dispositifId} effectifSizes={effectifSizes} @@ -117,8 +117,8 @@ export const QuadrantSection = ({ ({ ...formation, - tauxInsertion: formation.tauxInsertion6mois, - tauxPoursuite: formation.tauxPoursuiteEtudes, + tauxInsertion: formation.tauxInsertion, + tauxPoursuite: formation.tauxPoursuite, }))} /> ))} diff --git a/ui/app/(wrapped)/panorama/etablissement/[uai]/RegionSection.tsx b/ui/app/(wrapped)/panorama/etablissement/[uai]/RegionSection.tsx index 5cddab991..35ec9dfa2 100644 --- a/ui/app/(wrapped)/panorama/etablissement/[uai]/RegionSection.tsx +++ b/ui/app/(wrapped)/panorama/etablissement/[uai]/RegionSection.tsx @@ -33,11 +33,11 @@ export const RegionSection = ({ label="Taux de remplissage dans la région" /> diff --git a/ui/app/(wrapped)/panorama/etablissement/[uai]/page.tsx b/ui/app/(wrapped)/panorama/etablissement/[uai]/page.tsx index e5e394271..c1063b697 100644 --- a/ui/app/(wrapped)/panorama/etablissement/[uai]/page.tsx +++ b/ui/app/(wrapped)/panorama/etablissement/[uai]/page.tsx @@ -87,8 +87,8 @@ export default function Panorama({ ; + } = qs.parse(queryParams.toString()); + + const setSearchParams = (params: { order?: typeof order }) => { + router.replace( + createParametrizedUrl(location.pathname, { ...searchParams, ...params }) + ); + }; + + const handleOrder = (column: Order["orderBy"]) => { + if (order?.orderBy !== column) { + setSearchParams({ order: { order: "desc", orderBy: column } }); + return; + } + setSearchParams({ + order: { + order: order?.order === "asc" ? "desc" : "asc", + orderBy: column, + }, + }); + }; + + const order = searchParams.order ?? { order: "asc" }; const onCodeRegionChanged = (codeRegion: string) => { router.push(`/panorama/region/${codeRegion}`); @@ -48,9 +76,12 @@ export default function Panorama({ ); const { data } = useQuery( - ["formationForPanorama", { codeRegion }], + ["formationForPanorama", codeRegion, order], api.getDataForPanoramaRegion({ - query: { codeRegion }, + query: { + codeRegion, + ...order, + }, }).call, { keepPreviousData: true, staleTime: 10000000 } ); @@ -74,9 +105,11 @@ export default function Panorama({ [0]["query"]; + export type PanoramaFormationRegion = ApiType< typeof api.getDataForPanoramaRegion >["formations"][number]; @@ -30,3 +33,6 @@ export type StatsFormationsDepartement = ApiType< export type StatsFormations = | StatsFormationsRegion | StatsFormationsDepartement; + + +export type Order = Pick; diff --git a/ui/app/(wrapped)/pilotage-reforme/components/VueRegionAcademieSection.tsx b/ui/app/(wrapped)/pilotage-reforme/components/VueRegionAcademieSection.tsx index 83f09138d..76044cb68 100644 --- a/ui/app/(wrapped)/pilotage-reforme/components/VueRegionAcademieSection.tsx +++ b/ui/app/(wrapped)/pilotage-reforme/components/VueRegionAcademieSection.tsx @@ -17,8 +17,8 @@ import { Order, PilotageReformeStatsRegion } from "../types"; const PILOTAGE_REFORME_STATS_REGIONS_COLUMNS = { libelleRegion: "Région", - tauxInsertion6mois: "Emploi", - tauxPoursuiteEtudes: "Poursuite", + tauxInsertion: "Emploi", + tauxPoursuite: "Poursuite", tauxDecrochage: "Décrochage", tauxTransformation: "Transformation", }; @@ -103,7 +103,7 @@ export const VueRegionAcademieSection = ({ onClick={() => handleOrder("insertion")} > - {PILOTAGE_REFORME_STATS_REGIONS_COLUMNS.tauxInsertion6mois} + {PILOTAGE_REFORME_STATS_REGIONS_COLUMNS.tauxInsertion} handleOrder("poursuite")} > - {PILOTAGE_REFORME_STATS_REGIONS_COLUMNS.tauxPoursuiteEtudes} + {PILOTAGE_REFORME_STATS_REGIONS_COLUMNS.tauxPoursuite} diff --git a/ui/components/TableQuadrant.tsx b/ui/components/TableQuadrant.tsx index 1bc1b77a4..9c2643035 100644 --- a/ui/components/TableQuadrant.tsx +++ b/ui/components/TableQuadrant.tsx @@ -154,10 +154,10 @@ export const TableQuadrant = ({ - + - + ))} From cbd77c9731a62ef2803320289589f152bf713945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20D=C3=A9tr=C3=A9?= Date: Thu, 9 Nov 2023 17:49:06 +0100 Subject: [PATCH 04/28] fix: tooltips --- ui/app/(wrapped)/console/formations/page.tsx | 8 +++++++- .../restitution/ConsoleSection/ConsoleSection.tsx | 8 +++++++- ui/components/TableQuadrant.tsx | 15 +++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/ui/app/(wrapped)/console/formations/page.tsx b/ui/app/(wrapped)/console/formations/page.tsx index 8f1cd032c..cfa7f7f6c 100644 --- a/ui/app/(wrapped)/console/formations/page.tsx +++ b/ui/app/(wrapped)/console/formations/page.tsx @@ -495,7 +495,13 @@ export default function Formations() { {FORMATIONS_COLUMNS.libelleFiliere} - {FORMATIONS_COLUMNS.positionQuadrant} + + {FORMATIONS_COLUMNS.positionQuadrant} + + diff --git a/ui/app/(wrapped)/intentions/restitution/ConsoleSection/ConsoleSection.tsx b/ui/app/(wrapped)/intentions/restitution/ConsoleSection/ConsoleSection.tsx index dc3c552a8..9aff6ad29 100644 --- a/ui/app/(wrapped)/intentions/restitution/ConsoleSection/ConsoleSection.tsx +++ b/ui/app/(wrapped)/intentions/restitution/ConsoleSection/ConsoleSection.tsx @@ -303,7 +303,13 @@ export const ConsoleSection = ({ {STATS_DEMANDES_COLUMNS.commentaire} - {STATS_DEMANDES_COLUMNS.positionQuadrant} + + {STATS_DEMANDES_COLUMNS.positionQuadrant} + + handleOrder && handleOrder("tauxPression")} + textAlign={"center"} > {handleOrder && } TX PRESSION @@ -110,22 +113,34 @@ export const TableQuadrant = ({ /> handleOrder && handleOrder("tauxInsertion")} + textAlign={"center"} > {handleOrder && } TX EMPLOI + handleOrder && handleOrder("tauxPoursuite")} + textAlign={"center"} > {handleOrder && } TX POURSUITE + From 02527918249ceadcc38918e7524be850f0079657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20D=C3=A9tr=C3=A9?= Date: Fri, 10 Nov 2023 11:43:12 +0100 Subject: [PATCH 05/28] fix: divers panorama + refacto --- .../getDepartementsStats.query.ts | 3 +- .../data/queries/utils/positionQuadrant.ts | 2 + .../data/routes/etablissements.routes.ts | 11 +- .../getDataForPanorama/dependencies.ts | 2 +- .../getEtablissement/dependencies.ts} | 108 ++++++++++++++---- .../getEtablissement.usecase.ts | 30 +++++ .../getFormationsStatsQuery.dep.ts | 16 +-- ...etFormationsTransformationStats.usecase.ts | 9 +- .../dependencies.ts | 4 +- .../getRestitutionIntentionsStats.usecase.ts | 75 ++++++------ .../etablissements/etablissements.client.ts | 14 +-- .../etablissements/etablissements.schema.ts | 63 +++++----- .../departement/[codeDepartement]/page.tsx | 10 +- .../etablissement/[uai]/FormationsSection.tsx | 4 +- .../etablissement/[uai]/QuadrantSection.tsx | 41 ++++++- .../panorama/etablissement/[uai]/page.tsx | 39 ++++++- .../panorama/region/[codeRegion]/page.tsx | 10 +- ui/app/(wrapped)/panorama/types.ts | 16 ++- 18 files changed, 326 insertions(+), 131 deletions(-) rename server/src/modules/data/{queries/getEtablissement/getEtablissement.query.ts => usecases/getEtablissement/dependencies.ts} (55%) create mode 100644 server/src/modules/data/usecases/getEtablissement/getEtablissement.usecase.ts diff --git a/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts b/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts index 785911790..976a7f7ea 100644 --- a/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts +++ b/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts @@ -2,7 +2,7 @@ import { sql } from "kysely"; import { kdb } from "../../../../db/db"; import { effectifAnnee } from "../utils/effectifAnnee"; -import { notHistorique } from "../utils/notHistorique"; +import { notHistorique, notHistoriqueIndicateurRegionSortie } from "../utils/notHistorique"; import { selectTauxInsertion6moisAgg } from "../utils/tauxInsertion6mois"; import { selectTauxPoursuiteAgg } from "../utils/tauxPoursuite"; import { selectTauxPressionAgg } from "../utils/tauxPression"; @@ -31,6 +31,7 @@ export const getDepartementsStats = async ({ "departement.codeRegion", "indicateurRegionSortie.codeRegion" ) + .where(notHistoriqueIndicateurRegionSortie) .where("departement.codeDepartement", "=", codeDepartement) .$call((q) => { if (!codeDiplome?.length) return q; diff --git a/server/src/modules/data/queries/utils/positionQuadrant.ts b/server/src/modules/data/queries/utils/positionQuadrant.ts index 5214a5e98..a1a0d66d5 100644 --- a/server/src/modules/data/queries/utils/positionQuadrant.ts +++ b/server/src/modules/data/queries/utils/positionQuadrant.ts @@ -1,6 +1,7 @@ import { ExpressionBuilder, sql } from "kysely"; import { DB } from "../../../../db/schema"; +import { notHistoriqueIndicateurRegionSortie } from "./notHistorique"; import { selectTauxInsertion6mois, selectTauxInsertion6moisAgg, @@ -81,6 +82,7 @@ export function withPositionQuadrant>({ sql`ANY(array_agg(${eb.ref(codeRegionRef)}))` ) .where("indicateurRegionSortie.millesimeSortie", "=", millesimeSortie) + .where(notHistoriqueIndicateurRegionSortie) .innerJoin( "formation", "formation.codeFormationDiplome", diff --git a/server/src/modules/data/routes/etablissements.routes.ts b/server/src/modules/data/routes/etablissements.routes.ts index 553c437e8..f9476dccc 100644 --- a/server/src/modules/data/routes/etablissements.routes.ts +++ b/server/src/modules/data/routes/etablissements.routes.ts @@ -1,7 +1,7 @@ import { ROUTES_CONFIG } from "shared"; import { Server } from "../../../server"; -import { getEtablissement } from "../queries/getEtablissement/getEtablissement.query"; +import { getEtablissement } from "../usecases/getEtablissement/getEtablissement.usecase"; import { getEtablissements } from "../usecases/getEtablissements/getEtablissements.usecase"; export const etablissementsRoutes = ({ server }: { server: Server }) => { server.get( @@ -18,11 +18,14 @@ export const etablissementsRoutes = ({ server }: { server: Server }) => { ); server.get( - "/etablissement/:uai", + "/etablissement", { schema: ROUTES_CONFIG.getEtablissement }, async (request, response) => { - const { uai } = request.params; - const etablissement = await getEtablissement({ uai }); + const { order, orderBy, ...filters } = request.query; + const etablissement = await getEtablissement({ + ...filters, + orderBy: order && orderBy ? { order, column: orderBy } : undefined, + }); if (!etablissement) return response.status(404).send(); response.status(200).send(etablissement); } diff --git a/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts b/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts index 05cc17ecc..93ef5814c 100644 --- a/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts +++ b/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts @@ -182,7 +182,7 @@ const queryFormations = ({ sql`${sql.raw(orderBy.order)} NULLS LAST` ); }) - .orderBy("tauxDevenirFavorable", "desc") + .orderBy("libelleDiplome", "asc") export const queryFormationsRegion = async ({ codeRegion, diff --git a/server/src/modules/data/queries/getEtablissement/getEtablissement.query.ts b/server/src/modules/data/usecases/getEtablissement/dependencies.ts similarity index 55% rename from server/src/modules/data/queries/getEtablissement/getEtablissement.query.ts rename to server/src/modules/data/usecases/getEtablissement/dependencies.ts index 94be14db4..aea6542fb 100644 --- a/server/src/modules/data/queries/getEtablissement/getEtablissement.query.ts +++ b/server/src/modules/data/usecases/getEtablissement/dependencies.ts @@ -2,22 +2,26 @@ import { sql } from "kysely"; import { jsonArrayFrom } from "kysely/helpers/postgres"; import { kdb } from "../../../../db/db"; -import { cleanNull } from "../../../../utils/noNull"; -import { hasContinuum } from "../utils/hasContinuum"; -import { notHistorique } from "../utils/notHistorique"; -import { withPositionQuadrant } from "../utils/positionQuadrant"; -import { withInsertionReg } from "../utils/tauxInsertion6mois"; -import { withPoursuiteReg } from "../utils/tauxPoursuite"; -import { selectTauxPression } from "../utils/tauxPression"; +import { effectifAnnee } from "../../queries/utils/effectifAnnee"; +import { hasContinuum } from "../../queries/utils/hasContinuum"; +import { notHistorique } from "../../queries/utils/notHistorique"; +import { withPositionQuadrant } from "../../queries/utils/positionQuadrant"; +import { withTauxDevenirFavorableReg } from "../../queries/utils/tauxDevenirFavorable"; +import { withInsertionReg } from "../../queries/utils/tauxInsertion6mois"; +import { withPoursuiteReg } from "../../queries/utils/tauxPoursuite"; +import { selectTauxPression } from "../../queries/utils/tauxPression"; +import { selectTauxRemplissageAgg } from "../../queries/utils/tauxRemplissage"; -export const getEtablissement = async ({ +const getEtablissementInDb = async ({ uai, millesimeSortie = "2020_2021", rentreeScolaire = "2022", + orderBy }: { uai: string; millesimeSortie?: string; rentreeScolaire?: string; + orderBy?: { column: string; order: "asc" | "desc" }; }) => { const etablissement = await kdb .selectFrom("etablissement") @@ -69,9 +73,8 @@ export const getEtablissement = async ({ "dispositif.codeDispositif", "formationEtablissement.dispositifId" ) - .select([ - "formation.libelleDiplome", - "formationEtablissement.cfd", + .select((sb) => [ + "formationEtablissement.cfd as codeFormationDiplome", "formationEtablissement.dispositifId", "libelleDispositif", "formation.codeNiveauDiplome", @@ -79,9 +82,16 @@ export const getEtablissement = async ({ "formation.libelleFiliere", "formation.CPC", "formation.CPCSecteur", + sql`CONCAT(${sb.ref("formation.libelleDiplome")},' (',${sb.ref("niveauDiplome.libelleNiveauDiplome")}, ')')`.as("libelleDiplome"), "formation.CPCSousSecteur", - sql`NULLIF((jsonb_extract_path("indicateurEntree"."effectifs","indicateurEntree"."anneeDebut"::text)), 'null')::INT - `.as("effectif"), + sql`COUNT(e."UAI")`.as("nbEtablissement"), + selectTauxRemplissageAgg("indicateurEntree").as("tauxRemplissage"), + sql`SUM(${effectifAnnee({ alias: "indicateurEntree" })})`.as( + "effectif" + ), + sql`SUM(${effectifAnnee({ alias: "indicateurEntree" })})`.as( + "effectifPrecedent" + ), selectTauxPression("indicateurEntree").as("tauxPression"), ]) .select((eb) => [ @@ -93,6 +103,22 @@ export const getEtablissement = async ({ dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", }).as("continuum"), + (eb) => + withInsertionReg({ + eb, + millesimeSortie: "2019_2020", + cfdRef: "formationEtablissement.cfd", + dispositifIdRef: "formationEtablissement.dispositifId", + codeRegionRef: "etablissement.codeRegion", + }).as("tauxInsertionPrecedent"), + (eb) => + withPoursuiteReg({ + eb, + millesimeSortie: "2019_2020", + cfdRef: "formationEtablissement.cfd", + dispositifIdRef: "formationEtablissement.dispositifId", + codeRegionRef: "etablissement.codeRegion", + }).as("tauxPoursuitePrecedent"), withInsertionReg({ eb, millesimeSortie, @@ -107,6 +133,13 @@ export const getEtablissement = async ({ dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", }).as("tauxPoursuite"), + withTauxDevenirFavorableReg({ + eb, + millesimeSortie, + cfdRef: "formationEtablissement.cfd", + dispositifIdRef: "formationEtablissement.dispositifId", + codeRegionRef: "etablissement.codeRegion", + }).as("tauxDevenirFavorable"), withPositionQuadrant({ eb, millesimeSortie, @@ -115,6 +148,35 @@ export const getEtablissement = async ({ codeRegionRef: "etablissement.codeRegion", }).as("positionQuadrant"), ]) + .$narrowType<{ + tauxInsertion: number; + tauxPoursuite: number; + tauxDevenirFavorable: number; + }>() + .having( + (eb) => + withInsertionReg({ + eb, + millesimeSortie, + cfdRef: "formationEtablissement.cfd", + dispositifIdRef: "formationEtablissement.dispositifId", + codeRegionRef: "etablissement.codeRegion", + }), + "is not", + null + ) + .having( + (eb) => + withPoursuiteReg({ + eb, + millesimeSortie, + cfdRef: "formationEtablissement.cfd", + dispositifIdRef: "formationEtablissement.dispositifId", + codeRegionRef: "etablissement.codeRegion", + }), + "is not", + null + ) .where(notHistorique) .whereRef("formationEtablissement.UAI", "=", "etablissement.UAI") .groupBy([ @@ -132,6 +194,14 @@ export const getEtablissement = async ({ "libelleNiveauDiplome", "libelleDispositif", ]) + .$call((q) => { + if (!orderBy) return q; + return q.orderBy( + sql.ref(orderBy.column), + sql`${sql.raw(orderBy.order)} NULLS LAST` + ); + }) + .orderBy("libelleDiplome", "asc") ).as("formations") ) .where("etablissement.UAI", "=", uai) @@ -144,11 +214,9 @@ export const getEtablissement = async ({ ]) .executeTakeFirst(); - return ( - etablissement && - cleanNull({ - ...etablissement, - formations: etablissement.formations.map(cleanNull), - }) - ); + return etablissement; +}; + +export const dependencies = { + getEtablissementInDb, }; diff --git a/server/src/modules/data/usecases/getEtablissement/getEtablissement.usecase.ts b/server/src/modules/data/usecases/getEtablissement/getEtablissement.usecase.ts new file mode 100644 index 000000000..2d8a4e55b --- /dev/null +++ b/server/src/modules/data/usecases/getEtablissement/getEtablissement.usecase.ts @@ -0,0 +1,30 @@ +import { inject } from "injecti"; + +import { cleanNull } from "../../../../utils/noNull"; +import { dependencies } from "./dependencies"; + +export const [getEtablissement] = inject( + { getEtablissementInD: dependencies.getEtablissementInDb }, + (deps) => + async ( + { + uai, + orderBy + }: { + uai: string; + orderBy?: { column: string; order: "asc" | "desc" }; + }) => { + const etablissement = await deps.getEtablissementInD({ + uai, + orderBy + }); + + return ( + etablissement && + cleanNull({ + ...etablissement, + formations: etablissement.formations.map(cleanNull), + }) + ); + } +); diff --git a/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsStatsQuery.dep.ts b/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsStatsQuery.dep.ts index 022d93489..3acadee1d 100644 --- a/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsStatsQuery.dep.ts +++ b/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsStatsQuery.dep.ts @@ -63,6 +63,7 @@ export const getFormationsTransformationStatsQuery = ({ status, type, rentreeScolaire = "2024", + millesimeSortie = "2020_2021", codeRegion, codeAcademie, codeDepartement, @@ -74,6 +75,7 @@ export const getFormationsTransformationStatsQuery = ({ status?: "draft" | "submitted"; type?: "fermeture" | "ouverture"; rentreeScolaire?: string; + millesimeSortie?: string; codeRegion?: string; codeAcademie?: string; codeDepartement?: string; @@ -113,14 +115,14 @@ export const getFormationsTransformationStatsQuery = ({ (eb) => withInsertionReg({ eb, - millesimeSortie: "2020_2021", + millesimeSortie, cfdRef: "demande.cfd", dispositifIdRef: "demande.dispositifId", codeRegionRef: "dataEtablissement.codeRegion", }).as("tauxInsertion"), withPoursuiteReg({ eb, - millesimeSortie: "2020_2021", + millesimeSortie, cfdRef: "demande.cfd", dispositifIdRef: "demande.dispositifId", codeRegionRef: "dataEtablissement.codeRegion", @@ -133,14 +135,14 @@ export const getFormationsTransformationStatsQuery = ({ }).as("tauxPression"), withTauxDevenirFavorableReg({ eb, - millesimeSortie: "2020_2021", + millesimeSortie, cfdRef: "demande.cfd", dispositifIdRef: "demande.dispositifId", codeRegionRef: "dataEtablissement.codeRegion", }).as("tauxDevenirFavorable"), withPositionQuadrant({ eb, - millesimeSortie: "2020_2021", + millesimeSortie, cfdRef: "demande.cfd", dispositifIdRef: "demande.dispositifId", codeRegionRef: "dataEtablissement.codeRegion", @@ -156,7 +158,7 @@ export const getFormationsTransformationStatsQuery = ({ eb.fn.sum(selectPlacesTransformees(eb)).as("placesTransformees"), hasContinuum({ eb, - millesimeSortie: "2020_2021", + millesimeSortie, cfdRef: "demande.cfd", dispositifIdRef: "demande.dispositifId", codeRegionRef: "dataEtablissement.codeRegion", @@ -179,7 +181,7 @@ export const getFormationsTransformationStatsQuery = ({ (eb) => withInsertionReg({ eb, - millesimeSortie: "2020_2021", + millesimeSortie, cfdRef: "demande.cfd", dispositifIdRef: "demande.dispositifId", codeRegionRef: "dataEtablissement.codeRegion", @@ -191,7 +193,7 @@ export const getFormationsTransformationStatsQuery = ({ (eb) => withPoursuiteReg({ eb, - millesimeSortie: "2020_2021", + millesimeSortie, cfdRef: "demande.cfd", dispositifIdRef: "demande.dispositifId", codeRegionRef: "dataEtablissement.codeRegion", diff --git a/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsTransformationStats.usecase.ts b/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsTransformationStats.usecase.ts index a5bc38d4c..71ed38476 100644 --- a/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsTransformationStats.usecase.ts +++ b/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsTransformationStats.usecase.ts @@ -6,7 +6,7 @@ import { getRegionStats } from "./getRegionStats.dep"; export const [getFormationsTransformationStats] = inject( { getFormationsTransformationStatsQuery, getRegionStats }, (deps) => - async (filters: { + async (activeFilters: { status?: "draft" | "submitted"; type?: "fermeture" | "ouverture"; rentreeScolaire?: string; @@ -19,11 +19,8 @@ export const [getFormationsTransformationStats] = inject( orderBy?: { column: string; order: "asc" | "desc" }; }) => { const [stats, formations] = await Promise.all([ - deps.getRegionStats({ - ...filters, - millesimeSortie: "2020_2021", - }), - deps.getFormationsTransformationStatsQuery(filters), + deps.getRegionStats(activeFilters), + deps.getFormationsTransformationStatsQuery(activeFilters), ]); return { stats, formations }; } diff --git a/server/src/modules/data/usecases/getRestitutionIntentionsStats/dependencies.ts b/server/src/modules/data/usecases/getRestitutionIntentionsStats/dependencies.ts index 496ac09fc..f4f94e64f 100644 --- a/server/src/modules/data/usecases/getRestitutionIntentionsStats/dependencies.ts +++ b/server/src/modules/data/usecases/getRestitutionIntentionsStats/dependencies.ts @@ -71,7 +71,7 @@ const findRestitutionIntentionsStatsInDB = async ({ uai?: string[]; compensation?: string; user: Pick; - millesimeSortie: string; + millesimeSortie?: string; offset?: number; limit?: number; orderBy?: { order: "asc" | "desc"; column: string }; @@ -315,7 +315,7 @@ const findRestitutionIntentionsStatsInDB = async ({ demande.statsSortieMoyennes?.tauxInsertion ?? undefined, tauxPoursuiteMoyen: demande.statsSortieMoyennes?.tauxPoursuite ?? undefined, - positionQuadrant: + positionQuadrant: demande.statsSortieMoyennes?.positionQuadrant ?? "Hors quadrant", }) ), diff --git a/server/src/modules/data/usecases/getRestitutionIntentionsStats/getRestitutionIntentionsStats.usecase.ts b/server/src/modules/data/usecases/getRestitutionIntentionsStats/getRestitutionIntentionsStats.usecase.ts index 5e13b55ee..ffa361513 100644 --- a/server/src/modules/data/usecases/getRestitutionIntentionsStats/getRestitutionIntentionsStats.usecase.ts +++ b/server/src/modules/data/usecases/getRestitutionIntentionsStats/getRestitutionIntentionsStats.usecase.ts @@ -6,47 +6,44 @@ const getRestitutionIntentionsStatsFactory = findRestitutionIntentionsStatsInDB = dependencies.findRestitutionIntentionsStatsInDB, findFiltersInDb = dependencies.findFiltersInDb, }) => - async (activeFilters: { - status?: "draft" | "submitted"; - codeRegion?: string[]; - rentreeScolaire?: string; - typeDemande?: string[]; - motif?: string[]; - cfd?: string[]; - codeNiveauDiplome?: string[]; - dispositif?: string[]; - filiere?: string[]; - coloration?: string; - amiCMA?: string; - secteur?: string; - cfdFamille?: string[]; - codeDepartement?: string[]; - codeAcademie?: string[]; - commune?: string[]; - uai?: string[]; - compensation?: string; - user: Pick; - offset?: number; - limit?: number; - orderBy?: { - order: "asc" | "desc"; - column: string; - }; - }) => { - const [{ count, demandes }, filters] = await Promise.all([ - findRestitutionIntentionsStatsInDB({ - ...activeFilters, - millesimeSortie: "2020_2021", - }), - findFiltersInDb(activeFilters), - ]); + async (activeFilters: { + status?: "draft" | "submitted"; + codeRegion?: string[]; + rentreeScolaire?: string; + typeDemande?: string[]; + motif?: string[]; + cfd?: string[]; + codeNiveauDiplome?: string[]; + dispositif?: string[]; + filiere?: string[]; + coloration?: string; + amiCMA?: string; + secteur?: string; + cfdFamille?: string[]; + codeDepartement?: string[]; + codeAcademie?: string[]; + commune?: string[]; + uai?: string[]; + compensation?: string; + user: Pick; + offset?: number; + limit?: number; + orderBy?: { + order: "asc" | "desc"; + column: string; + }; + }) => { + const [{ count, demandes }, filters] = await Promise.all([ + findRestitutionIntentionsStatsInDB(activeFilters), + findFiltersInDb(activeFilters), + ]); - return { - count, - filters, - demandes, + return { + count, + filters, + demandes, + }; }; - }; export const getRestitutionIntentionsStats = getRestitutionIntentionsStatsFactory({}); diff --git a/shared/client/etablissements/etablissements.client.ts b/shared/client/etablissements/etablissements.client.ts index 4bcad3e19..428c68f1b 100644 --- a/shared/client/etablissements/etablissements.client.ts +++ b/shared/client/etablissements/etablissements.client.ts @@ -4,16 +4,14 @@ import { createClientMethod } from "../clientFactory"; import { ROUTES_CONFIG } from "../ROUTES_CONFIG"; export const createEtablissementClient = (instance: AxiosInstance) => ({ - getEtablissements: createClientMethod( - { - method: "GET", - url: "/etablissements", - instance, - } - ), + getEtablissements: createClientMethod({ + method: "GET", + url: "/etablissements", + instance, + }), getEtablissement: createClientMethod({ method: "GET", - url: ({ params }) => `/etablissement/${params.uai}`, + url: "/etablissement", instance, }), getRegionStats: createClientMethod({ diff --git a/shared/client/etablissements/etablissements.schema.ts b/shared/client/etablissements/etablissements.schema.ts index 2ccb9eee0..de2ab7120 100644 --- a/shared/client/etablissements/etablissements.schema.ts +++ b/shared/client/etablissements/etablissements.schema.ts @@ -63,6 +63,36 @@ const FiltersSchema = Type.Object({ orderBy: Type.Optional(Type.KeyOf(Type.Omit(EtablissementLineSchema, []))), }); +const FormationSchema = Type.Object({ + codeFormationDiplome: Type.String(), + libelleDiplome: Type.String(), + codeNiveauDiplome: Type.String(), + libelleNiveauDiplome: Type.Optional(Type.String()), + dispositifId: Type.Optional(Type.String()), + libelleDispositif: Type.Optional(Type.String()), + nbEtablissement: Type.Number(), + effectif: Type.Optional(Type.Number()), + effectifPrecedent: Type.Optional(Type.Number()), + tauxRemplissage: Type.Optional(Type.Number()), + tauxPression: Type.Optional(Type.Number()), + tauxInsertion: Type.Number(), + tauxInsertionPrecedent: Type.Optional(Type.Number()), + tauxPoursuite: Type.Number(), + tauxPoursuitePrecedent: Type.Optional(Type.Number()), + tauxDevenirFavorable: Type.Number(), + positionQuadrant: Type.Optional(Type.String()), + CPC: Type.Optional(Type.String()), + CPCSecteur: Type.Optional(Type.String()), + CPCSousSecteur: Type.Optional(Type.String()), + libelleFiliere: Type.Optional(Type.String()), + continuum: Type.Optional( + Type.Object({ + cfd: Type.String(), + libelle: Type.Optional(Type.String()), + }) + ), +}); + export const etablissementSchemas = { getEtablissements: { querystring: Type.Intersect([ @@ -95,7 +125,11 @@ export const etablissementSchemas = { }, }, getEtablissement: { - params: Type.Object({ uai: Type.String() }), + querystring: Type.Object({ + uai: Type.String(), + order: Type.Optional(Type.Union([Type.Literal("asc"), Type.Literal("desc")])), + orderBy: Type.Optional(Type.KeyOf(FormationSchema)), + }), response: { 200: Type.Object({ uai: Type.String(), @@ -104,32 +138,7 @@ export const etablissementSchemas = { valeurAjoutee: Type.Optional(Type.Number()), codeRegion: Type.Optional(Type.String()), libelleRegion: Type.Optional(Type.String()), - formations: Type.Array( - Type.Object({ - cfd: Type.String(), - codeNiveauDiplome: Type.String(), - libelleDiplome: Type.String(), - dispositifId: Type.Optional(Type.String()), - libelleDispositif: Type.Optional(Type.String()), - libelleNiveauDiplome: Type.Optional(Type.String()), - effectif: Type.Optional(Type.Number()), - tauxPression: Type.Optional(Type.Number()), - tauxInsertion: Type.Optional(Type.Number()), - tauxPoursuite: Type.Optional(Type.Number()), - tauxDevenirFavorable: Type.Optional(Type.Number()), - positionQuadrant: Type.Optional(Type.String()), - CPC: Type.Optional(Type.String()), - CPCSecteur: Type.Optional(Type.String()), - CPCSousSecteur: Type.Optional(Type.String()), - libelleFiliere: Type.Optional(Type.String()), - continuum: Type.Optional( - Type.Object({ - cfd: Type.String(), - libelle: Type.Optional(Type.String()), - }) - ), - }) - ), + formations: Type.Array(FormationSchema), }), }, }, diff --git a/ui/app/(wrapped)/panorama/departement/[codeDepartement]/page.tsx b/ui/app/(wrapped)/panorama/departement/[codeDepartement]/page.tsx index 5becece62..17c75ee8e 100644 --- a/ui/app/(wrapped)/panorama/departement/[codeDepartement]/page.tsx +++ b/ui/app/(wrapped)/panorama/departement/[codeDepartement]/page.tsx @@ -12,7 +12,7 @@ import { IndicateursSection } from "../../components/IndicateursSection"; import { InfoSection } from "../../components/InfoSection"; import { QuadrantSection } from "../../components/QuadrantSection"; import { TopFlopSection } from "../../components/TopFlopSection"; -import { Order } from "../../types"; +import { OrderPanoramaFormation } from "../../types"; export default function Panorama({ params: { codeDepartement }, @@ -24,7 +24,7 @@ export default function Panorama({ const router = useRouter(); const queryParams = useSearchParams(); const searchParams: { - order?: Partial; + order?: Partial; } = qs.parse(queryParams.toString()); const setSearchParams = (params: { order?: typeof order }) => { @@ -33,7 +33,7 @@ export default function Panorama({ ); }; - const handleOrder = (column: Order["orderBy"]) => { + const handleOrder = (column: OrderPanoramaFormation["orderBy"]) => { if (order?.orderBy !== column) { setSearchParams({ order: { order: "desc", orderBy: column } }); return; @@ -110,7 +110,9 @@ export default function Panorama({ meanPoursuite={stats?.tauxPoursuite} quadrantFormations={data?.formations} order={order} - handleOrder={handleOrder} + handleOrder={(column?: string) => + handleOrder(column as OrderPanoramaFormation["orderBy"]) + } /> {formations?.map((formation) => ( - + {formation.libelleDiplome} {formation.libelleNiveauDiplome} {formation.effectif} diff --git a/ui/app/(wrapped)/panorama/etablissement/[uai]/QuadrantSection.tsx b/ui/app/(wrapped)/panorama/etablissement/[uai]/QuadrantSection.tsx index db209cb4f..63f07d2ec 100644 --- a/ui/app/(wrapped)/panorama/etablissement/[uai]/QuadrantSection.tsx +++ b/ui/app/(wrapped)/panorama/etablissement/[uai]/QuadrantSection.tsx @@ -1,4 +1,4 @@ -import { ViewIcon } from "@chakra-ui/icons"; +import { DownloadIcon, ViewIcon } from "@chakra-ui/icons"; import { AspectRatio, Box, @@ -16,6 +16,8 @@ import { ApiType } from "shared"; import { api } from "../../../../../api.client"; import { Quadrant } from "../../../../../components/Quadrant"; import { TableQuadrant } from "../../../../../components/TableQuadrant"; +import { downloadCsv } from "../../../../../utils/downloadCsv"; +import { OrderPanoramaEtablissement } from "../../types"; import { FormationTooltipContent } from "./FormationTooltipContent"; type RequiredFields = T & Required>; @@ -33,12 +35,16 @@ export const QuadrantSection = ({ meanInsertion, codeNiveauDiplome, rentreeScolaire, + order, + handleOrder, }: { quadrantFormations?: ApiType["formations"]; meanPoursuite?: number; meanInsertion?: number; codeNiveauDiplome?: string[]; rentreeScolaire?: string; + order?: Partial; + handleOrder: (column: OrderPanoramaEtablissement["orderBy"]) => void; }) => { const [typeVue, setTypeVue] = useState<"quadrant" | "tableau">("quadrant"); @@ -82,6 +88,31 @@ export const QuadrantSection = ({ typeVue === "quadrant" ? "tableau" : "quadrant" }`} + @@ -110,7 +141,9 @@ export const QuadrantSection = ({ tauxInsertion: formation.tauxInsertion, tauxPoursuite: formation.tauxPoursuite, }))} - itemId={(item) => item.cfd + item.dispositifId} + itemId={(item) => + item.codeFormationDiplome + item.dispositifId + } effectifSizes={effectifSizes} /> ) : ( @@ -120,6 +153,10 @@ export const QuadrantSection = ({ tauxInsertion: formation.tauxInsertion, tauxPoursuite: formation.tauxPoursuite, }))} + order={order} + handleOrder={(column?: string) => + handleOrder(column as OrderPanoramaEtablissement["orderBy"]) + } /> ))} {!filteredFormations && } diff --git a/ui/app/(wrapped)/panorama/etablissement/[uai]/page.tsx b/ui/app/(wrapped)/panorama/etablissement/[uai]/page.tsx index c1063b697..eacc4da4c 100644 --- a/ui/app/(wrapped)/panorama/etablissement/[uai]/page.tsx +++ b/ui/app/(wrapped)/panorama/etablissement/[uai]/page.tsx @@ -1,12 +1,15 @@ "use client"; import { useQuery } from "@tanstack/react-query"; -import { useRouter } from "next/navigation"; +import { useRouter, useSearchParams } from "next/navigation"; +import qs from "qs"; import { useContext, useState } from "react"; import { api } from "../../../../../api.client"; +import { createParametrizedUrl } from "../../../../../utils/createParametrizedUrl"; import { UaiFilterContext } from "../../../../layoutClient"; import { InfoSection } from "../../components/InfoSection"; +import { OrderPanoramaEtablissement } from "../../types"; import { PanoramaSelection } from "../PanoramaSelection"; import { EtablissementSection } from "./EtablissementSection"; import { FiltersSection } from "./FiltersSection"; @@ -22,6 +25,31 @@ export default function Panorama({ }; }) { const router = useRouter(); + const queryParams = useSearchParams(); + const searchParams: { + order?: Partial; + } = qs.parse(queryParams.toString()); + + const setSearchParams = (params: { order?: typeof order }) => { + router.replace( + createParametrizedUrl(location.pathname, { ...searchParams, ...params }) + ); + }; + + const handleOrder = (column: OrderPanoramaEtablissement["orderBy"]) => { + if (order?.orderBy !== column) { + setSearchParams({ order: { order: "desc", orderBy: column } }); + return; + } + setSearchParams({ + order: { + order: order?.order === "asc" ? "desc" : "asc", + orderBy: column, + }, + }); + }; + + const order = searchParams.order ?? { order: "asc" }; const { setUaiFilter } = useContext(UaiFilterContext); const onUaiChanged = (uai: string) => { @@ -31,9 +59,12 @@ export default function Panorama({ const [codeNiveauDiplome, setCodeNiveauDiplome] = useState(); const { data: etablissement, isError } = useQuery( - ["getEtablissement", { uai }], + ["getEtablissement", uai, order], api.getEtablissement({ - params: { uai }, + query: { + uai, + ...order, + }, }).call, { keepPreviousData: true, staleTime: 10000000, retry: false } ); @@ -90,6 +121,8 @@ export default function Panorama({ meanInsertion={regionStats?.tauxInsertion} meanPoursuite={regionStats?.tauxPoursuite} quadrantFormations={etablissement?.formations} + order={order} + handleOrder={handleOrder} /> ; + order?: Partial; } = qs.parse(queryParams.toString()); const setSearchParams = (params: { order?: typeof order }) => { @@ -33,7 +33,7 @@ export default function Panorama({ ); }; - const handleOrder = (column: Order["orderBy"]) => { + const handleOrder = (column: OrderPanoramaFormation["orderBy"]) => { if (order?.orderBy !== column) { setSearchParams({ order: { order: "desc", orderBy: column } }); return; @@ -109,7 +109,9 @@ export default function Panorama({ meanPoursuite={stats?.tauxPoursuite} quadrantFormations={data?.formations} order={order} - handleOrder={handleOrder} + handleOrder={(column?: string) => + handleOrder(column as OrderPanoramaFormation["orderBy"]) + } /> [0]["query"]; +export type QueryPanoramaFormation = Parameters[0]["query"] | Parameters[0]["query"]; +export type QueryPanoramaEtablissement = Parameters[0]["query"]; export type PanoramaFormationRegion = ApiType< typeof api.getDataForPanoramaRegion @@ -19,13 +20,22 @@ export type PanoramaFormationsDepartement = ApiType< typeof api.getDataForPanoramaDepartement >["formations"]; +export type PanoramaFormationEtablissement = ApiType< + typeof api.getEtablissement +>["formations"][number]; +export type PanoramaFormationsEtablissement = ApiType< + typeof api.getEtablissement +>["formations"]; + export type PanoramaFormation = | PanoramaFormationRegion | PanoramaFormationDepartement; + export type PanoramaFormations = | PanoramaFormationsRegion | PanoramaFormationsDepartement; + export type StatsFormationsRegion = ApiType; export type StatsFormationsDepartement = ApiType< typeof api.getDepartementStats @@ -35,4 +45,6 @@ export type StatsFormations = | StatsFormationsDepartement; -export type Order = Pick; +export type OrderPanoramaFormation = Pick; +export type OrderPanoramaEtablissement = Pick; +export type Order = OrderPanoramaEtablissement | OrderPanoramaFormation; From cffb264c5284b5f0a1afa67a853b0d0d9c730fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20D=C3=A9tr=C3=A9?= Date: Mon, 13 Nov 2023 16:59:39 +0100 Subject: [PATCH 06/28] fix: position quadrant et niveau diplome --- .../getDepartementsStats.query.ts | 16 ++-- .../getRegionStats/getRegionStats.query.ts | 25 +++--- .../data/queries/utils/getMillesime.ts | 6 ++ .../data/queries/utils/positionQuadrant.ts | 33 +++---- .../modules/data/routes/panorama.routes.ts | 1 - .../getDataForPanorama/dependencies.ts | 85 +++++++++++++++++-- .../getDataForPanorama.usecase.ts | 42 ++++++--- .../usecases/getEtablissement/dependencies.ts | 14 ++- .../getFormationsStatsQuery.dep.ts | 2 +- .../etablissements/etablissements.schema.ts | 4 +- shared/client/formations/formation.schema.ts | 12 +++ .../panorama/components/FiltersSection.tsx | 37 +++----- .../components/IndicateursSection.tsx | 40 ++++----- .../panorama/components/QuadrantSection.tsx | 45 ++++------ .../panorama/components/TopFlopSection.tsx | 23 ++--- .../departement/[codeDepartement]/page.tsx | 56 ++++++------ .../panorama/region/[codeRegion]/page.tsx | 56 +++++++----- ui/app/(wrapped)/panorama/types.ts | 8 +- 18 files changed, 299 insertions(+), 206 deletions(-) create mode 100644 server/src/modules/data/queries/utils/getMillesime.ts diff --git a/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts b/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts index 976a7f7ea..df2c55460 100644 --- a/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts +++ b/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts @@ -10,12 +10,12 @@ import { selectTauxRemplissageAgg } from "../utils/tauxRemplissage"; export const getDepartementsStats = async ({ codeDepartement, - codeDiplome, + codesNiveauxDiplomes, rentreeScolaire = "2022", millesimeSortie = "2020_2021", }: { codeDepartement: string; - codeDiplome?: string[]; + codesNiveauxDiplomes?: string[]; rentreeScolaire?: string; millesimeSortie?: string; }) => { @@ -34,8 +34,8 @@ export const getDepartementsStats = async ({ .where(notHistoriqueIndicateurRegionSortie) .where("departement.codeDepartement", "=", codeDepartement) .$call((q) => { - if (!codeDiplome?.length) return q; - return q.where("formation.codeNiveauDiplome", "in", codeDiplome); + if (!codesNiveauxDiplomes?.length) return q; + return q.where("formation.codeNiveauDiplome", "in", codesNiveauxDiplomes); }) .where("indicateurRegionSortie.millesimeSortie", "=", millesimeSortie) .where((eb) => @@ -53,7 +53,7 @@ export const getDepartementsStats = async ({ "tauxPoursuite" ), ]) - .executeTakeFirstOrThrow(); + .executeTakeFirst(); const stats = await kdb .selectFrom("formationEtablissement") @@ -62,7 +62,7 @@ export const getDepartementsStats = async ({ "formation.codeFormationDiplome", "formationEtablissement.cfd" ) - .innerJoin("indicateurEntree", (join) => + .leftJoin("indicateurEntree", (join) => join .onRef( "formationEtablissement.id", @@ -83,8 +83,8 @@ export const getDepartementsStats = async ({ "etablissement.codeDepartement" ) .$call((q) => { - if (!codeDiplome?.length) return q; - return q.where("formation.codeNiveauDiplome", "in", codeDiplome); + if (!codesNiveauxDiplomes?.length) return q; + return q.where("formation.codeNiveauDiplome", "in", codesNiveauxDiplomes); }) .where(notHistorique) .select([ diff --git a/server/src/modules/data/queries/getRegionStats/getRegionStats.query.ts b/server/src/modules/data/queries/getRegionStats/getRegionStats.query.ts index 158f89285..685428148 100644 --- a/server/src/modules/data/queries/getRegionStats/getRegionStats.query.ts +++ b/server/src/modules/data/queries/getRegionStats/getRegionStats.query.ts @@ -13,12 +13,12 @@ import { selectTauxRemplissageAgg } from "../utils/tauxRemplissage"; export const getRegionStats = async ({ codeRegion, - codeDiplome, + codesNiveauxDiplomes, rentreeScolaire = "2022", millesimeSortie = "2020_2021", }: { codeRegion: string; - codeDiplome?: string[]; + codesNiveauxDiplomes?: string[]; rentreeScolaire?: string; millesimeSortie?: string; }) => { @@ -30,12 +30,12 @@ export const getRegionStats = async ({ "indicateurRegionSortie.cfd" ) .where("indicateurRegionSortie.codeRegion", "=", codeRegion) - .$call((q) => { - if (!codeDiplome?.length) return q; - return q.where("formation.codeNiveauDiplome", "in", codeDiplome); - }) .where("indicateurRegionSortie.millesimeSortie", "=", millesimeSortie) .where(notHistoriqueIndicateurRegionSortie) + .$call((q) => { + if (!codesNiveauxDiplomes?.length) return q; + return q.where("formation.codeNiveauDiplome", "in", codesNiveauxDiplomes); + }) .select([ selectTauxInsertion6moisAgg("indicateurRegionSortie").as( "tauxInsertion" @@ -44,7 +44,7 @@ export const getRegionStats = async ({ "tauxPoursuite" ), ]) - .executeTakeFirstOrThrow(); + .executeTakeFirst(); const stats = await kdb .selectFrom("formationEtablissement") @@ -53,7 +53,7 @@ export const getRegionStats = async ({ "formation.codeFormationDiplome", "formationEtablissement.cfd" ) - .innerJoin("indicateurEntree", (join) => + .leftJoin("indicateurEntree", (join) => join .onRef( "formationEtablissement.id", @@ -70,8 +70,8 @@ export const getRegionStats = async ({ .where("etablissement.codeRegion", "=", codeRegion) .innerJoin("region", "region.codeRegion", "etablissement.codeRegion") .$call((q) => { - if (!codeDiplome?.length) return q; - return q.where("formation.codeNiveauDiplome", "in", codeDiplome); + if (!codesNiveauxDiplomes?.length) return q; + return q.where("formation.codeNiveauDiplome", "in", codesNiveauxDiplomes); }) .where(notHistorique) .select([ @@ -88,5 +88,8 @@ export const getRegionStats = async ({ .groupBy("region.libelleRegion") .executeTakeFirstOrThrow(); - return { ...stats, ...statsSortie }; + return { + ...stats, + ...statsSortie + }; }; diff --git a/server/src/modules/data/queries/utils/getMillesime.ts b/server/src/modules/data/queries/utils/getMillesime.ts new file mode 100644 index 000000000..6f5c37c76 --- /dev/null +++ b/server/src/modules/data/queries/utils/getMillesime.ts @@ -0,0 +1,6 @@ +export const getMillesimePrecedent = (millesimeSortie: string): string => + `${parseInt(millesimeSortie.split("_")[0]) - 1}_${parseInt(millesimeSortie.split("_")[2]) - 1}`; + +export const getMillesimeSuivant = (millesimeSortie: string): string => + `${parseInt(millesimeSortie.split("_")[0]) + 1}_${parseInt(millesimeSortie.split("_")[2]) + 1}`; + diff --git a/server/src/modules/data/queries/utils/positionQuadrant.ts b/server/src/modules/data/queries/utils/positionQuadrant.ts index a1a0d66d5..243935a40 100644 --- a/server/src/modules/data/queries/utils/positionQuadrant.ts +++ b/server/src/modules/data/queries/utils/positionQuadrant.ts @@ -32,7 +32,7 @@ export const getPositionQuadrant = ( return sql` CASE - WHEN (${tauxInsertion} >= ${tauxInsertionReg} AND ${tauxPoursuite} > ${tauxPoursuiteReg}) THEN 'Q1' + WHEN (${tauxInsertion} >= ${tauxInsertionReg} AND ${tauxPoursuite} >= ${tauxPoursuiteReg}) THEN 'Q1' WHEN (${tauxInsertion} >= ${tauxInsertionReg} AND ${tauxPoursuite} < ${tauxPoursuiteReg}) THEN 'Q2' WHEN (${tauxInsertion} < ${tauxInsertionReg} AND ${tauxPoursuite} >= ${tauxPoursuiteReg}) THEN 'Q3' WHEN (${tauxInsertion} < ${tauxInsertionReg} AND ${tauxPoursuite} < ${tauxPoursuiteReg}) THEN 'Q4' @@ -49,21 +49,21 @@ export function withPositionQuadrant>({ dispositifIdRef, codeRegionRef, millesimeSortie, - codeNiveauDiplomeRef, + codesNiveauxDiplomes, }: { eb: EB; cfdRef: EbRef; dispositifIdRef: EbRef; codeRegionRef: EbRef; millesimeSortie: string; - codeNiveauDiplomeRef?: EbRef; + codesNiveauxDiplomes?: string[]; }) { const tauxInsertionReg = withInsertionReg({ eb, cfdRef, dispositifIdRef, codeRegionRef, - millesimeSortie, + millesimeSortie }); const tauxPoursuiteReg = withPoursuiteReg({ @@ -83,18 +83,19 @@ export function withPositionQuadrant>({ ) .where("indicateurRegionSortie.millesimeSortie", "=", millesimeSortie) .where(notHistoriqueIndicateurRegionSortie) - .innerJoin( - "formation", - "formation.codeFormationDiplome", - "indicateurRegionSortie.cfd" - ) .$call((eb) => { - if (codeNiveauDiplomeRef) - return eb.whereRef( - "formation.codeNiveauDiplome", - "=", - codeNiveauDiplomeRef - ); + if (codesNiveauxDiplomes) + return eb + .innerJoin( + "formation", + "formation.codeFormationDiplome", + "indicateurRegionSortie.cfd" + ) + .where( + "formation.codeNiveauDiplome", + "in", + codesNiveauxDiplomes + ); return eb; }) .select([ @@ -103,7 +104,7 @@ export function withPositionQuadrant>({ WHEN (${tauxInsertionReg} >= ${selectTauxInsertion6moisAgg( "indicateurRegionSortie" )} - AND ${tauxPoursuiteReg} > ${selectTauxPoursuiteAgg( + AND ${tauxPoursuiteReg} >= ${selectTauxPoursuiteAgg( "indicateurRegionSortie" )}) THEN 'Q1' diff --git a/server/src/modules/data/routes/panorama.routes.ts b/server/src/modules/data/routes/panorama.routes.ts index 3ae2d6a5c..f6413b4ee 100644 --- a/server/src/modules/data/routes/panorama.routes.ts +++ b/server/src/modules/data/routes/panorama.routes.ts @@ -11,7 +11,6 @@ export const panoramaRoutes = ({ server }: { server: Server }) => { { schema: ROUTES_CONFIG.getDataForPanoramaRegion }, async (request, response) => { const { order, orderBy, ...filters } = request.query; - console.log(request.query) const stats = await getDataForPanoramaRegion({ ...filters, orderBy: order && orderBy ? { order, column: orderBy } : undefined, diff --git a/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts b/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts index 93ef5814c..17578d8a9 100644 --- a/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts +++ b/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts @@ -3,7 +3,9 @@ import { sql } from "kysely"; import { kdb } from "../../../../db/db"; import { cleanNull } from "../../../../utils/noNull"; import { effectifAnnee } from "../../queries/utils/effectifAnnee"; +import { getMillesimePrecedent } from "../../queries/utils/getMillesime"; import { hasContinuum } from "../../queries/utils/hasContinuum"; +import { notHistorique } from "../../queries/utils/notHistorique"; import { withPositionQuadrant } from "../../queries/utils/positionQuadrant"; import { withTauxDevenirFavorableReg } from "../../queries/utils/tauxDevenirFavorable"; import { withInsertionReg } from "../../queries/utils/tauxInsertion6mois"; @@ -14,10 +16,14 @@ import { selectTauxRemplissageAgg } from "../../queries/utils/tauxRemplissage"; const queryFormations = ({ rentreeScolaire = "2022", millesimeSortie = "2020_2021", + codesNiveauxDiplomes, + libellesFilieres, orderBy, }: { rentreeScolaire?: string; millesimeSortie?: string; + codesNiveauxDiplomes?: string[]; + libellesFilieres?: string[]; orderBy?: { column: string; order: "asc" | "desc" }; }) => kdb @@ -37,7 +43,7 @@ const queryFormations = ({ "formationEtablissement.dispositifId", "dispositif.codeDispositif" ) - .innerJoin("indicateurEntree", (join) => + .leftJoin("indicateurEntree", (join) => join .onRef( "formationEtablissement.id", @@ -61,6 +67,15 @@ const queryFormations = ({ .onRef("formationEtablissement.id", "=", "iep.formationEtablissementId") .on("iep.rentreeScolaire", "=", "2021") ) + .where(notHistorique) + .$call((q) => { + if (!codesNiveauxDiplomes) return q; + return q.where("formation.codeNiveauDiplome", "in", codesNiveauxDiplomes) + }) + .$call((q) => { + if (!libellesFilieres) return q; + return q.where("formation.libelleFiliere", "in", libellesFilieres) + }) .select((eb) => [ "codeFormationDiplome", "formationEtablissement.dispositifId", @@ -84,7 +99,7 @@ const queryFormations = ({ (eb) => withInsertionReg({ eb, - millesimeSortie: "2019_2020", + millesimeSortie: getMillesimePrecedent(millesimeSortie), cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", @@ -92,7 +107,7 @@ const queryFormations = ({ (eb) => withPoursuiteReg({ eb, - millesimeSortie: "2019_2020", + millesimeSortie: getMillesimePrecedent(millesimeSortie), cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", @@ -136,6 +151,7 @@ const queryFormations = ({ cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", + codesNiveauxDiplomes }).as("positionQuadrant"), ]) .$narrowType<{ @@ -182,22 +198,24 @@ const queryFormations = ({ sql`${sql.raw(orderBy.order)} NULLS LAST` ); }) - .orderBy("libelleDiplome", "asc") + .orderBy("libelleNiveauDiplome", "asc") export const queryFormationsRegion = async ({ codeRegion, rentreeScolaire = "2022", millesimeSortie = "2020_2021", + codesNiveauxDiplomes, + libellesFilieres, orderBy }: { codeRegion: string; rentreeScolaire?: string; millesimeSortie?: string; + codesNiveauxDiplomes?: string[]; + libellesFilieres?: string[]; orderBy?: { column: string; order: "asc" | "desc" }; }) => { - - console.log(orderBy) - const formations = await queryFormations({ rentreeScolaire, millesimeSortie, orderBy }) + const formations = await queryFormations({ rentreeScolaire, millesimeSortie, codesNiveauxDiplomes, libellesFilieres, orderBy }) .where("etablissement.codeRegion", "=", codeRegion) .execute(); @@ -208,16 +226,67 @@ export const queryFormationsDepartement = async ({ codeDepartement, rentreeScolaire = "2022", millesimeSortie = "2020_2021", + codesNiveauxDiplomes, + libellesFilieres, orderBy }: { codeDepartement: string; rentreeScolaire?: string; millesimeSortie?: string; + codesNiveauxDiplomes?: string[]; + libellesFilieres?: string[]; orderBy?: { column: string; order: "asc" | "desc" }; }) => { - const formations = await queryFormations({ rentreeScolaire, millesimeSortie, orderBy }) + const formations = await queryFormations({ rentreeScolaire, millesimeSortie, codesNiveauxDiplomes, libellesFilieres, orderBy }) .where("etablissement.codeDepartement", "=", codeDepartement) .execute(); return formations.map(cleanNull); }; + +export const getFilters = async ({ + codeRegion, + codeDepartement +}: { + codeRegion?: string; + codeDepartement?: string; +}) => { + const filtersBase = kdb. + selectFrom("niveauDiplome") + .leftJoin("formation", "formation.codeNiveauDiplome", "niveauDiplome.codeNiveauDiplome") + .leftJoin("formationEtablissement", "formationEtablissement.cfd", "formation.codeFormationDiplome") + .leftJoin("etablissement", "etablissement.UAI", "formationEtablissement.UAI") + .$call((eb) => { + if (!codeRegion) return eb; + return eb.where("etablissement.codeRegion", "=", codeRegion); + }) + .$call((eb) => { + if (!codeDepartement) return eb; + return eb.where("etablissement.codeDepartement", "=", codeDepartement); + }) + .distinct() + .$castTo<{ label: string; value: string }>() + + + const diplomes = await filtersBase + .select([ + "niveauDiplome.codeNiveauDiplome as value", + "niveauDiplome.libelleNiveauDiplome as label" + ]) + .where("formation.codeNiveauDiplome", "is not", null) + .execute(); + + const filieres = await filtersBase + .select([ + "formation.libelleFiliere as label", + "formation.libelleFiliere as value", + ]) + .where("formation.libelleFiliere", "is not", null) + .execute(); + + + return { + diplomes: diplomes.map(cleanNull), + filieres: filieres.map(cleanNull) + } +} diff --git a/server/src/modules/data/usecases/getDataForPanorama/getDataForPanorama.usecase.ts b/server/src/modules/data/usecases/getDataForPanorama/getDataForPanorama.usecase.ts index 2a2cc9ebb..aa78cd230 100644 --- a/server/src/modules/data/usecases/getDataForPanorama/getDataForPanorama.usecase.ts +++ b/server/src/modules/data/usecases/getDataForPanorama/getDataForPanorama.usecase.ts @@ -1,49 +1,69 @@ import { inject } from "injecti"; -import { - queryFormationsDepartement, - queryFormationsRegion, -} from "./dependencies"; +import { getFilters, queryFormationsDepartement, queryFormationsRegion } from "./dependencies"; export const [getDataForPanoramaRegion] = inject( - { queryFormationsRegion }, + { + queryFormationsRegion, + getFilters + }, (deps) => async ( { codeRegion, + codesNiveauxDiplomes, + libellesFilieres, orderBy }: { codeRegion: string; + codesNiveauxDiplomes?: string[]; + libellesFilieres?: string[]; orderBy?: { column: string; order: "asc" | "desc" }; }) => { - console.log("codeRegion", codeRegion) - console.log("orderBy", orderBy) - const formations = await deps.queryFormationsRegion({ codeRegion, orderBy }); + + const formations = await deps.queryFormationsRegion({ codeRegion, codesNiveauxDiplomes, libellesFilieres, orderBy }); + const { diplomes, filieres } = await deps.getFilters({ codeRegion }) return { formations, + filters: { + diplomes, + filieres + } }; } ); export const [getDataForPanoramaDepartement] = inject( - { queryFormationsDepartement }, + { + queryFormationsDepartement, + getFilters + }, (deps) => async ( { codeDepartement, + codesNiveauxDiplomes, + libellesFilieres, orderBy }: { codeDepartement: string; + codesNiveauxDiplomes?: string[]; + libellesFilieres?: string[]; orderBy?: { column: string; order: "asc" | "desc" }; }) => { + const formations = await deps.queryFormationsDepartement({ - codeDepartement, - orderBy + codeDepartement, codesNiveauxDiplomes, libellesFilieres, orderBy }); + const { diplomes, filieres } = await deps.getFilters({ codeDepartement }) return { formations, + filters: { + diplomes, + filieres + } }; } ); diff --git a/server/src/modules/data/usecases/getEtablissement/dependencies.ts b/server/src/modules/data/usecases/getEtablissement/dependencies.ts index aea6542fb..a3cf2a70c 100644 --- a/server/src/modules/data/usecases/getEtablissement/dependencies.ts +++ b/server/src/modules/data/usecases/getEtablissement/dependencies.ts @@ -3,6 +3,7 @@ import { jsonArrayFrom } from "kysely/helpers/postgres"; import { kdb } from "../../../../db/db"; import { effectifAnnee } from "../../queries/utils/effectifAnnee"; +import { getMillesimePrecedent } from "../../queries/utils/getMillesime"; import { hasContinuum } from "../../queries/utils/hasContinuum"; import { notHistorique } from "../../queries/utils/notHistorique"; import { withPositionQuadrant } from "../../queries/utils/positionQuadrant"; @@ -44,7 +45,7 @@ const getEtablissementInDb = async ({ jsonArrayFrom( eb .selectFrom("formationEtablissement") - .innerJoin("indicateurEntree", (join) => + .leftJoin("indicateurEntree", (join) => join .onRef( "formationEtablissement.id", @@ -73,6 +74,11 @@ const getEtablissementInDb = async ({ "dispositif.codeDispositif", "formationEtablissement.dispositifId" ) + .leftJoin("indicateurEntree as iep", (join) => + join + .onRef("formationEtablissement.id", "=", "iep.formationEtablissementId") + .on("iep.rentreeScolaire", "=", "2021") + ) .select((sb) => [ "formationEtablissement.cfd as codeFormationDiplome", "formationEtablissement.dispositifId", @@ -89,7 +95,7 @@ const getEtablissementInDb = async ({ sql`SUM(${effectifAnnee({ alias: "indicateurEntree" })})`.as( "effectif" ), - sql`SUM(${effectifAnnee({ alias: "indicateurEntree" })})`.as( + sql`SUM(${effectifAnnee({ alias: "iep" })})`.as( "effectifPrecedent" ), selectTauxPression("indicateurEntree").as("tauxPression"), @@ -106,7 +112,7 @@ const getEtablissementInDb = async ({ (eb) => withInsertionReg({ eb, - millesimeSortie: "2019_2020", + millesimeSortie: getMillesimePrecedent(millesimeSortie), cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", @@ -114,7 +120,7 @@ const getEtablissementInDb = async ({ (eb) => withPoursuiteReg({ eb, - millesimeSortie: "2019_2020", + millesimeSortie: getMillesimePrecedent(millesimeSortie), cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", diff --git a/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsStatsQuery.dep.ts b/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsStatsQuery.dep.ts index 3acadee1d..27d5f28e6 100644 --- a/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsStatsQuery.dep.ts +++ b/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsStatsQuery.dep.ts @@ -146,7 +146,7 @@ export const getFormationsTransformationStatsQuery = ({ cfdRef: "demande.cfd", dispositifIdRef: "demande.dispositifId", codeRegionRef: "dataEtablissement.codeRegion", - codeNiveauDiplomeRef: codeNiveauDiplome ? "dataFormation.codeNiveauDiplome" : undefined, + codesNiveauxDiplomes: codeNiveauDiplome, }).as("positionQuadrant"), selectNbDemandes(eb).as("nbDemandes"), selectNbEtablissements(eb).as("nbEtablissements"), diff --git a/shared/client/etablissements/etablissements.schema.ts b/shared/client/etablissements/etablissements.schema.ts index de2ab7120..04e66f5a5 100644 --- a/shared/client/etablissements/etablissements.schema.ts +++ b/shared/client/etablissements/etablissements.schema.ts @@ -147,7 +147,7 @@ export const etablissementSchemas = { codeRegion: Type.String(), }), querystring: Type.Object({ - codeDiplome: Type.Optional(Type.Array(Type.String())), + codesNiveauxDiplomes: Type.Optional(Type.Array(Type.String())), }), response: { 200: Type.Object({ @@ -166,7 +166,7 @@ export const etablissementSchemas = { codeDepartement: Type.String(), }), querystring: Type.Object({ - codeDiplome: Type.Optional(Type.Array(Type.String())), + codesNiveauxDiplomes: Type.Optional(Type.Array(Type.String())), }), response: { 200: Type.Object({ diff --git a/shared/client/formations/formation.schema.ts b/shared/client/formations/formation.schema.ts index dde1883c0..d396ab6a1 100644 --- a/shared/client/formations/formation.schema.ts +++ b/shared/client/formations/formation.schema.ts @@ -120,24 +120,36 @@ export const formationSchemas = { getDataForPanoramaRegion: { querystring: Type.Object({ codeRegion: Type.String(), + codesNiveauxDiplomes: Type.Optional(Type.Array(Type.String())), + libellesFilieres: Type.Optional(Type.Array(Type.String())), order: Type.Optional(Type.Union([Type.Literal("asc"), Type.Literal("desc")])), orderBy: Type.Optional(Type.KeyOf(FormationSchema)), }), response: { 200: Type.Object({ formations: Type.Array(FormationSchema), + filters: Type.Object({ + diplomes: Type.Array(OptionSchema), + filieres: Type.Array(OptionSchema), + }) }), }, }, getDataForPanoramaDepartement: { querystring: Type.Object({ codeDepartement: Type.String(), + codesNiveauxDiplomes: Type.Optional(Type.Array(Type.String())), + libellesFilieres: Type.Optional(Type.Array(Type.String())), order: Type.Optional(Type.Union([Type.Literal("asc"), Type.Literal("desc")])), orderBy: Type.Optional(Type.KeyOf(FormationSchema)), }), response: { 200: Type.Object({ formations: Type.Array(FormationSchema), + filters: Type.Object({ + diplomes: Type.Array(OptionSchema), + filieres: Type.Array(OptionSchema), + }) }), }, }, diff --git a/ui/app/(wrapped)/panorama/components/FiltersSection.tsx b/ui/app/(wrapped)/panorama/components/FiltersSection.tsx index 3a9e51610..053272def 100644 --- a/ui/app/(wrapped)/panorama/components/FiltersSection.tsx +++ b/ui/app/(wrapped)/panorama/components/FiltersSection.tsx @@ -2,32 +2,19 @@ import { Container, Flex } from "@chakra-ui/react"; import { Multiselect } from "@/components/Multiselect"; -import { PanoramaFormations } from "../types"; +import { FiltersPanoramaFormation } from "../types"; export const FiltersSection = ({ - formations, - onLibelleFiliereChanged, - libelleFiliere, + handleFilters, + activeFilters, + libelleFiliereOptions, }: { - formations?: PanoramaFormations; - onLibelleFiliereChanged?: (diplome: string[]) => void; - libelleFiliere?: string[]; + handleFilters: ( + type: keyof FiltersPanoramaFormation, + value: FiltersPanoramaFormation[keyof FiltersPanoramaFormation] + ) => void; + activeFilters: Partial; + libelleFiliereOptions?: { value: string; label: string }[]; }) => { - const libelleFiliereOptions = Object.values( - formations?.reduce( - (acc, cur) => { - if (!cur.libelleFiliere) return acc; - return { - ...acc, - [cur.libelleFiliere]: { - value: cur.libelleFiliere, - label: cur.libelleFiliere as string, - }, - }; - }, - {} as Record - ) ?? {} - ); - return ( handleFilters("libellesFilieres", selected)} width={250} options={libelleFiliereOptions} - value={libelleFiliere ?? []} + value={activeFilters.libellesFilieres ?? []} ml="2" > Secteur d’activité diff --git a/ui/app/(wrapped)/panorama/components/IndicateursSection.tsx b/ui/app/(wrapped)/panorama/components/IndicateursSection.tsx index ca78adb96..34e353469 100644 --- a/ui/app/(wrapped)/panorama/components/IndicateursSection.tsx +++ b/ui/app/(wrapped)/panorama/components/IndicateursSection.tsx @@ -16,7 +16,7 @@ import { } from "@chakra-ui/react"; import { Multiselect } from "../../../../components/Multiselect"; -import { PanoramaFormations, StatsFormations } from "../types"; +import { FiltersPanoramaFormation, StatsFormations } from "../types"; const StatCard = ({ label, @@ -50,37 +50,25 @@ export const IndicateursSection = ({ onCodeChanged, options, stats, - codeDiplome, - onDiplomeChanged, - formations, + handleFilters, + activeFilters, + diplomeOptions, typeTerritoire = "region", }: { - onDiplomeChanged?: (diplome: string[]) => void; - codeDiplome?: string[]; code?: string; onCodeChanged: (code: string) => void; + handleFilters: ( + type: keyof FiltersPanoramaFormation, + value: FiltersPanoramaFormation[keyof FiltersPanoramaFormation] + ) => void; + activeFilters: Partial; options?: { label: string; value: string }[]; stats?: StatsFormations; - formations?: PanoramaFormations; + diplomeOptions?: { value: string; label: string }[]; typeTerritoire?: "region" | "departement"; }) => { const labelRegion = options?.find((item) => item.value === code)?.label; - const diplomeOptions = Object.values( - formations?.reduce( - (acc, cur) => { - return { - ...acc, - [cur.codeNiveauDiplome]: { - value: cur.codeNiveauDiplome, - label: cur.libelleNiveauDiplome as string, - }, - }; - }, - {} as Record - ) ?? {} - ); - return ( Diplôme + handleFilters("codesNiveauxDiplomes", selected) + } width="100%" options={diplomeOptions} - value={codeDiplome ?? []} + value={activeFilters.codesNiveauxDiplomes ?? []} size="md" > Diplôme @@ -160,7 +150,7 @@ export const IndicateursSection = ({ label={`Effectif en entrée dans votre ${ typeTerritoire === "region" ? "région" : "département" }`} - value={stats?.effectif ?? "-"} + value={stats?.effectif ? stats.effectif : "-"} /> diff --git a/ui/app/(wrapped)/panorama/components/QuadrantSection.tsx b/ui/app/(wrapped)/panorama/components/QuadrantSection.tsx index 7cc509ba4..8cb9c3310 100644 --- a/ui/app/(wrapped)/panorama/components/QuadrantSection.tsx +++ b/ui/app/(wrapped)/panorama/components/QuadrantSection.tsx @@ -57,29 +57,15 @@ type Tendances = { const filterFormations = ({ effectifMin, - codeNiveauDiplome, - libelleFiliere, quadrantFormations, tendances, }: { effectifMin: number; - codeNiveauDiplome?: string[]; - libelleFiliere?: string[]; quadrantFormations?: PanoramaFormations; tendances: Tendances; }) => quadrantFormations ?.filter((item) => { - if ( - libelleFiliere?.length && - (!item.libelleFiliere || !libelleFiliere.includes(item.libelleFiliere)) - ) - return false; - if ( - codeNiveauDiplome?.length && - !codeNiveauDiplome.includes(item.codeNiveauDiplome) - ) - return false; return item.effectif && item.effectif >= effectifMin; }) .filter((item) => { @@ -141,16 +127,12 @@ export const QuadrantSection = ({ quadrantFormations, meanPoursuite, meanInsertion, - codeNiveauDiplome, - libelleFiliere, order, handleOrder, }: { quadrantFormations?: PanoramaFormations; meanPoursuite?: number; meanInsertion?: number; - codeNiveauDiplome?: string[]; - libelleFiliere?: string[]; order?: Partial; handleOrder: (column: Order["orderBy"]) => void; }) => { @@ -178,18 +160,10 @@ export const QuadrantSection = ({ () => filterFormations({ effectifMin, - codeNiveauDiplome, quadrantFormations, tendances, - libelleFiliere, }), - [ - effectifMin, - codeNiveauDiplome, - quadrantFormations, - tendances, - libelleFiliere, - ] + [effectifMin, quadrantFormations, tendances] ); const handleOppositesTendances = (value: boolean, name: keyof Tendances) => { @@ -357,6 +331,9 @@ export const QuadrantSection = ({ ml="2" aria-label="csv" variant="solid" + isDisabled={ + !filteredFormations || filteredFormations.length === 0 + } onClick={async () => { if (!filteredFormations) return; downloadCsv( @@ -395,7 +372,10 @@ export const QuadrantSection = ({ <> {filteredFormations && - (typeVue === "quadrant" ? ( + filteredFormations.length && + meanInsertion && + meanPoursuite ? ( + typeVue === "quadrant" ? ( - ))} + ) + ) : ( + + + Aucune donnée à afficher pour les filtres sélectionnés + + + )} {!filteredFormations && } diff --git a/ui/app/(wrapped)/panorama/components/TopFlopSection.tsx b/ui/app/(wrapped)/panorama/components/TopFlopSection.tsx index 2290f73f2..1c1e9664d 100644 --- a/ui/app/(wrapped)/panorama/components/TopFlopSection.tsx +++ b/ui/app/(wrapped)/panorama/components/TopFlopSection.tsx @@ -1,5 +1,6 @@ import { Box, + Center, Container, Divider, Flex, @@ -19,28 +20,14 @@ import { FormationTooltipContent } from "./FormationTooltipContent"; export const TopFlopSection = ({ quadrantFormations, - codeNiveauDiplome, - libelleFiliere, }: { quadrantFormations?: PanoramaFormations; meanPoursuite?: number; meanInsertion?: number; - codeNiveauDiplome?: string[]; - libelleFiliere?: string[]; }) => { const topFlopFormations = useMemo(() => { if (!quadrantFormations) return; const filtered = quadrantFormations.filter((item) => { - if ( - libelleFiliere?.length && - (!item.libelleFiliere || !libelleFiliere.includes(item.libelleFiliere)) - ) - return false; - if ( - codeNiveauDiplome?.length && - !codeNiveauDiplome.includes(item.codeNiveauDiplome) - ) - return false; return item.dispositifId && !["253", "240"].includes(item.dispositifId); }); const nbTopFlop = Math.min(filtered.length, 20) / 2; @@ -54,7 +41,7 @@ export const TopFlopSection = ({ const flop = sorted.slice().reverse().slice(0, Math.floor(nbTopFlop)); return { top, flop }; - }, [quadrantFormations, codeNiveauDiplome, libelleFiliere]); + }, [quadrantFormations]); return ( @@ -67,8 +54,12 @@ export const TopFlopSection = ({ formations à examiner - {topFlopFormations && ( + {topFlopFormations && quadrantFormations?.length ? ( + ) : ( +
+ Aucune donnée à afficher pour les filtres sélectionnés +
)}
); diff --git a/ui/app/(wrapped)/panorama/departement/[codeDepartement]/page.tsx b/ui/app/(wrapped)/panorama/departement/[codeDepartement]/page.tsx index 17c75ee8e..169f22cdb 100644 --- a/ui/app/(wrapped)/panorama/departement/[codeDepartement]/page.tsx +++ b/ui/app/(wrapped)/panorama/departement/[codeDepartement]/page.tsx @@ -3,7 +3,6 @@ import { useQuery } from "@tanstack/react-query"; import { useRouter, useSearchParams } from "next/navigation"; import qs from "qs"; -import { useState } from "react"; import { api } from "../../../../../api.client"; import { createParametrizedUrl } from "../../../../../utils/createParametrizedUrl"; @@ -12,7 +11,7 @@ import { IndicateursSection } from "../../components/IndicateursSection"; import { InfoSection } from "../../components/InfoSection"; import { QuadrantSection } from "../../components/QuadrantSection"; import { TopFlopSection } from "../../components/TopFlopSection"; -import { OrderPanoramaFormation } from "../../types"; +import { FiltersPanoramaFormation, OrderPanoramaFormation } from "../../types"; export default function Panorama({ params: { codeDepartement }, @@ -25,9 +24,16 @@ export default function Panorama({ const queryParams = useSearchParams(); const searchParams: { order?: Partial; + filters?: Partial; } = qs.parse(queryParams.toString()); - const setSearchParams = (params: { order?: typeof order }) => { + const order = searchParams.order ?? { order: "asc" }; + const filters = searchParams.filters ?? {}; + + const setSearchParams = (params: { + order?: typeof order; + filters?: typeof filters; + }) => { router.replace( createParametrizedUrl(location.pathname, { ...searchParams, ...params }) ); @@ -35,10 +41,14 @@ export default function Panorama({ const handleOrder = (column: OrderPanoramaFormation["orderBy"]) => { if (order?.orderBy !== column) { - setSearchParams({ order: { order: "desc", orderBy: column } }); + setSearchParams({ + ...filters, + order: { order: "desc", orderBy: column }, + }); return; } setSearchParams({ + ...filters, order: { order: order?.order === "asc" ? "desc" : "asc", orderBy: column, @@ -46,13 +56,18 @@ export default function Panorama({ }); }; - const order = searchParams.order ?? { order: "asc" }; + const handleFilters = ( + type: keyof FiltersPanoramaFormation, + value: FiltersPanoramaFormation[keyof FiltersPanoramaFormation] + ) => { + setSearchParams({ + filters: { ...filters, [type]: value }, + }); + }; const onCodeDepartementChanged = (codeDepartement: string) => { router.push(`/panorama/departement/${codeDepartement}`); }; - const [codeNiveauDiplome, setCodeNiveauDiplome] = useState(); - const [libelleFiliere, setLibelleFiliere] = useState(); const { data: departementsOptions } = useQuery( ["departements"], @@ -64,10 +79,10 @@ export default function Panorama({ ); const { data: stats } = useQuery( - ["departement", codeDepartement, codeNiveauDiplome], + ["departement", codeDepartement, filters], api.getDepartementStats({ params: { codeDepartement }, - query: { codeDiplome: codeNiveauDiplome }, + query: { ...filters }, }).call, { keepPreviousData: true, @@ -76,11 +91,12 @@ export default function Panorama({ ); const { data } = useQuery( - ["formationForPanorama", codeDepartement, order], + ["formationForPanorama", codeDepartement, order, filters], api.getDataForPanoramaDepartement({ query: { codeDepartement, ...order, + ...filters, }, }).call, { keepPreviousData: true, staleTime: 10000000 } @@ -93,19 +109,13 @@ export default function Panorama({ code={codeDepartement} options={departementsOptions} stats={stats} - onDiplomeChanged={setCodeNiveauDiplome} - formations={data?.formations} - codeDiplome={codeNiveauDiplome} + handleFilters={handleFilters} + activeFilters={filters} + diplomeOptions={data?.filters.diplomes} typeTerritoire="departement" /> - + - + ; + filters?: Partial; } = qs.parse(queryParams.toString()); - const setSearchParams = (params: { order?: typeof order }) => { + const order = searchParams.order ?? { order: "asc" }; + const filters = searchParams.filters ?? {}; + + const setSearchParams = (params: { + order?: typeof order; + filters?: typeof filters; + }) => { router.replace( createParametrizedUrl(location.pathname, { ...searchParams, ...params }) ); @@ -35,10 +41,14 @@ export default function Panorama({ const handleOrder = (column: OrderPanoramaFormation["orderBy"]) => { if (order?.orderBy !== column) { - setSearchParams({ order: { order: "desc", orderBy: column } }); + setSearchParams({ + ...filters, + order: { order: "desc", orderBy: column }, + }); return; } setSearchParams({ + ...filters, order: { order: order?.order === "asc" ? "desc" : "asc", orderBy: column, @@ -46,13 +56,18 @@ export default function Panorama({ }); }; - const order = searchParams.order ?? { order: "asc" }; + const handleFilters = ( + type: keyof FiltersPanoramaFormation, + value: FiltersPanoramaFormation[keyof FiltersPanoramaFormation] + ) => { + setSearchParams({ + filters: { ...filters, [type]: value }, + }); + }; const onCodeRegionChanged = (codeRegion: string) => { router.push(`/panorama/region/${codeRegion}`); }; - const [codeNiveauDiplome, setCodeNiveauDiplome] = useState(); - const [libelleFiliere, setLibelleFiliere] = useState(); const { data: regionOptions } = useQuery( ["regions"], @@ -64,10 +79,10 @@ export default function Panorama({ ); const { data: stats } = useQuery( - ["region", codeRegion, codeNiveauDiplome], + ["region", codeRegion, filters], api.getRegionStats({ params: { codeRegion }, - query: { codeDiplome: codeNiveauDiplome }, + query: { ...filters }, }).call, { keepPreviousData: true, @@ -76,11 +91,12 @@ export default function Panorama({ ); const { data } = useQuery( - ["formationForPanorama", codeRegion, order], + ["formationForPanorama", codeRegion, order, filters], api.getDataForPanoramaRegion({ query: { codeRegion, ...order, + ...filters, }, }).call, { keepPreviousData: true, staleTime: 10000000 } @@ -93,18 +109,16 @@ export default function Panorama({ code={codeRegion} options={regionOptions} stats={stats} - onDiplomeChanged={setCodeNiveauDiplome} - formations={data?.formations} - codeDiplome={codeNiveauDiplome} + handleFilters={handleFilters} + activeFilters={filters} + diplomeOptions={data?.filters.diplomes} /> - + ); diff --git a/ui/app/(wrapped)/panorama/types.ts b/ui/app/(wrapped)/panorama/types.ts index 5de3f6a9a..4f702380a 100644 --- a/ui/app/(wrapped)/panorama/types.ts +++ b/ui/app/(wrapped)/panorama/types.ts @@ -2,7 +2,6 @@ import { ApiType } from "shared"; import { api } from "@/api.client"; - export type QueryPanoramaFormation = Parameters[0]["query"] | Parameters[0]["query"]; export type QueryPanoramaEtablissement = Parameters[0]["query"]; @@ -48,3 +47,10 @@ export type StatsFormations = export type OrderPanoramaFormation = Pick; export type OrderPanoramaEtablissement = Pick; export type Order = OrderPanoramaEtablissement | OrderPanoramaFormation; + + +export type FiltersPanoramaFormation = Pick< + QueryPanoramaFormation, + | "codesNiveauxDiplomes" + | "libellesFilieres" +>; From 0f831c50746df5e01bfc71fd5ade2d71ecb408e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20D=C3=A9tr=C3=A9?= Date: Mon, 13 Nov 2023 17:16:52 +0100 Subject: [PATCH 07/28] feat: design --- .../getTransformationStats.usecase.ts | 18 +++++++++------- .../pilotageTransfo/pilotageTransfo.schema.ts | 1 + .../VueTauxTransformationSection.tsx | 21 +++++++++++++++---- .../intentions/saisie/page.client.tsx | 11 ++++++++++ 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/server/src/modules/data/usecases/getTransformationStats/getTransformationStats.usecase.ts b/server/src/modules/data/usecases/getTransformationStats/getTransformationStats.usecase.ts index 405a15507..ee325e679 100644 --- a/server/src/modules/data/usecases/getTransformationStats/getTransformationStats.usecase.ts +++ b/server/src/modules/data/usecases/getTransformationStats/getTransformationStats.usecase.ts @@ -41,8 +41,8 @@ const formatTerritoire = (item: DataTerritoire) => ({ differenceCapaciteApprentissage: item.differenceCapaciteApprentissage || 0, placesTransformees: item.placesOuvertesScolaire + - item.placesOuvertesApprentissage + - item.placesFermeesScolaire || 0, + item.placesOuvertesApprentissage + + item.placesFermeesScolaire || 0, }); const formatResult = ( @@ -58,13 +58,13 @@ const formatResult = ( result[0]?.national.placesOuvertesApprentissage || 0, placesOuvertes: result[0]?.national.placesOuvertesScolaire + - result[0]?.national.placesOuvertesApprentissage || 0, + result[0]?.national.placesOuvertesApprentissage || 0, placesFermeesScolaire: result[0]?.national.placesFermeesScolaire || 0, placesFermeesApprentissage: result[0]?.national.placesFermeesApprentissage || 0, placesFermees: result[0]?.national.placesFermeesScolaire + - result[0]?.national.placesFermeesApprentissage || 0, + result[0]?.national.placesFermeesApprentissage || 0, ratioFermeture: Math.round( ((result[0]?.national.placesFermeesScolaire + @@ -89,11 +89,12 @@ const formatResult = ( result[0]?.national.differenceCapaciteApprentissage || 0, placesTransformees: result[0]?.national.differenceCapaciteScolaire + - result[0]?.national.differenceCapaciteApprentissage || 0, + result[0]?.national.differenceCapaciteApprentissage || 0, tauxTransformation: Math.round( (result[0]?.national.transformes / effectifNational || 0) * 10000 ) / 100, + effectif: effectifNational || 0, }, regions: _.chain(result) .groupBy((item) => item.region.codeRegion) @@ -105,6 +106,7 @@ const formatResult = ( (items[0].region.transforme / effectifsRegions[items[0].region.codeRegion ?? ""] || 0) * 10000 ) / 100, + effectif: effectifsRegions[items[0].region.codeRegion ?? ""] || 0, })) .orderBy( (item) => { @@ -125,8 +127,9 @@ const formatResult = ( Math.round( (items[0].academie.transforme / effectifsAcademie[items[0].academie.codeAcademie ?? ""] || 0) * - 10000 + 10000 ) / 100, + effectif: effectifsAcademie[items[0].academie.codeAcademie ?? ""] || 0, })) .orderBy( (item) => { @@ -147,9 +150,10 @@ const formatResult = ( Math.round( (items[0].departement.transforme / effectifsDepartements[ - items[0].departement.codeDepartement ?? "" + items[0].departement.codeDepartement ?? "" ] || 0) * 10000 ) / 100, + effectif: effectifsDepartements[items[0].departement.codeDepartement ?? ""] || 0, })) .orderBy( (item) => { diff --git a/shared/client/pilotageTransfo/pilotageTransfo.schema.ts b/shared/client/pilotageTransfo/pilotageTransfo.schema.ts index f4a2dbdf5..4e7e2eabb 100644 --- a/shared/client/pilotageTransfo/pilotageTransfo.schema.ts +++ b/shared/client/pilotageTransfo/pilotageTransfo.schema.ts @@ -22,6 +22,7 @@ const ScopedStatsTransfoSchema = Type.Object({ ratioOuverture: Type.Number(), ratioFermeture: Type.Number(), tauxTransformation: Type.Number(), + effectif: Type.Number(), }); const StatsTransfoSchema = Type.Object({ diff --git a/ui/app/(wrapped)/intentions/pilotage/components/VueTauxTransformationSection.tsx b/ui/app/(wrapped)/intentions/pilotage/components/VueTauxTransformationSection.tsx index 74ba55649..43007919a 100644 --- a/ui/app/(wrapped)/intentions/pilotage/components/VueTauxTransformationSection.tsx +++ b/ui/app/(wrapped)/intentions/pilotage/components/VueTauxTransformationSection.tsx @@ -125,6 +125,7 @@ export const VueTauxTransformationSection = ({ cursor="pointer" pb="4" width="20%" + whiteSpace={"normal"} onClick={() => handleOrder("placesTransformees")} > @@ -135,6 +136,18 @@ export const VueTauxTransformationSection = ({ cursor="pointer" pb="4" width="20%" + whiteSpace={"normal"} + onClick={() => handleOrder("effectif")} + > + + Effectif en entrée + + handleOrder("tauxTransformation")} > @@ -181,10 +194,10 @@ export const VueTauxTransformationSection = ({ {region.libelle} - {region.placesOuvertesScolaire + - region.placesOuvertesApprentissage + - region.placesFermeesScolaire + - region.placesFermeesApprentissage} + {region.placesTransformees} + + + {region.effectif} { {DEMANDES_COLUMNS.createdAt} + handleOrder("updatedAt")} + > + + {DEMANDES_COLUMNS.updatedAt} + @@ -358,6 +366,9 @@ export const PageClient = () => { {new Date(demande.createdAt).toLocaleString()} + + {new Date(demande.updatedAt).toLocaleString()} + ) )} From 6cc258a3dc980ee2a75c7020ad5ed65bef4dba59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20D=C3=A9tr=C3=A9?= Date: Tue, 14 Nov 2023 11:55:37 +0100 Subject: [PATCH 08/28] fix: fix --- server/src/modules/data/usecases/getFormations/dependencies.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/server/src/modules/data/usecases/getFormations/dependencies.ts b/server/src/modules/data/usecases/getFormations/dependencies.ts index c0166fbfd..fd624080c 100644 --- a/server/src/modules/data/usecases/getFormations/dependencies.ts +++ b/server/src/modules/data/usecases/getFormations/dependencies.ts @@ -176,7 +176,6 @@ const findFormationsInDb = async ({ cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", - codeNiveauDiplomeRef: "formation.codeNiveauDiplome", }).as("positionQuadrant"), ]) .where( From f82da9398938f67498872b28d1c499163408a2c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20D=C3=A9tr=C3=A9?= Date: Wed, 15 Nov 2023 11:09:40 +0100 Subject: [PATCH 09/28] =?UTF-8?q?refacto:=20colors=20du=20th=C3=A8me=20DSF?= =?UTF-8?q?R?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../getDepartementsStats.query.ts | 13 ++-- .../getRegionStats/getRegionStats.query.ts | 10 +-- .../data/queries/utils/getMillesime.ts | 9 ++- .../data/queries/utils/positionQuadrant.ts | 42 +++++------ .../getDataForPanorama/dependencies.ts | 68 ++++++++++++------ .../getDataForPanorama.usecase.ts | 72 ++++++++++--------- .../usecases/getEtablissement/dependencies.ts | 20 ++++-- .../getEtablissement.usecase.ts | 17 +++-- .../usecases/getFormations/dependencies.ts | 34 ++++----- .../getFormations/getFormations.usecase.ts | 58 +++++++-------- .../dependencies.ts | 6 +- .../getRestitutionIntentionsStats.usecase.ts | 72 +++++++++---------- .../getTransformationStats.usecase.ts | 18 ++--- .../etablissements/etablissements.client.ts | 12 ++-- .../etablissements/etablissements.schema.ts | 4 +- shared/client/formations/formation.schema.ts | 12 ++-- ui/app/(wrapped)/components/Nav.tsx | 6 +- .../etablissements/components/LineContent.tsx | 4 +- .../(wrapped)/console/etablissements/page.tsx | 2 +- .../formations/components/LineContent.tsx | 4 +- ui/app/(wrapped)/console/formations/page.tsx | 2 +- .../components/IndicateursClesSection.tsx | 6 +- .../pilotage/components/QuadrantSection.tsx | 6 +- .../VueOuverturesFermeturesSection.tsx | 8 ++- .../VueTauxTransformationSection.tsx | 8 ++- ui/app/(wrapped)/intentions/pilotage/page.tsx | 2 +- .../ConsoleSection/ConsoleSection.tsx | 2 +- .../HeaderSection/PrimaryFiltersSection.tsx | 9 ++- .../(wrapped)/intentions/restitution/page.tsx | 2 +- .../intentions/saisie/components/InfoBox.tsx | 4 +- .../saisie/intentionForm/IntentionForm.tsx | 2 +- .../capaciteSection/CapaciteSection.tsx | 4 +- .../cfdUaiSection/CfdUaiSection.tsx | 7 +- .../typeDemandeSection/TypeDemandeField.tsx | 2 +- .../typeDemandeSection/TypeDemandeSection.tsx | 4 +- .../components/IndicateursSection.tsx | 2 +- .../panorama/components/TopFlopSection.tsx | 6 +- .../departement/PanoramaSelection.tsx | 2 +- .../etablissement/PanoramaSelection.tsx | 2 +- .../[uai]/EtablissementSection.tsx | 2 +- ui/app/(wrapped)/panorama/layout.tsx | 2 +- .../panorama/region/PanoramaSelection.tsx | 2 +- ui/app/(wrapped)/panorama/types.ts | 24 ++++--- .../pilotage-reforme/components/BarGraph.tsx | 16 +++-- .../components/IndicateursClesSection.tsx | 46 +++++++++--- .../components/VueRegionAcademieSection.tsx | 8 ++- ui/app/(wrapped)/pilotage-reforme/page.tsx | 2 +- ui/components/CartoGraph.tsx | 41 ++++++++--- ui/components/InfoBlock.tsx | 2 +- ui/components/Quadrant.tsx | 8 ++- ui/components/TableQuadrant.tsx | 8 +-- ui/theme/Button.theme.ts | 2 +- ui/theme/theme.ts | 34 +++++++++ 53 files changed, 455 insertions(+), 305 deletions(-) diff --git a/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts b/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts index df2c55460..81a1b8b66 100644 --- a/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts +++ b/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts @@ -2,7 +2,10 @@ import { sql } from "kysely"; import { kdb } from "../../../../db/db"; import { effectifAnnee } from "../utils/effectifAnnee"; -import { notHistorique, notHistoriqueIndicateurRegionSortie } from "../utils/notHistorique"; +import { + notHistorique, + notHistoriqueIndicateurRegionSortie, +} from "../utils/notHistorique"; import { selectTauxInsertion6moisAgg } from "../utils/tauxInsertion6mois"; import { selectTauxPoursuiteAgg } from "../utils/tauxPoursuite"; import { selectTauxPressionAgg } from "../utils/tauxPression"; @@ -46,12 +49,8 @@ export const getDepartementsStats = async ({ ) ) .select([ - selectTauxInsertion6moisAgg("indicateurRegionSortie").as( - "tauxInsertion" - ), - selectTauxPoursuiteAgg("indicateurRegionSortie").as( - "tauxPoursuite" - ), + selectTauxInsertion6moisAgg("indicateurRegionSortie").as("tauxInsertion"), + selectTauxPoursuiteAgg("indicateurRegionSortie").as("tauxPoursuite"), ]) .executeTakeFirst(); diff --git a/server/src/modules/data/queries/getRegionStats/getRegionStats.query.ts b/server/src/modules/data/queries/getRegionStats/getRegionStats.query.ts index 685428148..017c64160 100644 --- a/server/src/modules/data/queries/getRegionStats/getRegionStats.query.ts +++ b/server/src/modules/data/queries/getRegionStats/getRegionStats.query.ts @@ -37,12 +37,8 @@ export const getRegionStats = async ({ return q.where("formation.codeNiveauDiplome", "in", codesNiveauxDiplomes); }) .select([ - selectTauxInsertion6moisAgg("indicateurRegionSortie").as( - "tauxInsertion" - ), - selectTauxPoursuiteAgg("indicateurRegionSortie").as( - "tauxPoursuite" - ), + selectTauxInsertion6moisAgg("indicateurRegionSortie").as("tauxInsertion"), + selectTauxPoursuiteAgg("indicateurRegionSortie").as("tauxPoursuite"), ]) .executeTakeFirst(); @@ -90,6 +86,6 @@ export const getRegionStats = async ({ return { ...stats, - ...statsSortie + ...statsSortie, }; }; diff --git a/server/src/modules/data/queries/utils/getMillesime.ts b/server/src/modules/data/queries/utils/getMillesime.ts index 6f5c37c76..0fa59ceda 100644 --- a/server/src/modules/data/queries/utils/getMillesime.ts +++ b/server/src/modules/data/queries/utils/getMillesime.ts @@ -1,6 +1,9 @@ export const getMillesimePrecedent = (millesimeSortie: string): string => - `${parseInt(millesimeSortie.split("_")[0]) - 1}_${parseInt(millesimeSortie.split("_")[2]) - 1}`; + `${parseInt(millesimeSortie.split("_")[0]) - 1}_${ + parseInt(millesimeSortie.split("_")[2]) - 1 + }`; export const getMillesimeSuivant = (millesimeSortie: string): string => - `${parseInt(millesimeSortie.split("_")[0]) + 1}_${parseInt(millesimeSortie.split("_")[2]) + 1}`; - + `${parseInt(millesimeSortie.split("_")[0]) + 1}_${ + parseInt(millesimeSortie.split("_")[2]) + 1 + }`; diff --git a/server/src/modules/data/queries/utils/positionQuadrant.ts b/server/src/modules/data/queries/utils/positionQuadrant.ts index 243935a40..9be09c567 100644 --- a/server/src/modules/data/queries/utils/positionQuadrant.ts +++ b/server/src/modules/data/queries/utils/positionQuadrant.ts @@ -39,7 +39,7 @@ export const getPositionQuadrant = ( ELSE 'Hors quadrant' END `; -} +}; type EbRef> = Parameters[0]; @@ -63,7 +63,7 @@ export function withPositionQuadrant>({ cfdRef, dispositifIdRef, codeRegionRef, - millesimeSortie + millesimeSortie, }); const tauxPoursuiteReg = withPoursuiteReg({ @@ -91,43 +91,39 @@ export function withPositionQuadrant>({ "formation.codeFormationDiplome", "indicateurRegionSortie.cfd" ) - .where( - "formation.codeNiveauDiplome", - "in", - codesNiveauxDiplomes - ); + .where("formation.codeNiveauDiplome", "in", codesNiveauxDiplomes); return eb; }) .select([ sql` CASE WHEN (${tauxInsertionReg} >= ${selectTauxInsertion6moisAgg( - "indicateurRegionSortie" - )} + "indicateurRegionSortie" + )} AND ${tauxPoursuiteReg} >= ${selectTauxPoursuiteAgg( - "indicateurRegionSortie" - )}) + "indicateurRegionSortie" + )}) THEN 'Q1' WHEN (${tauxInsertionReg} >= ${selectTauxInsertion6moisAgg( - "indicateurRegionSortie" - )} + "indicateurRegionSortie" + )} AND ${tauxPoursuiteReg} < ${selectTauxPoursuiteAgg( - "indicateurRegionSortie" - )}) + "indicateurRegionSortie" + )}) THEN 'Q2' WHEN (${tauxInsertionReg} < ${selectTauxInsertion6moisAgg( - "indicateurRegionSortie" - )} + "indicateurRegionSortie" + )} AND ${tauxPoursuiteReg} >= ${selectTauxPoursuiteAgg( - "indicateurRegionSortie" - )}) + "indicateurRegionSortie" + )}) THEN 'Q3' WHEN (${tauxInsertionReg} < ${selectTauxInsertion6moisAgg( - "indicateurRegionSortie" - )} + "indicateurRegionSortie" + )} AND ${tauxPoursuiteReg} < ${selectTauxPoursuiteAgg( - "indicateurRegionSortie" - )}) + "indicateurRegionSortie" + )}) THEN 'Q4' ELSE 'Hors quadrant' END`.as("positionQuadrant"), diff --git a/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts b/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts index 17578d8a9..d89a1e903 100644 --- a/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts +++ b/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts @@ -70,11 +70,11 @@ const queryFormations = ({ .where(notHistorique) .$call((q) => { if (!codesNiveauxDiplomes) return q; - return q.where("formation.codeNiveauDiplome", "in", codesNiveauxDiplomes) + return q.where("formation.codeNiveauDiplome", "in", codesNiveauxDiplomes); }) .$call((q) => { if (!libellesFilieres) return q; - return q.where("formation.libelleFiliere", "in", libellesFilieres) + return q.where("formation.libelleFiliere", "in", libellesFilieres); }) .select((eb) => [ "codeFormationDiplome", @@ -94,7 +94,9 @@ const queryFormations = ({ sql`SUM(${effectifAnnee({ alias: "iep" })})`.as( "effectifPrecedent" ), - sql`CONCAT(${eb.ref("formation.libelleDiplome")},' (',${eb.ref("niveauDiplome.libelleNiveauDiplome")}, ')')`.as("libelleDiplome"), + sql`CONCAT(${eb.ref("formation.libelleDiplome")},' (',${eb.ref( + "niveauDiplome.libelleNiveauDiplome" + )}, ')')`.as("libelleDiplome"), selectTauxPressionAgg("indicateurEntree").as("tauxPression"), (eb) => withInsertionReg({ @@ -151,7 +153,7 @@ const queryFormations = ({ cfdRef: "formationEtablissement.cfd", dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", - codesNiveauxDiplomes + codesNiveauxDiplomes, }).as("positionQuadrant"), ]) .$narrowType<{ @@ -198,7 +200,7 @@ const queryFormations = ({ sql`${sql.raw(orderBy.order)} NULLS LAST` ); }) - .orderBy("libelleNiveauDiplome", "asc") + .orderBy("libelleNiveauDiplome", "asc"); export const queryFormationsRegion = async ({ codeRegion, @@ -206,7 +208,7 @@ export const queryFormationsRegion = async ({ millesimeSortie = "2020_2021", codesNiveauxDiplomes, libellesFilieres, - orderBy + orderBy, }: { codeRegion: string; rentreeScolaire?: string; @@ -215,7 +217,13 @@ export const queryFormationsRegion = async ({ libellesFilieres?: string[]; orderBy?: { column: string; order: "asc" | "desc" }; }) => { - const formations = await queryFormations({ rentreeScolaire, millesimeSortie, codesNiveauxDiplomes, libellesFilieres, orderBy }) + const formations = await queryFormations({ + rentreeScolaire, + millesimeSortie, + codesNiveauxDiplomes, + libellesFilieres, + orderBy, + }) .where("etablissement.codeRegion", "=", codeRegion) .execute(); @@ -228,7 +236,7 @@ export const queryFormationsDepartement = async ({ millesimeSortie = "2020_2021", codesNiveauxDiplomes, libellesFilieres, - orderBy + orderBy, }: { codeDepartement: string; rentreeScolaire?: string; @@ -237,7 +245,13 @@ export const queryFormationsDepartement = async ({ libellesFilieres?: string[]; orderBy?: { column: string; order: "asc" | "desc" }; }) => { - const formations = await queryFormations({ rentreeScolaire, millesimeSortie, codesNiveauxDiplomes, libellesFilieres, orderBy }) + const formations = await queryFormations({ + rentreeScolaire, + millesimeSortie, + codesNiveauxDiplomes, + libellesFilieres, + orderBy, + }) .where("etablissement.codeDepartement", "=", codeDepartement) .execute(); @@ -246,16 +260,28 @@ export const queryFormationsDepartement = async ({ export const getFilters = async ({ codeRegion, - codeDepartement + codeDepartement, }: { codeRegion?: string; codeDepartement?: string; }) => { - const filtersBase = kdb. - selectFrom("niveauDiplome") - .leftJoin("formation", "formation.codeNiveauDiplome", "niveauDiplome.codeNiveauDiplome") - .leftJoin("formationEtablissement", "formationEtablissement.cfd", "formation.codeFormationDiplome") - .leftJoin("etablissement", "etablissement.UAI", "formationEtablissement.UAI") + const filtersBase = kdb + .selectFrom("niveauDiplome") + .leftJoin( + "formation", + "formation.codeNiveauDiplome", + "niveauDiplome.codeNiveauDiplome" + ) + .leftJoin( + "formationEtablissement", + "formationEtablissement.cfd", + "formation.codeFormationDiplome" + ) + .leftJoin( + "etablissement", + "etablissement.UAI", + "formationEtablissement.UAI" + ) .$call((eb) => { if (!codeRegion) return eb; return eb.where("etablissement.codeRegion", "=", codeRegion); @@ -265,13 +291,12 @@ export const getFilters = async ({ return eb.where("etablissement.codeDepartement", "=", codeDepartement); }) .distinct() - .$castTo<{ label: string; value: string }>() - + .$castTo<{ label: string; value: string }>(); const diplomes = await filtersBase .select([ "niveauDiplome.codeNiveauDiplome as value", - "niveauDiplome.libelleNiveauDiplome as label" + "niveauDiplome.libelleNiveauDiplome as label", ]) .where("formation.codeNiveauDiplome", "is not", null) .execute(); @@ -284,9 +309,8 @@ export const getFilters = async ({ .where("formation.libelleFiliere", "is not", null) .execute(); - return { diplomes: diplomes.map(cleanNull), - filieres: filieres.map(cleanNull) - } -} + filieres: filieres.map(cleanNull), + }; +}; diff --git a/server/src/modules/data/usecases/getDataForPanorama/getDataForPanorama.usecase.ts b/server/src/modules/data/usecases/getDataForPanorama/getDataForPanorama.usecase.ts index aa78cd230..785a33892 100644 --- a/server/src/modules/data/usecases/getDataForPanorama/getDataForPanorama.usecase.ts +++ b/server/src/modules/data/usecases/getDataForPanorama/getDataForPanorama.usecase.ts @@ -1,35 +1,42 @@ import { inject } from "injecti"; -import { getFilters, queryFormationsDepartement, queryFormationsRegion } from "./dependencies"; +import { + getFilters, + queryFormationsDepartement, + queryFormationsRegion, +} from "./dependencies"; export const [getDataForPanoramaRegion] = inject( { queryFormationsRegion, - getFilters + getFilters, }, (deps) => - async ( - { + async ({ + codeRegion, + codesNiveauxDiplomes, + libellesFilieres, + orderBy, + }: { + codeRegion: string; + codesNiveauxDiplomes?: string[]; + libellesFilieres?: string[]; + orderBy?: { column: string; order: "asc" | "desc" }; + }) => { + const formations = await deps.queryFormationsRegion({ codeRegion, codesNiveauxDiplomes, libellesFilieres, - orderBy - }: { - codeRegion: string; - codesNiveauxDiplomes?: string[]; - libellesFilieres?: string[]; - orderBy?: { column: string; order: "asc" | "desc" }; - }) => { - - const formations = await deps.queryFormationsRegion({ codeRegion, codesNiveauxDiplomes, libellesFilieres, orderBy }); - const { diplomes, filieres } = await deps.getFilters({ codeRegion }) + orderBy, + }); + const { diplomes, filieres } = await deps.getFilters({ codeRegion }); return { formations, filters: { diplomes, - filieres - } + filieres, + }, }; } ); @@ -37,33 +44,34 @@ export const [getDataForPanoramaRegion] = inject( export const [getDataForPanoramaDepartement] = inject( { queryFormationsDepartement, - getFilters + getFilters, }, (deps) => - async ( - { + async ({ + codeDepartement, + codesNiveauxDiplomes, + libellesFilieres, + orderBy, + }: { + codeDepartement: string; + codesNiveauxDiplomes?: string[]; + libellesFilieres?: string[]; + orderBy?: { column: string; order: "asc" | "desc" }; + }) => { + const formations = await deps.queryFormationsDepartement({ codeDepartement, codesNiveauxDiplomes, libellesFilieres, - orderBy - }: { - codeDepartement: string; - codesNiveauxDiplomes?: string[]; - libellesFilieres?: string[]; - orderBy?: { column: string; order: "asc" | "desc" }; - }) => { - - const formations = await deps.queryFormationsDepartement({ - codeDepartement, codesNiveauxDiplomes, libellesFilieres, orderBy + orderBy, }); - const { diplomes, filieres } = await deps.getFilters({ codeDepartement }) + const { diplomes, filieres } = await deps.getFilters({ codeDepartement }); return { formations, filters: { diplomes, - filieres - } + filieres, + }, }; } ); diff --git a/server/src/modules/data/usecases/getEtablissement/dependencies.ts b/server/src/modules/data/usecases/getEtablissement/dependencies.ts index a3cf2a70c..6599b5891 100644 --- a/server/src/modules/data/usecases/getEtablissement/dependencies.ts +++ b/server/src/modules/data/usecases/getEtablissement/dependencies.ts @@ -17,7 +17,7 @@ const getEtablissementInDb = async ({ uai, millesimeSortie = "2020_2021", rentreeScolaire = "2022", - orderBy + orderBy, }: { uai: string; millesimeSortie?: string; @@ -76,7 +76,11 @@ const getEtablissementInDb = async ({ ) .leftJoin("indicateurEntree as iep", (join) => join - .onRef("formationEtablissement.id", "=", "iep.formationEtablissementId") + .onRef( + "formationEtablissement.id", + "=", + "iep.formationEtablissementId" + ) .on("iep.rentreeScolaire", "=", "2021") ) .select((sb) => [ @@ -88,13 +92,17 @@ const getEtablissementInDb = async ({ "formation.libelleFiliere", "formation.CPC", "formation.CPCSecteur", - sql`CONCAT(${sb.ref("formation.libelleDiplome")},' (',${sb.ref("niveauDiplome.libelleNiveauDiplome")}, ')')`.as("libelleDiplome"), + sql`CONCAT(${sb.ref( + "formation.libelleDiplome" + )},' (',${sb.ref("niveauDiplome.libelleNiveauDiplome")}, ')')`.as( + "libelleDiplome" + ), "formation.CPCSousSecteur", sql`COUNT(e."UAI")`.as("nbEtablissement"), selectTauxRemplissageAgg("indicateurEntree").as("tauxRemplissage"), - sql`SUM(${effectifAnnee({ alias: "indicateurEntree" })})`.as( - "effectif" - ), + sql`SUM(${effectifAnnee({ + alias: "indicateurEntree", + })})`.as("effectif"), sql`SUM(${effectifAnnee({ alias: "iep" })})`.as( "effectifPrecedent" ), diff --git a/server/src/modules/data/usecases/getEtablissement/getEtablissement.usecase.ts b/server/src/modules/data/usecases/getEtablissement/getEtablissement.usecase.ts index 2d8a4e55b..af9ef4748 100644 --- a/server/src/modules/data/usecases/getEtablissement/getEtablissement.usecase.ts +++ b/server/src/modules/data/usecases/getEtablissement/getEtablissement.usecase.ts @@ -6,17 +6,16 @@ import { dependencies } from "./dependencies"; export const [getEtablissement] = inject( { getEtablissementInD: dependencies.getEtablissementInDb }, (deps) => - async ( - { - uai, - orderBy - }: { - uai: string; - orderBy?: { column: string; order: "asc" | "desc" }; - }) => { + async ({ + uai, + orderBy, + }: { + uai: string; + orderBy?: { column: string; order: "asc" | "desc" }; + }) => { const etablissement = await deps.getEtablissementInD({ uai, - orderBy + orderBy, }); return ( diff --git a/server/src/modules/data/usecases/getFormations/dependencies.ts b/server/src/modules/data/usecases/getFormations/dependencies.ts index fd624080c..0d754ef6a 100644 --- a/server/src/modules/data/usecases/getFormations/dependencies.ts +++ b/server/src/modules/data/usecases/getFormations/dependencies.ts @@ -188,24 +188,24 @@ const findFormationsInDb = async ({ cmpr("indicateurEntree.rentreeScolaire", "is not", null), withEmptyFormations ? not( - exists( - selectFrom("formationEtablissement as fe") - .select("cfd") - .distinct() - .innerJoin( - "indicateurEntree", - "id", - "formationEtablissementId" - ) - .where("rentreeScolaire", "in", rentreeScolaire) - .whereRef( - "fe.dispositifId", - "=", - "formationEtablissement.dispositifId" - ) - .whereRef("fe.cfd", "=", "formationEtablissement.cfd") + exists( + selectFrom("formationEtablissement as fe") + .select("cfd") + .distinct() + .innerJoin( + "indicateurEntree", + "id", + "formationEtablissementId" + ) + .where("rentreeScolaire", "in", rentreeScolaire) + .whereRef( + "fe.dispositifId", + "=", + "formationEtablissement.dispositifId" + ) + .whereRef("fe.cfd", "=", "formationEtablissement.cfd") + ) ) - ) : sql`false`, ]) ) diff --git a/server/src/modules/data/usecases/getFormations/getFormations.usecase.ts b/server/src/modules/data/usecases/getFormations/getFormations.usecase.ts index 8c07d039b..f784fc074 100644 --- a/server/src/modules/data/usecases/getFormations/getFormations.usecase.ts +++ b/server/src/modules/data/usecases/getFormations/getFormations.usecase.ts @@ -7,36 +7,36 @@ const getFormationsFactory = findFiltersInDb: dependencies.findFiltersInDb, } ) => - async (activeFilters: { - offset?: number; - limit?: number; - codeRegion?: string[]; - codeAcademie?: string[]; - codeDepartement?: string[]; - codeDiplome?: string[]; - codeDispositif?: string[]; - commune?: string[]; - cfd?: string[]; - rentreeScolaire?: string[]; - cfdFamille?: string[]; - CPC?: string[]; - CPCSecteur?: string[]; - CPCSousSecteur?: string[]; - libelleFiliere?: string[]; - orderBy?: { order: "asc" | "desc"; column: string }; - withEmptyFormations?: boolean; - positionQuadrant?: string; - }) => { - const [{ formations, count }, filters] = await Promise.all([ - deps.findFormationsInDb(activeFilters), - deps.findFiltersInDb(activeFilters), - ]); + async (activeFilters: { + offset?: number; + limit?: number; + codeRegion?: string[]; + codeAcademie?: string[]; + codeDepartement?: string[]; + codeDiplome?: string[]; + codeDispositif?: string[]; + commune?: string[]; + cfd?: string[]; + rentreeScolaire?: string[]; + cfdFamille?: string[]; + CPC?: string[]; + CPCSecteur?: string[]; + CPCSousSecteur?: string[]; + libelleFiliere?: string[]; + orderBy?: { order: "asc" | "desc"; column: string }; + withEmptyFormations?: boolean; + positionQuadrant?: string; + }) => { + const [{ formations, count }, filters] = await Promise.all([ + deps.findFormationsInDb(activeFilters), + deps.findFiltersInDb(activeFilters), + ]); - return { - count, - filters, - formations, - }; + return { + count, + filters, + formations, }; + }; export const getFormations = getFormationsFactory(); diff --git a/server/src/modules/data/usecases/getRestitutionIntentionsStats/dependencies.ts b/server/src/modules/data/usecases/getRestitutionIntentionsStats/dependencies.ts index f4f94e64f..01bafaaeb 100644 --- a/server/src/modules/data/usecases/getRestitutionIntentionsStats/dependencies.ts +++ b/server/src/modules/data/usecases/getRestitutionIntentionsStats/dependencies.ts @@ -701,10 +701,10 @@ const findFiltersInDb = async ({ ]), motif ? eb.or( - motif.map( - (m) => sql`${m} = any(${eb.ref("demande.motif")})` + motif.map( + (m) => sql`${m} = any(${eb.ref("demande.motif")})` + ) ) - ) : sql`false`, ]); }) diff --git a/server/src/modules/data/usecases/getRestitutionIntentionsStats/getRestitutionIntentionsStats.usecase.ts b/server/src/modules/data/usecases/getRestitutionIntentionsStats/getRestitutionIntentionsStats.usecase.ts index ffa361513..616b23d5b 100644 --- a/server/src/modules/data/usecases/getRestitutionIntentionsStats/getRestitutionIntentionsStats.usecase.ts +++ b/server/src/modules/data/usecases/getRestitutionIntentionsStats/getRestitutionIntentionsStats.usecase.ts @@ -6,44 +6,44 @@ const getRestitutionIntentionsStatsFactory = findRestitutionIntentionsStatsInDB = dependencies.findRestitutionIntentionsStatsInDB, findFiltersInDb = dependencies.findFiltersInDb, }) => - async (activeFilters: { - status?: "draft" | "submitted"; - codeRegion?: string[]; - rentreeScolaire?: string; - typeDemande?: string[]; - motif?: string[]; - cfd?: string[]; - codeNiveauDiplome?: string[]; - dispositif?: string[]; - filiere?: string[]; - coloration?: string; - amiCMA?: string; - secteur?: string; - cfdFamille?: string[]; - codeDepartement?: string[]; - codeAcademie?: string[]; - commune?: string[]; - uai?: string[]; - compensation?: string; - user: Pick; - offset?: number; - limit?: number; - orderBy?: { - order: "asc" | "desc"; - column: string; - }; - }) => { - const [{ count, demandes }, filters] = await Promise.all([ - findRestitutionIntentionsStatsInDB(activeFilters), - findFiltersInDb(activeFilters), - ]); + async (activeFilters: { + status?: "draft" | "submitted"; + codeRegion?: string[]; + rentreeScolaire?: string; + typeDemande?: string[]; + motif?: string[]; + cfd?: string[]; + codeNiveauDiplome?: string[]; + dispositif?: string[]; + filiere?: string[]; + coloration?: string; + amiCMA?: string; + secteur?: string; + cfdFamille?: string[]; + codeDepartement?: string[]; + codeAcademie?: string[]; + commune?: string[]; + uai?: string[]; + compensation?: string; + user: Pick; + offset?: number; + limit?: number; + orderBy?: { + order: "asc" | "desc"; + column: string; + }; + }) => { + const [{ count, demandes }, filters] = await Promise.all([ + findRestitutionIntentionsStatsInDB(activeFilters), + findFiltersInDb(activeFilters), + ]); - return { - count, - filters, - demandes, - }; + return { + count, + filters, + demandes, }; + }; export const getRestitutionIntentionsStats = getRestitutionIntentionsStatsFactory({}); diff --git a/server/src/modules/data/usecases/getTransformationStats/getTransformationStats.usecase.ts b/server/src/modules/data/usecases/getTransformationStats/getTransformationStats.usecase.ts index ee325e679..bbbd27db4 100644 --- a/server/src/modules/data/usecases/getTransformationStats/getTransformationStats.usecase.ts +++ b/server/src/modules/data/usecases/getTransformationStats/getTransformationStats.usecase.ts @@ -41,8 +41,8 @@ const formatTerritoire = (item: DataTerritoire) => ({ differenceCapaciteApprentissage: item.differenceCapaciteApprentissage || 0, placesTransformees: item.placesOuvertesScolaire + - item.placesOuvertesApprentissage + - item.placesFermeesScolaire || 0, + item.placesOuvertesApprentissage + + item.placesFermeesScolaire || 0, }); const formatResult = ( @@ -58,13 +58,13 @@ const formatResult = ( result[0]?.national.placesOuvertesApprentissage || 0, placesOuvertes: result[0]?.national.placesOuvertesScolaire + - result[0]?.national.placesOuvertesApprentissage || 0, + result[0]?.national.placesOuvertesApprentissage || 0, placesFermeesScolaire: result[0]?.national.placesFermeesScolaire || 0, placesFermeesApprentissage: result[0]?.national.placesFermeesApprentissage || 0, placesFermees: result[0]?.national.placesFermeesScolaire + - result[0]?.national.placesFermeesApprentissage || 0, + result[0]?.national.placesFermeesApprentissage || 0, ratioFermeture: Math.round( ((result[0]?.national.placesFermeesScolaire + @@ -89,7 +89,7 @@ const formatResult = ( result[0]?.national.differenceCapaciteApprentissage || 0, placesTransformees: result[0]?.national.differenceCapaciteScolaire + - result[0]?.national.differenceCapaciteApprentissage || 0, + result[0]?.national.differenceCapaciteApprentissage || 0, tauxTransformation: Math.round( (result[0]?.national.transformes / effectifNational || 0) * 10000 @@ -127,7 +127,7 @@ const formatResult = ( Math.round( (items[0].academie.transforme / effectifsAcademie[items[0].academie.codeAcademie ?? ""] || 0) * - 10000 + 10000 ) / 100, effectif: effectifsAcademie[items[0].academie.codeAcademie ?? ""] || 0, })) @@ -150,10 +150,12 @@ const formatResult = ( Math.round( (items[0].departement.transforme / effectifsDepartements[ - items[0].departement.codeDepartement ?? "" + items[0].departement.codeDepartement ?? "" ] || 0) * 10000 ) / 100, - effectif: effectifsDepartements[items[0].departement.codeDepartement ?? ""] || 0, + effectif: + effectifsDepartements[items[0].departement.codeDepartement ?? ""] || + 0, })) .orderBy( (item) => { diff --git a/shared/client/etablissements/etablissements.client.ts b/shared/client/etablissements/etablissements.client.ts index 428c68f1b..768bf18d0 100644 --- a/shared/client/etablissements/etablissements.client.ts +++ b/shared/client/etablissements/etablissements.client.ts @@ -4,11 +4,13 @@ import { createClientMethod } from "../clientFactory"; import { ROUTES_CONFIG } from "../ROUTES_CONFIG"; export const createEtablissementClient = (instance: AxiosInstance) => ({ - getEtablissements: createClientMethod({ - method: "GET", - url: "/etablissements", - instance, - }), + getEtablissements: createClientMethod( + { + method: "GET", + url: "/etablissements", + instance, + } + ), getEtablissement: createClientMethod({ method: "GET", url: "/etablissement", diff --git a/shared/client/etablissements/etablissements.schema.ts b/shared/client/etablissements/etablissements.schema.ts index 04e66f5a5..f2034123a 100644 --- a/shared/client/etablissements/etablissements.schema.ts +++ b/shared/client/etablissements/etablissements.schema.ts @@ -127,7 +127,9 @@ export const etablissementSchemas = { getEtablissement: { querystring: Type.Object({ uai: Type.String(), - order: Type.Optional(Type.Union([Type.Literal("asc"), Type.Literal("desc")])), + order: Type.Optional( + Type.Union([Type.Literal("asc"), Type.Literal("desc")]) + ), orderBy: Type.Optional(Type.KeyOf(FormationSchema)), }), response: { diff --git a/shared/client/formations/formation.schema.ts b/shared/client/formations/formation.schema.ts index d396ab6a1..d389f036b 100644 --- a/shared/client/formations/formation.schema.ts +++ b/shared/client/formations/formation.schema.ts @@ -122,7 +122,9 @@ export const formationSchemas = { codeRegion: Type.String(), codesNiveauxDiplomes: Type.Optional(Type.Array(Type.String())), libellesFilieres: Type.Optional(Type.Array(Type.String())), - order: Type.Optional(Type.Union([Type.Literal("asc"), Type.Literal("desc")])), + order: Type.Optional( + Type.Union([Type.Literal("asc"), Type.Literal("desc")]) + ), orderBy: Type.Optional(Type.KeyOf(FormationSchema)), }), response: { @@ -131,7 +133,7 @@ export const formationSchemas = { filters: Type.Object({ diplomes: Type.Array(OptionSchema), filieres: Type.Array(OptionSchema), - }) + }), }), }, }, @@ -140,7 +142,9 @@ export const formationSchemas = { codeDepartement: Type.String(), codesNiveauxDiplomes: Type.Optional(Type.Array(Type.String())), libellesFilieres: Type.Optional(Type.Array(Type.String())), - order: Type.Optional(Type.Union([Type.Literal("asc"), Type.Literal("desc")])), + order: Type.Optional( + Type.Union([Type.Literal("asc"), Type.Literal("desc")]) + ), orderBy: Type.Optional(Type.KeyOf(FormationSchema)), }), response: { @@ -149,7 +153,7 @@ export const formationSchemas = { filters: Type.Object({ diplomes: Type.Array(OptionSchema), filieres: Type.Array(OptionSchema), - }) + }), }), }, }, diff --git a/ui/app/(wrapped)/components/Nav.tsx b/ui/app/(wrapped)/components/Nav.tsx index afec7993b..502e9d158 100644 --- a/ui/app/(wrapped)/components/Nav.tsx +++ b/ui/app/(wrapped)/components/Nav.tsx @@ -44,7 +44,7 @@ const NavLink = chakra( color="bluefrance.113" borderBottomWidth={3} borderColor={isActive ? "bluefrance.113" : "transparent"} - _hover={{ textDecoration: "unset", bg: "blue.faded" }} + _hover={{ textDecoration: "unset", bg: "blueecume.925" }} > {children} @@ -81,7 +81,7 @@ const NavMenuLink = chakra( m="0" color="bluefrance.113" bg={isActive ? "grey.1000_hover" : "inherit"} - _hover={{ textDecoration: "unset", bg: "blue.faded" }} + _hover={{ textDecoration: "unset", bg: "blueecume.950" }} > {children} @@ -116,7 +116,7 @@ const NavMenuButton = chakra( color="bluefrance.113" borderBottomWidth={3} borderColor={isActive ? "bluefrance.113" : "transparent"} - _hover={{ textDecoration: "unset", bg: "blue.faded" }} + _hover={{ textDecoration: "unset", bg: "blueecume.950" }} as={Button} rightIcon={} > diff --git a/ui/app/(wrapped)/console/etablissements/components/LineContent.tsx b/ui/app/(wrapped)/console/etablissements/components/LineContent.tsx index c691ac9f9..553467049 100644 --- a/ui/app/(wrapped)/console/etablissements/components/LineContent.tsx +++ b/ui/app/(wrapped)/console/etablissements/components/LineContent.tsx @@ -98,7 +98,7 @@ export const EtablissementLineContent = ({ }; export const EtablissementLineLoader = () => ( - + {new Array(17).fill(0).map((_, i) => ( @@ -108,7 +108,7 @@ export const EtablissementLineLoader = () => ( ); export const EtablissementLinePlaceholder = () => ( - + ); diff --git a/ui/app/(wrapped)/console/etablissements/page.tsx b/ui/app/(wrapped)/console/etablissements/page.tsx index d0275ed6a..420c6c578 100644 --- a/ui/app/(wrapped)/console/etablissements/page.tsx +++ b/ui/app/(wrapped)/console/etablissements/page.tsx @@ -635,7 +635,7 @@ export default function Etablissements() { historique.map((historiqueLine) => ( diff --git a/ui/app/(wrapped)/console/formations/components/LineContent.tsx b/ui/app/(wrapped)/console/formations/components/LineContent.tsx index b19b546ee..b5fc2b29e 100644 --- a/ui/app/(wrapped)/console/formations/components/LineContent.tsx +++ b/ui/app/(wrapped)/console/formations/components/LineContent.tsx @@ -107,7 +107,7 @@ export const FormationLineContent = ({ }; export const FormationLineLoader = () => ( - + {new Array(17).fill(0).map((_, i) => ( @@ -117,7 +117,7 @@ export const FormationLineLoader = () => ( ); export const FormationLinePlaceholder = () => ( - + ); diff --git a/ui/app/(wrapped)/console/formations/page.tsx b/ui/app/(wrapped)/console/formations/page.tsx index cfa7f7f6c..592528103 100644 --- a/ui/app/(wrapped)/console/formations/page.tsx +++ b/ui/app/(wrapped)/console/formations/page.tsx @@ -534,7 +534,7 @@ export default function Formations() { historique.map((historiqueLine) => ( diff --git a/ui/app/(wrapped)/intentions/pilotage/components/IndicateursClesSection.tsx b/ui/app/(wrapped)/intentions/pilotage/components/IndicateursClesSection.tsx index e3bf7e093..4fb239395 100644 --- a/ui/app/(wrapped)/intentions/pilotage/components/IndicateursClesSection.tsx +++ b/ui/app/(wrapped)/intentions/pilotage/components/IndicateursClesSection.tsx @@ -139,7 +139,7 @@ const Delta = ({ delta }: { delta: number | null }) => { } return ( - + {deltaIcon} @@ -359,7 +359,7 @@ export const IndicateursClesSection = ({ - + (CALCULÉ SUR LES DEMANDES VALIDÉES) - + (CALCULÉ SUR LES PROJETS DE DEMANDE) - + DÉTAILS SUR LA FORMATION @@ -390,7 +390,7 @@ export const QuadrantSection = ({
- + FILTRES diff --git a/ui/app/(wrapped)/intentions/pilotage/components/VueOuverturesFermeturesSection.tsx b/ui/app/(wrapped)/intentions/pilotage/components/VueOuverturesFermeturesSection.tsx index f4d62d3d0..c0c583d49 100644 --- a/ui/app/(wrapped)/intentions/pilotage/components/VueOuverturesFermeturesSection.tsx +++ b/ui/app/(wrapped)/intentions/pilotage/components/VueOuverturesFermeturesSection.tsx @@ -22,7 +22,7 @@ const Loader = () => ( {new Array(7).fill(0).map((_, i) => ( - + @@ -185,7 +185,7 @@ export const VueOuverturesFermeturesSection = ({ {Object.values(data?.all?.regions ?? []).map((region) => { const trBgColor = region.codeRegion === codeRegion - ? "blue.main !important" + ? "blueecume.400_hover !important" : ""; const tdBgColor = @@ -197,7 +197,9 @@ export const VueOuverturesFermeturesSection = ({ region.codeRegion === codeRegion ? "white" : "inherit"; const color = - region.codeRegion === codeRegion ? "inherit" : "#000091"; + region.codeRegion === codeRegion + ? "inherit" + : "bluefrance.113"; return ( diff --git a/ui/app/(wrapped)/intentions/pilotage/components/VueTauxTransformationSection.tsx b/ui/app/(wrapped)/intentions/pilotage/components/VueTauxTransformationSection.tsx index 43007919a..fadb34ff8 100644 --- a/ui/app/(wrapped)/intentions/pilotage/components/VueTauxTransformationSection.tsx +++ b/ui/app/(wrapped)/intentions/pilotage/components/VueTauxTransformationSection.tsx @@ -22,7 +22,7 @@ const Loader = () => (
{new Array(7).fill(0).map((_, i) => ( - + @@ -160,7 +160,7 @@ export const VueTauxTransformationSection = ({ {Object.values(data?.all?.regions ?? []).map((region) => { const trBgColor = region.codeRegion === codeRegion - ? "blue.main !important" + ? "blueecume.400_hover !important" : ""; const tdBgColor = @@ -181,7 +181,9 @@ export const VueTauxTransformationSection = ({ region.codeRegion === codeRegion ? "white" : "inherit"; const color = - region.codeRegion === codeRegion ? "inherit" : "#000091"; + region.codeRegion === codeRegion + ? "inherit" + : "bluefrance.113"; return ( diff --git a/ui/app/(wrapped)/intentions/pilotage/page.tsx b/ui/app/(wrapped)/intentions/pilotage/page.tsx index a58c53298..dfd32f2fe 100644 --- a/ui/app/(wrapped)/intentions/pilotage/page.tsx +++ b/ui/app/(wrapped)/intentions/pilotage/page.tsx @@ -135,7 +135,7 @@ export default withAuth( }; return ( - + { return ( - + diff --git a/ui/app/(wrapped)/intentions/restitution/HeaderSection/PrimaryFiltersSection.tsx b/ui/app/(wrapped)/intentions/restitution/HeaderSection/PrimaryFiltersSection.tsx index 36e5ce630..e65bcdb27 100644 --- a/ui/app/(wrapped)/intentions/restitution/HeaderSection/PrimaryFiltersSection.tsx +++ b/ui/app/(wrapped)/intentions/restitution/HeaderSection/PrimaryFiltersSection.tsx @@ -36,7 +36,14 @@ export const PrimaryFiltersSection = ({ > ) : ( - + { return ( - + {children} diff --git a/ui/app/(wrapped)/intentions/saisie/intentionForm/IntentionForm.tsx b/ui/app/(wrapped)/intentions/saisie/intentionForm/IntentionForm.tsx index b031bb45a..8c54256f6 100644 --- a/ui/app/(wrapped)/intentions/saisie/intentionForm/IntentionForm.tsx +++ b/ui/app/(wrapped)/intentions/saisie/intentionForm/IntentionForm.tsx @@ -127,7 +127,7 @@ export const IntentionForm = ({ submitDemande(values))} diff --git a/ui/app/(wrapped)/intentions/saisie/intentionForm/capaciteSection/CapaciteSection.tsx b/ui/app/(wrapped)/intentions/saisie/intentionForm/capaciteSection/CapaciteSection.tsx index fae639836..62578ac5b 100644 --- a/ui/app/(wrapped)/intentions/saisie/intentionForm/capaciteSection/CapaciteSection.tsx +++ b/ui/app/(wrapped)/intentions/saisie/intentionForm/capaciteSection/CapaciteSection.tsx @@ -31,8 +31,8 @@ import { ColorationField } from "./ColorationField"; const ConstanteField = ({ value }: { value: string | number | undefined }) => ( - + {formId ? `Demande n° ${formId}` : "Nouvelle demande"} {!disabled && ( diff --git a/ui/app/(wrapped)/intentions/saisie/intentionForm/typeDemandeSection/TypeDemandeField.tsx b/ui/app/(wrapped)/intentions/saisie/intentionForm/typeDemandeSection/TypeDemandeField.tsx index 97d1d549a..00d4f8ca6 100644 --- a/ui/app/(wrapped)/intentions/saisie/intentionForm/typeDemandeSection/TypeDemandeField.tsx +++ b/ui/app/(wrapped)/intentions/saisie/intentionForm/typeDemandeSection/TypeDemandeField.tsx @@ -50,7 +50,7 @@ function RadioCard({ borderWidth="1px" aria-checked={selected} _checked={{ - bg: "blue.faded", + bg: "blueecume.925", boxShadow: `0 0 0 2px ${bf113}`, }} p={4} diff --git a/ui/app/(wrapped)/intentions/saisie/intentionForm/typeDemandeSection/TypeDemandeSection.tsx b/ui/app/(wrapped)/intentions/saisie/intentionForm/typeDemandeSection/TypeDemandeSection.tsx index 5422eb566..86878766e 100644 --- a/ui/app/(wrapped)/intentions/saisie/intentionForm/typeDemandeSection/TypeDemandeSection.tsx +++ b/ui/app/(wrapped)/intentions/saisie/intentionForm/typeDemandeSection/TypeDemandeSection.tsx @@ -46,11 +46,11 @@ export const TypeDemandeSection = ({ {isTypeCompensation(typeDemande) && ( diff --git a/ui/app/(wrapped)/panorama/components/TopFlopSection.tsx b/ui/app/(wrapped)/panorama/components/TopFlopSection.tsx index 1c1e9664d..07d07f6f9 100644 --- a/ui/app/(wrapped)/panorama/components/TopFlopSection.tsx +++ b/ui/app/(wrapped)/panorama/components/TopFlopSection.tsx @@ -71,7 +71,7 @@ const TopFlopChart = ({ topFlopFormations: { top: PanoramaFormations; flop: PanoramaFormations }; }) => { return ( - + Taux de devenir favorable @@ -99,7 +99,7 @@ const TopFlopChart = ({ ))} @@ -111,7 +111,7 @@ const TopFlopChart = ({ const TopItem = ({ formation, value, - color = "#8585F6", + color = "bluefrance.625", }: { formation: PanoramaFormation; value: number; diff --git a/ui/app/(wrapped)/panorama/departement/PanoramaSelection.tsx b/ui/app/(wrapped)/panorama/departement/PanoramaSelection.tsx index b66ba121f..265e67942 100644 --- a/ui/app/(wrapped)/panorama/departement/PanoramaSelection.tsx +++ b/ui/app/(wrapped)/panorama/departement/PanoramaSelection.tsx @@ -43,7 +43,7 @@ export function PanoramaSelection({ as="section" pb="12" pt="6" - bg="#F9F8F6" + bg="grey.975" maxWidth={"container.xl"} > diff --git a/ui/app/(wrapped)/panorama/etablissement/PanoramaSelection.tsx b/ui/app/(wrapped)/panorama/etablissement/PanoramaSelection.tsx index 3d1538fb7..f6a72a443 100644 --- a/ui/app/(wrapped)/panorama/etablissement/PanoramaSelection.tsx +++ b/ui/app/(wrapped)/panorama/etablissement/PanoramaSelection.tsx @@ -36,7 +36,7 @@ export function PanoramaSelection({ wrongUai }: { wrongUai?: string }) { as="section" pb="12" pt="6" - bg="#F9F8F6" + bg="grey.975" maxWidth={"container.xl"} > diff --git a/ui/app/(wrapped)/panorama/etablissement/[uai]/EtablissementSection.tsx b/ui/app/(wrapped)/panorama/etablissement/[uai]/EtablissementSection.tsx index dd8d71cfe..748f5f550 100644 --- a/ui/app/(wrapped)/panorama/etablissement/[uai]/EtablissementSection.tsx +++ b/ui/app/(wrapped)/panorama/etablissement/[uai]/EtablissementSection.tsx @@ -71,7 +71,7 @@ export const EtablissementSection = ({ as="section" pb="12" pt="6" - bg="#F9F8F6" + bg="grey.975" maxWidth={"container.xl"} > diff --git a/ui/app/(wrapped)/panorama/layout.tsx b/ui/app/(wrapped)/panorama/layout.tsx index a9967c74f..febf67cf1 100644 --- a/ui/app/(wrapped)/panorama/layout.tsx +++ b/ui/app/(wrapped)/panorama/layout.tsx @@ -60,7 +60,7 @@ export default function PanoramaLayout({ children }: { children: ReactNode }) { variant="enclosed-colored" minHeight="0" > - + Région diff --git a/ui/app/(wrapped)/panorama/region/PanoramaSelection.tsx b/ui/app/(wrapped)/panorama/region/PanoramaSelection.tsx index f5f77e328..bda7b6514 100644 --- a/ui/app/(wrapped)/panorama/region/PanoramaSelection.tsx +++ b/ui/app/(wrapped)/panorama/region/PanoramaSelection.tsx @@ -43,7 +43,7 @@ export function PanoramaSelection({ as="section" pb="12" pt="6" - bg="#F9F8F6" + bg="grey.975" maxWidth={"container.xl"} > diff --git a/ui/app/(wrapped)/panorama/types.ts b/ui/app/(wrapped)/panorama/types.ts index 4f702380a..cb188a1bf 100644 --- a/ui/app/(wrapped)/panorama/types.ts +++ b/ui/app/(wrapped)/panorama/types.ts @@ -2,8 +2,12 @@ import { ApiType } from "shared"; import { api } from "@/api.client"; -export type QueryPanoramaFormation = Parameters[0]["query"] | Parameters[0]["query"]; -export type QueryPanoramaEtablissement = Parameters[0]["query"]; +export type QueryPanoramaFormation = + | Parameters[0]["query"] + | Parameters[0]["query"]; +export type QueryPanoramaEtablissement = Parameters< + typeof api.getEtablissement +>[0]["query"]; export type PanoramaFormationRegion = ApiType< typeof api.getDataForPanoramaRegion @@ -34,7 +38,6 @@ export type PanoramaFormations = | PanoramaFormationsRegion | PanoramaFormationsDepartement; - export type StatsFormationsRegion = ApiType; export type StatsFormationsDepartement = ApiType< typeof api.getDepartementStats @@ -43,14 +46,17 @@ export type StatsFormations = | StatsFormationsRegion | StatsFormationsDepartement; - -export type OrderPanoramaFormation = Pick; -export type OrderPanoramaEtablissement = Pick; +export type OrderPanoramaFormation = Pick< + QueryPanoramaFormation, + "order" | "orderBy" +>; +export type OrderPanoramaEtablissement = Pick< + QueryPanoramaEtablissement, + "order" | "orderBy" +>; export type Order = OrderPanoramaEtablissement | OrderPanoramaFormation; - export type FiltersPanoramaFormation = Pick< QueryPanoramaFormation, - | "codesNiveauxDiplomes" - | "libellesFilieres" + "codesNiveauxDiplomes" | "libellesFilieres" >; diff --git a/ui/app/(wrapped)/pilotage-reforme/components/BarGraph.tsx b/ui/app/(wrapped)/pilotage-reforme/components/BarGraph.tsx index d04ca3bec..045bac278 100644 --- a/ui/app/(wrapped)/pilotage-reforme/components/BarGraph.tsx +++ b/ui/app/(wrapped)/pilotage-reforme/components/BarGraph.tsx @@ -1,4 +1,4 @@ -import { Box } from "@chakra-ui/react"; +import { Box, useToken } from "@chakra-ui/react"; import * as echarts from "echarts"; import { useLayoutEffect, useMemo, useRef } from "react"; @@ -26,6 +26,8 @@ export const BarGraph = function < }) { const chartRef = useRef(); const containerRef = useRef(null); + const bf113 = useToken("colors", "bluefrance.113"); + const be850 = useToken("colors", "blueecume.850_active"); const option = useMemo( () => ({ @@ -46,7 +48,7 @@ export const BarGraph = function < color: "inherit", }, textStyle: { - color: "#96A6D8", + color: "blueecume.400_active", }, itemGap: 25, }, @@ -57,7 +59,7 @@ export const BarGraph = function < graphData?.anneeN.libelleAnnee, ], axisLabel: { - color: "#000091", + color: bf113, fontWeight: 700, }, }, @@ -65,7 +67,7 @@ export const BarGraph = function < type: "value", axisLabel: { formatter: "{value} %", - color: "#000091", + color: bf113, fontWeight: 700, }, splitNumber: 3, @@ -82,7 +84,7 @@ export const BarGraph = function < graphData?.anneeN.nationale ?? 0, ], type: "bar", - color: "#000091", + color: bf113, barMaxWidth: 50, itemStyle: { borderRadius: [15, 15, 0, 0], @@ -97,7 +99,7 @@ export const BarGraph = function < ] : [], type: "bar", - color: "#0974F6", + color: be850, barMaxWidth: 50, itemStyle: { borderRadius: [15, 15, 0, 0], @@ -112,7 +114,7 @@ export const BarGraph = function < graphData?.anneeN.nationale ?? 0, ], type: "bar", - color: "#000091", + color: bf113, barMaxWidth: 50, itemStyle: { borderRadius: [15, 15, 0, 0], diff --git a/ui/app/(wrapped)/pilotage-reforme/components/IndicateursClesSection.tsx b/ui/app/(wrapped)/pilotage-reforme/components/IndicateursClesSection.tsx index 06553ff7c..8b5b95179 100644 --- a/ui/app/(wrapped)/pilotage-reforme/components/IndicateursClesSection.tsx +++ b/ui/app/(wrapped)/pilotage-reforme/components/IndicateursClesSection.tsx @@ -59,7 +59,12 @@ const DeltaIcon = ({ if (delta < 0) deltaIcon = ( - + {children} ); @@ -67,13 +72,23 @@ const DeltaIcon = ({ else deltaIcon = ( - + {children} ); } else { deltaIcon = ( - + - ); @@ -93,7 +108,7 @@ const IndicateurCompare = ({ <> - + {indicateuranneeNMoins1 ? `${indicateuranneeNMoins1} / N-1` : "-"} @@ -124,7 +139,11 @@ const IndicateurEffectifLine = ({ }) => ( <> - + {label} @@ -205,7 +224,12 @@ const Delta = ({ if (delta < 0) deltaIcon = ( - + {`${delta} pts`} ); @@ -218,7 +242,7 @@ const Delta = ({ else deltaIcon = ( - + {`+${delta} pts`} ); @@ -227,7 +251,7 @@ const Delta = ({ } return ( - + {deltaIcon} {isNational && } @@ -345,12 +369,12 @@ const StatCard = ({ mr="4" flex={1} textTransform={"uppercase"} - color={"#000091"} + color={"bluefrance.113"} fontWeight={700} > {label} - + {getValue(type) ? ( `${getValue(type)} %` ) : ( diff --git a/ui/app/(wrapped)/pilotage-reforme/components/VueRegionAcademieSection.tsx b/ui/app/(wrapped)/pilotage-reforme/components/VueRegionAcademieSection.tsx index 76044cb68..901406de0 100644 --- a/ui/app/(wrapped)/pilotage-reforme/components/VueRegionAcademieSection.tsx +++ b/ui/app/(wrapped)/pilotage-reforme/components/VueRegionAcademieSection.tsx @@ -28,7 +28,7 @@ const Loader = () => (
{new Array(7).fill(0).map((_, i) => ( - + @@ -122,7 +122,7 @@ export const VueRegionAcademieSection = ({ {data?.statsRegions.map((region) => { const trBgColor = region.codeRegion === codeRegion - ? "blue.main !important" + ? "blueecume.400_hover !important" : ""; const tdBgColor = @@ -134,7 +134,9 @@ export const VueRegionAcademieSection = ({ region.codeRegion === codeRegion ? "white" : "inherit"; const color = - region.codeRegion === codeRegion ? "inherit" : "#000091"; + region.codeRegion === codeRegion + ? "inherit" + : "bluefrance.113"; return ( + void; }) => { + const colorPalette = useMemo( + () => + customColorPalette + ? customColorPalette + : objectif === "bas" + ? [ + useToken("colors", "pinkmacaron.950"), + useToken("colors", "pinkmacaron.925"), + useToken("colors", "pinkmacaron.850"), + useToken("colors", "pinkmacaron.689"), + ] + : [ + useToken("colors", "blueecume.925"), + useToken("colors", "blueecume.675_hover"), + useToken("colors", "blueecume.400_hover"), + useToken("colors", "bluefrance.113"), + ], + [customColorPalette, objectif] + ); + + const bluefrance525 = useToken("colors", "bluefrance.525"); + const bluefrance113 = useToken("colors", "bluefrance.113"); + const chartRef = useRef(); const containerRef = useRef(null); @@ -92,11 +115,7 @@ export const CartoGraph = ({ const max = Math.max(...removeMax(data)); const diff = max - min; - const colorRange = customColorPalette - ? customColorPalette - : objectif === "bas" - ? ["#FEE9E6", "#FDDFDA", "#FCC0B4", "#E18B76"] - : ["#D5DBEF", "#ABB8DE", "#5770BE", "#000091"]; + const colorRange = colorPalette; const piecesStep = customPiecesSteps ? customPiecesSteps @@ -168,7 +187,7 @@ export const CartoGraph = ({ emphasis: { label: { show: false, - color: "#000091", + color: bluefrance113, fontWeight: 600, fontSize: 14, fontFamily: "Marianne, Arial", @@ -179,7 +198,7 @@ export const CartoGraph = ({ }, itemStyle: { areaColor: "inherit", - borderColor: "#6a6af4", + borderColor: bluefrance525, borderWidth: 1, }, }, @@ -187,7 +206,7 @@ export const CartoGraph = ({ select: { disabled: false, label: { - color: "#000091", + color: bluefrance113, fontWeight: 600, fontSize: 14, fontFamily: "Marianne, Arial", @@ -198,13 +217,13 @@ export const CartoGraph = ({ }, itemStyle: { areaColor: "white", - borderColor: "#000091", + borderColor: bluefrance113, }, }, nameProperty: getNameProperty(), nameMap: getNameMap(), itemStyle: { - borderColor: "#FFF", + borderColor: "white", }, data: graphData, }, diff --git a/ui/components/InfoBlock.tsx b/ui/components/InfoBlock.tsx index c40278fa6..70db9752b 100644 --- a/ui/components/InfoBlock.tsx +++ b/ui/components/InfoBlock.tsx @@ -7,7 +7,7 @@ export const InfoBlock = chakra( label, value, className, - textBg = "#EEEEEE", + textBg = "grey.950", }: { label: ReactNode; value: ReactNode; diff --git a/ui/components/Quadrant.tsx b/ui/components/Quadrant.tsx index ce7ec0c81..1ce334516 100644 --- a/ui/components/Quadrant.tsx +++ b/ui/components/Quadrant.tsx @@ -10,6 +10,7 @@ import { PopoverTrigger, useOutsideClick, usePopper, + useToken, } from "@chakra-ui/react"; import * as echarts from "echarts"; import { EChartsOption } from "echarts"; @@ -64,6 +65,9 @@ export const Quadrant = function < const chartRef = useRef(); const containerRef = useRef(null); + const greenColor = useToken("colors", "green.submitted"); + const redColor = useToken("colors", "redmarianne.925"); + const popperInstance = usePopper({ modifiers: [ { @@ -216,7 +220,7 @@ export const Quadrant = function < [ { coord: [0, 0], - itemStyle: { color: "#ffe2e1" }, + itemStyle: { color: redColor }, name: `Q4 - ${repartitionsQuadrants?.q4} formations`, label: { ...quadrantLabelStyle, @@ -228,7 +232,7 @@ export const Quadrant = function < [ { coord: [meanPoursuite, meanInsertion], - itemStyle: { color: "#C8F6D6" }, + itemStyle: { color: greenColor }, name: `Q1 - ${repartitionsQuadrants?.q1} formations`, label: { ...quadrantLabelStyle, diff --git a/ui/components/TableQuadrant.tsx b/ui/components/TableQuadrant.tsx index f62780e7c..359a8e38b 100644 --- a/ui/components/TableQuadrant.tsx +++ b/ui/components/TableQuadrant.tsx @@ -49,12 +49,12 @@ export const TableQuadrant = ({ const getTrBgColor = (formation: Formation) => { if (currentCfd && formation.cfd === currentCfd) - return "blue.main !important"; + return "blueecume.400_hover !important"; switch (formation.positionQuadrant) { case "Q1": - return "#C8F6D6"; + return "green.submitted"; case "Q4": - return "#ffe2e1"; + return "redmarianne.925"; default: return "inherit"; } @@ -69,7 +69,7 @@ export const TableQuadrant = ({ >
Date: Wed, 15 Nov 2023 12:11:28 +0100 Subject: [PATCH 10/28] fix: regressions panorama --- .../src/modules/data/queries/utils/getMillesime.ts | 6 ++---- .../modules/data/queries/utils/getRentreeScolaire.ts | 5 +++++ .../data/usecases/getDataForPanorama/dependencies.ts | 12 ++++-------- .../getDataForPanorama/getDataForPanorama.usecase.ts | 1 - .../data/usecases/getEtablissement/dependencies.ts | 3 ++- .../(wrapped)/panorama/components/TopFlopSection.tsx | 3 +-- 6 files changed, 14 insertions(+), 16 deletions(-) create mode 100644 server/src/modules/data/queries/utils/getRentreeScolaire.ts diff --git a/server/src/modules/data/queries/utils/getMillesime.ts b/server/src/modules/data/queries/utils/getMillesime.ts index 0fa59ceda..67f9c6d53 100644 --- a/server/src/modules/data/queries/utils/getMillesime.ts +++ b/server/src/modules/data/queries/utils/getMillesime.ts @@ -1,9 +1,7 @@ export const getMillesimePrecedent = (millesimeSortie: string): string => - `${parseInt(millesimeSortie.split("_")[0]) - 1}_${ - parseInt(millesimeSortie.split("_")[2]) - 1 + `${parseInt(millesimeSortie.split("_")[0]) - 1}_${parseInt(millesimeSortie.split("_")[1]) - 1 }`; export const getMillesimeSuivant = (millesimeSortie: string): string => - `${parseInt(millesimeSortie.split("_")[0]) + 1}_${ - parseInt(millesimeSortie.split("_")[2]) + 1 + `${parseInt(millesimeSortie.split("_")[0]) + 1}_${parseInt(millesimeSortie.split("_")[1]) + 1 }`; diff --git a/server/src/modules/data/queries/utils/getRentreeScolaire.ts b/server/src/modules/data/queries/utils/getRentreeScolaire.ts new file mode 100644 index 000000000..d9544e925 --- /dev/null +++ b/server/src/modules/data/queries/utils/getRentreeScolaire.ts @@ -0,0 +1,5 @@ +export const getRentreeScolairePrecedente = (rentreeScolaire: string): string => + `${parseInt(rentreeScolaire) - 1}` + +export const getRentreeScolaireSuivante = (rentreeScolaire: string): string => + `${parseInt(rentreeScolaire) + 1}`; diff --git a/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts b/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts index d89a1e903..e7a518969 100644 --- a/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts +++ b/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts @@ -4,6 +4,7 @@ import { kdb } from "../../../../db/db"; import { cleanNull } from "../../../../utils/noNull"; import { effectifAnnee } from "../../queries/utils/effectifAnnee"; import { getMillesimePrecedent } from "../../queries/utils/getMillesime"; +import { getRentreeScolairePrecedente } from "../../queries/utils/getRentreeScolaire"; import { hasContinuum } from "../../queries/utils/hasContinuum"; import { notHistorique } from "../../queries/utils/notHistorique"; import { withPositionQuadrant } from "../../queries/utils/positionQuadrant"; @@ -45,11 +46,7 @@ const queryFormations = ({ ) .leftJoin("indicateurEntree", (join) => join - .onRef( - "formationEtablissement.id", - "=", - "indicateurEntree.formationEtablissementId" - ) + .onRef("formationEtablissement.id", "=", "indicateurEntree.formationEtablissementId") .on("indicateurEntree.rentreeScolaire", "=", rentreeScolaire) ) .leftJoin( @@ -65,7 +62,7 @@ const queryFormations = ({ .leftJoin("indicateurEntree as iep", (join) => join .onRef("formationEtablissement.id", "=", "iep.formationEtablissementId") - .on("iep.rentreeScolaire", "=", "2021") + .on("iep.rentreeScolaire", "=", getRentreeScolairePrecedente(rentreeScolaire)) ) .where(notHistorique) .$call((q) => { @@ -188,7 +185,6 @@ const queryFormations = ({ .groupBy([ "formationEtablissement.cfd", "formation.id", - "indicateurEntree.rentreeScolaire", "formationEtablissement.dispositifId", "dispositif.codeDispositif", "niveauDiplome.libelleNiveauDiplome", @@ -200,7 +196,7 @@ const queryFormations = ({ sql`${sql.raw(orderBy.order)} NULLS LAST` ); }) - .orderBy("libelleNiveauDiplome", "asc"); + .orderBy("libelleDiplome", "asc"); export const queryFormationsRegion = async ({ codeRegion, diff --git a/server/src/modules/data/usecases/getDataForPanorama/getDataForPanorama.usecase.ts b/server/src/modules/data/usecases/getDataForPanorama/getDataForPanorama.usecase.ts index 785a33892..b349402ee 100644 --- a/server/src/modules/data/usecases/getDataForPanorama/getDataForPanorama.usecase.ts +++ b/server/src/modules/data/usecases/getDataForPanorama/getDataForPanorama.usecase.ts @@ -30,7 +30,6 @@ export const [getDataForPanoramaRegion] = inject( orderBy, }); const { diplomes, filieres } = await deps.getFilters({ codeRegion }); - return { formations, filters: { diff --git a/server/src/modules/data/usecases/getEtablissement/dependencies.ts b/server/src/modules/data/usecases/getEtablissement/dependencies.ts index 6599b5891..3babb76f0 100644 --- a/server/src/modules/data/usecases/getEtablissement/dependencies.ts +++ b/server/src/modules/data/usecases/getEtablissement/dependencies.ts @@ -4,6 +4,7 @@ import { jsonArrayFrom } from "kysely/helpers/postgres"; import { kdb } from "../../../../db/db"; import { effectifAnnee } from "../../queries/utils/effectifAnnee"; import { getMillesimePrecedent } from "../../queries/utils/getMillesime"; +import { getRentreeScolairePrecedente } from "../../queries/utils/getRentreeScolaire"; import { hasContinuum } from "../../queries/utils/hasContinuum"; import { notHistorique } from "../../queries/utils/notHistorique"; import { withPositionQuadrant } from "../../queries/utils/positionQuadrant"; @@ -81,7 +82,7 @@ const getEtablissementInDb = async ({ "=", "iep.formationEtablissementId" ) - .on("iep.rentreeScolaire", "=", "2021") + .on("iep.rentreeScolaire", "=", getRentreeScolairePrecedente(rentreeScolaire)) ) .select((sb) => [ "formationEtablissement.cfd as codeFormationDiplome", diff --git a/ui/app/(wrapped)/panorama/components/TopFlopSection.tsx b/ui/app/(wrapped)/panorama/components/TopFlopSection.tsx index 07d07f6f9..a661c028b 100644 --- a/ui/app/(wrapped)/panorama/components/TopFlopSection.tsx +++ b/ui/app/(wrapped)/panorama/components/TopFlopSection.tsx @@ -36,7 +36,6 @@ export const TopFlopSection = ({ .sort((a, b) => a.tauxDevenirFavorable < b.tauxDevenirFavorable ? 1 : -1 ); - const top = sorted.slice().slice(0, Math.ceil(nbTopFlop)); const flop = sorted.slice().reverse().slice(0, Math.floor(nbTopFlop)); @@ -97,7 +96,7 @@ const TopFlopChart = ({ .reverse() .map((item) => ( Date: Wed, 15 Nov 2023 13:08:52 +0100 Subject: [PATCH 11/28] fix: ajout de loaders --- .../data/queries/utils/getMillesime.ts | 6 +- .../data/queries/utils/getRentreeScolaire.ts | 2 +- .../getDataForPanorama/dependencies.ts | 12 +++- .../usecases/getEtablissement/dependencies.ts | 6 +- .../panorama/components/QuadrantSection.tsx | 19 +++-- .../panorama/components/TopFlopSection.tsx | 13 +++- .../etablissement/[uai]/FormationsSection.tsx | 71 +++++++++++++------ .../etablissement/[uai]/QuadrantSection.tsx | 17 ++++- .../panorama/etablissement/[uai]/page.tsx | 8 ++- .../panorama/region/[codeRegion]/page.tsx | 8 ++- 10 files changed, 125 insertions(+), 37 deletions(-) diff --git a/server/src/modules/data/queries/utils/getMillesime.ts b/server/src/modules/data/queries/utils/getMillesime.ts index 67f9c6d53..4b2a26164 100644 --- a/server/src/modules/data/queries/utils/getMillesime.ts +++ b/server/src/modules/data/queries/utils/getMillesime.ts @@ -1,7 +1,9 @@ export const getMillesimePrecedent = (millesimeSortie: string): string => - `${parseInt(millesimeSortie.split("_")[0]) - 1}_${parseInt(millesimeSortie.split("_")[1]) - 1 + `${parseInt(millesimeSortie.split("_")[0]) - 1}_${ + parseInt(millesimeSortie.split("_")[1]) - 1 }`; export const getMillesimeSuivant = (millesimeSortie: string): string => - `${parseInt(millesimeSortie.split("_")[0]) + 1}_${parseInt(millesimeSortie.split("_")[1]) + 1 + `${parseInt(millesimeSortie.split("_")[0]) + 1}_${ + parseInt(millesimeSortie.split("_")[1]) + 1 }`; diff --git a/server/src/modules/data/queries/utils/getRentreeScolaire.ts b/server/src/modules/data/queries/utils/getRentreeScolaire.ts index d9544e925..6dad5cffb 100644 --- a/server/src/modules/data/queries/utils/getRentreeScolaire.ts +++ b/server/src/modules/data/queries/utils/getRentreeScolaire.ts @@ -1,5 +1,5 @@ export const getRentreeScolairePrecedente = (rentreeScolaire: string): string => - `${parseInt(rentreeScolaire) - 1}` + `${parseInt(rentreeScolaire) - 1}`; export const getRentreeScolaireSuivante = (rentreeScolaire: string): string => `${parseInt(rentreeScolaire) + 1}`; diff --git a/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts b/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts index e7a518969..319fbdab2 100644 --- a/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts +++ b/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts @@ -46,7 +46,11 @@ const queryFormations = ({ ) .leftJoin("indicateurEntree", (join) => join - .onRef("formationEtablissement.id", "=", "indicateurEntree.formationEtablissementId") + .onRef( + "formationEtablissement.id", + "=", + "indicateurEntree.formationEtablissementId" + ) .on("indicateurEntree.rentreeScolaire", "=", rentreeScolaire) ) .leftJoin( @@ -62,7 +66,11 @@ const queryFormations = ({ .leftJoin("indicateurEntree as iep", (join) => join .onRef("formationEtablissement.id", "=", "iep.formationEtablissementId") - .on("iep.rentreeScolaire", "=", getRentreeScolairePrecedente(rentreeScolaire)) + .on( + "iep.rentreeScolaire", + "=", + getRentreeScolairePrecedente(rentreeScolaire) + ) ) .where(notHistorique) .$call((q) => { diff --git a/server/src/modules/data/usecases/getEtablissement/dependencies.ts b/server/src/modules/data/usecases/getEtablissement/dependencies.ts index 3babb76f0..e4c9f152c 100644 --- a/server/src/modules/data/usecases/getEtablissement/dependencies.ts +++ b/server/src/modules/data/usecases/getEtablissement/dependencies.ts @@ -82,7 +82,11 @@ const getEtablissementInDb = async ({ "=", "iep.formationEtablissementId" ) - .on("iep.rentreeScolaire", "=", getRentreeScolairePrecedente(rentreeScolaire)) + .on( + "iep.rentreeScolaire", + "=", + getRentreeScolairePrecedente(rentreeScolaire) + ) ) .select((sb) => [ "formationEtablissement.cfd as codeFormationDiplome", diff --git a/ui/app/(wrapped)/panorama/components/QuadrantSection.tsx b/ui/app/(wrapped)/panorama/components/QuadrantSection.tsx index 8cb9c3310..deaf3983c 100644 --- a/ui/app/(wrapped)/panorama/components/QuadrantSection.tsx +++ b/ui/app/(wrapped)/panorama/components/QuadrantSection.tsx @@ -19,6 +19,7 @@ import { SliderMark, SliderThumb, SliderTrack, + Spinner, Stack, Text, VStack, @@ -123,14 +124,22 @@ const filterFormations = ({ return mustBeReturned; }); +const Loader = () => ( +
+ +
+); + export const QuadrantSection = ({ quadrantFormations, + isLoading, meanPoursuite, meanInsertion, order, handleOrder, }: { quadrantFormations?: PanoramaFormations; + isLoading: boolean; meanPoursuite?: number; meanInsertion?: number; order?: Partial; @@ -371,10 +380,12 @@ export const QuadrantSection = ({ <> - {filteredFormations && - filteredFormations.length && - meanInsertion && - meanPoursuite ? ( + {isLoading ? ( + + ) : filteredFormations && + filteredFormations.length && + meanInsertion && + meanPoursuite ? ( typeVue === "quadrant" ? ( ( +
+ +
+); + export const TopFlopSection = ({ quadrantFormations, + isLoading, }: { quadrantFormations?: PanoramaFormations; meanPoursuite?: number; meanInsertion?: number; + isLoading: boolean; }) => { const topFlopFormations = useMemo(() => { if (!quadrantFormations) return; @@ -53,7 +62,9 @@ export const TopFlopSection = ({ formations à examiner - {topFlopFormations && quadrantFormations?.length ? ( + {isLoading ? ( + + ) : topFlopFormations && quadrantFormations?.length ? ( ) : (
diff --git a/ui/app/(wrapped)/panorama/etablissement/[uai]/FormationsSection.tsx b/ui/app/(wrapped)/panorama/etablissement/[uai]/FormationsSection.tsx index fa668cd36..a473bf8f5 100644 --- a/ui/app/(wrapped)/panorama/etablissement/[uai]/FormationsSection.tsx +++ b/ui/app/(wrapped)/panorama/etablissement/[uai]/FormationsSection.tsx @@ -2,6 +2,7 @@ import { Box, Container, Heading, + Skeleton, Table, TableContainer, Tbody, @@ -15,11 +16,35 @@ import { ApiType } from "shared"; import { api } from "../../../../../api.client"; +const Loader = () => ( + +
+ + {new Array(7).fill(0).map((_, i) => ( + + + + + + ))} + +
+ + + + + +
+ +); + export const FormationsSection = ({ formations, + isLoading, rentreeScolaire, }: { formations?: ApiType["formations"]; + isLoading: boolean; rentreeScolaire?: string; }) => { return ( @@ -34,28 +59,32 @@ export const FormationsSection = ({
- - - - - - - - - - - {formations?.map((formation) => ( - - - - + {isLoading ? ( + + ) : ( + +
FormationDiplômeEffectif
{formation.libelleDiplome}{formation.libelleNiveauDiplome}{formation.effectif}
+ + + + + - ))} - -
FormationDiplômeEffectif
-
+ + + {formations?.map((formation) => ( + + {formation.libelleDiplome} + {formation.libelleNiveauDiplome} + {formation.effectif} + + ))} + + + + )}
); diff --git a/ui/app/(wrapped)/panorama/etablissement/[uai]/QuadrantSection.tsx b/ui/app/(wrapped)/panorama/etablissement/[uai]/QuadrantSection.tsx index 63f07d2ec..ddde9a63d 100644 --- a/ui/app/(wrapped)/panorama/etablissement/[uai]/QuadrantSection.tsx +++ b/ui/app/(wrapped)/panorama/etablissement/[uai]/QuadrantSection.tsx @@ -3,10 +3,12 @@ import { AspectRatio, Box, Button, + Center, Container, Flex, Heading, Skeleton, + Spinner, Text, VStack, } from "@chakra-ui/react"; @@ -29,8 +31,14 @@ const effectifSizes = [ { max: 100, size: 40 }, ]; +const Loader = () => ( +
+ +
+); export const QuadrantSection = ({ quadrantFormations, + isLoading, meanPoursuite, meanInsertion, codeNiveauDiplome, @@ -39,6 +47,7 @@ export const QuadrantSection = ({ handleOrder, }: { quadrantFormations?: ApiType["formations"]; + isLoading: boolean; meanPoursuite?: number; meanInsertion?: number; codeNiveauDiplome?: string[]; @@ -129,7 +138,10 @@ export const QuadrantSection = ({
<> - {filteredFormations && + {isLoading ? ( + + ) : ( + filteredFormations && (typeVue === "quadrant" ? ( - ))} + )) + )} {!filteredFormations && } diff --git a/ui/app/(wrapped)/panorama/etablissement/[uai]/page.tsx b/ui/app/(wrapped)/panorama/etablissement/[uai]/page.tsx index eacc4da4c..8e74f53e7 100644 --- a/ui/app/(wrapped)/panorama/etablissement/[uai]/page.tsx +++ b/ui/app/(wrapped)/panorama/etablissement/[uai]/page.tsx @@ -58,7 +58,11 @@ export default function Panorama({ }; const [codeNiveauDiplome, setCodeNiveauDiplome] = useState(); - const { data: etablissement, isError } = useQuery( + const { + data: etablissement, + isError, + isLoading, + } = useQuery( ["getEtablissement", uai, order], api.getEtablissement({ query: { @@ -121,12 +125,14 @@ export default function Panorama({ meanInsertion={regionStats?.tauxInsertion} meanPoursuite={regionStats?.tauxPoursuite} quadrantFormations={etablissement?.formations} + isLoading={isLoading} order={order} handleOrder={handleOrder} /> diff --git a/ui/app/(wrapped)/panorama/region/[codeRegion]/page.tsx b/ui/app/(wrapped)/panorama/region/[codeRegion]/page.tsx index 25277f4b2..06dc66911 100644 --- a/ui/app/(wrapped)/panorama/region/[codeRegion]/page.tsx +++ b/ui/app/(wrapped)/panorama/region/[codeRegion]/page.tsx @@ -90,7 +90,7 @@ export default function Panorama({ } ); - const { data } = useQuery( + const { data, isLoading } = useQuery( ["formationForPanorama", codeRegion, order, filters], api.getDataForPanoramaRegion({ query: { @@ -122,12 +122,16 @@ export default function Panorama({ meanInsertion={stats?.tauxInsertion} meanPoursuite={stats?.tauxPoursuite} quadrantFormations={data?.formations} + isLoading={isLoading} order={order} handleOrder={(column?: string) => handleOrder(column as OrderPanoramaFormation["orderBy"]) } /> - + ); From c169592af534e3de024eb7d9a05e275d30e0d213 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20D=C3=A9tr=C3=A9?= Date: Wed, 15 Nov 2023 13:21:39 +0100 Subject: [PATCH 12/28] fix: fix --- .../panorama/departement/[codeDepartement]/page.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ui/app/(wrapped)/panorama/departement/[codeDepartement]/page.tsx b/ui/app/(wrapped)/panorama/departement/[codeDepartement]/page.tsx index 169f22cdb..1a89b7483 100644 --- a/ui/app/(wrapped)/panorama/departement/[codeDepartement]/page.tsx +++ b/ui/app/(wrapped)/panorama/departement/[codeDepartement]/page.tsx @@ -90,7 +90,7 @@ export default function Panorama({ } ); - const { data } = useQuery( + const { data, isLoading } = useQuery( ["formationForPanorama", codeDepartement, order, filters], api.getDataForPanoramaDepartement({ query: { @@ -119,12 +119,16 @@ export default function Panorama({ meanInsertion={stats?.tauxInsertion} meanPoursuite={stats?.tauxPoursuite} quadrantFormations={data?.formations} + isLoading={isLoading} order={order} handleOrder={(column?: string) => handleOrder(column as OrderPanoramaFormation["orderBy"]) } /> - + Date: Wed, 15 Nov 2023 13:32:17 +0100 Subject: [PATCH 13/28] feat: affichage du continuum sur le tableau quadrant --- ui/components/TableQuadrant.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/ui/components/TableQuadrant.tsx b/ui/components/TableQuadrant.tsx index 359a8e38b..001ae9977 100644 --- a/ui/components/TableQuadrant.tsx +++ b/ui/components/TableQuadrant.tsx @@ -24,6 +24,7 @@ type Formation = { tauxPression?: number; positionQuadrant?: string; cfd?: string; + continuum?: { cfd: string; libelle?: string }; }; export const TableQuadrant = ({ @@ -169,10 +170,18 @@ export const TableQuadrant = ({ - + - + ))} From 85a65422f89eed5f405f664052adca9ca483fc1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20D=C3=A9tr=C3=A9?= Date: Wed, 15 Nov 2023 15:07:25 +0100 Subject: [PATCH 14/28] =?UTF-8?q?fix:=20gestion=20des=20demandes=20uniques?= =?UTF-8?q?=20par=20libell=C3=A9=20FCIL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../intentions/repositories/findOneSimilarDemande.query.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/server/src/modules/intentions/repositories/findOneSimilarDemande.query.ts b/server/src/modules/intentions/repositories/findOneSimilarDemande.query.ts index c1f6e72a9..9af0a5431 100644 --- a/server/src/modules/intentions/repositories/findOneSimilarDemande.query.ts +++ b/server/src/modules/intentions/repositories/findOneSimilarDemande.query.ts @@ -5,12 +5,14 @@ export const findOneSimilarDemande = ({ cfd, uai, dispositifId, + libelleFCIL, rentreeScolaire, notId, }: { cfd: string; uai: string; dispositifId: string; + libelleFCIL?: string; rentreeScolaire: number; notId?: string; }) => @@ -20,6 +22,10 @@ export const findOneSimilarDemande = ({ .where("cfd", "=", cfd) .where("uai", "=", uai) .where("dispositifId", "=", dispositifId) + .$call((q) => { + if (!libelleFCIL) return q; + return q.where("libelleFCIL", "=", libelleFCIL); + }) .where("rentreeScolaire", "=", rentreeScolaire) .$call((q) => { if (!notId) return q; From b368429f2d360b0f6d3c31820e08581ab6221b2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20D=C3=A9tr=C3=A9?= Date: Wed, 15 Nov 2023 16:01:39 +0100 Subject: [PATCH 15/28] feat: ajout du CFD dans les exports quadrant --- .../pilotage/components/QuadrantSection.tsx | 1 + .../panorama/components/QuadrantSection.tsx | 17 +++++++++++++++++ .../etablissement/[uai]/QuadrantSection.tsx | 1 + 3 files changed, 19 insertions(+) diff --git a/ui/app/(wrapped)/intentions/pilotage/components/QuadrantSection.tsx b/ui/app/(wrapped)/intentions/pilotage/components/QuadrantSection.tsx index 91e54ec9b..783de41ce 100644 --- a/ui/app/(wrapped)/intentions/pilotage/components/QuadrantSection.tsx +++ b/ui/app/(wrapped)/intentions/pilotage/components/QuadrantSection.tsx @@ -188,6 +188,7 @@ export const QuadrantSection = ({ })), { libelleDiplome: "Formation", + cfd: "CFD", libelleDispositif: "Dispositif", tauxInsertion: "Taux d'emploi", tauxPoursuite: "Taux de poursuite", diff --git a/ui/app/(wrapped)/panorama/components/QuadrantSection.tsx b/ui/app/(wrapped)/panorama/components/QuadrantSection.tsx index deaf3983c..a08986eec 100644 --- a/ui/app/(wrapped)/panorama/components/QuadrantSection.tsx +++ b/ui/app/(wrapped)/panorama/components/QuadrantSection.tsx @@ -28,6 +28,7 @@ import { ReactNode, useMemo, useState } from "react"; import { Quadrant } from "../../../../components/Quadrant"; import { TableQuadrant } from "../../../../components/TableQuadrant"; +import { TooltipIcon } from "../../../../components/TooltipIcon"; import { downloadCsv } from "../../../../utils/downloadCsv"; import { Order, PanoramaFormations } from "../types"; import { FormationTooltipContent } from "./FormationTooltipContent"; @@ -308,6 +309,12 @@ export const QuadrantSection = ({ value={tendances["forte_pression"]} changeHandle={handleCheckboxCardChange} icon={} + tooltip={ + + } /> } + tooltip={ + + } /> void; className?: string; + tooltip?: ReactNode; }) => ( changeHandle(e.target.checked, name)} > {label} + {tooltip}
{icon} diff --git a/ui/app/(wrapped)/panorama/etablissement/[uai]/QuadrantSection.tsx b/ui/app/(wrapped)/panorama/etablissement/[uai]/QuadrantSection.tsx index ddde9a63d..6a20f2e79 100644 --- a/ui/app/(wrapped)/panorama/etablissement/[uai]/QuadrantSection.tsx +++ b/ui/app/(wrapped)/panorama/etablissement/[uai]/QuadrantSection.tsx @@ -110,6 +110,7 @@ export const QuadrantSection = ({ })), { libelleDiplome: "Formation", + codeFormationDiplome: "CFD", libelleDispositif: "Dispositif", tauxInsertion: "Taux d'emploi", tauxPoursuite: "Taux de poursuite", From 094fe227b494d32f39c5cdbdc404230b94995371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20D=C3=A9tr=C3=A9?= Date: Thu, 16 Nov 2023 12:46:42 +0100 Subject: [PATCH 16/28] fix: passage au calcul de la position quadrant en ts --- .../getDepartementsStats.query.ts | 12 +- .../getPilotageReformeStats.query.ts | 6 +- .../getPilotageReformeStatsRegions.query.ts | 2 +- .../getRegionStats/getRegionStats.query.ts | 12 +- .../queries/getStatsSortie/getStatsSortie.ts | 184 ++++++++++++++++++ .../data/queries/utils/getMillesime.ts | 9 - .../data/queries/utils/positionQuadrant.ts | 131 ------------- .../src/modules/data/services/getMillesime.ts | 29 +++ .../data/services/getPositionQuadrant.ts | 92 +++++++++ .../utils => services}/getRentreeScolaire.ts | 8 + .../inserJeunesApi/formatMillesime.ts | 16 -- .../getDataForPanorama/dependencies.ts | 54 +++-- .../getDataForPanorama.usecase.ts | 61 +++--- .../usecases/getEtablissement/dependencies.ts | 12 +- .../getEtablissement.usecase.ts | 25 ++- .../getEtablissements/dependencies.ts | 10 +- .../getEtablissements.usecase.ts | 26 ++- .../usecases/getFormations/dependencies.ts | 25 --- .../getFormations/getFormations.usecase.ts | 13 +- .../getFormationsStatsQuery.dep.ts | 9 - ...etFormationsTransformationStats.usecase.ts | 16 +- .../dependencies.ts | 48 +---- .../getRestitutionIntentionsStats.usecase.ts | 18 +- .../etablissements/etablissements.schema.ts | 5 +- shared/client/formations/formation.schema.ts | 17 +- .../pilotageTransfo/pilotageTransfo.schema.ts | 10 + .../restitutionIntentions.schema.ts | 6 +- .../etablissements/components/LineContent.tsx | 1 + .../(wrapped)/console/etablissements/page.tsx | 8 + .../ConsoleSection/ConsoleSection.tsx | 12 +- .../ConsoleSection/LineContent.tsx | 4 +- .../restitution/STATS_DEMANDES_COLUMN.ts | 4 +- .../panorama/components/FiltersSection.tsx | 4 +- .../components/IndicateursSection.tsx | 4 +- ui/app/(wrapped)/panorama/types.ts | 2 +- 35 files changed, 516 insertions(+), 379 deletions(-) create mode 100644 server/src/modules/data/queries/getStatsSortie/getStatsSortie.ts delete mode 100644 server/src/modules/data/queries/utils/getMillesime.ts delete mode 100644 server/src/modules/data/queries/utils/positionQuadrant.ts create mode 100644 server/src/modules/data/services/getMillesime.ts create mode 100644 server/src/modules/data/services/getPositionQuadrant.ts rename server/src/modules/data/{queries/utils => services}/getRentreeScolaire.ts (59%) delete mode 100644 server/src/modules/data/services/inserJeunesApi/formatMillesime.ts diff --git a/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts b/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts index 81a1b8b66..2dd6312e6 100644 --- a/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts +++ b/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts @@ -13,12 +13,12 @@ import { selectTauxRemplissageAgg } from "../utils/tauxRemplissage"; export const getDepartementsStats = async ({ codeDepartement, - codesNiveauxDiplomes, + codeNiveauDiplome, rentreeScolaire = "2022", millesimeSortie = "2020_2021", }: { codeDepartement: string; - codesNiveauxDiplomes?: string[]; + codeNiveauDiplome?: string[]; rentreeScolaire?: string; millesimeSortie?: string; }) => { @@ -37,8 +37,8 @@ export const getDepartementsStats = async ({ .where(notHistoriqueIndicateurRegionSortie) .where("departement.codeDepartement", "=", codeDepartement) .$call((q) => { - if (!codesNiveauxDiplomes?.length) return q; - return q.where("formation.codeNiveauDiplome", "in", codesNiveauxDiplomes); + if (!codeNiveauDiplome?.length) return q; + return q.where("formation.codeNiveauDiplome", "in", codeNiveauDiplome); }) .where("indicateurRegionSortie.millesimeSortie", "=", millesimeSortie) .where((eb) => @@ -82,8 +82,8 @@ export const getDepartementsStats = async ({ "etablissement.codeDepartement" ) .$call((q) => { - if (!codesNiveauxDiplomes?.length) return q; - return q.where("formation.codeNiveauDiplome", "in", codesNiveauxDiplomes); + if (!codeNiveauDiplome?.length) return q; + return q.where("formation.codeNiveauDiplome", "in", codeNiveauDiplome); }) .where(notHistorique) .select([ diff --git a/server/src/modules/data/queries/getPilotageReformeStats/getPilotageReformeStats.query.ts b/server/src/modules/data/queries/getPilotageReformeStats/getPilotageReformeStats.query.ts index 9d224c8e6..016542d29 100644 --- a/server/src/modules/data/queries/getPilotageReformeStats/getPilotageReformeStats.query.ts +++ b/server/src/modules/data/queries/getPilotageReformeStats/getPilotageReformeStats.query.ts @@ -2,10 +2,8 @@ import { sql } from "kysely"; import { kdb } from "../../../../db/db"; import { cleanNull } from "../../../../utils/noNull"; -import { - getMillesimeFromRentreeScolaire, - getRentreeScolaire, -} from "../../services/inserJeunesApi/formatMillesime"; +import { getMillesimeFromRentreeScolaire } from "../../services/getMillesime"; +import { getRentreeScolaire } from "../../services/getRentreeScolaire"; import { effectifAnnee } from "../utils/effectifAnnee"; import { notHistorique, diff --git a/server/src/modules/data/queries/getPilotageReformeStatsRegions/getPilotageReformeStatsRegions.query.ts b/server/src/modules/data/queries/getPilotageReformeStatsRegions/getPilotageReformeStatsRegions.query.ts index e7e207798..1fbf127d1 100644 --- a/server/src/modules/data/queries/getPilotageReformeStatsRegions/getPilotageReformeStatsRegions.query.ts +++ b/server/src/modules/data/queries/getPilotageReformeStatsRegions/getPilotageReformeStatsRegions.query.ts @@ -2,7 +2,7 @@ import { sql } from "kysely"; import { kdb } from "../../../../db/db"; import { cleanNull } from "../../../../utils/noNull"; -import { getMillesimeFromRentreeScolaire } from "../../services/inserJeunesApi/formatMillesime"; +import { getMillesimeFromRentreeScolaire } from "../../services/getMillesime"; import { notHistoriqueIndicateurRegionSortie } from "../utils/notHistorique"; import { selectTauxInsertion6moisAgg } from "../utils/tauxInsertion6mois"; import { selectTauxPoursuiteAgg } from "../utils/tauxPoursuite"; diff --git a/server/src/modules/data/queries/getRegionStats/getRegionStats.query.ts b/server/src/modules/data/queries/getRegionStats/getRegionStats.query.ts index 017c64160..669ce831c 100644 --- a/server/src/modules/data/queries/getRegionStats/getRegionStats.query.ts +++ b/server/src/modules/data/queries/getRegionStats/getRegionStats.query.ts @@ -13,12 +13,12 @@ import { selectTauxRemplissageAgg } from "../utils/tauxRemplissage"; export const getRegionStats = async ({ codeRegion, - codesNiveauxDiplomes, + codeNiveauDiplome, rentreeScolaire = "2022", millesimeSortie = "2020_2021", }: { codeRegion: string; - codesNiveauxDiplomes?: string[]; + codeNiveauDiplome?: string[]; rentreeScolaire?: string; millesimeSortie?: string; }) => { @@ -33,8 +33,8 @@ export const getRegionStats = async ({ .where("indicateurRegionSortie.millesimeSortie", "=", millesimeSortie) .where(notHistoriqueIndicateurRegionSortie) .$call((q) => { - if (!codesNiveauxDiplomes?.length) return q; - return q.where("formation.codeNiveauDiplome", "in", codesNiveauxDiplomes); + if (!codeNiveauDiplome?.length) return q; + return q.where("formation.codeNiveauDiplome", "in", codeNiveauDiplome); }) .select([ selectTauxInsertion6moisAgg("indicateurRegionSortie").as("tauxInsertion"), @@ -66,8 +66,8 @@ export const getRegionStats = async ({ .where("etablissement.codeRegion", "=", codeRegion) .innerJoin("region", "region.codeRegion", "etablissement.codeRegion") .$call((q) => { - if (!codesNiveauxDiplomes?.length) return q; - return q.where("formation.codeNiveauDiplome", "in", codesNiveauxDiplomes); + if (!codeNiveauDiplome?.length) return q; + return q.where("formation.codeNiveauDiplome", "in", codeNiveauDiplome); }) .where(notHistorique) .select([ diff --git a/server/src/modules/data/queries/getStatsSortie/getStatsSortie.ts b/server/src/modules/data/queries/getStatsSortie/getStatsSortie.ts new file mode 100644 index 000000000..eb0d6b23a --- /dev/null +++ b/server/src/modules/data/queries/getStatsSortie/getStatsSortie.ts @@ -0,0 +1,184 @@ +import { kdb } from "../../../../db/db"; +import { notHistoriqueIndicateurRegionSortie } from "../utils/notHistorique"; +import { selectTauxInsertion6moisAgg } from "../utils/tauxInsertion6mois"; +import { selectTauxPoursuiteAgg } from "../utils/tauxPoursuite"; + +const getStatsSortieBase = ({ + codeRegion, + codeDepartement, + codeNiveauDiplome, + millesimeSortie = "2020_2021", +}: { + codeRegion?: string | string[]; + codeDepartement?: string | string[]; + millesimeSortie?: string; + codeNiveauDiplome?: string[]; +}) => { + const statsSortie = kdb + .selectFrom("indicateurRegionSortie") + .innerJoin( + "formation", + "formation.codeFormationDiplome", + "indicateurRegionSortie.cfd" + ) + .where((w) => { + if (!codeRegion) return w.val(true); + if (Array.isArray(codeRegion)) + return w("indicateurRegionSortie.codeRegion", "in", codeRegion); + return w("indicateurRegionSortie.codeRegion", "=", codeRegion); + }) + .$call((q) => { + if (!codeDepartement?.length) return q; + if (Array.isArray(codeDepartement)) + return q + .innerJoin( + "departement", + "departement.codeRegion", + "indicateurRegionSortie.codeRegion" + ) + .where("departement.codeDepartement", "in", codeDepartement); + return q + .innerJoin( + "departement", + "departement.codeRegion", + "indicateurRegionSortie.codeRegion" + ) + .where("departement.codeDepartement", "=", codeDepartement); + }) + .$call((q) => { + if (!codeNiveauDiplome?.length) return q; + return q.where("formation.codeNiveauDiplome", "in", codeNiveauDiplome); + }) + .where("indicateurRegionSortie.millesimeSortie", "=", millesimeSortie) + .where(notHistoriqueIndicateurRegionSortie) + .select([ + selectTauxInsertion6moisAgg("indicateurRegionSortie").as("tauxInsertion"), + selectTauxPoursuiteAgg("indicateurRegionSortie").as("tauxPoursuite"), + ]); + + return statsSortie; +}; + +export const getStatsSortieParNiveauDiplome = async ({ + codeRegion, + codeNiveauDiplome, + millesimeSortie = "2020_2021", +}: { + codeRegion?: string[]; + millesimeSortie?: string; + codeNiveauDiplome?: string[]; +}) => { + const statsSortie = await getStatsSortieBase({ + codeRegion, + codeNiveauDiplome, + millesimeSortie, + }) + .select(["formation.codeNiveauDiplome"]) + .groupBy("formation.codeNiveauDiplome") + .execute(); + + return statsSortie.reduce( + (acc, cur) => { + acc[cur.codeNiveauDiplome] = { + tauxInsertion: cur.tauxInsertion, + tauxPoursuite: cur.tauxPoursuite, + }; + return acc; + }, + {} as Record + ); +}; + +export const getStatsSortieParRegionsEtNiveauDiplome = async ({ + codeRegion, + codeNiveauDiplome, + millesimeSortie = "2020_2021", +}: { + codeRegion?: string | string[]; + codeNiveauDiplome?: string[]; + millesimeSortie?: string; +}) => { + const statsSortie = await getStatsSortieBase({ + codeRegion, + codeNiveauDiplome, + millesimeSortie, + }) + .select([ + "indicateurRegionSortie.codeRegion", + "formation.codeNiveauDiplome", + ]) + .groupBy([ + "indicateurRegionSortie.codeRegion", + "formation.codeNiveauDiplome", + ]) + .execute(); + + return statsSortie.reduce( + (acc, cur) => { + acc[cur.codeRegion] = acc[cur.codeRegion] || {}; + acc[cur.codeRegion][cur.codeNiveauDiplome] = { + tauxInsertion: cur.tauxInsertion, + tauxPoursuite: cur.tauxPoursuite, + }; + return acc; + }, + {} as Record< + string, + Record + > + ); +}; + +export const getStatsSortieParRegions = async ({ + codeRegion, + codeDepartement, + codeNiveauDiplome, + millesimeSortie = "2020_2021", +}: { + codeRegion?: string | string[]; + codeDepartement?: string | string[]; + codeNiveauDiplome?: string[]; + millesimeSortie?: string; +}) => { + const statsSortie = await getStatsSortieBase({ + codeRegion, + codeDepartement, + codeNiveauDiplome, + millesimeSortie, + }) + .select(["indicateurRegionSortie.codeRegion"]) + .groupBy(["indicateurRegionSortie.codeRegion"]) + .execute(); + + return statsSortie.reduce( + (acc, cur) => { + acc[cur.codeRegion] = { + tauxInsertion: cur.tauxInsertion, + tauxPoursuite: cur.tauxPoursuite, + }; + return acc; + }, + {} as Record + ); +}; + +export const getStatsSortie = async ({ + codeRegion, + codeDepartement, + codeNiveauDiplome, + millesimeSortie = "2020_2021", +}: { + codeRegion?: string | string[]; + codeDepartement?: string | string[]; + codeNiveauDiplome?: string[]; + millesimeSortie?: string; +}) => { + const statsSortie = await getStatsSortieBase({ + codeRegion, + codeDepartement, + codeNiveauDiplome, + millesimeSortie, + }).executeTakeFirstOrThrow(); + + return statsSortie; +}; diff --git a/server/src/modules/data/queries/utils/getMillesime.ts b/server/src/modules/data/queries/utils/getMillesime.ts deleted file mode 100644 index 4b2a26164..000000000 --- a/server/src/modules/data/queries/utils/getMillesime.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const getMillesimePrecedent = (millesimeSortie: string): string => - `${parseInt(millesimeSortie.split("_")[0]) - 1}_${ - parseInt(millesimeSortie.split("_")[1]) - 1 - }`; - -export const getMillesimeSuivant = (millesimeSortie: string): string => - `${parseInt(millesimeSortie.split("_")[0]) + 1}_${ - parseInt(millesimeSortie.split("_")[1]) + 1 - }`; diff --git a/server/src/modules/data/queries/utils/positionQuadrant.ts b/server/src/modules/data/queries/utils/positionQuadrant.ts deleted file mode 100644 index 9be09c567..000000000 --- a/server/src/modules/data/queries/utils/positionQuadrant.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { ExpressionBuilder, sql } from "kysely"; - -import { DB } from "../../../../db/schema"; -import { notHistoriqueIndicateurRegionSortie } from "./notHistorique"; -import { - selectTauxInsertion6mois, - selectTauxInsertion6moisAgg, - withInsertionReg, -} from "./tauxInsertion6mois"; -import { - selectTauxPoursuite, - selectTauxPoursuiteAgg, - withPoursuiteReg, -} from "./tauxPoursuite"; - -export const getPositionQuadrant = ( - indicateurRegionSortieAlias: string, - indicateurRegionSortieRegAlias: string -) => { - const tauxPoursuite = sql`${selectTauxPoursuite( - indicateurRegionSortieAlias - )}`; - const tauxInsertion = sql`${selectTauxInsertion6mois( - indicateurRegionSortieAlias - )}`; - const tauxPoursuiteReg = sql`${selectTauxPoursuiteAgg( - indicateurRegionSortieRegAlias - )}`; - const tauxInsertionReg = sql`${selectTauxInsertion6moisAgg( - indicateurRegionSortieRegAlias - )}`; - - return sql` - CASE - WHEN (${tauxInsertion} >= ${tauxInsertionReg} AND ${tauxPoursuite} >= ${tauxPoursuiteReg}) THEN 'Q1' - WHEN (${tauxInsertion} >= ${tauxInsertionReg} AND ${tauxPoursuite} < ${tauxPoursuiteReg}) THEN 'Q2' - WHEN (${tauxInsertion} < ${tauxInsertionReg} AND ${tauxPoursuite} >= ${tauxPoursuiteReg}) THEN 'Q3' - WHEN (${tauxInsertion} < ${tauxInsertionReg} AND ${tauxPoursuite} < ${tauxPoursuiteReg}) THEN 'Q4' - ELSE 'Hors quadrant' - END - `; -}; - -type EbRef> = Parameters[0]; - -export function withPositionQuadrant>({ - eb, - cfdRef, - dispositifIdRef, - codeRegionRef, - millesimeSortie, - codesNiveauxDiplomes, -}: { - eb: EB; - cfdRef: EbRef; - dispositifIdRef: EbRef; - codeRegionRef: EbRef; - millesimeSortie: string; - codesNiveauxDiplomes?: string[]; -}) { - const tauxInsertionReg = withInsertionReg({ - eb, - cfdRef, - dispositifIdRef, - codeRegionRef, - millesimeSortie, - }); - - const tauxPoursuiteReg = withPoursuiteReg({ - eb, - cfdRef, - dispositifIdRef, - codeRegionRef, - millesimeSortie, - }); - - return eb - .selectFrom("indicateurRegionSortie") - .whereRef( - "indicateurRegionSortie.codeRegion", - "=", - sql`ANY(array_agg(${eb.ref(codeRegionRef)}))` - ) - .where("indicateurRegionSortie.millesimeSortie", "=", millesimeSortie) - .where(notHistoriqueIndicateurRegionSortie) - .$call((eb) => { - if (codesNiveauxDiplomes) - return eb - .innerJoin( - "formation", - "formation.codeFormationDiplome", - "indicateurRegionSortie.cfd" - ) - .where("formation.codeNiveauDiplome", "in", codesNiveauxDiplomes); - return eb; - }) - .select([ - sql` - CASE - WHEN (${tauxInsertionReg} >= ${selectTauxInsertion6moisAgg( - "indicateurRegionSortie" - )} - AND ${tauxPoursuiteReg} >= ${selectTauxPoursuiteAgg( - "indicateurRegionSortie" - )}) - THEN 'Q1' - WHEN (${tauxInsertionReg} >= ${selectTauxInsertion6moisAgg( - "indicateurRegionSortie" - )} - AND ${tauxPoursuiteReg} < ${selectTauxPoursuiteAgg( - "indicateurRegionSortie" - )}) - THEN 'Q2' - WHEN (${tauxInsertionReg} < ${selectTauxInsertion6moisAgg( - "indicateurRegionSortie" - )} - AND ${tauxPoursuiteReg} >= ${selectTauxPoursuiteAgg( - "indicateurRegionSortie" - )}) - THEN 'Q3' - WHEN (${tauxInsertionReg} < ${selectTauxInsertion6moisAgg( - "indicateurRegionSortie" - )} - AND ${tauxPoursuiteReg} < ${selectTauxPoursuiteAgg( - "indicateurRegionSortie" - )}) - THEN 'Q4' - ELSE 'Hors quadrant' - END`.as("positionQuadrant"), - ]); -} diff --git a/server/src/modules/data/services/getMillesime.ts b/server/src/modules/data/services/getMillesime.ts new file mode 100644 index 000000000..8734cd5c0 --- /dev/null +++ b/server/src/modules/data/services/getMillesime.ts @@ -0,0 +1,29 @@ +export const getMillesimePrecedent = (millesimeSortie: string): string => + `${parseInt(millesimeSortie.split("_")[0]) - 1}_${ + parseInt(millesimeSortie.split("_")[1]) - 1 + }`; + +export const getMillesimeSuivant = (millesimeSortie: string): string => + `${parseInt(millesimeSortie.split("_")[0]) + 1}_${ + parseInt(millesimeSortie.split("_")[1]) + 1 + }`; + +export const getMillesime = ({ + millesimeSortie, + offset, +}: { + millesimeSortie: string; + offset: number; +}): string => + `${parseInt(millesimeSortie.split("_")[0]) + offset}_${ + parseInt(millesimeSortie.split("_")[1]) + offset + }`; + +export const getMillesimeFromRentreeScolaire = ({ + rentreeScolaire, + offset, +}: { + rentreeScolaire: string; + offset: number; +}): string => + `${+rentreeScolaire + (offset - 2)}_${+rentreeScolaire + (offset - 1)}`; diff --git a/server/src/modules/data/services/getPositionQuadrant.ts b/server/src/modules/data/services/getPositionQuadrant.ts new file mode 100644 index 000000000..8a20354e9 --- /dev/null +++ b/server/src/modules/data/services/getPositionQuadrant.ts @@ -0,0 +1,92 @@ +export const getPositionQuadrant = ( + formation: { + tauxInsertion?: string | number; + tauxPoursuite?: string | number; + }, + moyenne?: { + tauxInsertion?: string | number; + tauxPoursuite?: string | number; + } +): string => { + if ( + !formation.tauxInsertion || + !formation.tauxPoursuite || + !moyenne?.tauxInsertion || + !moyenne.tauxPoursuite + ) + return "Hors quadrant"; + + const tauxInsertion = + typeof formation.tauxInsertion === "string" + ? parseInt(formation.tauxInsertion) + : formation.tauxInsertion; + const tauxPoursuite = + typeof formation.tauxPoursuite === "string" + ? parseInt(formation.tauxPoursuite) + : formation.tauxPoursuite; + const tauxInsertionMoyen = + typeof moyenne.tauxInsertion === "string" + ? parseInt(moyenne.tauxInsertion) + : moyenne.tauxInsertion; + const tauxPoursuiteMoyen = + typeof moyenne.tauxPoursuite === "string" + ? parseInt(moyenne.tauxPoursuite) + : moyenne.tauxPoursuite; + + if ( + tauxInsertion >= tauxInsertionMoyen && + tauxPoursuite >= tauxPoursuiteMoyen + ) { + return "Q1"; + } else if ( + tauxInsertion >= tauxInsertionMoyen && + tauxPoursuite < tauxPoursuiteMoyen + ) { + return "Q2"; + } else if ( + tauxInsertion < tauxInsertionMoyen && + tauxPoursuite >= tauxPoursuiteMoyen + ) { + return "Q3"; + } else if ( + tauxInsertion < tauxInsertionMoyen && + tauxPoursuite < tauxPoursuiteMoyen + ) { + return "Q4"; + } else return "Hors quadrant"; +}; + +export const filterPositionQuadrant = ( + formations: { positionQuadrant: string }[], + positionQuadrantFilter?: string +) => { + if (!positionQuadrantFilter || positionQuadrantFilter === "all") + return formations; + return formations.filter( + (formation) => formation.positionQuadrant === positionQuadrantFilter + ); +}; + +export const orderPositionQuadrant = ( + formations: { positionQuadrant: string }[], + orderBy?: { column: string; order: "asc" | "desc" } +) => { + if (orderBy && orderBy.column === "positionQuadrant") + return formations.sort((a, b) => + orderBy.order === "asc" + ? a.positionQuadrant.localeCompare(b.positionQuadrant) + : b.positionQuadrant.localeCompare(a.positionQuadrant) + ); + return formations; +}; + +export const filterOrderPositionQuadrant = ( + formations: { positionQuadrant: string }[], + positionQuadrantFilter?: string, + orderBy?: { column: string; order: "asc" | "desc" } +) => { + return orderPositionQuadrant( + filterPositionQuadrant(formations, positionQuadrantFilter), + orderBy + ); +}; diff --git a/server/src/modules/data/queries/utils/getRentreeScolaire.ts b/server/src/modules/data/services/getRentreeScolaire.ts similarity index 59% rename from server/src/modules/data/queries/utils/getRentreeScolaire.ts rename to server/src/modules/data/services/getRentreeScolaire.ts index 6dad5cffb..aa9dc906e 100644 --- a/server/src/modules/data/queries/utils/getRentreeScolaire.ts +++ b/server/src/modules/data/services/getRentreeScolaire.ts @@ -3,3 +3,11 @@ export const getRentreeScolairePrecedente = (rentreeScolaire: string): string => export const getRentreeScolaireSuivante = (rentreeScolaire: string): string => `${parseInt(rentreeScolaire) + 1}`; + +export const getRentreeScolaire = ({ + rentreeScolaire, + offset, +}: { + rentreeScolaire: string; + offset: number; +}): string => `${+rentreeScolaire - offset}`; diff --git a/server/src/modules/data/services/inserJeunesApi/formatMillesime.ts b/server/src/modules/data/services/inserJeunesApi/formatMillesime.ts deleted file mode 100644 index f090c3a6f..000000000 --- a/server/src/modules/data/services/inserJeunesApi/formatMillesime.ts +++ /dev/null @@ -1,16 +0,0 @@ -export const getMillesimeFromRentreeScolaire = ({ - rentreeScolaire, - offset, -}: { - rentreeScolaire: string; - offset: number; -}): string => - `${+rentreeScolaire + (offset - 2)}_${+rentreeScolaire + (offset - 1)}`; - -export const getRentreeScolaire = ({ - rentreeScolaire, - offset, -}: { - rentreeScolaire: string; - offset: number; -}): string => `${+rentreeScolaire - offset}`; diff --git a/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts b/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts index 319fbdab2..6181e7109 100644 --- a/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts +++ b/server/src/modules/data/usecases/getDataForPanorama/dependencies.ts @@ -3,28 +3,27 @@ import { sql } from "kysely"; import { kdb } from "../../../../db/db"; import { cleanNull } from "../../../../utils/noNull"; import { effectifAnnee } from "../../queries/utils/effectifAnnee"; -import { getMillesimePrecedent } from "../../queries/utils/getMillesime"; -import { getRentreeScolairePrecedente } from "../../queries/utils/getRentreeScolaire"; import { hasContinuum } from "../../queries/utils/hasContinuum"; import { notHistorique } from "../../queries/utils/notHistorique"; -import { withPositionQuadrant } from "../../queries/utils/positionQuadrant"; import { withTauxDevenirFavorableReg } from "../../queries/utils/tauxDevenirFavorable"; import { withInsertionReg } from "../../queries/utils/tauxInsertion6mois"; import { withPoursuiteReg } from "../../queries/utils/tauxPoursuite"; import { selectTauxPressionAgg } from "../../queries/utils/tauxPression"; import { selectTauxRemplissageAgg } from "../../queries/utils/tauxRemplissage"; +import { getMillesimePrecedent } from "../../services/getMillesime"; +import { getRentreeScolairePrecedente } from "../../services/getRentreeScolaire"; const queryFormations = ({ rentreeScolaire = "2022", millesimeSortie = "2020_2021", - codesNiveauxDiplomes, - libellesFilieres, + codeNiveauDiplome, + libelleFiliere, orderBy, }: { rentreeScolaire?: string; millesimeSortie?: string; - codesNiveauxDiplomes?: string[]; - libellesFilieres?: string[]; + codeNiveauDiplome?: string[]; + libelleFiliere?: string[]; orderBy?: { column: string; order: "asc" | "desc" }; }) => kdb @@ -74,12 +73,12 @@ const queryFormations = ({ ) .where(notHistorique) .$call((q) => { - if (!codesNiveauxDiplomes) return q; - return q.where("formation.codeNiveauDiplome", "in", codesNiveauxDiplomes); + if (!codeNiveauDiplome) return q; + return q.where("formation.codeNiveauDiplome", "in", codeNiveauDiplome); }) .$call((q) => { - if (!libellesFilieres) return q; - return q.where("formation.libelleFiliere", "in", libellesFilieres); + if (!libelleFiliere) return q; + return q.where("formation.libelleFiliere", "in", libelleFiliere); }) .select((eb) => [ "codeFormationDiplome", @@ -151,15 +150,6 @@ const queryFormations = ({ dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", }).as("tauxDevenirFavorable"), - (eb) => - withPositionQuadrant({ - eb, - millesimeSortie, - cfdRef: "formationEtablissement.cfd", - dispositifIdRef: "formationEtablissement.dispositifId", - codeRegionRef: "etablissement.codeRegion", - codesNiveauxDiplomes, - }).as("positionQuadrant"), ]) .$narrowType<{ tauxInsertion: number; @@ -210,22 +200,22 @@ export const queryFormationsRegion = async ({ codeRegion, rentreeScolaire = "2022", millesimeSortie = "2020_2021", - codesNiveauxDiplomes, - libellesFilieres, + codeNiveauDiplome, + libelleFiliere, orderBy, }: { codeRegion: string; rentreeScolaire?: string; millesimeSortie?: string; - codesNiveauxDiplomes?: string[]; - libellesFilieres?: string[]; + codeNiveauDiplome?: string[]; + libelleFiliere?: string[]; orderBy?: { column: string; order: "asc" | "desc" }; }) => { const formations = await queryFormations({ rentreeScolaire, millesimeSortie, - codesNiveauxDiplomes, - libellesFilieres, + codeNiveauDiplome, + libelleFiliere, orderBy, }) .where("etablissement.codeRegion", "=", codeRegion) @@ -238,22 +228,22 @@ export const queryFormationsDepartement = async ({ codeDepartement, rentreeScolaire = "2022", millesimeSortie = "2020_2021", - codesNiveauxDiplomes, - libellesFilieres, + codeNiveauDiplome, + libelleFiliere, orderBy, }: { codeDepartement: string; rentreeScolaire?: string; millesimeSortie?: string; - codesNiveauxDiplomes?: string[]; - libellesFilieres?: string[]; + codeNiveauDiplome?: string[]; + libelleFiliere?: string[]; orderBy?: { column: string; order: "asc" | "desc" }; }) => { const formations = await queryFormations({ rentreeScolaire, millesimeSortie, - codesNiveauxDiplomes, - libellesFilieres, + codeNiveauDiplome, + libelleFiliere, orderBy, }) .where("etablissement.codeDepartement", "=", codeDepartement) diff --git a/server/src/modules/data/usecases/getDataForPanorama/getDataForPanorama.usecase.ts b/server/src/modules/data/usecases/getDataForPanorama/getDataForPanorama.usecase.ts index b349402ee..f717f3e44 100644 --- a/server/src/modules/data/usecases/getDataForPanorama/getDataForPanorama.usecase.ts +++ b/server/src/modules/data/usecases/getDataForPanorama/getDataForPanorama.usecase.ts @@ -1,5 +1,7 @@ import { inject } from "injecti"; +import { getStatsSortie } from "../../queries/getStatsSortie/getStatsSortie"; +import { getPositionQuadrant } from "../../services/getPositionQuadrant"; import { getFilters, queryFormationsDepartement, @@ -12,26 +14,24 @@ export const [getDataForPanoramaRegion] = inject( getFilters, }, (deps) => - async ({ - codeRegion, - codesNiveauxDiplomes, - libellesFilieres, - orderBy, - }: { + async (activeFilters: { codeRegion: string; - codesNiveauxDiplomes?: string[]; - libellesFilieres?: string[]; + codeNiveauDiplome?: string[]; + libelleFiliere?: string[]; orderBy?: { column: string; order: "asc" | "desc" }; }) => { - const formations = await deps.queryFormationsRegion({ - codeRegion, - codesNiveauxDiplomes, - libellesFilieres, - orderBy, - }); - const { diplomes, filieres } = await deps.getFilters({ codeRegion }); + const [formations, { diplomes, filieres }, statsSortie] = + await Promise.all([ + deps.queryFormationsRegion(activeFilters), + deps.getFilters(activeFilters), + getStatsSortie(activeFilters), + ]); + return { - formations, + formations: formations.map((formation) => ({ + ...formation, + positionQuadrant: getPositionQuadrant(formation, statsSortie), + })), filters: { diplomes, filieres, @@ -46,27 +46,24 @@ export const [getDataForPanoramaDepartement] = inject( getFilters, }, (deps) => - async ({ - codeDepartement, - codesNiveauxDiplomes, - libellesFilieres, - orderBy, - }: { + async (activeFilters: { codeDepartement: string; - codesNiveauxDiplomes?: string[]; - libellesFilieres?: string[]; + codeNiveauDiplome?: string[]; + libelleFiliere?: string[]; orderBy?: { column: string; order: "asc" | "desc" }; }) => { - const formations = await deps.queryFormationsDepartement({ - codeDepartement, - codesNiveauxDiplomes, - libellesFilieres, - orderBy, - }); - const { diplomes, filieres } = await deps.getFilters({ codeDepartement }); + const [formations, { diplomes, filieres }, statsSortie] = + await Promise.all([ + deps.queryFormationsDepartement(activeFilters), + deps.getFilters(activeFilters), + getStatsSortie(activeFilters), + ]); return { - formations, + formations: formations.map((formation) => ({ + ...formation, + positionQuadrant: getPositionQuadrant(formation, statsSortie), + })), filters: { diplomes, filieres, diff --git a/server/src/modules/data/usecases/getEtablissement/dependencies.ts b/server/src/modules/data/usecases/getEtablissement/dependencies.ts index e4c9f152c..44228a599 100644 --- a/server/src/modules/data/usecases/getEtablissement/dependencies.ts +++ b/server/src/modules/data/usecases/getEtablissement/dependencies.ts @@ -3,16 +3,15 @@ import { jsonArrayFrom } from "kysely/helpers/postgres"; import { kdb } from "../../../../db/db"; import { effectifAnnee } from "../../queries/utils/effectifAnnee"; -import { getMillesimePrecedent } from "../../queries/utils/getMillesime"; -import { getRentreeScolairePrecedente } from "../../queries/utils/getRentreeScolaire"; import { hasContinuum } from "../../queries/utils/hasContinuum"; import { notHistorique } from "../../queries/utils/notHistorique"; -import { withPositionQuadrant } from "../../queries/utils/positionQuadrant"; import { withTauxDevenirFavorableReg } from "../../queries/utils/tauxDevenirFavorable"; import { withInsertionReg } from "../../queries/utils/tauxInsertion6mois"; import { withPoursuiteReg } from "../../queries/utils/tauxPoursuite"; import { selectTauxPression } from "../../queries/utils/tauxPression"; import { selectTauxRemplissageAgg } from "../../queries/utils/tauxRemplissage"; +import { getMillesimePrecedent } from "../../services/getMillesime"; +import { getRentreeScolairePrecedente } from "../../services/getRentreeScolaire"; const getEtablissementInDb = async ({ uai, @@ -159,13 +158,6 @@ const getEtablissementInDb = async ({ dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", }).as("tauxDevenirFavorable"), - withPositionQuadrant({ - eb, - millesimeSortie, - cfdRef: "formationEtablissement.cfd", - dispositifIdRef: "formationEtablissement.dispositifId", - codeRegionRef: "etablissement.codeRegion", - }).as("positionQuadrant"), ]) .$narrowType<{ tauxInsertion: number; diff --git a/server/src/modules/data/usecases/getEtablissement/getEtablissement.usecase.ts b/server/src/modules/data/usecases/getEtablissement/getEtablissement.usecase.ts index af9ef4748..22edaf3fe 100644 --- a/server/src/modules/data/usecases/getEtablissement/getEtablissement.usecase.ts +++ b/server/src/modules/data/usecases/getEtablissement/getEtablissement.usecase.ts @@ -1,28 +1,35 @@ import { inject } from "injecti"; import { cleanNull } from "../../../../utils/noNull"; +import { getStatsSortieParRegions } from "../../queries/getStatsSortie/getStatsSortie"; +import { getPositionQuadrant } from "../../services/getPositionQuadrant"; import { dependencies } from "./dependencies"; export const [getEtablissement] = inject( { getEtablissementInD: dependencies.getEtablissementInDb }, (deps) => - async ({ - uai, - orderBy, - }: { + async (activeFilters: { uai: string; orderBy?: { column: string; order: "asc" | "desc" }; }) => { - const etablissement = await deps.getEtablissementInD({ - uai, - orderBy, - }); + const [etablissement, statsSortie] = await Promise.all([ + deps.getEtablissementInD(activeFilters), + getStatsSortieParRegions({}), + ]); return ( etablissement && cleanNull({ ...etablissement, - formations: etablissement.formations.map(cleanNull), + formations: etablissement?.formations?.map((formation) => + cleanNull({ + ...formation, + positionQuadrant: getPositionQuadrant( + formation, + statsSortie[etablissement.codeRegion ?? ""] || {} + ), + }) + ), }) ); } diff --git a/server/src/modules/data/usecases/getEtablissements/dependencies.ts b/server/src/modules/data/usecases/getEtablissements/dependencies.ts index 2623b48bf..be932c255 100644 --- a/server/src/modules/data/usecases/getEtablissements/dependencies.ts +++ b/server/src/modules/data/usecases/getEtablissements/dependencies.ts @@ -7,7 +7,6 @@ import { capaciteAnnee } from "../../queries/utils/capaciteAnnee"; import { effectifAnnee } from "../../queries/utils/effectifAnnee"; import { hasContinuum } from "../../queries/utils/hasContinuum"; import { notHistorique } from "../../queries/utils/notHistorique"; -import { withPositionQuadrant } from "../../queries/utils/positionQuadrant"; import { withTauxDevenirFavorableReg } from "../../queries/utils/tauxDevenirFavorable"; import { withInsertionReg } from "../../queries/utils/tauxInsertion6mois"; import { withPoursuiteReg } from "../../queries/utils/tauxPoursuite"; @@ -106,6 +105,7 @@ const findEtablissementsInDb = async ({ .select([ sql`COUNT(*) OVER()`.as("count"), "departement.libelle as departement", + "etablissement.codeRegion", "etablissement.UAI", "libelleOfficielFamille", "libelleDispositif", @@ -170,14 +170,6 @@ const findEtablissementsInDb = async ({ dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", }).as("tauxDevenirFavorable"), - (eb) => - withPositionQuadrant({ - eb, - millesimeSortie, - cfdRef: "formationEtablissement.cfd", - dispositifIdRef: "formationEtablissement.dispositifId", - codeRegionRef: "etablissement.codeRegion", - }).as("positionQuadrant"), ]) .$call((q) => { if (!codeRegion) return q; diff --git a/server/src/modules/data/usecases/getEtablissements/getEtablissements.usecase.ts b/server/src/modules/data/usecases/getEtablissements/getEtablissements.usecase.ts index ae33f1940..e538cdbfa 100644 --- a/server/src/modules/data/usecases/getEtablissements/getEtablissements.usecase.ts +++ b/server/src/modules/data/usecases/getEtablissements/getEtablissements.usecase.ts @@ -1,3 +1,5 @@ +import { getStatsSortieParRegionsEtNiveauDiplome } from "../../queries/getStatsSortie/getStatsSortie"; +import { getPositionQuadrant } from "../../services/getPositionQuadrant"; import { dependencies } from "./dependencies"; const getEtablissementsFactory = @@ -22,15 +24,29 @@ const getEtablissementsFactory = secteur?: string[]; orderBy?: { order: "asc" | "desc"; column: string }; }) => { - const [{ etablissements, count }, filters] = await Promise.all([ - deps.findEtablissementsInDb(activeFilters), - deps.findFiltersInDb(activeFilters), - ]); + const [{ etablissements, count }, filters, statsSortie] = await Promise.all( + [ + deps.findEtablissementsInDb(activeFilters), + deps.findFiltersInDb(activeFilters), + getStatsSortieParRegionsEtNiveauDiplome(activeFilters), + ] + ); return { count, filters, - etablissements, + etablissements: etablissements.map((etablissement) => ({ + ...etablissement, + positionQuadrant: + statsSortie && statsSortie[etablissement.codeRegion ?? ""] + ? getPositionQuadrant( + etablissement, + statsSortie[etablissement.codeRegion ?? ""][ + etablissement.codeNiveauDiplome ?? "" + ] || {} + ) + : "Hors quadrant", + })), }; }; diff --git a/server/src/modules/data/usecases/getFormations/dependencies.ts b/server/src/modules/data/usecases/getFormations/dependencies.ts index 0d754ef6a..83890bb7d 100644 --- a/server/src/modules/data/usecases/getFormations/dependencies.ts +++ b/server/src/modules/data/usecases/getFormations/dependencies.ts @@ -6,7 +6,6 @@ import { cleanNull } from "../../../../utils/noNull"; import { capaciteAnnee } from "../../queries/utils/capaciteAnnee"; import { effectifAnnee } from "../../queries/utils/effectifAnnee"; import { hasContinuum } from "../../queries/utils/hasContinuum"; -import { withPositionQuadrant } from "../../queries/utils/positionQuadrant"; import { withTauxDevenirFavorableReg } from "../../queries/utils/tauxDevenirFavorable"; import { withInsertionReg } from "../../queries/utils/tauxInsertion6mois"; import { withPoursuiteReg } from "../../queries/utils/tauxPoursuite"; @@ -32,7 +31,6 @@ const findFormationsInDb = async ({ CPCSecteur, CPCSousSecteur, libelleFiliere, - positionQuadrant, }: { offset?: number; limit?: number; @@ -52,7 +50,6 @@ const findFormationsInDb = async ({ CPCSecteur?: string[]; CPCSousSecteur?: string[]; libelleFiliere?: string[]; - positionQuadrant?: string; } = {}) => { const query = kdb .selectFrom("formation") @@ -170,13 +167,6 @@ const findFormationsInDb = async ({ dispositifIdRef: "formationEtablissement.dispositifId", codeRegionRef: "etablissement.codeRegion", }).as("tauxDevenirFavorable"), - withPositionQuadrant({ - eb, - millesimeSortie, - cfdRef: "formationEtablissement.cfd", - dispositifIdRef: "formationEtablissement.dispositifId", - codeRegionRef: "etablissement.codeRegion", - }).as("positionQuadrant"), ]) .where( "codeFormationDiplome", @@ -219,21 +209,6 @@ const findFormationsInDb = async ({ "familleMetier.libelleOfficielFamille", "niveauDiplome.libelleNiveauDiplome", ]) - .having((h) => { - if (!positionQuadrant) return h.val(true); - return h( - (eb) => - withPositionQuadrant({ - eb, - millesimeSortie, - cfdRef: "formationEtablissement.cfd", - dispositifIdRef: "formationEtablissement.dispositifId", - codeRegionRef: "etablissement.codeRegion", - }), - "=", - positionQuadrant - ); - }) .$call((q) => { if (!codeRegion) return q; return q.where("etablissement.codeRegion", "in", codeRegion); diff --git a/server/src/modules/data/usecases/getFormations/getFormations.usecase.ts b/server/src/modules/data/usecases/getFormations/getFormations.usecase.ts index f784fc074..c47dcbb90 100644 --- a/server/src/modules/data/usecases/getFormations/getFormations.usecase.ts +++ b/server/src/modules/data/usecases/getFormations/getFormations.usecase.ts @@ -1,3 +1,5 @@ +import { getStatsSortieParNiveauDiplome } from "../../queries/getStatsSortie/getStatsSortie"; +import { getPositionQuadrant } from "../../services/getPositionQuadrant"; import { dependencies } from "./dependencies"; const getFormationsFactory = @@ -27,15 +29,22 @@ const getFormationsFactory = withEmptyFormations?: boolean; positionQuadrant?: string; }) => { - const [{ formations, count }, filters] = await Promise.all([ + const [{ formations, count }, filters, statsSortie] = await Promise.all([ deps.findFormationsInDb(activeFilters), deps.findFiltersInDb(activeFilters), + getStatsSortieParNiveauDiplome(activeFilters), ]); return { count, filters, - formations, + formations: formations.map((formation) => ({ + ...formation, + positionQuadrant: getPositionQuadrant( + formation, + statsSortie[formation.codeNiveauDiplome ?? ""] ?? {} + ), + })), }; }; diff --git a/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsStatsQuery.dep.ts b/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsStatsQuery.dep.ts index 27d5f28e6..bd625a58f 100644 --- a/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsStatsQuery.dep.ts +++ b/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsStatsQuery.dep.ts @@ -4,7 +4,6 @@ import { kdb } from "../../../../db/db"; import { DB } from "../../../../db/schema"; import { cleanNull } from "../../../../utils/noNull"; import { hasContinuum } from "../../queries/utils/hasContinuum"; -import { withPositionQuadrant } from "../../queries/utils/positionQuadrant"; import { withTauxDevenirFavorableReg } from "../../queries/utils/tauxDevenirFavorable"; import { withInsertionReg } from "../../queries/utils/tauxInsertion6mois"; import { withPoursuiteReg } from "../../queries/utils/tauxPoursuite"; @@ -140,14 +139,6 @@ export const getFormationsTransformationStatsQuery = ({ dispositifIdRef: "demande.dispositifId", codeRegionRef: "dataEtablissement.codeRegion", }).as("tauxDevenirFavorable"), - withPositionQuadrant({ - eb, - millesimeSortie, - cfdRef: "demande.cfd", - dispositifIdRef: "demande.dispositifId", - codeRegionRef: "dataEtablissement.codeRegion", - codesNiveauxDiplomes: codeNiveauDiplome, - }).as("positionQuadrant"), selectNbDemandes(eb).as("nbDemandes"), selectNbEtablissements(eb).as("nbEtablissements"), sql`ABS(${eb.fn.sum(selectDifferencePlaces(eb, type))})`.as( diff --git a/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsTransformationStats.usecase.ts b/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsTransformationStats.usecase.ts index 71ed38476..b1b10ef5d 100644 --- a/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsTransformationStats.usecase.ts +++ b/server/src/modules/data/usecases/getFormationsTransformationStats/getFormationsTransformationStats.usecase.ts @@ -1,5 +1,7 @@ import { inject } from "injecti"; +import { getStatsSortie } from "../../queries/getStatsSortie/getStatsSortie"; +import { getPositionQuadrant } from "../../services/getPositionQuadrant"; import { getFormationsTransformationStatsQuery } from "./getFormationsStatsQuery.dep"; import { getRegionStats } from "./getRegionStats.dep"; @@ -17,11 +19,19 @@ export const [getFormationsTransformationStats] = inject( codeNiveauDiplome?: string[]; filiere?: string[]; orderBy?: { column: string; order: "asc" | "desc" }; + positionQuadrant?: string; }) => { - const [stats, formations] = await Promise.all([ - deps.getRegionStats(activeFilters), + const [formations, statsSortie] = await Promise.all([ deps.getFormationsTransformationStatsQuery(activeFilters), + getStatsSortie(activeFilters), ]); - return { stats, formations }; + + return { + stats: statsSortie, + formations: formations.map((formation) => ({ + ...formation, + positionQuadrant: getPositionQuadrant(formation, statsSortie), + })), + }; } ); diff --git a/server/src/modules/data/usecases/getRestitutionIntentionsStats/dependencies.ts b/server/src/modules/data/usecases/getRestitutionIntentionsStats/dependencies.ts index 01bafaaeb..a24a387da 100644 --- a/server/src/modules/data/usecases/getRestitutionIntentionsStats/dependencies.ts +++ b/server/src/modules/data/usecases/getRestitutionIntentionsStats/dependencies.ts @@ -7,14 +7,8 @@ import { cleanNull } from "../../../../utils/noNull"; import { RequestUser } from "../../../core/model/User"; import { nbEtablissementFormationRegion } from "../../../data/queries/utils/nbEtablissementFormationRegion"; import { selectTauxDevenirFavorable } from "../../../data/queries/utils/tauxDevenirFavorable"; -import { - selectTauxInsertion6mois, - selectTauxInsertion6moisAgg, -} from "../../../data/queries/utils/tauxInsertion6mois"; -import { - selectTauxPoursuite, - selectTauxPoursuiteAgg, -} from "../../../data/queries/utils/tauxPoursuite"; +import { selectTauxInsertion6mois } from "../../../data/queries/utils/tauxInsertion6mois"; +import { selectTauxPoursuite } from "../../../data/queries/utils/tauxPoursuite"; import { selectTauxPressionParFormationEtParRegionDemande } from "../../../data/queries/utils/tauxPression"; import { countDifferenceCapaciteApprentissage, @@ -24,8 +18,6 @@ import { isIntentionVisible, isRegionVisible, } from "../../../utils/isIntentionVisible"; -import { notHistoriqueIndicateurRegionSortie } from "../../queries/utils/notHistorique"; -import { getPositionQuadrant } from "../../queries/utils/positionQuadrant"; const findRestitutionIntentionsStatsInDB = async ({ status, @@ -111,6 +103,7 @@ const findRestitutionIntentionsStatsInDB = async ({ ) .selectAll("demande") .select((eb) => [ + "niveauDiplome.codeNiveauDiplome as codeNiveauDiplome", "niveauDiplome.libelleNiveauDiplome as niveauDiplome", "dataFormation.libelle as libelleDiplome", "dataFormation.libelleFiliere as libelleFiliere", @@ -140,8 +133,8 @@ const findRestitutionIntentionsStatsInDB = async ({ .select(["demandeCompensee.id", "demandeCompensee.typeDemande"]) .limit(1) ).as("demandeCompensee"), - selectTauxInsertion6mois("indicateurRegionSortie").as("insertion"), - selectTauxPoursuite("indicateurRegionSortie").as("poursuite"), + selectTauxInsertion6mois("indicateurRegionSortie").as("tauxInsertion"), + selectTauxPoursuite("indicateurRegionSortie").as("tauxPoursuite"), selectTauxDevenirFavorable("indicateurRegionSortie").as( "devenirFavorable" ), @@ -152,31 +145,6 @@ const findRestitutionIntentionsStatsInDB = async ({ nbEtablissementFormationRegion({ eb, rentreeScolaire: "2022" }).as( "nbEtablissement" ), - jsonObjectFrom( - eb - .selectFrom("indicateurRegionSortie as subIRS") - .innerJoin( - "formation", - "formation.codeFormationDiplome", - "subIRS.cfd" - ) - .whereRef("subIRS.codeRegion", "=", "demande.codeRegion") - .whereRef("subIRS.dispositifId", "=", "demande.dispositifId") - .whereRef( - "formation.codeNiveauDiplome", - "=", - "dataFormation.codeNiveauDiplome" - ) - .where("subIRS.millesimeSortie", "=", millesimeSortie) - .where(notHistoriqueIndicateurRegionSortie) - .select([ - selectTauxInsertion6moisAgg("subIRS").as("tauxInsertion"), - selectTauxPoursuiteAgg("subIRS").as("tauxPoursuite"), - getPositionQuadrant("indicateurRegionSortie", "subIRS").as( - "positionQuadrant" - ), - ]) - ).as("statsSortieMoyennes"), ]) .$call((eb) => { if (status && status != undefined) @@ -311,12 +279,6 @@ const findRestitutionIntentionsStatsInDB = async ({ updatedAt: demande.updatedAt?.toISOString(), idCompensation: demande.demandeCompensee?.id, typeCompensation: demande.demandeCompensee?.typeDemande ?? undefined, - tauxInsertionMoyen: - demande.statsSortieMoyennes?.tauxInsertion ?? undefined, - tauxPoursuiteMoyen: - demande.statsSortieMoyennes?.tauxPoursuite ?? undefined, - positionQuadrant: - demande.statsSortieMoyennes?.positionQuadrant ?? "Hors quadrant", }) ), count: parseInt(demandes[0]?.count) || 0, diff --git a/server/src/modules/data/usecases/getRestitutionIntentionsStats/getRestitutionIntentionsStats.usecase.ts b/server/src/modules/data/usecases/getRestitutionIntentionsStats/getRestitutionIntentionsStats.usecase.ts index 616b23d5b..7a885a379 100644 --- a/server/src/modules/data/usecases/getRestitutionIntentionsStats/getRestitutionIntentionsStats.usecase.ts +++ b/server/src/modules/data/usecases/getRestitutionIntentionsStats/getRestitutionIntentionsStats.usecase.ts @@ -1,4 +1,7 @@ +import { cleanNull } from "../../../../utils/noNull"; import { RequestUser } from "../../../core/model/User"; +import { getStatsSortieParRegionsEtNiveauDiplome } from "../../queries/getStatsSortie/getStatsSortie"; +import { getPositionQuadrant } from "../../services/getPositionQuadrant"; import { dependencies } from "./dependencies"; const getRestitutionIntentionsStatsFactory = @@ -33,15 +36,26 @@ const getRestitutionIntentionsStatsFactory = column: string; }; }) => { - const [{ count, demandes }, filters] = await Promise.all([ + const [{ count, demandes }, filters, statsSortie] = await Promise.all([ findRestitutionIntentionsStatsInDB(activeFilters), findFiltersInDb(activeFilters), + getStatsSortieParRegionsEtNiveauDiplome(activeFilters), ]); return { count, filters, - demandes, + demandes: demandes?.map((demande) => + cleanNull({ + ...demande, + positionQuadrant: getPositionQuadrant( + demande, + statsSortie[demande.codeRegion ?? ""][ + demande.codeNiveauDiplome ?? "" + ] || {} + ), + }) + ), }; }; diff --git a/shared/client/etablissements/etablissements.schema.ts b/shared/client/etablissements/etablissements.schema.ts index f2034123a..75c6a3ef8 100644 --- a/shared/client/etablissements/etablissements.schema.ts +++ b/shared/client/etablissements/etablissements.schema.ts @@ -29,6 +29,7 @@ const EtablissementLineSchema = Type.Object({ tauxRemplissage: Type.Optional(Type.Number()), tauxPoursuite: Type.Optional(Type.Number()), tauxInsertion: Type.Optional(Type.Number()), + positionQuadrant: Type.Optional(Type.String()), tauxDevenirFavorable: Type.Optional(Type.Number()), valeurAjoutee: Type.Optional(Type.Number()), CPC: Type.Optional(Type.String()), @@ -149,7 +150,7 @@ export const etablissementSchemas = { codeRegion: Type.String(), }), querystring: Type.Object({ - codesNiveauxDiplomes: Type.Optional(Type.Array(Type.String())), + codeNiveauDiplome: Type.Optional(Type.Array(Type.String())), }), response: { 200: Type.Object({ @@ -168,7 +169,7 @@ export const etablissementSchemas = { codeDepartement: Type.String(), }), querystring: Type.Object({ - codesNiveauxDiplomes: Type.Optional(Type.Array(Type.String())), + codeNiveauDiplome: Type.Optional(Type.Array(Type.String())), }), response: { 200: Type.Object({ diff --git a/shared/client/formations/formation.schema.ts b/shared/client/formations/formation.schema.ts index d389f036b..3c44ef3ff 100644 --- a/shared/client/formations/formation.schema.ts +++ b/shared/client/formations/formation.schema.ts @@ -55,6 +55,15 @@ const FiltersSchema = Type.Object({ order: Type.Optional(Type.Union([Type.Literal("asc"), Type.Literal("desc")])), orderBy: Type.Optional(Type.KeyOf(FormationLineSchema)), withEmptyFormations: Type.Optional(Type.Boolean()), + positionQuadrant: Type.Optional( + Type.Union([ + Type.Literal("Q1"), + Type.Literal("Q2"), + Type.Literal("Q3"), + Type.Literal("Q4"), + Type.Literal("Hors quadrant"), + ]) + ), }); const FormationSchema = Type.Object({ @@ -120,8 +129,8 @@ export const formationSchemas = { getDataForPanoramaRegion: { querystring: Type.Object({ codeRegion: Type.String(), - codesNiveauxDiplomes: Type.Optional(Type.Array(Type.String())), - libellesFilieres: Type.Optional(Type.Array(Type.String())), + codeNiveauDiplome: Type.Optional(Type.Array(Type.String())), + libelleFiliere: Type.Optional(Type.Array(Type.String())), order: Type.Optional( Type.Union([Type.Literal("asc"), Type.Literal("desc")]) ), @@ -140,8 +149,8 @@ export const formationSchemas = { getDataForPanoramaDepartement: { querystring: Type.Object({ codeDepartement: Type.String(), - codesNiveauxDiplomes: Type.Optional(Type.Array(Type.String())), - libellesFilieres: Type.Optional(Type.Array(Type.String())), + codeNiveauDiplome: Type.Optional(Type.Array(Type.String())), + libelleFiliere: Type.Optional(Type.Array(Type.String())), order: Type.Optional( Type.Union([Type.Literal("asc"), Type.Literal("desc")]) ), diff --git a/shared/client/pilotageTransfo/pilotageTransfo.schema.ts b/shared/client/pilotageTransfo/pilotageTransfo.schema.ts index 4e7e2eabb..2c08f08fa 100644 --- a/shared/client/pilotageTransfo/pilotageTransfo.schema.ts +++ b/shared/client/pilotageTransfo/pilotageTransfo.schema.ts @@ -130,6 +130,16 @@ export const pilotageTransformationSchemas = { tauxPression: Type.Optional( Type.Union([Type.Literal("eleve"), Type.Literal("faible")]) ), + positionQuadrant: Type.Optional( + Type.Union([ + Type.Literal("Q1"), + Type.Literal("Q2"), + Type.Literal("Q3"), + Type.Literal("Q4"), + Type.Literal("Hors quadrant"), + Type.Literal("All"), + ]) + ), }), Type.Object({ order: Type.Optional( diff --git a/shared/client/restitutionIntentions/restitutionIntentions.schema.ts b/shared/client/restitutionIntentions/restitutionIntentions.schema.ts index fc509eb1c..83ed36588 100644 --- a/shared/client/restitutionIntentions/restitutionIntentions.schema.ts +++ b/shared/client/restitutionIntentions/restitutionIntentions.schema.ts @@ -44,14 +44,12 @@ const StatsDemandesItem = Type.Object({ capaciteApprentissageActuelle: Type.Optional(Type.Number()), capaciteApprentissage: Type.Optional(Type.Number()), capaciteApprentissageColoree: Type.Optional(Type.Number()), - insertion: Type.Optional(Type.Number()), - poursuite: Type.Optional(Type.Number()), + tauxInsertion: Type.Optional(Type.Number()), + tauxPoursuite: Type.Optional(Type.Number()), devenirFavorable: Type.Optional(Type.Number()), pression: Type.Optional(Type.Number()), nbEtablissement: Type.Optional(Type.Number()), positionQuadrant: Type.Optional(Type.String()), - tauxInsertionMoyen: Type.Optional(Type.Number()), - tauxPoursuiteMoyen: Type.Optional(Type.Number()), }); const StatsFiltersSchema = Type.Object({ diff --git a/ui/app/(wrapped)/console/etablissements/components/LineContent.tsx b/ui/app/(wrapped)/console/etablissements/components/LineContent.tsx index 553467049..9976edef4 100644 --- a/ui/app/(wrapped)/console/etablissements/components/LineContent.tsx +++ b/ui/app/(wrapped)/console/etablissements/components/LineContent.tsx @@ -77,6 +77,7 @@ export const EtablissementLineContent = ({ + {line.positionQuadrant} + + {ETABLISSEMENTS_COLUMNS.positionQuadrant} + + handleOrder("tauxDevenirFavorable")} diff --git a/ui/app/(wrapped)/intentions/restitution/ConsoleSection/ConsoleSection.tsx b/ui/app/(wrapped)/intentions/restitution/ConsoleSection/ConsoleSection.tsx index 026909486..2fdf3bf15 100644 --- a/ui/app/(wrapped)/intentions/restitution/ConsoleSection/ConsoleSection.tsx +++ b/ui/app/(wrapped)/intentions/restitution/ConsoleSection/ConsoleSection.tsx @@ -211,13 +211,13 @@ export const ConsoleSection = ({ textAlign="center" cursor="pointer" pb="4" - onClick={() => handleOrder("insertion")} + onClick={() => handleOrder("tauxInsertion")} minW={200} maxW={200} whiteSpace="normal" > - - {STATS_DEMANDES_COLUMNS.insertion} + + {STATS_DEMANDES_COLUMNS.tauxInsertion} handleOrder("poursuite")} + onClick={() => handleOrder("tauxPoursuite")} minW={250} maxW={250} whiteSpace="normal" > - - {STATS_DEMANDES_COLUMNS.poursuite} + + {STATS_DEMANDES_COLUMNS.tauxPoursuite} {demande.differenceCapaciteScolaire ?? 0} {demande.differenceCapaciteApprentissage ?? 0} - + - + diff --git a/ui/app/(wrapped)/intentions/restitution/STATS_DEMANDES_COLUMN.ts b/ui/app/(wrapped)/intentions/restitution/STATS_DEMANDES_COLUMN.ts index 5f3f274a6..b61404cbd 100644 --- a/ui/app/(wrapped)/intentions/restitution/STATS_DEMANDES_COLUMN.ts +++ b/ui/app/(wrapped)/intentions/restitution/STATS_DEMANDES_COLUMN.ts @@ -41,8 +41,8 @@ export const STATS_DEMANDES_COLUMNS = { capaciteApprentissageActuelle: "Capacité apprentissage actuelle", capaciteApprentissage: "Capacité apprentissage", capaciteApprentissageColoree: "Capacité apprentissage coloree", - insertion: "Tx d'emploi à 6 mois régional", - poursuite: "Tx de poursuite d'études régional", + tauxInsertion: "Tx d'emploi à 6 mois régional", + tauxPoursuite: "Tx de poursuite d'études régional", devenirFavorable: "Tx de devenir favorable régional", positionQuadrant: "Position dans le quadrant", pression: "Tx de pression régional", diff --git a/ui/app/(wrapped)/panorama/components/FiltersSection.tsx b/ui/app/(wrapped)/panorama/components/FiltersSection.tsx index 053272def..4d22af7d5 100644 --- a/ui/app/(wrapped)/panorama/components/FiltersSection.tsx +++ b/ui/app/(wrapped)/panorama/components/FiltersSection.tsx @@ -28,10 +28,10 @@ export const FiltersSection = ({ > handleFilters("libellesFilieres", selected)} + onChange={(selected) => handleFilters("libelleFiliere", selected)} width={250} options={libelleFiliereOptions} - value={activeFilters.libellesFilieres ?? []} + value={activeFilters.libelleFiliere ?? []} ml="2" > Secteur d’activité diff --git a/ui/app/(wrapped)/panorama/components/IndicateursSection.tsx b/ui/app/(wrapped)/panorama/components/IndicateursSection.tsx index d92601b26..3127d0b31 100644 --- a/ui/app/(wrapped)/panorama/components/IndicateursSection.tsx +++ b/ui/app/(wrapped)/panorama/components/IndicateursSection.tsx @@ -99,11 +99,11 @@ export const IndicateursSection = ({ Diplôme - handleFilters("codesNiveauxDiplomes", selected) + handleFilters("codeNiveauDiplome", selected) } width="100%" options={diplomeOptions} - value={activeFilters.codesNiveauxDiplomes ?? []} + value={activeFilters.codeNiveauDiplome ?? []} size="md" > Diplôme diff --git a/ui/app/(wrapped)/panorama/types.ts b/ui/app/(wrapped)/panorama/types.ts index cb188a1bf..8fbd6531c 100644 --- a/ui/app/(wrapped)/panorama/types.ts +++ b/ui/app/(wrapped)/panorama/types.ts @@ -58,5 +58,5 @@ export type Order = OrderPanoramaEtablissement | OrderPanoramaFormation; export type FiltersPanoramaFormation = Pick< QueryPanoramaFormation, - "codesNiveauxDiplomes" | "libellesFilieres" + "codeNiveauDiplome" | "libelleFiliere" >; From 4eb3cb5799edb6eca9abcce9a2b8d10fe29a808b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20D=C3=A9tr=C3=A9?= Date: Thu, 16 Nov 2023 16:14:17 +0100 Subject: [PATCH 17/28] fix: fix --- .../getRestitutionIntentionsStats.usecase.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/server/src/modules/data/usecases/getRestitutionIntentionsStats/getRestitutionIntentionsStats.usecase.ts b/server/src/modules/data/usecases/getRestitutionIntentionsStats/getRestitutionIntentionsStats.usecase.ts index 7a885a379..6b7d5108b 100644 --- a/server/src/modules/data/usecases/getRestitutionIntentionsStats/getRestitutionIntentionsStats.usecase.ts +++ b/server/src/modules/data/usecases/getRestitutionIntentionsStats/getRestitutionIntentionsStats.usecase.ts @@ -48,12 +48,15 @@ const getRestitutionIntentionsStatsFactory = demandes: demandes?.map((demande) => cleanNull({ ...demande, - positionQuadrant: getPositionQuadrant( - demande, - statsSortie[demande.codeRegion ?? ""][ - demande.codeNiveauDiplome ?? "" - ] || {} - ), + positionQuadrant: + statsSortie && statsSortie[demande.codeRegion ?? ""] + ? getPositionQuadrant( + demande, + statsSortie[demande.codeRegion ?? ""][ + demande.codeNiveauDiplome ?? "" + ] || {} + ) + : "Hors quadrant", }) ), }; From 707c42024e937eef8793b4ea1f6870dd9e726b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20D=C3=A9tr=C3=A9?= Date: Tue, 21 Nov 2023 15:04:33 +0100 Subject: [PATCH 18/28] fix: nombre formations panorama + fix divers --- Makefile | 3 ++ .../getDepartementsStats.query.ts | 13 +++---- .../getRegionStats/getRegionStats.query.ts | 13 +++---- .../(wrapped)/console/etablissements/page.tsx | 2 +- ui/app/(wrapped)/console/formations/page.tsx | 2 +- .../ConsoleSection/ConsoleSection.tsx | 2 +- .../saisie/intentionForm/IntentionForm.tsx | 37 +------------------ .../panorama/components/TopFlopSection.tsx | 2 +- 8 files changed, 21 insertions(+), 53 deletions(-) diff --git a/Makefile b/Makefile index 42a538bd8..7c98cfea3 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,9 @@ clean: typecheck: yarn --cwd server typecheck && yarn --cwd ui typecheck +prettier_fix: + yarn prettier:fix + test: yarn --cwd server test diff --git a/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts b/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts index 2dd6312e6..515c6fcb6 100644 --- a/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts +++ b/server/src/modules/data/queries/getDepartementsStats/getDepartementsStats.query.ts @@ -62,13 +62,11 @@ export const getDepartementsStats = async ({ "formationEtablissement.cfd" ) .leftJoin("indicateurEntree", (join) => - join - .onRef( - "formationEtablissement.id", - "=", - "indicateurEntree.formationEtablissementId" - ) - .on("indicateurEntree.rentreeScolaire", "=", rentreeScolaire) + join.onRef( + "formationEtablissement.id", + "=", + "indicateurEntree.formationEtablissementId" + ) ) .innerJoin( "etablissement", @@ -86,6 +84,7 @@ export const getDepartementsStats = async ({ return q.where("formation.codeNiveauDiplome", "in", codeNiveauDiplome); }) .where(notHistorique) + .where("indicateurEntree.rentreeScolaire", "=", rentreeScolaire) .select([ "departement.codeRegion", "departement.libelle as libelleDepartement", diff --git a/server/src/modules/data/queries/getRegionStats/getRegionStats.query.ts b/server/src/modules/data/queries/getRegionStats/getRegionStats.query.ts index 669ce831c..1af2e7d1a 100644 --- a/server/src/modules/data/queries/getRegionStats/getRegionStats.query.ts +++ b/server/src/modules/data/queries/getRegionStats/getRegionStats.query.ts @@ -50,13 +50,11 @@ export const getRegionStats = async ({ "formationEtablissement.cfd" ) .leftJoin("indicateurEntree", (join) => - join - .onRef( - "formationEtablissement.id", - "=", - "indicateurEntree.formationEtablissementId" - ) - .on("indicateurEntree.rentreeScolaire", "=", rentreeScolaire) + join.onRef( + "formationEtablissement.id", + "=", + "indicateurEntree.formationEtablissementId" + ) ) .innerJoin( "etablissement", @@ -64,6 +62,7 @@ export const getRegionStats = async ({ "etablissement.UAI" ) .where("etablissement.codeRegion", "=", codeRegion) + .where("indicateurEntree.rentreeScolaire", "=", rentreeScolaire) .innerJoin("region", "region.codeRegion", "etablissement.codeRegion") .$call((q) => { if (!codeNiveauDiplome?.length) return q; diff --git a/ui/app/(wrapped)/console/etablissements/page.tsx b/ui/app/(wrapped)/console/etablissements/page.tsx index 24cba7e59..aa6938f70 100644 --- a/ui/app/(wrapped)/console/etablissements/page.tsx +++ b/ui/app/(wrapped)/console/etablissements/page.tsx @@ -543,7 +543,7 @@ export default function Etablissements() { {ETABLISSEMENTS_COLUMNS.tauxDevenirFavorable} { - if (!formId) return; - await api.deleteDemande({ params: { id: formId } }).call(); - }, - onSuccess: () => push("/intentions/saisie"), - }); - - const isSubmitting = isSubmittingDraft || isSubmittingDemande || isDeleting; - const isSuccess = isDraftSuccess || isDeleteSuccess || isDemandeSuccess; + const isSubmitting = isSubmittingDraft || isSubmittingDemande; + const isSuccess = isDraftSuccess || isDemandeSuccess; const isActionsDisabled = isSuccess || isSubmitting; const [isFCIL, setIsFCIL] = useState( @@ -171,25 +157,6 @@ export const IntentionForm = ({ formMetadata={formMetadata} footerActions={ <> - {formId && ( - ( - - )} - /> - )}