Skip to content

Commit

Permalink
feat: questionnaire
Browse files Browse the repository at this point in the history
  • Loading branch information
Victor Zeinstra committed Jul 25, 2023
1 parent 0fbd052 commit 07a15b7
Show file tree
Hide file tree
Showing 10 changed files with 197 additions and 47 deletions.
25 changes: 17 additions & 8 deletions packages/code-du-travail-frontend/src/Feedback/Questionnaire.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,39 @@
import styled from "styled-components";
import { Button, Heading } from "@socialgouv/cdtn-ui";

import { QuestionnaireItem } from "./QuestionnaireItem";
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 [dirty, setDirty] = useState(false);
const [status, setStatus] = useState<FEEDBACK_RESULT>();
const [displayError, setDisplayError] = useState(false);
return (
<>
<Heading variant="primary" stripe="left">
<StyledHeading variant="primary" stripe="left">
Comment s&apos;est passée cette simulation pour vous ?
</Heading>
</StyledHeading>
<StyledQuestionnaireItem
badEventValue={FEEDBACK_RESULT.NOT_GOOD}
averageEventValue={FEEDBACK_RESULT.AVERAGE}
goodEventValue={FEEDBACK_RESULT.GOOD}
badText="Pas bien"
isDirty={(isDirty) => {
setDirty(isDirty);
setDisplayError(!isDirty);
onChange={(status: FEEDBACK_RESULT) => {
setDisplayError(false);
setStatus(status);
}}
displayError={displayError}
/>
<StyledButton
onClick={() => {
if (!dirty) {
if (!status) {
setDisplayError(true);
} else {
trackFeedback(EVENT_ACTION.GLOBAL, status);
onClick();
}
}}
Expand All @@ -40,6 +45,10 @@ export const Questionnaire = ({ onClick }: QuestionnaireProps): JSX.Element => {
);
};

const StyledHeading = styled(Heading)`
margin-left: 0 !important;
`;

const StyledButton = styled(Button)`
margin: 12px auto 24px 24px;
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ 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";

type QuestionnaireAdvancedProps = {
onClick: () => void;
Expand All @@ -11,63 +17,80 @@ type QuestionnaireAdvancedProps = {
export const QuestionnaireAdvanced = ({
onClick,
}: QuestionnaireAdvancedProps): JSX.Element => {
const [dirtySimulator, setDirtySimulator] = useState(false);
const [statusSimulator, setStatusSimulator] = useState<FEEDBACK_RESULT>();
const [displayErrorSimulator, setDisplayErrorSimulator] = useState(false);
const [dirtyQuestion, setDirtyQuestion] = useState(false);
const [statusQuestion, setStatusQuestion] = useState<FEEDBACK_RESULT>();
const [displayErrorQuestion, setDisplayErrorQuestion] = useState(false);
const [dirtyExplanation, setDirtyExplanation] = useState(false);
const [statusExplanation, setStatusExplanation] = useState<FEEDBACK_RESULT>();
const [displayErrorExplanation, setDisplayErrorExplanation] = useState(false);
const [feedbackText, setFeedbackText] = useState<string>();
return (
<>
<Heading variant="primary" stripe="left">
<StyledHeading variant="primary" stripe="left">
Merci pour votre aide ! Pouvez-vous nous en dire plus ?
</Heading>
</StyledHeading>
<FormContainer>
<StyledQuestionnaireItem
badEventValue={FEEDBACK_RESULT.NOT_AT_ALL}
averageEventValue={FEEDBACK_RESULT.AVERAGE}
goodEventValue={FEEDBACK_RESULT.EASY}
title="Le simulateur était-il facile à utiliser ?"
badText="Pas du tout"
goodText="Facile"
isDirty={(isDirty) => {
setDirtySimulator(isDirty);
setDisplayErrorSimulator(!isDirty);
onChange={(status) => {
setStatusSimulator(status);
setDisplayErrorSimulator(false);
}}
displayError={displayErrorSimulator}
></StyledQuestionnaireItem>
<StyledQuestionnaireItem
badEventValue={FEEDBACK_RESULT.NOT_AT_ALL}
averageEventValue={FEEDBACK_RESULT.AVERAGE}
goodEventValue={FEEDBACK_RESULT.YES}
title="Les questions étaient-elles claires et compréhensible ?"
badText="Pas du tout"
goodText="Oui"
isDirty={(isDirty) => {
setDirtyQuestion(isDirty);
setDisplayErrorQuestion(!isDirty);
onChange={(status) => {
setStatusQuestion(status);
setDisplayErrorQuestion(false);
}}
displayError={displayErrorQuestion}
></StyledQuestionnaireItem>
<StyledQuestionnaireItem
badEventValue={FEEDBACK_RESULT.NOT_AT_ALL}
averageEventValue={FEEDBACK_RESULT.AVERAGE}
goodEventValue={FEEDBACK_RESULT.YES}
title="Les explications du résultat obtenu étaient-elles claires et compréhensible ?"
badText="Pas du tout"
goodText="Oui"
isDirty={(isDirty) => {
setDirtyExplanation(isDirty);
setDisplayErrorExplanation(!isDirty);
onChange={(status) => {
setStatusExplanation(status);
setDisplayErrorExplanation(false);
}}
displayError={displayErrorExplanation}
></StyledQuestionnaireItem>
<QuestionnaireText
title="Vous souhaitez nous en dire davantage ?"
placeholder="ex: la question sur la date de début du contrat n'est pas claire"
onChange={setFeedbackText}
></QuestionnaireText>
</FormContainer>
<StyledButton
variant="primary"
onClick={() => {
if (!dirtySimulator) {
if (!statusSimulator) {
setDisplayErrorSimulator(true);
} else if (!dirtyQuestion) {
} else if (!statusQuestion) {
setDisplayErrorQuestion(true);
} else if (!dirtyExplanation) {
} else if (!statusExplanation) {
setDisplayErrorExplanation(true);
} else {
trackFeedback(EVENT_ACTION.EASINESS, statusSimulator);
trackFeedback(EVENT_ACTION.QUESTION_CLARITY, statusQuestion);
trackFeedback(EVENT_ACTION.RESULT_CLARITY, statusExplanation);
if (feedbackText) {
trackFeedbackText(feedbackText);
}
onClick();
}
}}
Expand All @@ -78,6 +101,10 @@ export const QuestionnaireAdvanced = ({
);
};

const StyledHeading = styled(Heading)`
margin-left: 0 !important;
`;

const StyledButton = styled(Button)`
margin: 12px auto 24px 24px;
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,69 @@ 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;
mediumText?: string;
averageText?: string;
goodText?: string;
className?: string;
title?: string;
isDirty?: (isDirty: boolean) => void;
displayError?: boolean;
onChange: (status: FEEDBACK_RESULT) => void;
};

export enum Status {
BAD = "bad",
AVERAGE = "average",
GOOD = "good",
}

export const QuestionnaireItem = ({
badEventValue,
averageEventValue,
goodEventValue,
badText,
mediumText,
averageText,
goodText,
className,
title,
isDirty = () => {},
displayError = false,
onChange,
}: QuestionnaireItemProps): JSX.Element => {
const [status, setStatus] = useState<"bad" | "medium" | "good">();
const [status, setStatus] = useState<Status>();
return (
<div className={className}>
{title && <b>{title}</b>}
<ButtonContainer>
<StyledButton
variant={status === "bad" ? "light" : "naked"}
variant={status === Status.BAD ? "light" : "naked"}
onClick={() => {
setStatus("bad");
isDirty(true);
setStatus(Status.BAD);
onChange(badEventValue);
}}
>
<icons.Bad width="32px" />
{badText ?? "Pas bien"}
</StyledButton>
<StyledButton
variant={status === "medium" ? "light" : "naked"}
variant={status === Status.AVERAGE ? "light" : "naked"}
onClick={() => {
setStatus("medium");
isDirty(true);
setStatus(Status.AVERAGE);
onChange(averageEventValue);
}}
>
<icons.Medium width="32px" />
{mediumText ?? "Moyen"}
{averageText ?? "Moyen"}
</StyledButton>
<StyledButton
variant={status === "good" ? "light" : "naked"}
variant={status === Status.GOOD ? "light" : "naked"}
onClick={() => {
setStatus("good");
isDirty(true);
setStatus(Status.GOOD);
onChange(goodEventValue);
}}
>
<icons.Good width="32px" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,24 @@ type QuestionnaireItemProps = {
className?: string;
title?: string;
placeholder?: string;
onChange: (text: string) => void;
};

export const QuestionnaireText = ({
className,
title,
placeholder,
onChange,
}: QuestionnaireItemProps): JSX.Element => {
const maxCharacters = 200;
return (
<StyledContainer className={className}>
{title && <b>{title}</b>}
<StyledTextarea placeholder={placeholder} maxLength={maxCharacters} />
<StyledTextarea
placeholder={placeholder}
maxLength={maxCharacters}
onChange={(event) => onChange(event.target.value)}
/>
<MaxCharacterText>{maxCharacters} caractères maximum</MaxCharacterText>
</StyledContainer>
);
Expand All @@ -29,6 +35,7 @@ const StyledContainer = styled.div`

const StyledTextarea = styled(Textarea)`
width: 420px;
max-width: 100%;
`;

const MaxCharacterText = styled.span`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { fireEvent, render, screen } from "@testing-library/react";
import { Feedback } from "..";
import { ui } from "./ui";

describe("Etant donné un composant Feedback", () => {
beforeEach(() => {
render(<Feedback />);
});
test("Vérification que l'introduction s'affiche", () => {
expect(ui.introduction.title.query()).toBeInTheDocument();
expect(ui.introduction.button.query()).toBeInTheDocument();
});
describe("Etant donné un click 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("Etant donné un click sur le bouton 'Donner mon avis'", () => {
beforeEach(() => {
fireEvent.click(ui.introduction.button.get());
});
test("Vérification que le composant ne s'affiche plus", () => {
expect(ui.questionnaire.title.query()).toBeInTheDocument();
expect(ui.questionnaire.notGood.query()).toBeInTheDocument();
expect(ui.questionnaire.average.query()).toBeInTheDocument();
expect(ui.questionnaire.good.query()).toBeInTheDocument();
});
});
});
15 changes: 15 additions & 0 deletions packages/code-du-travail-frontend/src/Feedback/__tests__/ui.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { byTestId, byText } from "testing-library-selector";

export const ui = {
closeButton: byTestId("feedbackCloseButton"),
introduction: {
title: byText("Votre avis sur ce simulateur nous intéresse"),
button: byText("Donner mon avis"),
},
questionnaire: {
title: byText(/Comment s'est passée cette simulation pour vous/),
notGood: byText("Pas bien"),
average: byText("Moyen"),
good: byText("Très bien"),
},
};
8 changes: 6 additions & 2 deletions packages/code-du-travail-frontend/src/Feedback/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ export const Feedback = (): JSX.Element => {
const [closed, setClosed] = useState(false);
return !closed ? (
<StyledContainer>
<StyledCloseIcon onClick={() => setClosed(true)} />
<StyledCloseIcon
onClick={() => setClosed(true)}
data-testid="feedbackCloseButton"
/>
{!status && (
<Introduction
onClick={() => {
Expand Down Expand Up @@ -47,7 +50,8 @@ const { colors } = theme;
const StyledContainer = styled.div`
border: 1px solid ${colors.secondary};
border-radius: 6px;
width: 600px;
width: 520px;
max-width: 100%;
display: flex;
flex-direction: column;
margin-top: 42px;
Expand Down
Loading

0 comments on commit 07a15b7

Please sign in to comment.