Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dsfr): MAJ des composants avec le dsfr #124

Draft
wants to merge 14 commits into
base: master
Choose a base branch
from
Draft
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ Cloner le repo, puis :
yarn test
```

## Lib
Utilisation de la lib du DSFR pour l'UI
- https://react-dsfr-components.etalab.studio
- https://react-dsfr.etalab.studio/mui
- Liste de icons : https://remixicon.com/ (si un carré apparaît à la place de l'icon, relancer l'app : `yarn dev`)


## Comment intégrer le widget

L’équipe de 1000jours Blues vous propose d’intégrer son questionnaire EPDS sur votre site grâce à un module (widget).
Expand Down
14 changes: 12 additions & 2 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
module.exports = {
const withTM = require("next-transpile-modules")(["@codegouvfr/react-dsfr"])

/** @type {import('next').NextConfig} */
const nextConfig = withTM({
reactStrictMode: true,
i18n: {
locales: ["fr-FR"],
Expand All @@ -19,6 +22,13 @@ module.exports = {
}
}

config.module.rules.push({
test: /\.woff2$/,
type: "asset/resource",
})

return config
},
}
})

module.exports = nextConfig
17 changes: 11 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@
"name": "nos1000jours-blues-epds-widget",
"private": true,
"scripts": {
"predev": "only-include-used-icons",
"prebuild": "only-include-used-icons",
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"test": "jest"
"test": "jest --transformIgnorePatterns \"node_modules/(?!@toolz/allow)/\" --env=jsdom"
},
"dependencies": {
"@apollo/client": "^3.5.7",
"@dataesr/react-dsfr": "^3.3.5",
"@gouvfr/dsfr": "^1.8.1",
"@codegouvfr/react-dsfr": "^0.25.3",
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"@mui/material": "^5.11.3",
"@socialgouv/matomo-next": "^1.4.0",
"@socialgouv/nos1000jours-lib": "^1.7.0",
"bootstrap": "^5.1.3",
Expand All @@ -22,11 +26,12 @@
"jspdf": "^2.5.1",
"moment": "^2.29.1",
"next": "12.2.6",
"next-transpile-modules": "^10.0.0",
"papaparse": "^5.3.2",
"react": "17.0.2",
"react": "^18.2.0",
"react-bootstrap": "^2.1.0",
"react-bootstrap-icons": "^1.7.2",
"react-dom": "17.0.2",
"react-dom": "^18.2.0",
"sass": "^1.48.0",
"swr": "^1.3.0"
},
Expand All @@ -52,4 +57,4 @@
]
},
"version": "1.48.0"
}
}
37 changes: 27 additions & 10 deletions pages/_app.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,37 @@
import "bootstrap/dist/css/bootstrap.css"
import "../styles/index.scss"
import "@gouvfr/dsfr/dist/dsfr/dsfr.min.css"

import { init } from "@socialgouv/matomo-next"
import App from "next/app"
import React from "react"
import { ThemeProvider } from "react-bootstrap"
import Head from "next/head"
import Link from "next/link"
import React from "react"
import { init } from "@socialgouv/matomo-next"
import { MuiDsfrThemeProvider } from "@codegouvfr/react-dsfr/mui"
import { createNextDsfrIntegrationApi } from "@codegouvfr/react-dsfr/next-pagesdir"

const MATOMO_URL = process.env.NEXT_PUBLIC_MATOMO_URL
const MATOMO_SITE_ID = process.env.NEXT_PUBLIC_MATOMO_SITE_ID
const MATOMO_ENABLED = process.env.NEXT_PUBLIC_MATOMO_ENABLED

const theme = {
font: "Marianne",
}
const { withDsfr, dsfrDocumentApi } = createNextDsfrIntegrationApi({
defaultColorScheme: "system",
Link,
preloadFonts: [
"Marianne-Light",
"Marianne-Light_Italic",
"Marianne-Regular",
"Marianne-Regular_Italic",
"Marianne-Medium",
"Marianne-Medium_Italic",
"Marianne-Bold",
"Marianne-Bold_Italic",
"Spectral-Regular",
"Spectral-ExtraBold",
],
})

export { dsfrDocumentApi }

class MyApp extends App {
componentDidMount() {
if (MATOMO_ENABLED === "true")
Expand All @@ -25,7 +42,7 @@ class MyApp extends App {
const { Component, pageProps } = this.props
return (
<React.Fragment>
<ThemeProvider theme={theme}>
<MuiDsfrThemeProvider>
<Head>
<title>1000 premiers jours</title>
<meta
Expand All @@ -35,10 +52,10 @@ class MyApp extends App {
/>
</Head>
<Component {...pageProps} />
</ThemeProvider>
</MuiDsfrThemeProvider>
</React.Fragment>
)
}
}

export default MyApp
export default withDsfr(MyApp)
7 changes: 4 additions & 3 deletions pages/ab-testing/demographic-data-survey.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import * as StorageUtils from "../../src/utils/storage.utils"
import * as DemographicDataUtils from "../../src/utils/ab-testing/demographic-data.utils"
import { JobSelector } from "../../src/components/JobSelector"
import { DepartmentCodeSelector } from "../../src/components/DepartmentCodeSelector"
import Button from "@codegouvfr/react-dsfr/Button"

export default function DemographicDataSurvey() {
const router = useRouter()
Expand Down Expand Up @@ -256,13 +257,13 @@ export default function DemographicDataSurvey() {

<i className="required-field">Tous les champs sont obligatoires</i>
<div className="button-validation">
<button
className="fr-btn fr-btn--lg"
<Button
size="large"
disabled={!isValidateButtonEnabled}
onClick={sendData}
>
{demographicData?.buttonLabelInInfoDemographicSurvey ?? "Envoyer"}
</button>
</Button>
{isLoading ? <LoaderFoButton /> : null}
</div>
</div>
Expand Down
6 changes: 2 additions & 4 deletions pages/contact/contact-confirmed.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import {
STORAGE_CONTACT_TYPE,
STORAGE_SOURCE,
} from "../../src/constants/constants"
import { } from "@dataesr/react-dsfr"
import { WidgetHeader } from "../../src/components/WidgetHeader"
import * as StorageUtils from "../../src/utils/storage.utils"
import Button from "@codegouvfr/react-dsfr/Button"

export default function ContactConfirmed() {
const router = useRouter()
Expand Down Expand Up @@ -52,9 +52,7 @@ export default function ContactConfirmed() {
</p>

{websiteSource !== OPEN_CONTACT_FROM_EMAIL && (
<button className="fr-btn" onClick={goToResults}>
Retour à mon résultat
</button>
<Button onClick={goToResults}>Retour à mon résultat</Button>
)}
</div>
</ContentLayout>
Expand Down
125 changes: 58 additions & 67 deletions pages/contact/contact-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import React, { useEffect, useState } from "react"
import { Col } from "react-bootstrap"
import { ContentLayout } from "../../src/components/Layout"
import { } from "@dataesr/react-dsfr"
import {
PATTERN_EMAIL,
RequestContact,
Expand All @@ -16,14 +15,17 @@ import {
convertDateToString,
LoaderFoButton,
} from "../../src/utils/main.utils"
import * as StorageUtils from "../../src/utils/storage.utils"
import { DatePickerLastChild } from "../../src/components/contact/DatePickerLastChild"
import { useMutation } from "@apollo/client"
import { client, EPDS_CONTACT_INFORMATION, SAVE_DEMANDE_DE_CONTACT } from "../../apollo-client"
import { useRouter } from "next/router"
import { WidgetHeader } from "../../src/components/WidgetHeader"
import { Form } from "../../src/constants/specificLabels"
import * as StorageUtils from "../../src/utils/storage.utils"
import * as ContactUtils from "../../src/utils/contact.utils"
import * as DsfrUtils from "../../src/utils/dsfr-components.utils"
import Button from "@codegouvfr/react-dsfr/Button"
import Input from "@codegouvfr/react-dsfr/Input"

export default function ContactForm() {
const router = useRouter()
Expand Down Expand Up @@ -117,53 +119,53 @@ export default function ContactForm() {
})
}

const emailInput = (isRequired) => (
<div
className={`form-group fr-input-group ${isEmailValid ? "fr-input-group--valid" : ""
}`}
>
<label htmlFor="inputEmail">Votre email {isRequired ? "*" : null} :</label>
<input
type="email"
className={`form-control fr-input ${isEmailValid ? "custom-input-valid" : ""
}`}
id="inputEmail"
name="inputEmail"
pattern={PATTERN_EMAIL}
onChange={(e) => setEmailValid(e.target.validity.valid)}
placeholder={Form.placeholder.email}
required={isRequired}
/>
const emailInput = (isRequired) => {
const emailLabel = `Votre email ${isRequired ? "*" : ""} :`
const emailState = DsfrUtils.getInputState(isEmailValid)
const emailStateMsg = isEmailValid === false ? Form.error.email : ""

{isEmailValid === false && <InputError error={Form.error.email} />}
{isRequired && requiredField}
</div>
)
return (
<div style={{ marginBottom: "1.5rem" }}>
<Input
label={emailLabel}
hintText={isRequired ? requiredField : ""}
state={emailState}
stateRelatedMessage={emailStateMsg}
onChange={(e) => setEmailValid(e.target.validity.valid)}
nativeInputProps={{
placeholder: Form.placeholder.email,
type: "email",
required: isRequired,
pattern: PATTERN_EMAIL,
}}
/>
</div>
)
}

const phoneInput = (isRequired) => (
<div
className={`form-group fr-input-group ${isPhoneValid ? "fr-input-group--valid" : ""
}`}
>
<label htmlFor="inputPhone">Votre numéro de téléphone {isRequired ? "*" : null} :</label>
<input
type="tel"
className={`form-control fr-input ${isPhoneValid ? "custom-input-valid" : ""
}`}
id="inputPhone"
name="inputPhone"
pattern="[0-9]{10}"
onChange={(e) => setPhoneValid(e.target.validity.valid)}
placeholder="Écrivez ici le numéro pour vous contacter"
required={isRequired}
/>
const phoneInput = (isRequired) => {
const phoneLabel = `Votre numéro de téléphone ${isRequired ? "*" : ""} :`
const phoneState = DsfrUtils.getInputState(isPhoneValid)
const phoneStateMsg = isPhoneValid === false ? Form.error.phone : ""

{isPhoneValid === false && (
<InputError error="Le numéro de téléphone n'est pas au bon format" />
)}
{isRequired ? requiredField : null}
</div>
)
return (
<div style={{ marginBottom: "1.5rem" }}>
<Input
label={phoneLabel}
hintText={isRequired ? requiredField : ""}
state={phoneState}
stateRelatedMessage={phoneStateMsg}
onChange={(e) => setPhoneValid(e.target.validity.valid)}
nativeInputProps={{
placeholder: Form.placeholder.phone,
type: "tel",
isRequired: isRequired,
pattern: "[0-9]{10}",
}}
/>
</div>
)
}

const setOrderPhoneAndEmailInputs = () => {
if (contactType == RequestContact.type.email) {
Expand Down Expand Up @@ -219,16 +221,12 @@ export default function ContactForm() {
<WidgetHeader title="être contacté(e)" locale={localeSelected} />

<form className="contact-form" onSubmit={sendForm}>
<div className={`form-group fr-input-group`}>
<label htmlFor="inputName">Votre prénom :</label>
<input
type="text"
className={`form-control fr-input`}
id="inputName"
name="inputName"
placeholder={Form.placeholder.name}
/>
</div>
<Input
label="Votre prénom :"
nativeInputProps={{
placeholder: Form.placeholder.name
}}
/>

{setOrderPhoneAndEmailInputs()}
<ChildCounter />
Expand All @@ -237,29 +235,22 @@ export default function ContactForm() {
) : null}

<Col className="be-contacted-bottom-buttons">
<button className="fr-btn fr-btn--secondary" onClick={cancel}>
<Button priority="secondary" onClick={cancel}>
Annuler
</button>
<button
className="fr-btn"
</Button>
<Button
type="submit"
disabled={!canSend || isLoading}
>
Valider
{isLoading ? <LoaderFoButton /> : null}
</button>
</Button>
</Col>
</form>
</ContentLayout>
)
}

const InputError = ({ error }) => (
<p id="text-input-error-desc-error" className="fr-error-text">
{error}
</p>
)

/**
* Vérifie la validité du formulaire en fonction des informations complétées
* @param {RequestContact.type} contactType Le type de contact
Expand Down
Loading