From 969c330a99e7f027775578ffbbc6e17cdd58fa92 Mon Sep 17 00:00:00 2001 From: Victor Zeinstra Date: Thu, 3 Aug 2023 17:22:02 +0200 Subject: [PATCH] =?UTF-8?q?feat:=205271=20indemnit=C3=A9=20de=20licencieme?= =?UTF-8?q?nt=20cr=C3=A9er=20un=20questionnaire=20sp=C3=A9cifique=20(#5287?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martial Maillot Co-authored-by: Victor Zeinstra Co-authored-by: Maxime Golfier <25312957+maxgfr@users.noreply.github.com> --- .../pages/outils/[slug].tsx | 12 +- .../outils/IndemniteLicenciement/index.tsx | 76 +++++----- .../outils/common/Feedback/Questionnaire.tsx | 60 ++++++++ .../common/Feedback/QuestionnaireAdvanced.tsx | 115 +++++++++++++++ .../common/Feedback/QuestionnaireEnd.tsx | 24 ++++ .../common/Feedback/QuestionnaireItem.tsx | 110 ++++++++++++++ .../common/Feedback/QuestionnaireText.tsx | 47 ++++++ .../Feedback/__tests__/feedback.test.tsx | 134 ++++++++++++++++++ .../outils/common/Feedback/__tests__/ui.ts | 53 +++++++ .../src/outils/common/Feedback/index.tsx | 99 +++++++++++++ .../outils/common/Feedback/introduction.tsx | 26 ++++ .../src/outils/common/Feedback/tracking.ts | 36 +++++ packages/react-ui/src/Button/index.js | 24 +++- .../react-ui/src/Titles/Heading/index.tsx | 2 + .../src/icons/components/monochrome/Bad.js | 46 ++++++ .../src/icons/components/monochrome/Good.js | 47 ++++++ .../src/icons/components/monochrome/Medium.js | 47 ++++++ .../src/icons/components/monochrome/index.js | 3 + packages/react-ui/src/icons/index.js | 3 + .../react-ui/src/icons/src/monochrome/bad.svg | 13 ++ .../src/icons/src/monochrome/good.svg | 12 ++ .../src/icons/src/monochrome/medium.svg | 12 ++ 22 files changed, 959 insertions(+), 42 deletions(-) create mode 100644 packages/code-du-travail-frontend/src/outils/common/Feedback/Questionnaire.tsx create mode 100644 packages/code-du-travail-frontend/src/outils/common/Feedback/QuestionnaireAdvanced.tsx create mode 100644 packages/code-du-travail-frontend/src/outils/common/Feedback/QuestionnaireEnd.tsx create mode 100644 packages/code-du-travail-frontend/src/outils/common/Feedback/QuestionnaireItem.tsx create mode 100644 packages/code-du-travail-frontend/src/outils/common/Feedback/QuestionnaireText.tsx create mode 100644 packages/code-du-travail-frontend/src/outils/common/Feedback/__tests__/feedback.test.tsx create mode 100644 packages/code-du-travail-frontend/src/outils/common/Feedback/__tests__/ui.ts create mode 100644 packages/code-du-travail-frontend/src/outils/common/Feedback/index.tsx create mode 100644 packages/code-du-travail-frontend/src/outils/common/Feedback/introduction.tsx create mode 100644 packages/code-du-travail-frontend/src/outils/common/Feedback/tracking.ts create mode 100644 packages/react-ui/src/icons/components/monochrome/Bad.js create mode 100644 packages/react-ui/src/icons/components/monochrome/Good.js create mode 100644 packages/react-ui/src/icons/components/monochrome/Medium.js create mode 100644 packages/react-ui/src/icons/src/monochrome/bad.svg create mode 100644 packages/react-ui/src/icons/src/monochrome/good.svg create mode 100644 packages/react-ui/src/icons/src/monochrome/medium.svg diff --git a/packages/code-du-travail-frontend/pages/outils/[slug].tsx b/packages/code-du-travail-frontend/pages/outils/[slug].tsx index 3a2ee4a47e..7f54ab37b1 100644 --- a/packages/code-du-travail-frontend/pages/outils/[slug].tsx +++ b/packages/code-du-travail-frontend/pages/outils/[slug].tsx @@ -70,18 +70,20 @@ function Outils({
+ + + - - - - + {router.asPath !== "/outils/indemnite-licenciement" && ( + + )}
@@ -149,5 +151,5 @@ export const ShareContainer = styled.div` export const Flex = styled.div` display: flex; - flex-direction: column-reverse; + flex-direction: column; `; diff --git a/packages/code-du-travail-frontend/src/outils/IndemniteLicenciement/index.tsx b/packages/code-du-travail-frontend/src/outils/IndemniteLicenciement/index.tsx index d38bb96d7d..c8848c761c 100644 --- a/packages/code-du-travail-frontend/src/outils/IndemniteLicenciement/index.tsx +++ b/packages/code-du-travail-frontend/src/outils/IndemniteLicenciement/index.tsx @@ -18,6 +18,7 @@ import { } from "./store"; import { ToolName } from "../types"; import { PublicodesSimulator } from "@socialgouv/modeles-social"; +import { Feedback } from "../common/Feedback"; type Props = { icon: string; @@ -119,42 +120,45 @@ const IndemniteLicenciementSimulator = ({ }; return ( - - simulator={PublicodesSimulator.INDEMNITE_LICENCIEMENT} - title={title} - displayTitle={displayTitle} - icon={icon} - duration="5 à 10 min" - steps={steps} - onStepChange={[ - { - stepName: IndemniteLicenciementStepName.ContratTravail, - isStepValid: isStepContratTravailValid, - onNextStep: onNextStepContratTravail, - }, - { - stepName: IndemniteLicenciementStepName.Agreement, - isStepValid: isStepAgreementValid, - onNextStep: onNextStepAgreement, - }, - { - stepName: IndemniteLicenciementStepName.Anciennete, - isStepValid: isStepAncienneteValid, - onNextStep: onNextStepAnciennete, - }, - { - stepName: IndemniteLicenciementStepName.Salaires, - isStepValid: isStepSalairesValid, - onNextStep: onNextStepSalaires, - }, - { - stepName: IndemniteLicenciementStepName.Informations, - isStepValid: isStepInformationsValid, - onNextStep: onNextStepInformations, - }, - ]} - hiddenStep={getHiddenSteps()} - /> + <> + + simulator={PublicodesSimulator.INDEMNITE_LICENCIEMENT} + title={title} + displayTitle={displayTitle} + icon={icon} + duration="5 à 10 min" + steps={steps} + onStepChange={[ + { + stepName: IndemniteLicenciementStepName.ContratTravail, + isStepValid: isStepContratTravailValid, + onNextStep: onNextStepContratTravail, + }, + { + stepName: IndemniteLicenciementStepName.Agreement, + isStepValid: isStepAgreementValid, + onNextStep: onNextStepAgreement, + }, + { + stepName: IndemniteLicenciementStepName.Anciennete, + isStepValid: isStepAncienneteValid, + onNextStep: onNextStepAnciennete, + }, + { + stepName: IndemniteLicenciementStepName.Salaires, + isStepValid: isStepSalairesValid, + onNextStep: onNextStepSalaires, + }, + { + stepName: IndemniteLicenciementStepName.Informations, + isStepValid: isStepInformationsValid, + onNextStep: onNextStepInformations, + }, + ]} + hiddenStep={getHiddenSteps()} + /> + + ); }; diff --git a/packages/code-du-travail-frontend/src/outils/common/Feedback/Questionnaire.tsx b/packages/code-du-travail-frontend/src/outils/common/Feedback/Questionnaire.tsx new file mode 100644 index 0000000000..edbbc97545 --- /dev/null +++ b/packages/code-du-travail-frontend/src/outils/common/Feedback/Questionnaire.tsx @@ -0,0 +1,60 @@ +import styled from "styled-components"; +import { Button, Heading } from "@socialgouv/cdtn-ui"; + +import { QuestionnaireItem, Status } from "./QuestionnaireItem"; +import { trackFeedback, EVENT_ACTION, FEEDBACK_RESULT } from "./tracking"; +import { useState } from "react"; + +type QuestionnaireProps = { + onClick: () => void; +}; + +export const Questionnaire = ({ onClick }: QuestionnaireProps): JSX.Element => { + const [status, setStatus] = useState(); + const [displayError, setDisplayError] = useState(false); + return ( + <> + + Comment s'est passée cette simulation pour vous ? + + { + setStatus(status); + setDisplayError(false); + }} + displayError={displayError} + /> + { + if (!status) { + setDisplayError(true); + } else { + trackFeedback(EVENT_ACTION.GLOBAL, status); + onClick(); + } + }} + variant="primary" + > + Envoyer + + + ); +}; + +const StyledHeading = styled(Heading)` + margin-left: 0; + margin-bottom: 0; + padding-top: 6px; +`; + +const StyledButton = styled(Button)` + margin: 12px auto 24px 24px; +`; + +const StyledQuestionnaireItem = styled(QuestionnaireItem)` + padding: 24px; +`; diff --git a/packages/code-du-travail-frontend/src/outils/common/Feedback/QuestionnaireAdvanced.tsx b/packages/code-du-travail-frontend/src/outils/common/Feedback/QuestionnaireAdvanced.tsx new file mode 100644 index 0000000000..a1ec4a87b7 --- /dev/null +++ b/packages/code-du-travail-frontend/src/outils/common/Feedback/QuestionnaireAdvanced.tsx @@ -0,0 +1,115 @@ +import { Button, Heading } from "@socialgouv/cdtn-ui"; +import { QuestionnaireItem } from "./QuestionnaireItem"; +import { QuestionnaireText } from "./QuestionnaireText"; +import styled from "styled-components"; +import { useState } from "react"; +import { + trackFeedback, + trackFeedbackText, + FEEDBACK_RESULT, + EVENT_ACTION, +} from "./tracking"; +import { useRouter } from "next/router"; + +type QuestionnaireAdvancedProps = { + onClick: () => void; +}; + +export const QuestionnaireAdvanced = ({ + onClick, +}: QuestionnaireAdvancedProps): React.ReactElement => { + const router = useRouter(); + const [statusSimulator, setStatusSimulator] = useState(); + const [statusQuestion, setStatusQuestion] = useState(); + const [statusExplanation, setStatusExplanation] = useState(); + const [feedbackText, setFeedbackText] = useState(); + return ( + <> + + Merci pour votre aide ! Pouvez-vous nous en dire plus ? + + + { + setStatusSimulator(status); + }} + dataTestId="simulator" + /> + { + setStatusQuestion(status); + }} + dataTestId="questionClarity" + /> + { + setStatusExplanation(status); + }} + dataTestId="resultClarity" + /> + + + { + if (statusSimulator) { + trackFeedback(EVENT_ACTION.EASINESS, statusSimulator); + } + if (statusQuestion) { + trackFeedback(EVENT_ACTION.QUESTION_CLARITY, statusQuestion); + } + if (statusExplanation) { + trackFeedback(EVENT_ACTION.RESULT_CLARITY, statusExplanation); + } + if (feedbackText) { + trackFeedbackText(feedbackText, router.asPath); + } + onClick(); + }} + > + Envoyer + + + ); +}; + +const StyledHeading = styled(Heading)` + margin-left: 0; + margin-bottom: 0; + padding-top: 6px; +`; + +const StyledButton = styled(Button)` + margin: 12px auto 24px 24px; +`; + +const FormContainer = styled.div` + padding: 0 24px; +`; + +const StyledQuestionnaireItem = styled(QuestionnaireItem)` + margin: 24px 0; +`; diff --git a/packages/code-du-travail-frontend/src/outils/common/Feedback/QuestionnaireEnd.tsx b/packages/code-du-travail-frontend/src/outils/common/Feedback/QuestionnaireEnd.tsx new file mode 100644 index 0000000000..9155f6bc8a --- /dev/null +++ b/packages/code-du-travail-frontend/src/outils/common/Feedback/QuestionnaireEnd.tsx @@ -0,0 +1,24 @@ +import { Heading } from "@socialgouv/cdtn-ui"; +import styled from "styled-components"; + +export const QuestionnaireEnd = (): JSX.Element => { + return ( + <> + + Merci pour votre aide ! + + + Votre évaluation sera étudiée au plus vite par nos équipes + + + ); +}; + +const StyledHeading = styled(Heading)` + margin-left: 0; + padding-top: 6px; +`; + +const StyledText = styled.span` + margin: 12px auto 24px 24px; +`; diff --git a/packages/code-du-travail-frontend/src/outils/common/Feedback/QuestionnaireItem.tsx b/packages/code-du-travail-frontend/src/outils/common/Feedback/QuestionnaireItem.tsx new file mode 100644 index 0000000000..f02122f1d7 --- /dev/null +++ b/packages/code-du-travail-frontend/src/outils/common/Feedback/QuestionnaireItem.tsx @@ -0,0 +1,110 @@ +import { Button } from "@socialgouv/cdtn-ui"; +import { icons, theme } from "@socialgouv/cdtn-ui"; +import { useState } from "react"; +import styled from "styled-components"; +import { FEEDBACK_RESULT } from "./tracking"; + +type QuestionnaireItemProps = { + badEventValue: FEEDBACK_RESULT; + averageEventValue: FEEDBACK_RESULT; + goodEventValue: FEEDBACK_RESULT; + badText?: string; + averageText?: string; + goodText?: string; + className?: string; + title?: string; + displayError?: boolean; + onChange: (status: FEEDBACK_RESULT) => void; + dataTestId?: string; +}; + +export enum Status { + BAD = "bad", + AVERAGE = "average", + GOOD = "good", +} + +export const QuestionnaireItem = ({ + badEventValue, + averageEventValue, + goodEventValue, + badText, + averageText, + goodText, + className, + title, + displayError, + onChange, + dataTestId, +}: QuestionnaireItemProps): JSX.Element => { + const [status, setStatus] = useState(); + return ( +
+ {title && {title}} + + { + setStatus(Status.BAD); + onChange(badEventValue); + }} + data-testId={`${dataTestId}-bad`} + > + + {badText ?? "Pas bien"} + + { + setStatus(Status.AVERAGE); + onChange(averageEventValue); + }} + data-testId={`${dataTestId}-average`} + > + + {averageText ?? "Moyen"} + + { + setStatus(Status.GOOD); + onChange(goodEventValue); + }} + data-testId={`${dataTestId}-good`} + > + + {goodText ?? "Très bien"} + + + {displayError && ( + Vous devez choisir une des réponses + )} +
+ ); +}; + +const { colors } = theme; + +const ButtonContainer = styled.div` + display: flex; + flex-direction: row; + padding: 6px 0; + max-width: 300px; + justify-content: space-between; +`; + +const StyledButton = styled(Button)` + display: flex; + flex-direction: column; + width: 80px; + height: 60px; + padding: 0; + border: 1px solid ${colors.secondary}; + border-radius: 3px; + font-size: 12px; + font-weight: bold; +`; + +const StyledError = styled.span` + color: ${colors.error}; +`; diff --git a/packages/code-du-travail-frontend/src/outils/common/Feedback/QuestionnaireText.tsx b/packages/code-du-travail-frontend/src/outils/common/Feedback/QuestionnaireText.tsx new file mode 100644 index 0000000000..b84e037bf7 --- /dev/null +++ b/packages/code-du-travail-frontend/src/outils/common/Feedback/QuestionnaireText.tsx @@ -0,0 +1,47 @@ +import { Textarea } from "@socialgouv/cdtn-ui"; +import styled from "styled-components"; + +type QuestionnaireItemProps = { + className?: string; + title?: string; + placeholder?: string; + onChange: (text: string) => void; + dataTestId?: string; +}; + +export const QuestionnaireText = ({ + className, + title, + placeholder, + onChange, + dataTestId, +}: QuestionnaireItemProps): JSX.Element => { + const maxCharacters = 200; + return ( + + {title && {title}} + onChange(event.target.value)} + data-testid={dataTestId} + /> + {maxCharacters} caractères maximum + + ); +}; + +const StyledContainer = styled.div` + display: flex; + flex-direction: column; +`; + +const StyledTextarea = styled(Textarea)` + width: 420px; + max-width: 100%; +`; + +const MaxCharacterText = styled.span` + margin: 12px 0; + font-size: 14px; +`; diff --git a/packages/code-du-travail-frontend/src/outils/common/Feedback/__tests__/feedback.test.tsx b/packages/code-du-travail-frontend/src/outils/common/Feedback/__tests__/feedback.test.tsx new file mode 100644 index 0000000000..115839e943 --- /dev/null +++ b/packages/code-du-travail-frontend/src/outils/common/Feedback/__tests__/feedback.test.tsx @@ -0,0 +1,134 @@ +import { fireEvent, render, screen } from "@testing-library/react"; +import { Feedback } from ".."; +import { ui } from "./ui"; +import { push as matopush } from "@socialgouv/matomo-next"; + +jest.mock("@socialgouv/matomo-next", () => { + return { + push: jest.fn(), + }; +}); + +describe("Etant donné un composant Feedback", () => { + beforeEach(() => { + render(); + }); + test("Vérification que l'introduction s'affiche", () => { + expect(ui.introduction.title.query()).toBeInTheDocument(); + expect(ui.introduction.button.query()).toBeInTheDocument(); + }); + describe("Lors d'un clique sur le bouton 'Fermer'", () => { + beforeEach(() => { + fireEvent.click(ui.closeButton.get()); + }); + test("Vérification que le composant ne s'affiche plus", () => { + expect(ui.introduction.title.query()).not.toBeInTheDocument(); + expect(ui.introduction.button.query()).not.toBeInTheDocument(); + }); + }); + describe("Lors d'un clique sur le bouton 'Donner mon avis'", () => { + beforeEach(() => { + fireEvent.click(ui.introduction.button.get()); + }); + test("Vérification que le 1er questionnaire s'affiche bien", () => { + expect(ui.questionnaire1.title.query()).toBeInTheDocument(); + expect(ui.questionnaire1.bad.query()).toBeInTheDocument(); + expect(ui.questionnaire1.average.query()).toBeInTheDocument(); + expect(ui.questionnaire1.good.query()).toBeInTheDocument(); + expect(ui.sendButton.query()).toBeInTheDocument(); + }); + describe("Lors d'un clic directement sur le bouton 'Envoyer'", () => { + beforeEach(() => { + fireEvent.click(ui.sendButton.get()); + }); + test("Vérification que le message d'erreur s'affiche bien", () => { + expect(ui.questionnaire1.requiredError.query()).toBeInTheDocument(); + }); + }); + describe("Lors d'une sélection et clique sur le bouton 'Envoyer'", () => { + beforeEach(() => { + fireEvent.click(ui.questionnaire1.average.get()); + fireEvent.click(ui.sendButton.get()); + }); + test("Vérification du tracking et que le 2e questionnaire s'affiche", () => { + expect(matopush).toHaveBeenCalledWith([ + "trackEvent", + "feedback_simulateurs", + "Comment_s_est_passée_la_simulation", + "moyen", + ]); + + expect(ui.questionnaire2.simulator.title.query()).toBeInTheDocument(); + expect(ui.questionnaire2.simulator.bad.query()).toBeInTheDocument(); + expect(ui.questionnaire2.simulator.average.query()).toBeInTheDocument(); + expect(ui.questionnaire2.simulator.good.query()).toBeInTheDocument(); + + expect( + ui.questionnaire2.questionClarity.title.query() + ).toBeInTheDocument(); + expect( + ui.questionnaire2.questionClarity.bad.query() + ).toBeInTheDocument(); + expect( + ui.questionnaire2.questionClarity.average.query() + ).toBeInTheDocument(); + expect( + ui.questionnaire2.questionClarity.good.query() + ).toBeInTheDocument(); + + expect( + ui.questionnaire2.resultClarity.title.query() + ).toBeInTheDocument(); + expect(ui.questionnaire2.resultClarity.bad.query()).toBeInTheDocument(); + expect( + ui.questionnaire2.resultClarity.average.query() + ).toBeInTheDocument(); + expect( + ui.questionnaire2.resultClarity.good.query() + ).toBeInTheDocument(); + + expect(ui.questionnaire2.more.title.query()).toBeInTheDocument(); + expect(ui.questionnaire2.more.input.query()).toBeInTheDocument(); + }); + describe("Lors d'une sélection et clique sur le bouton 'Envoyer'", () => { + beforeEach(() => { + fireEvent.click(ui.questionnaire2.simulator.bad.get()); + fireEvent.click(ui.questionnaire2.questionClarity.average.get()); + fireEvent.click(ui.questionnaire2.resultClarity.good.get()); + fireEvent.change(ui.questionnaire2.more.input.get(), { + target: { value: "test" }, + }); + fireEvent.click(ui.sendButton.get()); + }); + test("Vérification du tracking et que la fin du questionnaire s'affiche", () => { + expect(matopush).toHaveBeenCalledWith([ + "trackEvent", + "feedback_simulateurs", + "Facilité_utilisation_simulateur", + "pas_du_tout", + ]); + expect(matopush).toHaveBeenCalledWith([ + "trackEvent", + "feedback_simulateurs", + "Clarté_questions", + "moyen", + ]); + expect(matopush).toHaveBeenCalledWith([ + "trackEvent", + "feedback_simulateurs", + "Clarté_résultat", + "oui", + ]); + expect(matopush).toHaveBeenCalledWith([ + "trackEvent", + "feedback_suggestion", + "test", + "mock", + ]); + expect(ui.questionnaireEnd.title.query()).toBeInTheDocument(); + expect(ui.questionnaireEnd.description.query()).toBeInTheDocument(); + }); + }); + }); + }); +}); diff --git a/packages/code-du-travail-frontend/src/outils/common/Feedback/__tests__/ui.ts b/packages/code-du-travail-frontend/src/outils/common/Feedback/__tests__/ui.ts new file mode 100644 index 0000000000..3ca0dd5542 --- /dev/null +++ b/packages/code-du-travail-frontend/src/outils/common/Feedback/__tests__/ui.ts @@ -0,0 +1,53 @@ +import { byTestId, byText } from "testing-library-selector"; + +export const ui = { + closeButton: byTestId("feedbackCloseButton"), + sendButton: byText("Envoyer"), + introduction: { + title: byText("Votre avis sur ce simulateur nous intéresse"), + button: byText("Donner mon avis"), + }, + questionnaire1: { + title: byText(/Comment s'est passée cette simulation pour vous \?/), + bad: byText("Pas bien"), + average: byText("Moyen"), + good: byText("Très bien"), + requiredError: byText("Vous devez choisir une des réponses"), + }, + questionnaire2: { + title: byText(/Merci pour votre aide ! Pouvez-vous nous en dire plus \?/), + simulator: { + title: byText(/Le simulateur était-il facile à utiliser \?/), + bad: byTestId("simulator-bad"), + average: byTestId("simulator-average"), + good: byTestId("simulator-good"), + }, + questionClarity: { + title: byText( + /Les questions étaient-elles claires et compréhensibles \?/ + ), + bad: byTestId("questionClarity-bad"), + average: byTestId("questionClarity-average"), + good: byTestId("questionClarity-good"), + }, + resultClarity: { + title: byText( + /Les explications du résultat obtenu étaient-elles claires et compréhensibles \?/ + ), + bad: byTestId("resultClarity-bad"), + average: byTestId("resultClarity-average"), + good: byTestId("resultClarity-good"), + }, + more: { + title: byText(/Vous souhaitez nous en dire davantage \?/), + input: byTestId("more-input"), + }, + requiredError: byText("Vous devez choisir une des réponses"), + }, + questionnaireEnd: { + title: byText(/Merci pour votre aide !/), + description: byText( + /Votre évaluation sera étudiée au plus vite par nos équipes/ + ), + }, +}; diff --git a/packages/code-du-travail-frontend/src/outils/common/Feedback/index.tsx b/packages/code-du-travail-frontend/src/outils/common/Feedback/index.tsx new file mode 100644 index 0000000000..41757ce632 --- /dev/null +++ b/packages/code-du-travail-frontend/src/outils/common/Feedback/index.tsx @@ -0,0 +1,99 @@ +import styled from "styled-components"; +import { theme, icons, Wrapper } from "@socialgouv/cdtn-ui"; +import { Introduction } from "./introduction"; +import { useState } from "react"; +import { Questionnaire } from "./Questionnaire"; +import { QuestionnaireAdvanced } from "./QuestionnaireAdvanced"; +import { QuestionnaireEnd } from "./QuestionnaireEnd"; + +export const Feedback = (): JSX.Element => { + const [status, setStatus] = useState< + "questionnaire" | "questionnaireAdvanced" | "questionnaireEnd" + >(); + const [closed, setClosed] = useState(false); + const [position, setPosition] = useState(0); + const [bodyPosition, setBodyPosition] = useState(0); + return !closed ? ( + <> + {!status && ( + { + setStatus("questionnaire"); + }} + variant="main" + > + setClosed(true)} + data-testid="feedbackCloseButton" + /> + { + setStatus("questionnaire"); + }} + /> + + )} + {status && ( + { + if (!el) return; + + setPosition(el.getBoundingClientRect().top); + setBodyPosition(document.body.getBoundingClientRect().top); + }} + > + setClosed(true)} + data-testid="feedbackCloseButton" + /> + {status === "questionnaire" && ( + { + setStatus("questionnaireAdvanced"); + }} + /> + )} + {status === "questionnaireAdvanced" && ( + { + setStatus("questionnaireEnd"); + window.scrollTo(0, position - bodyPosition - 220); + }} + /> + )} + {status === "questionnaireEnd" && } + + )} + + ) : ( + <> + ); +}; + +const { colors } = theme; + +const IntroContainer = styled(Wrapper)` + border: 1px solid ${colors.secondary}; + border-radius: 6px; + width: 460px; + max-width: 100%; + display: flex; + flex-direction: column; + margin: 42px 0 0 auto; + padding: 0 0 28px 0 !important; + position: relative; +`; + +const StyledContainer = styled(IntroContainer)` + width: 520px; +`; + +const StyledCloseIcon = styled(icons.Close)` + position: absolute; + top: 8px; + right: 8px; + width: 24px; + cursor: pointer; + margin: 3px; +`; diff --git a/packages/code-du-travail-frontend/src/outils/common/Feedback/introduction.tsx b/packages/code-du-travail-frontend/src/outils/common/Feedback/introduction.tsx new file mode 100644 index 0000000000..ab2e441e68 --- /dev/null +++ b/packages/code-du-travail-frontend/src/outils/common/Feedback/introduction.tsx @@ -0,0 +1,26 @@ +import styled from "styled-components"; +import { Button, Heading } from "@socialgouv/cdtn-ui"; + +type IntroductionProps = { + onClick: () => void; +}; + +export const Introduction = ({ onClick }: IntroductionProps): JSX.Element => { + return ( + <> + + Votre avis sur ce simulateur nous intéresse + + Donner mon avis + + ); +}; + +const StyledHeading = styled(Heading)` + text-align: center; + margin-top: 16px; +`; + +const StyledButton = styled(Button)` + margin: 0 auto; +`; diff --git a/packages/code-du-travail-frontend/src/outils/common/Feedback/tracking.ts b/packages/code-du-travail-frontend/src/outils/common/Feedback/tracking.ts new file mode 100644 index 0000000000..896077e56b --- /dev/null +++ b/packages/code-du-travail-frontend/src/outils/common/Feedback/tracking.ts @@ -0,0 +1,36 @@ +import { MatomoBaseEvent } from "../../../lib/matomo"; +import { push as matopush } from "@socialgouv/matomo-next"; + +const EVENT_CATEGORY = "feedback_simulateurs"; +export enum EVENT_ACTION { + GLOBAL = "Comment_s_est_passée_la_simulation", + EASINESS = "Facilité_utilisation_simulateur", + QUESTION_CLARITY = "Clarté_questions", + RESULT_CLARITY = "Clarté_résultat", + SUGGESTION = "Suggestion", +} + +export enum FEEDBACK_RESULT { + NOT_GOOD = "pas_bien", + NOT_AT_ALL = "pas_du_tout", + AVERAGE = "moyen", + GOOD = "très_bien", + EASY = "facile", + YES = "oui", +} + +export const trackFeedback = ( + event: EVENT_ACTION, + feedback: FEEDBACK_RESULT +) => { + matopush([MatomoBaseEvent.TRACK_EVENT, EVENT_CATEGORY, event, feedback]); +}; + +export const trackFeedbackText = (text: string, url: string) => { + matopush([ + "trackEvent", + "feedback_suggestion", + text, + url.replace(/\?.*$/, ""), + ]); +}; diff --git a/packages/react-ui/src/Button/index.js b/packages/react-ui/src/Button/index.js index ff049218b0..6680b7ebe8 100644 --- a/packages/react-ui/src/Button/index.js +++ b/packages/react-ui/src/Button/index.js @@ -84,6 +84,27 @@ export const StyledButton = styled.button` } `; } + if (variant === "light") { + return css` + padding: 0; + color: ${theme.paragraph}; + font-weight: normal; + font-size: ${fonts.sizes.default}; + line-height: ${fonts.lineHeight}; + vertical-align: baseline; + text-decoration: none; + text-align: left; + background-color: rgba( + ${theme.secondary}, + 0.26 + )}; + border: none; + border-radius: 0; + overflow: visible; + transition: color ${animations.transitionTiming} linear, + text-decoration ${animations.transitionTiming} linear; + `; + } let height = "5.2rem"; let backgroundColor = theme[variant]; @@ -128,7 +149,7 @@ export const StyledButton = styled.button` opacity = "0.6"; } - if (variant === "primary") { + if (variant === "primary" || variant === "light") { boxShadow = `${largeShadow} ${rgba( theme.primary, 0.26 @@ -212,6 +233,7 @@ Button.propTypes = { "naked", "primary", "secondary", + "light", ]), }; diff --git a/packages/react-ui/src/Titles/Heading/index.tsx b/packages/react-ui/src/Titles/Heading/index.tsx index dc8eebfc94..bac1a7d924 100644 --- a/packages/react-ui/src/Titles/Heading/index.tsx +++ b/packages/react-ui/src/Titles/Heading/index.tsx @@ -16,6 +16,7 @@ type Props = { ariaLevel?: number | string; id?: string; dataTestid?: string; + className?: string; }; export const Heading = (props: Props) => ( @@ -29,6 +30,7 @@ export const Heading = (props: Props) => ( aria-level={props.ariaLevel} id={props.id} data-testid={props.dataTestid ?? "heading"} + className={props.className} > {props.stripe !== "none" && ( ( + + Avis/Éléments/Mauvais/Emoji/Défaut + + + + + + + + + +); + +const Memo = memo(SvgArrowTurn); +export default Memo; diff --git a/packages/react-ui/src/icons/components/monochrome/Good.js b/packages/react-ui/src/icons/components/monochrome/Good.js new file mode 100644 index 0000000000..faf8c88329 --- /dev/null +++ b/packages/react-ui/src/icons/components/monochrome/Good.js @@ -0,0 +1,47 @@ +import * as React from "react"; +import { memo } from "react"; + +const SvgArrowTurn = (props) => ( + + Avis/Éléments/Bon/Emoji/Défaut + + + + + + + + + +); + +const Memo = memo(SvgArrowTurn); +export default Memo; diff --git a/packages/react-ui/src/icons/components/monochrome/Medium.js b/packages/react-ui/src/icons/components/monochrome/Medium.js new file mode 100644 index 0000000000..ff9eddecf0 --- /dev/null +++ b/packages/react-ui/src/icons/components/monochrome/Medium.js @@ -0,0 +1,47 @@ +import * as React from "react"; +import { memo } from "react"; + +const SvgArrowTurn = (props) => ( + + Avis/Éléments/Moyen/Emoji/Défaut + + + + + + + + + +); + +const Memo = memo(SvgArrowTurn); +export default Memo; diff --git a/packages/react-ui/src/icons/components/monochrome/index.js b/packages/react-ui/src/icons/components/monochrome/index.js index cd9b75b35f..93a9d24933 100644 --- a/packages/react-ui/src/icons/components/monochrome/index.js +++ b/packages/react-ui/src/icons/components/monochrome/index.js @@ -1,6 +1,7 @@ export { default as ArrowDown } from "./ArrowDown"; export { default as ArrowRight } from "./ArrowRight"; export { default as ArrowTurn } from "./ArrowTurn"; +export { default as Bad } from "./Bad"; export { default as Burger } from "./Burger"; export { default as Calendar } from "./Calendar"; export { default as Check } from "./Check"; @@ -11,10 +12,12 @@ export { default as DirectionRight } from "./DirectionRight"; export { default as Download } from "./Download"; export { default as Euro } from "./Euro"; export { default as External } from "./External"; +export { default as Good } from "./Good"; export { default as Help } from "./Help"; export { default as Home } from "./Home"; export { default as Link } from "./Link"; export { default as Mail } from "./Mail"; +export { default as Medium } from "./Medium"; export { default as More } from "./More"; export { default as Search } from "./Search"; export { default as Shade } from "./Shade"; diff --git a/packages/react-ui/src/icons/index.js b/packages/react-ui/src/icons/index.js index e83a1cbb67..d703e170d7 100644 --- a/packages/react-ui/src/icons/index.js +++ b/packages/react-ui/src/icons/index.js @@ -49,6 +49,7 @@ export { default as Youth } from "./components/bicolor/Youth.js"; export { default as ArrowDown } from "./components/monochrome/ArrowDown"; export { default as ArrowRight } from "./components/monochrome/ArrowRight"; export { default as ArrowTurn } from "./components/monochrome/ArrowTurn"; +export { default as Bad } from "./components/monochrome/Bad"; export { default as Burger } from "./components/monochrome/Burger"; export { default as Calendar } from "./components/monochrome/Calendar"; export { default as External } from "./components/monochrome/Calendar"; @@ -59,10 +60,12 @@ export { default as DirectionLeft } from "./components/monochrome/DirectionLeft" export { default as DirectionRight } from "./components/monochrome/DirectionRight"; export { default as Download } from "./components/monochrome/Download"; export { default as Euro } from "./components/monochrome/Euro"; +export { default as Good } from "./components/monochrome/Good"; export { default as Help } from "./components/monochrome/Help"; export { default as Home } from "./components/monochrome/Home"; export { default as Link } from "./components/monochrome/Link"; export { default as Mail } from "./components/monochrome/Mail"; +export { default as Medium } from "./components/monochrome/Medium"; export { default as More } from "./components/monochrome/More"; export { default as Search } from "./components/monochrome/Search"; export { default as Shade } from "./components/monochrome/Shade"; diff --git a/packages/react-ui/src/icons/src/monochrome/bad.svg b/packages/react-ui/src/icons/src/monochrome/bad.svg new file mode 100644 index 0000000000..976f92cf24 --- /dev/null +++ b/packages/react-ui/src/icons/src/monochrome/bad.svg @@ -0,0 +1,13 @@ + + + + Avis/Éléments/Mauvais/Emoji/Défaut + + + + + + + + + diff --git a/packages/react-ui/src/icons/src/monochrome/good.svg b/packages/react-ui/src/icons/src/monochrome/good.svg new file mode 100644 index 0000000000..fd6425218c --- /dev/null +++ b/packages/react-ui/src/icons/src/monochrome/good.svg @@ -0,0 +1,12 @@ + + + Avis/Éléments/Bon/Emoji/Défaut + + + + + + + + + diff --git a/packages/react-ui/src/icons/src/monochrome/medium.svg b/packages/react-ui/src/icons/src/monochrome/medium.svg new file mode 100644 index 0000000000..12761dee33 --- /dev/null +++ b/packages/react-ui/src/icons/src/monochrome/medium.svg @@ -0,0 +1,12 @@ + + + Avis/Éléments/Moyen/Emoji/Défaut + + + + + + + + +