From 30694a9f30858814c8e640a83c376c727517ee13 Mon Sep 17 00:00:00 2001 From: Victor Zeinstra Date: Thu, 7 Nov 2024 11:16:14 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20d=C3=A9velopper=20la=20page=20conventio?= =?UTF-8?q?n=20collective=20(#6225)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: dsfr * fix: dsfr * fix: dsfr * fix: tests * fix: build * fix: build * fix: build * feat(dsfr): ajout du footer (#6079) * feat: add code * fix: tests * fix: tests * fix: tests * fix: tests * fix: tests * fix: dernier titi * fix: autoclick * fix: bug * feat(css): ajout de la lib `panda-css` (zero-runtime) (#6085) * fix: pandacss * fix: build * fix: build * feat(dsfr): ajout de la page stats (#6090) * fix: pandacss * fix: build * fix: build * fix(stats): add page * fix: stats * fix: tests * fix: tests * Update packages/code-du-travail-frontend/src/modules/mentions-legales/index.tsx Co-authored-by: Martial Maillot * fix(recherche): remonter les pré-qualifiés dans la recherche (#6082) * chore(release): version 4.151.1 * fix(csp): remove reporting on sentry (#6092) * fix: config * fix: config * fix: config * empty * fix: config * empty * Update packages/code-du-travail-frontend/src/modules/mentions-legales/index.tsx Co-authored-by: Martial Maillot * Update packages/code-du-travail-frontend/src/modules/mentions-legales/index.tsx Co-authored-by: Martial Maillot * fix: config * chore(dsfr): mise à jour de la version DSFR * fix(dsfr): ignore les exceptions d'hydratation * feat(tests): ajout du module de testing (#6096) * fix: tests * fix: tests * fix: command * fix: merge date * fix: tests * fix: tests * fix: tests * fix: tests * fix(dsfr): ignore les exceptions d'hydratation * fix: readme * feat(DSFR): migration de la page article du code du travail (#6099) * feat: 6093 dsfr page politique de confidentialit (#6094) * feat: implémentation page politique confidentialité dsfr * chore: clean * fix: iframe dark mode * chore: refacto + e2e test * feat: convert a to Link * chore: review * chore: rename test --------- Co-authored-by: victor * feat(dsfr): ajout des liens d'évitement (#6120) * feat(dsfr): migration de la page plan du site (#6097) * feat(dsfr): mise à jour des snapshots * feat(dsfr): mise à jour des snapshots * chore(dsfr): mise à jour de la lib DSFR * feat(dsfr): ajout du composant "Avez-vous trouvé une réponse à votre question" (#6121) * fix: merge date * fix: satisfaction * fix: retours preavis * fix: retours preavis * fix: tests * move feedback component to the page articleCodeDuTravail.tsx * clean-up css * fix: feedback * fix: feedback * fix: tests * fix: tests * feat(dsfr): création du composant "Besoin de plus d'information" (#6135) * fix: ui * fix: composant --------- Co-authored-by: carolineBda Co-authored-by: Martial Maillot * fix: retours * fix: tests * feat: nouvelle API pour les articles du code du travail (#6132) Co-authored-by: carolineBda * fix(spec) : fix de la spec article-code-du-travail.spec.ts * fix(dsfr): ajout de la config pour supprimer le `insafe-inline` des `scripts` dans les `csp` (#6151) * feat(dsfr): ajout de matomo pour tracker les events (#6157) * fix: matomo * fix: matomo --------- Co-authored-by: Martial Maillot * fix(feedback): ajout d'une logique de caractères restants (#6156) * fix: tests * feat: limiter à 500 caractères la saisie * feat: limiter à 500 caractères la saisie --------- Co-authored-by: Martial Maillot * feat(dsfr): ajout du nouveau logo (#6159) * feat(dsfr): ajout des pages d'erreurs (404 + 500) (#6146) * fix: pages * fix: 404 * fix: tests * fix: tests * fix: tests * fix: lint * test error * fix errors * Fix spec * add button to test error page * feat: force error 500 for testing purpose * feat: revert errors --------- Co-authored-by: carolineBda Co-authored-by: Martial Maillot * feat: séparation des anciennes API et des nouvelles (#6183) * fix(article code du travail): retrait du tag Code du travail (#6182) * feat(config): correction de `husky`, ajout de `prettier` pour le formattage et de `lint-staged` pour runner le formattage au `precommit` (#6192) * fix: prettier * fix: prettier * fix: readme * fix: readme * fix: bug * fix: prettier * fix: prettier * fix: tests * fix: tests * fix: prettier * fix: prettier * fix: branch * merge dev * feat: implémentation simulateur brut net * chore: fix ts * chore: snap * chore: clean * chore: clean * chore: clean * chore: review * feat: update responsive * Revert "Merge branch 'dev' into simulateur-brut-net-dsfr" This reverts commit 07489287af016ae667dfc30c55e93a3783d4b211, reversing changes made to cd15bc7ee0bbe31de5978c9adcda83165707941d. * chore: clean * feat: chore clean * chore: clean * chore: remove undesired files * chore: remove undesired files * chore: clean * feat: implementation page convention collective * feat: update button link * fix: meta description share * feat: switch simu brut net couleur par defaut * feat: ajout de l'icone * feat: update svg * fix: ts * fix: bug load * chore: review * fix: mobile display * chore: review * chore: review * chore: review * chore review * fix: TU * chore: review * fix: validate html * chore: review * chore: clean --------- Co-authored-by: maxgfr <25312957+maxgfr@users.noreply.github.com> Co-authored-by: Caroline <4971715+carolineBda@users.noreply.github.com> Co-authored-by: Martial Maillot Co-authored-by: Social Groovy Bot <45039513+SocialGroovyBot@users.noreply.github.com> Co-authored-by: victor Co-authored-by: carolineBda --- .../app/convention-collective/page.tsx | 48 ++++++++++ .../light/conventions-collectives.spec.ts | 10 +- .../integration/light/validate-html.spec.ts | 1 - .../pages/convention-collective/index.tsx | 94 ------------------- .../convention-collective/AgreementSearch.svg | 16 ++++ .../convention-collective/Agreements.tsx | 44 +++++++++ .../AgreementsGlossaire.tsx | 49 ++++++++++ .../convention-collective/AgreementsIntro.tsx | 84 +++++++++++++++++ .../AgreementsSection.tsx | 30 ++++++ .../modules/convention-collective/index.ts | 1 + .../src/modules/layout/ContainerSimulator.tsx | 50 ++++++++++ 11 files changed, 329 insertions(+), 98 deletions(-) create mode 100644 packages/code-du-travail-frontend/app/convention-collective/page.tsx delete mode 100644 packages/code-du-travail-frontend/pages/convention-collective/index.tsx create mode 100644 packages/code-du-travail-frontend/src/modules/convention-collective/AgreementSearch.svg create mode 100644 packages/code-du-travail-frontend/src/modules/convention-collective/Agreements.tsx create mode 100644 packages/code-du-travail-frontend/src/modules/convention-collective/AgreementsGlossaire.tsx create mode 100644 packages/code-du-travail-frontend/src/modules/convention-collective/AgreementsIntro.tsx create mode 100644 packages/code-du-travail-frontend/src/modules/convention-collective/AgreementsSection.tsx create mode 100644 packages/code-du-travail-frontend/src/modules/layout/ContainerSimulator.tsx diff --git a/packages/code-du-travail-frontend/app/convention-collective/page.tsx b/packages/code-du-travail-frontend/app/convention-collective/page.tsx new file mode 100644 index 0000000000..db4ac7317a --- /dev/null +++ b/packages/code-du-travail-frontend/app/convention-collective/page.tsx @@ -0,0 +1,48 @@ +import { DsfrLayout } from "../../src/modules/layout"; +import { + Agreements, + AgreementsPerLetter, +} from "../../src/modules/convention-collective/Agreements"; +import { fetchAllAgreements } from "../../src/modules/convention-collective"; +import { generateDefaultMetadata } from "../../src/modules/common/metas"; + +export const metadata = generateDefaultMetadata({ + title: "Votre convention collective", + description: + "Retrouvez les questions/réponses fréquentes organisées par thème pour votre convention collective", + path: "/convention-collective", +}); + +const removeAccents = (text: string) => + text.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); + +async function AgreementPage() { + const agreements = await fetchAllAgreements( + ["slug", "shortTitle"], + "shortTitle" + ); + const firstLettersAgreements = agreements.reduce( + (agreementPerletter, agreement) => { + const { shortTitle } = agreement; + const firstLetter = removeAccents(shortTitle[0]); + if (!agreementPerletter[firstLetter]) { + return { + ...agreementPerletter, + [firstLetter]: [agreement], + }; + } + return { + ...agreementPerletter, + [firstLetter]: [...agreementPerletter[firstLetter], agreement], + }; + }, + {} + ); + return ( + + + + ); +} + +export default AgreementPage; diff --git a/packages/code-du-travail-frontend/cypress/integration/light/conventions-collectives.spec.ts b/packages/code-du-travail-frontend/cypress/integration/light/conventions-collectives.spec.ts index 2bce232c15..7143e6499e 100644 --- a/packages/code-du-travail-frontend/cypress/integration/light/conventions-collectives.spec.ts +++ b/packages/code-du-travail-frontend/cypress/integration/light/conventions-collectives.spec.ts @@ -4,17 +4,21 @@ describe("Conventions collectives", () => { cy.get("#navigation").contains("Votre convention collective").click(); cy.url().should("include", "/convention-collective"); - cy.get("h1").should("have.text", "Votre convention collective"); + cy.findByRole("heading", { level: 1 }).should( + "have.text", + "Votre convention collective" + ); cy.get("body").should( "contain", "Retrouvez les questions/réponses fréquentes organisées par thème" ); - cy.get("#content li").should("have.length", 49); - cy.get("#content li").first().click(); + cy.get("#content a").should("have.length", 49); + cy.get("#content a").first().click(); cy.url().should( "include", "/convention-collective/2941-aide-accompagnement-soins-et-services-a-domicile-bad" ); + cy.get('[data-accordion-component="Accordion"]') .eq(0) .find('[data-accordion-component="AccordionItemButton"]') diff --git a/packages/code-du-travail-frontend/cypress/integration/light/validate-html.spec.ts b/packages/code-du-travail-frontend/cypress/integration/light/validate-html.spec.ts index 52eed505c3..2865ec2500 100644 --- a/packages/code-du-travail-frontend/cypress/integration/light/validate-html.spec.ts +++ b/packages/code-du-travail-frontend/cypress/integration/light/validate-html.spec.ts @@ -3,7 +3,6 @@ import { localConfig } from "../html-validation/validate-html.spec"; describe("Validation de l'html d'un échantillon de pages", () => { [ - "/convention-collective", "/convention-collective/3248-metallurgie", "/contribution", "/contribution/les-conges-pour-evenements-familiaux", diff --git a/packages/code-du-travail-frontend/pages/convention-collective/index.tsx b/packages/code-du-travail-frontend/pages/convention-collective/index.tsx deleted file mode 100644 index be1b6cd1cb..0000000000 --- a/packages/code-du-travail-frontend/pages/convention-collective/index.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { - Button, - Container, - FlatList, - PageTitle, - Section, - theme, - Toast, -} from "@socialgouv/cdtn-ui"; -import React from "react"; - -import Metas from "../../src/common/Metas"; -import { Layout } from "../../src/layout/Layout"; -import { ListLink } from "../../src/search/SearchResults/Results"; -import styled from "styled-components"; -import Link from "next/link"; -import { SOURCES } from "@socialgouv/cdtn-utils"; -import { REVALIDATE_TIME } from "../../src/config"; -import { getAllAgreements } from "../../src/api"; - -function Page({ ccs }) { - return ( - - - -
- - - Votre convention collective - - -

- La convention collective est un texte qui adapte les règles du - Code du travail sur des points précis (primes, congés, salaires - minima, préavis, prévoyance…) pour un secteur d’activité. - L’activité économique principale exercée par l’employeur détermine - la convention collective applicable. Elle est négociée et conclue - d’une part par les organisations syndicales représentatives des - salariés et d’autre part par les employeurs, éventuellement réunis - en organisations syndicales ou associations. -

-
-

- Vous ne connaissez pas votre convention collective ?{" "} - - - -

- - - {ccs.map((item) => ( - - - - ))} - -
-
-
- ); -} - -export default Page; - -export async function getStaticProps() { - try { - let data = await getAllAgreements(); - return { props: { ccs: data }, revalidate: REVALIDATE_TIME }; - } catch (error) { - console.error(error); - return { props: { ccs: [] }, revalidate: REVALIDATE_TIME }; - } -} - -const ListItem = styled.li` - margin-top: ${theme.spacings.medium}; -`; diff --git a/packages/code-du-travail-frontend/src/modules/convention-collective/AgreementSearch.svg b/packages/code-du-travail-frontend/src/modules/convention-collective/AgreementSearch.svg new file mode 100644 index 0000000000..fcf2d69ee1 --- /dev/null +++ b/packages/code-du-travail-frontend/src/modules/convention-collective/AgreementSearch.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/packages/code-du-travail-frontend/src/modules/convention-collective/Agreements.tsx b/packages/code-du-travail-frontend/src/modules/convention-collective/Agreements.tsx new file mode 100644 index 0000000000..1dfb08f578 --- /dev/null +++ b/packages/code-du-travail-frontend/src/modules/convention-collective/Agreements.tsx @@ -0,0 +1,44 @@ +import { fr } from "@codegouvfr/react-dsfr"; +import { ContainerSimulator } from "../layout/ContainerSimulator"; +import { ElasticAgreement } from "@socialgouv/cdtn-types"; +import { AgreementsSection } from "./AgreementsSection"; +import { AgreementsGlossaire } from "./AgreementsGlossaire"; +import { AgreementsIntro } from "./AgreementsIntro"; + +type Agreement = Pick; + +export type AgreementsPerLetter = { + [letter: string]: Agreement[]; +}; + +type Props = { + firstLettersAgreements: AgreementsPerLetter; +}; + +export const Agreements = ({ firstLettersAgreements }: Props) => { + return ( + +

+ Votre convention collective +

+ +
+ +
+
+ {Object.entries(firstLettersAgreements).map(([letter, agreements]) => ( + + ))} +
+
+ ); +}; diff --git a/packages/code-du-travail-frontend/src/modules/convention-collective/AgreementsGlossaire.tsx b/packages/code-du-travail-frontend/src/modules/convention-collective/AgreementsGlossaire.tsx new file mode 100644 index 0000000000..9cdf975416 --- /dev/null +++ b/packages/code-du-travail-frontend/src/modules/convention-collective/AgreementsGlossaire.tsx @@ -0,0 +1,49 @@ +import { fr } from "@codegouvfr/react-dsfr"; +import Link from "next/link"; +import { css } from "../../../styled-system/css"; + +type Props = { + letters: string[]; +}; + +export const AgreementsGlossaire = ({ letters }: Props) => { + return ( + <> +

Les conventions collectives traitées

+

+ Les conventions collectives présentées sont les plus représentatives en + termes de nombre de salariés. +

+
+
    + {letters.map((letter, index) => ( + <> +
  • + + {letter} + +
  • + + ))} +
+
+ + ); +}; + +const ul = css({ + listStyle: "none!", + display: "flex", + flexDirection: "row", +}); + +const li = css({ + _before: { + content: `"- "`, + fontSize: "28px", + fontWeight: "bold", + }, +}); diff --git a/packages/code-du-travail-frontend/src/modules/convention-collective/AgreementsIntro.tsx b/packages/code-du-travail-frontend/src/modules/convention-collective/AgreementsIntro.tsx new file mode 100644 index 0000000000..6b9b7ad3dc --- /dev/null +++ b/packages/code-du-travail-frontend/src/modules/convention-collective/AgreementsIntro.tsx @@ -0,0 +1,84 @@ +import { fr } from "@codegouvfr/react-dsfr"; +import Link from "next/link"; +import { css } from "../../../styled-system/css"; +import Image from "next/image"; +import { Highlight } from "@codegouvfr/react-dsfr/Highlight"; +import AgreementSearch from "./AgreementSearch.svg"; + +export const AgreementsIntro = () => { + return ( + <> +
+
+ Trouver sa convention collective +

+ Trouver sa convention collective +

+
+ + + La convention collective est un texte conclu au niveau d'une + branche d'activité (Ex : Transports routiers). Elle adapte + les règles du Code du travail sur des points précis, en fonction des + situations particulières de la branche (primes, congés, salaires + minima, préavis, prévoyance...) + +
+
+ + Vous pouvez retrouver le nom de votre convention collective sur + votre bulletin de paie ou sur votre contrat de travail. + +
+
+ + Je connais ma convention collective je la saisis + + + Je cherche mon entreprise pour trouver ma convention collective + +
+
+ + ); +}; + +const block = css({ + background: "var(--background-alt-blue-cumulus)", +}); + +const ImageContainer = css({ + height: "52px", +}); diff --git a/packages/code-du-travail-frontend/src/modules/convention-collective/AgreementsSection.tsx b/packages/code-du-travail-frontend/src/modules/convention-collective/AgreementsSection.tsx new file mode 100644 index 0000000000..ffcd2e90e3 --- /dev/null +++ b/packages/code-du-travail-frontend/src/modules/convention-collective/AgreementsSection.tsx @@ -0,0 +1,30 @@ +import { fr } from "@codegouvfr/react-dsfr"; +import { getRouteBySource, SOURCES } from "@socialgouv/cdtn-utils"; +import { ListWithArrow } from "../common/ListWithArrow"; +import Link from "next/link"; +import { ElasticAgreement } from "@socialgouv/cdtn-types"; + +type Agreement = Pick; +type Props = { + letter: string; + agreements: Agreement[]; +}; + +export const AgreementsSection = ({ letter, agreements }: Props) => { + return ( + <> +
+ {letter} +
+ { + return ( + + {shortTitle} + + ); + })} + /> + + ); +}; diff --git a/packages/code-du-travail-frontend/src/modules/convention-collective/index.ts b/packages/code-du-travail-frontend/src/modules/convention-collective/index.ts index b69c251208..7b93cd8ada 100644 --- a/packages/code-du-travail-frontend/src/modules/convention-collective/index.ts +++ b/packages/code-du-travail-frontend/src/modules/convention-collective/index.ts @@ -1 +1,2 @@ export * from "./queries"; +export * from "./Agreements"; diff --git a/packages/code-du-travail-frontend/src/modules/layout/ContainerSimulator.tsx b/packages/code-du-travail-frontend/src/modules/layout/ContainerSimulator.tsx new file mode 100644 index 0000000000..f573816769 --- /dev/null +++ b/packages/code-du-travail-frontend/src/modules/layout/ContainerSimulator.tsx @@ -0,0 +1,50 @@ +import { fr } from "@codegouvfr/react-dsfr"; +import { Breadcrumb, BreadcrumbProps } from "@codegouvfr/react-dsfr/Breadcrumb"; + +import { RelatedItems } from "../common/RelatedItems"; +import { Share } from "../common/Share"; +import { RelatedItem } from "../documents"; +import { Feedback } from "../layout/feedback"; + +type Props = { + relatedItems: { items: RelatedItem[]; title: string }[]; + title: string; + description: string; + children: React.ReactNode; +} & Pick; + +export const ContainerSimulator = ({ + children, + relatedItems, + title, + description, + segments = [], +}: Props) => { + return ( +
+ +
{children}
+
+ +
+ +
+ {relatedItems.length > 0 && ( +
+ +
+ )} +
+ +
+
+
+ ); +};