From 71d63d2f55fb53eb1483b6b0670f134a47241f28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?BITARD=20Micha=C3=ABl?= <michael.bitard@beta.gouv.fr> Date: Thu, 6 Mar 2025 16:58:58 +0000 Subject: [PATCH] =?UTF-8?q?fix(phases):=20on=20affiche=20la=20liste=20des?= =?UTF-8?q?=20d=C3=A9marches=20quand=20on=20a=20plusieurs=20d=C3=A9marches?= =?UTF-8?q?=20sans=20aucune=20phase=20(pub/pnm-public/camino!1658)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...AvecUnOctroiEnConstructionEtUnTravaux.html | 11 +++- packages/ui/src/components/titre.tsx | 8 ++- .../ui/src/components/titre/phase.test.ts | 57 ++++++++++++++++++- packages/ui/src/components/titre/phase.ts | 9 ++- .../titre/titre-timeline.stories.tsx | 17 ++++++ ...ies_snapshots_MultipleDemarcheNoPhase.html | 12 ++++ .../src/components/titre/titre-timeline.tsx | 33 ++++++++++- 7 files changed, 139 insertions(+), 8 deletions(-) create mode 100644 packages/ui/src/components/titre/titre-timeline.stories_snapshots_MultipleDemarcheNoPhase.html diff --git a/packages/ui/src/components/titre.stories_snapshots_TitreAvecUnOctroiEnConstructionEtUnTravaux.html b/packages/ui/src/components/titre.stories_snapshots_TitreAvecUnOctroiEnConstructionEtUnTravaux.html index d3be05d16..d514dbc3a 100644 --- a/packages/ui/src/components/titre.stories_snapshots_TitreAvecUnOctroiEnConstructionEtUnTravaux.html +++ b/packages/ui/src/components/titre.stories_snapshots_TitreAvecUnOctroiEnConstructionEtUnTravaux.html @@ -40,7 +40,16 @@ </div> <div class="fr-mb-3w fr-mt-3w" style="height: 1px; width: 100%; background-color: var(--grey-900-175);"></div> <!----> - <!----> + <div class="fr-pt-4w fr-pb-4w"> + <h2>Démarches</h2> + <div class="fr-alert fr-alert--warning"> + <p class="fr-alert__title fr-h4">Plusieurs démarches sans phase</p>Nous affichons toutes les démarches en mode dégradé, normalement, on ne peut avoir plusieurs démarches que si au moins l'une d'entre elle a une phase.<br><strong>Il faudrait très probablement que l'Octroi aille jusqu'au bout avant de créer d'autres démarches.</strong> + </div> + <ul> + <li><a href="/mocked-href" title="oct" aria-label="oct">Octroi</a></li> + <li><a href="/mocked-href" title="dam" aria-label="dam">Déclaration d'arrêt définitif des travaux</a></li> + </ul> + </div> <div> <div class="fr-grid-row fr-grid-row--middle"> <h2 style="margin: 0px;">Octroi</h2> diff --git a/packages/ui/src/components/titre.tsx b/packages/ui/src/components/titre.tsx index 93f2cea3d..311cb2146 100644 --- a/packages/ui/src/components/titre.tsx +++ b/packages/ui/src/components/titre.tsx @@ -164,7 +164,11 @@ export const PureTitre = defineComponent<Props>(props => { let demarcheSlug = props.currentDemarcheSlug - if ((isNullOrUndefinedOrEmpty(demarcheSlug) || isNullOrUndefined(data.demarches.find(({ slug }) => slug === props.currentDemarcheSlug))) && phases.value.length > 0) { + if ( + (isNullOrUndefinedOrEmpty(demarcheSlug) || isNullOrUndefined(data.demarches.find(({ slug }) => slug === props.currentDemarcheSlug))) && + !('erreur' in phases.value) && + phases.value.length > 0 + ) { demarcheSlug = phases.value[phases.value.length - 1][phases.value[phases.value.length - 1].length - 1].slug } @@ -324,7 +328,7 @@ export const PureTitre = defineComponent<Props>(props => { } const hasNoPhases = computed<boolean>(() => { - return phases.value.length === 0 + return !('erreur' in phases.value) && phases.value.length === 0 }) const addDemarchePopup = ref<boolean>(false) diff --git a/packages/ui/src/components/titre/phase.test.ts b/packages/ui/src/components/titre/phase.test.ts index aa2e9c16c..7d5269c6f 100644 --- a/packages/ui/src/components/titre/phase.test.ts +++ b/packages/ui/src/components/titre/phase.test.ts @@ -5,6 +5,62 @@ import { demarcheIdValidator, demarcheSlugValidator } from 'camino-common/src/de import { TitreGetDemarche } from 'camino-common/src/titres' import { ETAPE_IS_NOT_BROUILLON, etapeIdValidator, etapeSlugValidator } from 'camino-common/src/etape' +test('phase en erreur', () => { + const demarches: TitreGetDemarche[] = [ + { + id: demarcheIdValidator.parse('idMut'), + slug: demarcheSlugValidator.parse('slug-mut'), + description: null, + etapes: [], + demarche_type_id: 'mut', + demarche_statut_id: 'acp', + demarche_date_debut: null, + demarche_date_fin: null, + ordre: 1, + }, + { + id: demarcheIdValidator.parse('idDemPro'), + slug: demarcheSlugValidator.parse('dem-slug-pro'), + description: null, + etapes: [], + demarche_type_id: 'pro', + demarche_statut_id: 'acp', + demarche_date_debut: null, + demarche_date_fin: null, + ordre: 2, + }, + ] + const actual = phaseWithAlterations(demarches, toCaminoDate('2024-07-11')) + expect(actual).toMatchInlineSnapshot(` + { + "demarches": [ + { + "demarche_date_debut": null, + "demarche_date_fin": null, + "demarche_statut_id": "acp", + "demarche_type_id": "mut", + "description": null, + "etapes": [], + "id": "idMut", + "ordre": 1, + "slug": "slug-mut", + }, + { + "demarche_date_debut": null, + "demarche_date_fin": null, + "demarche_statut_id": "acp", + "demarche_type_id": "pro", + "description": null, + "etapes": [], + "id": "idDemPro", + "ordre": 2, + "slug": "dem-slug-pro", + }, + ], + "erreur": "plusieurs démarches sans phase", + } +`) +}) test('phase acceptée et publiée', () => { const demarches: TitreGetDemarche[] = [ { @@ -63,7 +119,6 @@ test('phase acceptée et publiée', () => { }, ] const actual = phaseWithAlterations(demarches, toCaminoDate('2024-07-11')) - expect(actual[0]).toHaveLength(2) expect(actual).toMatchInlineSnapshot(` [ [ diff --git a/packages/ui/src/components/titre/phase.ts b/packages/ui/src/components/titre/phase.ts index b075f6623..5eb476c61 100644 --- a/packages/ui/src/components/titre/phase.ts +++ b/packages/ui/src/components/titre/phase.ts @@ -14,7 +14,9 @@ type PhaseWithDateDebut = OmitDistributive<TitreGetDemarche, 'demarche_date_debu type DemarcheAlteration = TitreGetDemarche & { date_etape_decision_ok: CaminoDate; events: TitreTimelineEvents[] } -export type PhaseWithAlterations = [PhaseWithDateDebut, ...DemarcheAlteration[]][] | [[OmitDistributive<TitreGetDemarche, 'demarche_date_debut'> & { demarche_date_debut: null }]] +const erreurPlusieursDemarches = 'plusieurs démarches sans phase' as const +export type PhaseErreurs = { erreur: string; demarches: Pick<TitreGetDemarche, 'slug' | 'demarche_type_id'>[] } +export type PhaseWithAlterations = [PhaseWithDateDebut, ...DemarcheAlteration[]][] | [[OmitDistributive<TitreGetDemarche, 'demarche_date_debut'> & { demarche_date_debut: null }]] | PhaseErreurs export const phaseWithAlterations = (demarches: TitreGetDemarche[], currentDate: CaminoDate): PhaseWithAlterations => { if (isNullOrUndefinedOrEmpty(demarches)) { return [] @@ -27,7 +29,10 @@ export const phaseWithAlterations = (demarches: TitreGetDemarche[], currentDate: const demarchesUsed: DemarcheSlug[] = simplePhases.map(({ slug }) => slug) if (isNullOrUndefinedOrEmpty(simplePhases)) { if (demarches.length > 1) { - console.error('Le titre a plusieurs démarches sans phase') + return { + erreur: erreurPlusieursDemarches, + demarches, + } } return [[{ ...demarches[0], demarche_date_debut: null }]] diff --git a/packages/ui/src/components/titre/titre-timeline.stories.tsx b/packages/ui/src/components/titre/titre-timeline.stories.tsx index 7cacdd481..1d5ca401a 100644 --- a/packages/ui/src/components/titre/titre-timeline.stories.tsx +++ b/packages/ui/src/components/titre/titre-timeline.stories.tsx @@ -3,6 +3,7 @@ import { demarcheSlugValidator } from 'camino-common/src/demarche' import { toCaminoDate } from 'camino-common/src/date' import { Phase, TitreTimeline } from './titre-timeline' import { titreSlugValidator } from 'camino-common/src/validators/titres' +import { DEMARCHES_TYPES_IDS } from 'camino-common/src/static/demarchesTypes' const meta: Meta = { title: 'Components/Titre/Timeline', @@ -261,6 +262,22 @@ export const OneDemarcheNoPhase: StoryFn = () => ( </div> ) +export const MultipleDemarcheNoPhase: StoryFn = () => ( + <div> + <TitreTimeline + titreSlug={titreSlugValidator.parse('slug-titre')} + phasesWithAlterations={{ + erreur: 'plusieurs démarches sans phase', + demarches: [ + { slug: demarcheSlugValidator.parse('slug-id1'), demarche_type_id: DEMARCHES_TYPES_IDS.Octroi }, + { slug: demarcheSlugValidator.parse('slug-id2'), demarche_type_id: DEMARCHES_TYPES_IDS.Prolongation }, + ], + }} + currentDemarcheSlug={demarcheSlugValidator.parse('slug-demarche2')} + /> + </div> +) + export const NoDemarcheNoPhase: StoryFn = () => ( <div> <TitreTimeline titreSlug={titreSlugValidator.parse('slug-titre')} phasesWithAlterations={[]} currentDemarcheSlug={demarcheSlugValidator.parse('slug-demarche2')} /> diff --git a/packages/ui/src/components/titre/titre-timeline.stories_snapshots_MultipleDemarcheNoPhase.html b/packages/ui/src/components/titre/titre-timeline.stories_snapshots_MultipleDemarcheNoPhase.html new file mode 100644 index 000000000..a6e862c04 --- /dev/null +++ b/packages/ui/src/components/titre/titre-timeline.stories_snapshots_MultipleDemarcheNoPhase.html @@ -0,0 +1,12 @@ +<div> + <div> + <h2>Démarches</h2> + <div class="fr-alert fr-alert--warning"> + <p class="fr-alert__title fr-h4">Plusieurs démarches sans phase</p>Nous affichons toutes les démarches en mode dégradé, normalement, on ne peut avoir plusieurs démarches que si au moins l'une d'entre elle a une phase.<br><strong>Il faudrait très probablement que l'Octroi aille jusqu'au bout avant de créer d'autres démarches.</strong> + </div> + <ul> + <li><a href="/mocked-href" title="oct" aria-label="oct">Octroi</a></li> + <li><a href="/mocked-href" title="pro" aria-label="pro">Prolongation</a></li> + </ul> + </div> +</div> \ No newline at end of file diff --git a/packages/ui/src/components/titre/titre-timeline.tsx b/packages/ui/src/components/titre/titre-timeline.tsx index 78a7d348e..dd971d593 100644 --- a/packages/ui/src/components/titre/titre-timeline.tsx +++ b/packages/ui/src/components/titre/titre-timeline.tsx @@ -11,13 +11,15 @@ import { TitreSlug } from 'camino-common/src/validators/titres' import { TravauxIcone } from './travaux-icone' import { DsfrSeparator } from '../_ui/dsfr-separator' import { capitalize } from 'camino-common/src/strings' +import { PhaseErreurs } from './phase' +import { Alert } from '../_ui/alert' type NoPhase = [[Pick<PhaseWithDateDebut, 'slug' | 'demarche_type_id'> & { demarche_date_debut: null }]] export type Phase = [PhaseWithDateDebut, ...DemarcheAlteration[]][] type TitreTimelineEvents = Pick<TitreGetDemarche, 'slug' | 'demarche_type_id'> & { first_etape_date: CaminoDate | null } type Props = { titreSlug: TitreSlug - phasesWithAlterations: Phase | NoPhase + phasesWithAlterations: Phase | NoPhase | PhaseErreurs currentDemarcheSlug: DemarcheSlug class?: HTMLAttributes['class'] } @@ -39,6 +41,33 @@ const isNoPhase = (phase: Phase | NoPhase): phase is NoPhase => { const minWidth = 200 export const TitreTimeline: FunctionalComponent<Props> = props => { + if ('erreur' in props.phasesWithAlterations) { + return ( + <div> + <h2>Démarches</h2> + <Alert + type="warning" + title={'Plusieurs démarches sans phase'} + description={ + <> + Nous affichons toutes les démarches en mode dégradé, normalement, on ne peut avoir plusieurs démarches que si au moins l'une d'entre elle a une phase. + <br /> + <strong>Il faudrait très probablement que l'Octroi aille jusqu'au bout avant de créer d'autres démarches.</strong> + </> + } + /> + <ul> + {props.phasesWithAlterations.demarches.map(demarche => ( + <li> + <CaminoRouterLink isDisabled={false} to={{ name: 'titre', params: { id: props.titreSlug }, query: { demarcheSlug: demarche.slug } }} title={demarche.demarche_type_id}> + {capitalize(DemarchesTypes[demarche.demarche_type_id].nom)} + </CaminoRouterLink> + </li> + ))} + </ul> + </div> + ) + } if (props.phasesWithAlterations.length === 0 || isNoPhase(props.phasesWithAlterations)) { return null } @@ -154,7 +183,7 @@ export const TitreTimeline: FunctionalComponent<Props> = props => { </Fragment> ))} </div> - {index !== props.phasesWithAlterations.length - 1 ? <div style={{ border: '2px solid black' }}></div> : null} + {!('erreur' in props.phasesWithAlterations) && index !== props.phasesWithAlterations.length - 1 ? <div style={{ border: '2px solid black' }}></div> : null} </Fragment> ))} </div> -- GitLab