From 70459d86736e3ef8156bab8478fd963ea9076afe Mon Sep 17 00:00:00 2001 From: Sandrine Ricardo Date: Mon, 28 Oct 2024 12:42:31 +0100 Subject: [PATCH 01/32] feat(control): add form for lic papier --- .../details/ControllerControlDrawer.js | 2 +- .../components/home/ControllerHome.js | 25 ++-- .../components/list/table/ControlsTable.js | 2 +- .../ControllerControlNoLicPreliminaryForm.js | 117 --------------- .../ControllerControlPreliminaryForm.js | 140 ++++++++++++++++++ .../ControllerControlNewLicPapier.js | 54 +++++++ .../noLic/ControllerControlNewNoLic.js | 19 ++- .../noLic/ControllerControlNoLic.js | 12 +- .../noLic/ControllerControlNoLicDrawer.js | 10 +- .../noLic/ControllerControlNoLicHistory.js | 0 .../ControllerControlNoLicInformations.js | 2 +- ...trollerControlNoLicInformationsEmployee.js | 2 +- web/controller/utils/useReadControlData.js | 3 +- 13 files changed, 234 insertions(+), 154 deletions(-) delete mode 100644 web/controller/components/noLic/ControllerControlNoLicPreliminaryForm.js create mode 100644 web/controller/components/noQRCode/ControllerControlPreliminaryForm.js create mode 100644 web/controller/components/noQRCode/licPapier/ControllerControlNewLicPapier.js rename web/controller/components/{ => noQRCode}/noLic/ControllerControlNewNoLic.js (58%) rename web/controller/components/{ => noQRCode}/noLic/ControllerControlNoLic.js (93%) rename web/controller/components/{ => noQRCode}/noLic/ControllerControlNoLicDrawer.js (85%) rename web/controller/components/{ => noQRCode}/noLic/ControllerControlNoLicHistory.js (100%) rename web/controller/components/{ => noQRCode}/noLic/ControllerControlNoLicInformations.js (86%) rename web/controller/components/{ => noQRCode}/noLic/ControllerControlNoLicInformationsEmployee.js (97%) diff --git a/web/controller/components/details/ControllerControlDrawer.js b/web/controller/components/details/ControllerControlDrawer.js index eadb5348..cf12e86f 100644 --- a/web/controller/components/details/ControllerControlDrawer.js +++ b/web/controller/components/details/ControllerControlDrawer.js @@ -4,7 +4,7 @@ import { CONTROL_TYPES, useReadControlData } from "../../utils/useReadControlData"; -import { ControllerControlNoLicDrawer } from "../noLic/ControllerControlNoLicDrawer"; +import { ControllerControlNoLicDrawer } from "../noQRCode/noLic/ControllerControlNoLicDrawer"; import { ControlDrawer } from "../../utils/ControlDrawer"; export function ControllerControlDrawer({ controlId, controlType, onClose }) { diff --git a/web/controller/components/home/ControllerHome.js b/web/controller/components/home/ControllerHome.js index 81e6258d..bd86318e 100644 --- a/web/controller/components/home/ControllerHome.js +++ b/web/controller/components/home/ControllerHome.js @@ -14,7 +14,8 @@ import { InfoHoraireServiceController } from "./InfoHoraireServiceController"; import classNames from "classnames"; import { useModals } from "common/utils/modals"; import { ControlTypeFilters } from "../filters/ControlTypeFilter"; -import { ControllerControlNewNoLic } from "../noLic/ControllerControlNewNoLic"; +import { ControllerControlNewNoLic } from "../noQRCode/noLic/ControllerControlNewNoLic"; +import { ControllerControlNewLicPapier } from "../noQRCode/licPapier/ControllerControlNewLicPapier"; import { usePageTitle } from "../../../common/UsePageTitle"; import { Typography } from "@mui/material"; import Modal from "../../../common/Modal"; @@ -66,11 +67,11 @@ export function ControllerHome() { const location = useLocation(); const modals = useModals(); const controllerUserInfo = store.controllerInfo(); - const [modal, setModal] = useState({ isOpen: false, parcours: "" }); const [showHoraireServiceModal, setShowHoraireServiceModal] = useState(false); const [controlOnFocus, setControlOnFocus] = React.useState(null); const [openNewNoLic, setOpenNewNoLic] = React.useState(false); + const [openNewLicPapier, setOpenNewLicPapier] = React.useState(false); const [controls, loadControls, loadingControls] = useLoadControls(); @@ -112,6 +113,11 @@ export function ControllerHome() { onClose={() => setOpenNewNoLic(false)} setControlOnFocus={setControlOnFocus} /> + setOpenNewLicPapier(false)} + setControlOnFocus={setControlOnFocus} + /> Bonjour, {controllerUserInfo.firstName} @@ -142,9 +148,7 @@ export function ControllerHome() { - setModal({ isOpen: true, parcours: "d'un LIC papier" }) - } + onClick={() => setOpenNewLicPapier(true)} /> @@ -189,17 +193,6 @@ export function ControllerHome() { clickOnRow={(id, type) => setControlOnFocus({ id, type })} /> - setModal({ isOpen: false, parcours: "" })} - title="En cours de construction" - content={ - <> - Le parcours de contrôle {modal.parcours} dans votre interface - Mobilic est en cours de conception. - - } - /> setShowHoraireServiceModal(false)} diff --git a/web/controller/components/list/table/ControlsTable.js b/web/controller/components/list/table/ControlsTable.js index bfb07cdf..62fb7b7b 100644 --- a/web/controller/components/list/table/ControlsTable.js +++ b/web/controller/components/list/table/ControlsTable.js @@ -45,7 +45,7 @@ const ControlsTable = ({ entries, onRowClick, period = "day" }) => { entry.id, entry.type === "Mobilic" ? CONTROL_TYPES.MOBILIC - : CONTROL_TYPES.NO_LIC + : CONTROL_TYPES.NO_LIC // TODO LIC PAPIER ) } > diff --git a/web/controller/components/noLic/ControllerControlNoLicPreliminaryForm.js b/web/controller/components/noLic/ControllerControlNoLicPreliminaryForm.js deleted file mode 100644 index 4bdf84dc..00000000 --- a/web/controller/components/noLic/ControllerControlNoLicPreliminaryForm.js +++ /dev/null @@ -1,117 +0,0 @@ -import React from "react"; -import { useLoadingScreen } from "common/utils/loading"; -import { CONTROLLER_SAVE_CONTROL_BULLETIN } from "common/utils/apiQueries"; -import { useApi } from "common/utils/api"; -import Stack from "@mui/material/Stack"; -import Typography from "@mui/material/Typography"; -import { Button } from "@codegouvfr/react-dsfr/Button"; -import { useSnackbarAlerts } from "../../../common/Snackbar"; -import { formatApiError } from "common/utils/errors"; -import { MandatoryField } from "../../../common/MandatoryField"; -import { Input } from "../../../common/forms/Input"; - -export function ControllerControlNoLicPreliminaryForm({ onSubmit, onClose }) { - const api = useApi(); - const withLoadingScreen = useLoadingScreen(); - const alerts = useSnackbarAlerts(); - - const [userFirstName, setUserFirstName] = React.useState(""); - const [userLastName, setUserLastName] = React.useState(""); - const [companyName, setCompanyName] = React.useState(""); - const [ - vehicleRegistrationNumber, - setVehicleRegistrationNumber - ] = React.useState(""); - - const canSubmitForm = React.useMemo( - () => - !!userFirstName && - userLastName && - companyName && - vehicleRegistrationNumber, - [userFirstName, userLastName, companyName, vehicleRegistrationNumber] - ); - - const submitPreliminaryForm = async () => - withLoadingScreen(async () => { - try { - const apiResponse = await api.graphQlMutate( - CONTROLLER_SAVE_CONTROL_BULLETIN, - { - userFirstName, - userLastName, - companyName, - vehicleRegistrationNumber - }, - { context: { nonPublicApi: true } } - ); - onSubmit(apiResponse.data.controllerSaveControlBulletin.id); - alerts.success("Le contrôle a été créé.", "", 3000); - } catch (err) { - alerts.error(formatApiError(err), "", 6000); - } - }); - - return ( - <> - - Nouveau contrôle “Pas de LIC à bord” - - - Veuillez renseigner ces informations afin de créer le contrôle - - - - - setUserLastName(e.target.value), - name: "userLastName" - }} - label="Nom du salarié" - required - /> - - setUserFirstName(e.target.value), - name: "userFirstName" - }} - label="Prénom du salarié" - required - /> - setCompanyName(e.target.value), - name: "companyName" - }} - label="Nom de l'entreprise" - required - /> - setVehicleRegistrationNumber(e.target.value), - name: "vehicleRegistrationNumber" - }} - label="Immatriculation du véhicule" - required - /> - - - - - - - ); -} diff --git a/web/controller/components/noQRCode/ControllerControlPreliminaryForm.js b/web/controller/components/noQRCode/ControllerControlPreliminaryForm.js new file mode 100644 index 00000000..d8e2a313 --- /dev/null +++ b/web/controller/components/noQRCode/ControllerControlPreliminaryForm.js @@ -0,0 +1,140 @@ +import React from "react"; +import { useLoadingScreen } from "common/utils/loading"; +import { CONTROLLER_SAVE_CONTROL_BULLETIN } from "common/utils/apiQueries"; +import { useApi } from "common/utils/api"; +import Stack from "@mui/material/Stack"; +import { Button } from "@codegouvfr/react-dsfr/Button"; +import { useSnackbarAlerts } from "../../../common/Snackbar"; +import { formatApiError } from "common/utils/errors"; +import { MandatoryField } from "../../../common/MandatoryField"; +import { Input } from "../../../common/forms/Input"; +import { RadioButtons } from "../../../common/forms/RadioButtons"; +import { CONTROL_TYPES } from "../../utils/useReadControlData"; + +export function ControllerControlPreliminaryForm({ type, onSubmit, onClose }) { + const api = useApi(); + const withLoadingScreen = useLoadingScreen(); + const alerts = useSnackbarAlerts(); + + const [userFirstName, setUserFirstName] = React.useState(""); + const [userLastName, setUserLastName] = React.useState(""); + const [companyName, setCompanyName] = React.useState(""); + const [ + vehicleRegistrationNumber, + setVehicleRegistrationNumber + ] = React.useState(""); + const [dayPageFilled, setDayPageFilled] = React.useState(); + + const canSubmitForm = React.useMemo( + () => + !!userFirstName && + !!userLastName && + !!companyName && + !!vehicleRegistrationNumber && + (type === CONTROL_TYPES.NO_LIC || dayPageFilled !== undefined), + [ + userFirstName, + userLastName, + companyName, + vehicleRegistrationNumber, + dayPageFilled + ] + ); + + const submitPreliminaryForm = async () => + withLoadingScreen(async () => { + try { + const apiResponse = await api.graphQlMutate( + CONTROLLER_SAVE_CONTROL_BULLETIN, + { + userFirstName, + userLastName, + companyName, + vehicleRegistrationNumber + }, + { context: { nonPublicApi: true } } + ); + onSubmit(apiResponse.data.controllerSaveControlBulletin.id); + alerts.success("Le contrôle a été créé.", "", 3000); + } catch (err) { + alerts.error(formatApiError(err), "", 6000); + } + }); + + return ( + + + setUserLastName(e.target.value), + name: "userLastName" + }} + label="Nom du salarié" + required + /> + + setUserFirstName(e.target.value), + name: "userFirstName" + }} + label="Prénom du salarié" + required + /> + setCompanyName(e.target.value), + name: "companyName" + }} + label="Nom de l'entreprise" + required + /> + setVehicleRegistrationNumber(e.target.value), + name: "vehicleRegistrationNumber" + }} + label="Immatriculation du véhicule" + required + /> + {type === CONTROL_TYPES.LIC_PAPIER && ( + setDayPageFilled(true) + } + }, + { + label: "Non", + nativeInputProps: { + checked: dayPageFilled === false, + onChange: () => setDayPageFilled(false) + } + } + ]} + required + /> + )} + + + + + + ); +} diff --git a/web/controller/components/noQRCode/licPapier/ControllerControlNewLicPapier.js b/web/controller/components/noQRCode/licPapier/ControllerControlNewLicPapier.js new file mode 100644 index 00000000..ec4c59f1 --- /dev/null +++ b/web/controller/components/noQRCode/licPapier/ControllerControlNewLicPapier.js @@ -0,0 +1,54 @@ +import React from "react"; +import { Link } from "react-router-dom"; +import classNames from "classnames"; +import Container from "@mui/material/Container"; +import Box from "@mui/material/Box"; +import Typography from "@mui/material/Typography"; +import { ControllerControlPreliminaryForm } from "../ControllerControlPreliminaryForm"; +import { CONTROL_TYPES } from "../../../utils/useReadControlData"; +import { ControlDrawer } from "../../../utils/ControlDrawer"; + +export function ControllerControlNewLicPapier({ + isOpen, + onClose, + setControlOnFocus +}) { + const type = CONTROL_TYPES.LIC_PAPIER; + const onControlCreated = id => { + onClose(); + setControlOnFocus({ + id, + type + }); + }; + return ( + + + + + Fermer + + + + Nouveau contrôle “LIC papier présenté” + +

+ Veuillez renseigner ces informations afin de créer le contrôle : +

+ +
+
+ ); +} diff --git a/web/controller/components/noLic/ControllerControlNewNoLic.js b/web/controller/components/noQRCode/noLic/ControllerControlNewNoLic.js similarity index 58% rename from web/controller/components/noLic/ControllerControlNewNoLic.js rename to web/controller/components/noQRCode/noLic/ControllerControlNewNoLic.js index 4bfb6d3e..4d0a2cab 100644 --- a/web/controller/components/noLic/ControllerControlNewNoLic.js +++ b/web/controller/components/noQRCode/noLic/ControllerControlNewNoLic.js @@ -3,20 +3,22 @@ import { Link } from "react-router-dom"; import classNames from "classnames"; import Container from "@mui/material/Container"; import Box from "@mui/material/Box"; -import { ControllerControlNoLicPreliminaryForm } from "./ControllerControlNoLicPreliminaryForm"; -import { CONTROL_TYPES } from "../../utils/useReadControlData"; -import { ControlDrawer } from "../../utils/ControlDrawer"; +import Typography from "@mui/material/Typography"; +import { ControllerControlPreliminaryForm } from "../ControllerControlPreliminaryForm"; +import { CONTROL_TYPES } from "../../../utils/useReadControlData"; +import { ControlDrawer } from "../../../utils/ControlDrawer"; export function ControllerControlNewNoLic({ isOpen, onClose, setControlOnFocus }) { + const type = CONTROL_TYPES.NO_LIC; const onControlCreated = id => { onClose(); setControlOnFocus({ id, - type: CONTROL_TYPES.NO_LIC + type }); }; return ( @@ -35,7 +37,14 @@ export function ControllerControlNewNoLic({ Fermer - + Nouveau contrôle “Pas de LIC à bord” + +

+ Veuillez renseigner ces informations afin de créer le contrôle : +

+ diff --git a/web/controller/components/noLic/ControllerControlNoLic.js b/web/controller/components/noQRCode/noLic/ControllerControlNoLic.js similarity index 93% rename from web/controller/components/noLic/ControllerControlNoLic.js rename to web/controller/components/noQRCode/noLic/ControllerControlNoLic.js index 98494ea1..ed8814fd 100644 --- a/web/controller/components/noLic/ControllerControlNoLic.js +++ b/web/controller/components/noQRCode/noLic/ControllerControlNoLic.js @@ -11,14 +11,14 @@ import WarningAmberOutlinedIcon from "@mui/icons-material/WarningOutlined"; import HistoryOutlinedIcon from "@mui/icons-material/HistoryOutlined"; import { ControllerControlNoLicHistory } from "./ControllerControlNoLicHistory"; import { ControllerControlNoLicInformations } from "./ControllerControlNoLicInformations"; -import { useDownloadBDC } from "../../utils/useDownloadBDC"; -import { ControllerControlBottomMenu as BottomMenu } from "../menu/ControllerControlBottomMenu"; -import { canDownloadBDC } from "../../utils/controlBulletin"; -import { TextWithBadge } from "../../../common/TextWithBadge"; -import { UserReadAlerts } from "../../../control/components/UserReadAlerts"; +import { useDownloadBDC } from "../../../utils/useDownloadBDC"; +import { ControllerControlBottomMenu as BottomMenu } from "../../menu/ControllerControlBottomMenu"; +import { canDownloadBDC } from "../../../utils/controlBulletin"; +import { TextWithBadge } from "../../../../common/TextWithBadge"; +import { UserReadAlerts } from "../../../../control/components/UserReadAlerts"; import Typography from "@mui/material/Typography"; import Box from "@mui/material/Box"; -import Notice from "../../../common/Notice"; +import Notice from "../../../../common/Notice"; const useStyles = makeStyles(theme => ({ middleTab: { diff --git a/web/controller/components/noLic/ControllerControlNoLicDrawer.js b/web/controller/components/noQRCode/noLic/ControllerControlNoLicDrawer.js similarity index 85% rename from web/controller/components/noLic/ControllerControlNoLicDrawer.js rename to web/controller/components/noQRCode/noLic/ControllerControlNoLicDrawer.js index a61191e3..12d3b2d9 100644 --- a/web/controller/components/noLic/ControllerControlNoLicDrawer.js +++ b/web/controller/components/noQRCode/noLic/ControllerControlNoLicDrawer.js @@ -1,10 +1,10 @@ import React from "react"; -import { ControllerControlHeader } from "../details/ControllerControlHeader"; +import { ControllerControlHeader } from "../../details/ControllerControlHeader"; import { ControllerControlNoLic } from "./ControllerControlNoLic"; -import { ControlBulletinDrawer } from "../controlBulletin/ControlBulletinDrawer"; -import { ControlDrawer } from "../../utils/ControlDrawer"; -import { useReportInfractions } from "../../utils/useReportInfractions"; -import { canDownloadBDC } from "../../utils/controlBulletin"; +import { ControlBulletinDrawer } from "../../controlBulletin/ControlBulletinDrawer"; +import { ControlDrawer } from "../../../utils/ControlDrawer"; +import { useReportInfractions } from "../../../utils/useReportInfractions"; +import { canDownloadBDC } from "../../../utils/controlBulletin"; export function ControllerControlNoLicDrawer({ controlData, diff --git a/web/controller/components/noLic/ControllerControlNoLicHistory.js b/web/controller/components/noQRCode/noLic/ControllerControlNoLicHistory.js similarity index 100% rename from web/controller/components/noLic/ControllerControlNoLicHistory.js rename to web/controller/components/noQRCode/noLic/ControllerControlNoLicHistory.js diff --git a/web/controller/components/noLic/ControllerControlNoLicInformations.js b/web/controller/components/noQRCode/noLic/ControllerControlNoLicInformations.js similarity index 86% rename from web/controller/components/noLic/ControllerControlNoLicInformations.js rename to web/controller/components/noQRCode/noLic/ControllerControlNoLicInformations.js index b3289a18..30b11314 100644 --- a/web/controller/components/noLic/ControllerControlNoLicInformations.js +++ b/web/controller/components/noQRCode/noLic/ControllerControlNoLicInformations.js @@ -1,6 +1,6 @@ import React from "react"; import Stack from "@mui/material/Stack"; -import { ControllerControlNote as Notes } from "../details/ControllerControlNote"; +import { ControllerControlNote as Notes } from "../../details/ControllerControlNote"; import { ControllerControlNoLicInformationsEmployee as InformationsEmployee } from "./ControllerControlNoLicInformationsEmployee"; export function ControllerControlNoLicInformations({ controlData }) { diff --git a/web/controller/components/noLic/ControllerControlNoLicInformationsEmployee.js b/web/controller/components/noQRCode/noLic/ControllerControlNoLicInformationsEmployee.js similarity index 97% rename from web/controller/components/noLic/ControllerControlNoLicInformationsEmployee.js rename to web/controller/components/noQRCode/noLic/ControllerControlNoLicInformationsEmployee.js index 4455af3d..d1ea1b35 100644 --- a/web/controller/components/noLic/ControllerControlNoLicInformationsEmployee.js +++ b/web/controller/components/noQRCode/noLic/ControllerControlNoLicInformationsEmployee.js @@ -7,7 +7,7 @@ import ListItem from "@mui/material/ListItem"; import DriveEtaIcon from "@mui/icons-material/DirectionsCar"; import BusinessIcon from "@mui/icons-material/Business"; import ListItemIcon from "@mui/material/ListItemIcon"; -import { InfoItem } from "../../../home/InfoField"; +import { InfoItem } from "../../../../home/InfoField"; const useStyles = makeStyles(theme => ({ sectionBody: { diff --git a/web/controller/utils/useReadControlData.js b/web/controller/utils/useReadControlData.js index 2da63816..43dbd1a1 100644 --- a/web/controller/utils/useReadControlData.js +++ b/web/controller/utils/useReadControlData.js @@ -10,7 +10,8 @@ import { useSnackbarAlerts } from "../../common/Snackbar"; export const CONTROL_TYPES = { MOBILIC: "mobilic", - NO_LIC: "no-lic" + NO_LIC: "no-lic", + LIC_PAPIER: "lic-papier" }; export const useReadControlData = (controlId, controlType) => { From d98050efd5383fe60f134fea453e72f35f5f16eb Mon Sep 17 00:00:00 2001 From: Sandrine Ricardo Date: Mon, 28 Oct 2024 19:44:20 +0100 Subject: [PATCH 02/32] feat(control): add fields for no lic and lic papier - extracted birth date in a component - updated control type to match server --- common/utils/apiFragments.js | 2 + common/utils/apiQueries.js | 6 + web/common/forms/BirthDate.js | 147 ++++++++++++++++++ .../ControlBulletinFormStep1.js | 147 +----------------- .../ControllerControlPreliminaryForm.js | 86 ++++++++-- web/controller/utils/useReadControlData.js | 4 +- 6 files changed, 241 insertions(+), 151 deletions(-) create mode 100644 web/common/forms/BirthDate.js diff --git a/common/utils/apiFragments.js b/common/utils/apiFragments.js index fed5999e..b40230cc 100644 --- a/common/utils/apiFragments.js +++ b/common/utils/apiFragments.js @@ -249,6 +249,7 @@ export const CONTROL_BULLETIN_FRAGMENT = gql` licenseCopyNumber observation isVehicleImmobilized + businessType } `; @@ -264,6 +265,7 @@ export const CONTROL_DATA_FRAGMENT = gql` userLastName controlBulletinCreationTime vehicleRegistrationNumber + isDayPageFilled note nbReportedInfractions controlBulletin { diff --git a/common/utils/apiQueries.js b/common/utils/apiQueries.js index 2dfd6f46..63d6555d 100644 --- a/common/utils/apiQueries.js +++ b/common/utils/apiQueries.js @@ -1845,6 +1845,7 @@ export const CONTROLLER_SAVE_CONTROL_BULLETIN = gql` ${CONTROL_DATA_FRAGMENT} mutation controllerSaveControlBulletin( $controlId: Int + $type: String $userFirstName: String $userLastName: String $userBirthDate: Date @@ -1866,9 +1867,12 @@ export const CONTROLLER_SAVE_CONTROL_BULLETIN = gql` $licenseCopyNumber: String $isVehicleImmobilized: Boolean $observation: String + $businessType: String + $isDayPageFilled: Boolean ) { controllerSaveControlBulletin( controlId: $controlId + type: $type userFirstName: $userFirstName userLastName: $userLastName userNationality: $userNationality @@ -1890,6 +1894,8 @@ export const CONTROLLER_SAVE_CONTROL_BULLETIN = gql` licenseCopyNumber: $licenseCopyNumber isVehicleImmobilized: $isVehicleImmobilized observation: $observation + businessType: $businessType + isDayPageFilled: $isDayPageFilled ) { ...ControlData controlBulletin { diff --git a/web/common/forms/BirthDate.js b/web/common/forms/BirthDate.js new file mode 100644 index 00000000..d9380cff --- /dev/null +++ b/web/common/forms/BirthDate.js @@ -0,0 +1,147 @@ +import React from "react"; + +import classNames from "classnames"; +import { CURRENT_YEAR } from "common/utils/time"; +import { Input } from "./Input"; + +const BIRTH_DATE_MIN_YEAR = 100; +const BIRTH_DATE_MAX_YEAR = 18; + +export function BirthDate({ label, userBirthDate, setUserBirthDate }) { + const [day, setDay] = React.useState(); + const [month, setMonth] = React.useState(); + const [year, setYear] = React.useState(); + + const [dayState, setDayState] = React.useState("default"); + const [monthState, setMonthState] = React.useState("default"); + const [yearState, setYearState] = React.useState("default"); + const [dateState, setDateState] = React.useState("default"); + + React.useEffect(() => { + if (!userBirthDate) { + return; + } + const date = new Date(userBirthDate); + setYear(date.getFullYear()); + setMonth(date.getMonth() + 1); + setDay(date.getDate()); + }, [userBirthDate]); + + const MAX_BIRTH_DATE_YEAR = React.useMemo( + () => CURRENT_YEAR - BIRTH_DATE_MAX_YEAR, + [CURRENT_YEAR] + ); + const MIN_BIRTH_DATE_YEAR = React.useMemo( + () => CURRENT_YEAR - BIRTH_DATE_MIN_YEAR, + [CURRENT_YEAR] + ); + + const onValidateBirthDate = () => { + let hasError = false; + if (year < MIN_BIRTH_DATE_YEAR || year > MAX_BIRTH_DATE_YEAR) { + setYearState("error"); + hasError = true; + } else { + setYearState("default"); + } + if (month < 1 || month > 12) { + setMonthState("error"); + hasError = true; + } else { + setMonthState("default"); + } + if (day < 1 || day > 31) { + setDayState("error"); + hasError = true; + } else { + setDayState("default"); + } + + if (!hasError && day && month && year) { + const date = new Date(year, month - 1, day, 10, 0, 0, 0); + const validYear = date.getFullYear() === parseInt(year); + const validMonth = date.getMonth() === parseInt(month - 1); + const validDay = date.getDate() === parseInt(day); + if (validYear && validMonth && validDay) { + setDateState("default"); + const newDateString = date.toISOString().split("T")[0]; + setUserBirthDate(newDateString); + } else { + setDateState("error"); + } + } else { + setDateState("default"); + } + }; + + return ( +
+ + {label} + +
+ setDay(e.target.value), + onBlur: onValidateBirthDate, + type: "number", + inputMode: "numeric" + }} + type="number" + label="Jour" + hintText="Entre 1 et 31" + required + state={dayState} + stateRelatedMessage="Jour invalide. Exemple : 14." + /> +
+
+ setMonth(e.target.value), + onBlur: onValidateBirthDate, + type: "number", + inputMode: "numeric" + }} + label="Mois" + hintText="Entre 1 et 12" + required + state={monthState} + stateRelatedMessage="Mois invalide. Exemple : 12." + /> +
+
+ setYear(e.target.value), + onBlur: onValidateBirthDate, + type: "number", + inputMode: "numeric" + }} + label="Année" + hintText="Exemple : 1984" + required + state={yearState} + stateRelatedMessage="Année invalide : elle doit être comprise entre 1924 et 2006. Exemple : 1990." + /> +
+ {dateState === "error" && ( +

+ Date invalide : ce jour n'existe pas. +

+ )} +
+ ); +} diff --git a/web/controller/components/controlBulletin/ControlBulletinFormStep1.js b/web/controller/components/controlBulletin/ControlBulletinFormStep1.js index 4294d063..d6c7dc0c 100644 --- a/web/controller/components/controlBulletin/ControlBulletinFormStep1.js +++ b/web/controller/components/controlBulletin/ControlBulletinFormStep1.js @@ -6,14 +6,10 @@ import { DEPARTMENTS } from "../../utils/departments"; import { useApi } from "common/utils/api"; import { CONTROL_LOCATION_QUERY } from "common/utils/apiQueries"; import { DsfrAutocomplete } from "../utils/DsfrAutocomplete"; -import { Box, Grid } from "@mui/material"; -import { CURRENT_YEAR } from "common/utils/time"; import { MandatoryField } from "../../../common/MandatoryField"; import { Input } from "../../../common/forms/Input"; import { Select } from "../../../common/forms/Select"; - -const BIRTH_DATE_MIN_YEAR = 100; -const BIRTH_DATE_MAX_YEAR = 18; +import { BirthDate } from "../../../common/forms/BirthDate"; export function ControlBulletinFormStep1({ handleEditControlBulletin, @@ -23,72 +19,6 @@ export function ControlBulletinFormStep1({ const [departmentLocations, setDepartmentLocations] = React.useState([]); const api = useApi(); - const [day, setDay] = React.useState(); - const [month, setMonth] = React.useState(); - const [year, setYear] = React.useState(); - - const [dayState, setDayState] = React.useState("default"); - const [monthState, setMonthState] = React.useState("default"); - const [yearState, setYearState] = React.useState("default"); - const [dateState, setDateState] = React.useState("default"); - - React.useEffect(() => { - const { userBirthDate } = controlBulletin; - if (!userBirthDate) { - return; - } - const date = new Date(userBirthDate); - setYear(date.getFullYear()); - setMonth(date.getMonth() + 1); - setDay(date.getDate()); - }, [controlBulletin]); - - const MAX_BIRTH_DATE_YEAR = React.useMemo( - () => CURRENT_YEAR - BIRTH_DATE_MAX_YEAR, - [CURRENT_YEAR] - ); - const MIN_BIRTH_DATE_YEAR = React.useMemo( - () => CURRENT_YEAR - BIRTH_DATE_MIN_YEAR, - [CURRENT_YEAR] - ); - - const onValidateBirthDate = () => { - let hasError = false; - if (year < MIN_BIRTH_DATE_YEAR || year > MAX_BIRTH_DATE_YEAR) { - setYearState("error"); - hasError = true; - } else { - setYearState("default"); - } - if (month < 1 || month > 12) { - setMonthState("error"); - hasError = true; - } else { - setMonthState("default"); - } - if (day < 1 || day > 31) { - setDayState("error"); - hasError = true; - } else { - setDayState("default"); - } - - if (!hasError && day && month && year) { - const date = new Date(year, month - 1, day, 10, 0, 0, 0); - const validYear = date.getFullYear() === parseInt(year); - const validMonth = date.getMonth() === parseInt(month - 1); - const validDay = date.getDate() === parseInt(day); - if (validYear && validMonth && validDay) { - setDateState("default"); - const newDateString = date.toISOString().split("T")[0]; - editControlBulletinField(newDateString, "userBirthDate"); - } else { - setDateState("error"); - } - } else { - setDateState("default"); - } - }; React.useEffect(() => { const loadData = async () => { @@ -201,74 +131,13 @@ export function ControlBulletinFormStep1({ } required /> - - - - - - setDay(e.target.value), - onBlur: onValidateBirthDate, - type: "number", - inputMode: "numeric" - }} - type="number" - label="Jour" - hintText="Entre 1 et 31" - required - state={dayState} - stateRelatedMessage="Jour invalide. Exemple : 14." - /> - - - setMonth(e.target.value), - onBlur: onValidateBirthDate, - type: "number", - inputMode: "numeric" - }} - label="Mois" - hintText="Entre 1 et 12" - required - state={monthState} - stateRelatedMessage="Mois invalide. Exemple : 12." - /> - - - setYear(e.target.value), - onBlur: onValidateBirthDate, - type: "number", - inputMode: "numeric" - }} - label="Année" - hintText="Exemple : 1984" - required - state={yearState} - stateRelatedMessage="Année invalide : elle doit être comprise entre 1924 et 2006. Exemple : 1990." - /> - - - {dateState === "error" && ( -

- Date invalide : ce jour n'existe pas. -

- )} -
+ + editControlBulletinField(newDateString, "userBirthDate") + } + /> setUserNationality(e.target.value), + value: userNationality, + name: "userNationality" + }} + required + > + {COUNTRIES.map(option => ( + + ))} + + + {/* TODO LIC PAPIER */} + + + + {type === CONTROL_TYPES.LIC_PAPIER && ( setDayPageFilled(true) + checked: isDayPageFilled === true, + onChange: () => setIsDayPageFilled(true) } }, { label: "Non", nativeInputProps: { - checked: dayPageFilled === false, - onChange: () => setDayPageFilled(false) + checked: isDayPageFilled === false, + onChange: () => setIsDayPageFilled(false) } } ]} required /> )} + - - + submitPreliminaryForm(), + children: "Créer le contrôle", + disabled: !canSubmitForm + }, + { + children: "Annuler", + onClick: () => onClose(), + priority: "secondary" + } + ]} + inlineLayoutWhen="sm and up" + alignment="right" + /> ); } From 813b6220816894ccf761e73ba4a2b25925215b6c Mon Sep 17 00:00:00 2001 From: Sandrine Ricardo Date: Wed, 13 Nov 2024 09:41:07 +0100 Subject: [PATCH 10/32] fix(control): remove warn changing an uncontrolled input to be controlled --- web/common/forms/BirthDate.js | 17 ++++++++++------- .../ControllerControlPreliminaryForm.js | 4 ++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/web/common/forms/BirthDate.js b/web/common/forms/BirthDate.js index d9380cff..117f9039 100644 --- a/web/common/forms/BirthDate.js +++ b/web/common/forms/BirthDate.js @@ -8,9 +8,9 @@ const BIRTH_DATE_MIN_YEAR = 100; const BIRTH_DATE_MAX_YEAR = 18; export function BirthDate({ label, userBirthDate, setUserBirthDate }) { - const [day, setDay] = React.useState(); - const [month, setMonth] = React.useState(); - const [year, setYear] = React.useState(); + const [day, setDay] = React.useState(""); + const [month, setMonth] = React.useState(""); + const [year, setYear] = React.useState(""); const [dayState, setDayState] = React.useState("default"); const [monthState, setMonthState] = React.useState("default"); @@ -38,26 +38,29 @@ export function BirthDate({ label, userBirthDate, setUserBirthDate }) { const onValidateBirthDate = () => { let hasError = false; - if (year < MIN_BIRTH_DATE_YEAR || year > MAX_BIRTH_DATE_YEAR) { + if ( + year !== "" && + (year < MIN_BIRTH_DATE_YEAR || year > MAX_BIRTH_DATE_YEAR) + ) { setYearState("error"); hasError = true; } else { setYearState("default"); } - if (month < 1 || month > 12) { + if (month !== "" && (month < 1 || month > 12)) { setMonthState("error"); hasError = true; } else { setMonthState("default"); } - if (day < 1 || day > 31) { + if (day !== "" && (day < 1 || day > 31)) { setDayState("error"); hasError = true; } else { setDayState("default"); } - if (!hasError && day && month && year) { + if (!hasError && day !== "" && month !== "" && year !== "") { const date = new Date(year, month - 1, day, 10, 0, 0, 0); const validYear = date.getFullYear() === parseInt(year); const validMonth = date.getMonth() === parseInt(month - 1); diff --git a/web/controller/components/noQRCode/ControllerControlPreliminaryForm.js b/web/controller/components/noQRCode/ControllerControlPreliminaryForm.js index 6f481546..bd64e89d 100644 --- a/web/controller/components/noQRCode/ControllerControlPreliminaryForm.js +++ b/web/controller/components/noQRCode/ControllerControlPreliminaryForm.js @@ -33,7 +33,7 @@ export function ControllerControlPreliminaryForm({ type, onSubmit, onClose }) { vehicleRegistrationNumber, setVehicleRegistrationNumber ] = React.useState(""); - const [isDayPageFilled, setIsDayPageFilled] = React.useState(); + const [isDayPageFilled, setIsDayPageFilled] = React.useState(null); const canSubmitForm = React.useMemo( () => @@ -182,7 +182,7 @@ export function ControllerControlPreliminaryForm({ type, onSubmit, onClose }) { { label: "Oui", nativeInputProps: { - checked: isDayPageFilled, + checked: isDayPageFilled === true, onChange: () => setIsDayPageFilled(true) } }, From 9d367f236f2c47ac1d2e598561691e0cfbeabac9 Mon Sep 17 00:00:00 2001 From: Sandrine Ricardo Date: Wed, 13 Nov 2024 09:53:24 +0100 Subject: [PATCH 11/32] fix: notice link to infractions tab is now accessible to keyboard --- .../noQRCode/noLic/ControllerControlNoLic.js | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/web/controller/components/noQRCode/noLic/ControllerControlNoLic.js b/web/controller/components/noQRCode/noLic/ControllerControlNoLic.js index ed8814fd..f683b570 100644 --- a/web/controller/components/noQRCode/noLic/ControllerControlNoLic.js +++ b/web/controller/components/noQRCode/noLic/ControllerControlNoLic.js @@ -16,7 +16,6 @@ import { ControllerControlBottomMenu as BottomMenu } from "../../menu/Controller import { canDownloadBDC } from "../../../utils/controlBulletin"; import { TextWithBadge } from "../../../../common/TextWithBadge"; import { UserReadAlerts } from "../../../../control/components/UserReadAlerts"; -import Typography from "@mui/material/Typography"; import Box from "@mui/material/Box"; import Notice from "../../../../common/Notice"; @@ -148,16 +147,22 @@ export function ControllerControlNoLic({ - - Mobilic a relevé des infractions par défaut, vous pouvez - modifier la sélection au sein de{" "} - setTab(TABS[1].name)} - > - l’onglet infractions - - + Mobilic a relevé des infractions par défaut, vous pouvez + modifier la sélection au sein de{" "} + setTab(TABS[1].name)} + onKeyDown={e => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + setTab(TABS[1].name); + } + }} + > + l’onglet infractions + } /> From 4399d6da84c41e2d82b286fac7422abba951ba7a Mon Sep 17 00:00:00 2001 From: Sandrine Ricardo Date: Wed, 13 Nov 2024 09:58:33 +0100 Subject: [PATCH 12/32] fix(control): only display infractions notice if there is at least one alert --- .../components/noQRCode/noLic/ControllerControlNoLic.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/web/controller/components/noQRCode/noLic/ControllerControlNoLic.js b/web/controller/components/noQRCode/noLic/ControllerControlNoLic.js index f683b570..23599859 100644 --- a/web/controller/components/noQRCode/noLic/ControllerControlNoLic.js +++ b/web/controller/components/noQRCode/noLic/ControllerControlNoLic.js @@ -112,8 +112,12 @@ export function ControllerControlNoLic({ }; const showModifyInfractionsAlert = useMemo(() => { - return !reportedInfractionsLastUpdateTime && tab !== TABS[1].name; - }, [reportedInfractionsLastUpdateTime, tab]); + return ( + !reportedInfractionsLastUpdateTime && + tab !== TABS[1].name && + totalAlertsNumber > 0 + ); + }, [reportedInfractionsLastUpdateTime, tab, totalAlertsNumber]); return ( <> From 95c2e3ef93dd6027394c1adf15fba35f54d65999 Mon Sep 17 00:00:00 2001 From: Sandrine Ricardo Date: Thu, 21 Nov 2024 13:21:29 +0100 Subject: [PATCH 13/32] refactor(control): use control type instead of no lic boolean --- web/control/components/UserReadAlerts.js | 16 +++++--- .../details/ControllerControlDrawer.js | 1 + .../noQRCode/noLic/ControllerControlNoLic.js | 38 ++----------------- .../noLic/ControllerControlNoLicDrawer.js | 2 + 4 files changed, 17 insertions(+), 40 deletions(-) diff --git a/web/control/components/UserReadAlerts.js b/web/control/components/UserReadAlerts.js index be262e73..196182e7 100644 --- a/web/control/components/UserReadAlerts.js +++ b/web/control/components/UserReadAlerts.js @@ -15,6 +15,8 @@ import { FieldTitle } from "../../common/typography/FieldTitle"; import { DisplayBusinessTypes } from "./Alerts/BusinessTypesFromGroupedAlerts"; import { getBusinessTypesFromGroupedAlerts } from "../utils/businessTypesFromGroupedAlerts"; import { Description } from "../../common/typography/Description"; +import { CONTROL_TYPES } from "../../controller/utils/useReadControlData"; + const useStyles = makeStyles(theme => ({ container: { paddingBottom: theme.spacing(4), @@ -63,7 +65,7 @@ export function UserReadAlerts({ onUpdateInfraction, reportedInfractionsLastUpdateTime, readOnlyAlerts, - noLic + controlType }) { const classes = useStyles(); @@ -74,14 +76,18 @@ export function UserReadAlerts({ return ( - {!noLic && } + {controlType === CONTROL_TYPES.MOBILIC && ( + + )} {isReportingInfractions && ( {totalAlertsNumber === 1 ? HELPER_TEXT_SINGLE_INFRACTION - : HELPER_TEXT_SEVERAL_INFRACTIONS} + : HELPER_TEXT_SEVERAL_INFRACTIONS + // TODO 835 update sentence + } )} {!isReportingInfractions && ( @@ -96,7 +102,7 @@ export function UserReadAlerts({ )}`} )} - {!noLic && ( + {controlType === CONTROL_TYPES.MOBILIC && ( <> Infractions calculées par Mobilic @@ -152,7 +158,7 @@ export function UserReadAlerts({ ) : ( - !noLic && ( + controlType === CONTROL_TYPES.MOBILIC && ( ({ middleTab: { @@ -89,6 +88,7 @@ const getTabs = alertNumber => [ ]; export function ControllerControlNoLic({ + controlType, controlData, editBDC, reportedInfractionsLastUpdateTime, @@ -113,14 +113,6 @@ export function ControllerControlNoLic({ setTab(TABS[1].name); }; - const showModifyInfractionsAlert = useMemo(() => { - return ( - !reportedInfractionsLastUpdateTime && - tab !== TABS[1].name && - totalAlertsNumber > 0 - ); - }, [reportedInfractionsLastUpdateTime, tab, totalAlertsNumber]); - return ( <> @@ -149,30 +141,6 @@ export function ControllerControlNoLic({ - {!!showModifyInfractionsAlert && ( - - Mobilic a relevé des infractions par défaut, vous pouvez - modifier la sélection au sein de{" "} - setTab(TABS[1].name)} - onKeyDown={e => { - if (e.key === "Enter" || e.key === " ") { - e.preventDefault(); - setTab(TABS[1].name); - } - }} - > - l’onglet infractions - - - } - /> - )} {TABS.map(t => ( { } diff --git a/web/controller/components/noQRCode/noLic/ControllerControlNoLicDrawer.js b/web/controller/components/noQRCode/noLic/ControllerControlNoLicDrawer.js index 12d3b2d9..af06d442 100644 --- a/web/controller/components/noQRCode/noLic/ControllerControlNoLicDrawer.js +++ b/web/controller/components/noQRCode/noLic/ControllerControlNoLicDrawer.js @@ -7,6 +7,7 @@ import { useReportInfractions } from "../../../utils/useReportInfractions"; import { canDownloadBDC } from "../../../utils/controlBulletin"; export function ControllerControlNoLicDrawer({ + controlType, controlData, setControlData, isOpen, @@ -64,6 +65,7 @@ export function ControllerControlNoLicDrawer({ enableExport={false} /> Date: Thu, 21 Nov 2024 13:22:03 +0100 Subject: [PATCH 14/32] feat(control): handle extra null in infractions --- web/control/components/RegulatoryAlert.js | 51 ++++++++++++----------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/web/control/components/RegulatoryAlert.js b/web/control/components/RegulatoryAlert.js index b65cc83e..eeffcdd4 100644 --- a/web/control/components/RegulatoryAlert.js +++ b/web/control/components/RegulatoryAlert.js @@ -47,25 +47,25 @@ export function formatAlertText(alert, type) { switch (type) { case ALERT_TYPES.minimumDailyRest: { const maxBreakLengthInSeconds = - alert.extra.breach_period_max_break_in_seconds; - return ( + alert.extra?.breach_period_max_break_in_seconds; + return maxBreakLengthInSeconds ? ( Durée de la plus longue période de repos consécutif effectuée entre le{" "} {formatDate(alert.extra.breach_period_start)} et le{" "} {formatDate(alert.extra.breach_period_end)} :{" "} {formatTimer(maxBreakLengthInSeconds)} - ); + ) : null; } case ALERT_TYPES.maximumWorkedDaysInWeek: { - const maxBreakLengthInSeconds = alert.extra.rest_duration_s; - const tooManyDays = alert.extra.too_many_days; - const restDurationText = ( + const maxBreakLengthInSeconds = alert.extra?.rest_duration_s; + const tooManyDays = alert.extra?.too_many_days; + const restDurationText = maxBreakLengthInSeconds ? ( <> Durée du repos hebdomadaire :{" "} {formatTimer(maxBreakLengthInSeconds)}. - ); + ) : null; const tooManyDaysText = ( <>La semaine ne comporte aucune journée non travaillée. ); @@ -99,20 +99,20 @@ export function formatAlertText(alert, type) { } case ALERT_TYPES.maximumUninterruptedWorkTime: { const uninterruptedWorkTime = - alert.extra.longest_uninterrupted_work_in_seconds; - return ( + alert.extra?.longest_uninterrupted_work_in_seconds; + return uninterruptedWorkTime ? ( Durée du temps de travail ininterrompu constaté :{" "} {formatTimer(uninterruptedWorkTime)} entre le{" "} {formatDate(alert.extra.longest_uninterrupted_work_start)} et le{" "} {formatDate(alert.extra.longest_uninterrupted_work_end)} - ); + ) : null; } case ALERT_TYPES.minimumWorkDayBreak: { - const breakTimeInSeconds = alert.extra.total_break_time_in_seconds; - const workTimeInSeconds = alert.extra.work_range_in_seconds; - return ( + const breakTimeInSeconds = alert.extra?.total_break_time_in_seconds; + const workTimeInSeconds = alert.extra?.work_range_in_seconds; + return breakTimeInSeconds && workTimeInSeconds ? ( Durée du temps de pause :{" "} {formatMinutesFromSeconds(breakTimeInSeconds)} pour une période @@ -120,12 +120,16 @@ export function formatAlertText(alert, type) { le {formatDate(alert.extra.work_range_start)} et le{" "} {formatDate(alert.extra.work_range_end)} - ); + ) : null; } case ALERT_TYPES.maximumWorkDayTime: { - const nightWork = alert.extra.night_work; - const workTime = alert.extra.work_range_in_seconds; - return ( + const { + nightWork, + work_range_in_seconds: workTime, + work_range_start, + work_range_end + } = alert.extra || {}; + return workTime && work_range_start && work_range_end ? ( Temps de travail total effectué entre le{" "} {formatDate(alert.extra.work_range_start)} et le{" "} @@ -134,22 +138,19 @@ export function formatAlertText(alert, type) { {" : "} {formatTimer(workTime)} - ); + ) : null; } case ALERT_TYPES.maximumWorkInCalendarWeek: { - const { - work_duration_in_seconds, - work_range_start, - work_range_end - } = alert.extra; - return ( + const { work_duration_in_seconds, work_range_start, work_range_end } = + alert.extra || {}; + return work_duration_in_seconds && work_range_start && work_range_end ? ( Temps de travail total effectué entre le{" "} {formatDate(work_range_start)} et le {formatDate(work_range_end)} :{" "} {formatTimer(work_duration_in_seconds)} - ); + ) : null; } default: return ; From ec24ef86393fb2955ea6db3b4fb85b654e0e5311 Mon Sep 17 00:00:00 2001 From: Sandrine Ricardo Date: Mon, 25 Nov 2024 13:10:28 +0100 Subject: [PATCH 15/32] feat(control): add control type and unit to infraction component --- common/utils/regulation/groupAlertsByDay.js | 2 + web/control/components/Alerts/AlertGroup.js | 121 ++++++++++++------ .../components/Alerts/InfractionDay.js | 10 ++ .../components/Alerts/InfractionWeek.js | 10 ++ web/control/components/UserReadAlerts.js | 5 +- .../ControlBulletinFormStep3.js | 2 + .../ControllerControlBulletin.js | 1 + .../noQRCode/ControllerControlNew.js | 4 +- web/controller/utils/useReadControlData.js | 3 +- 9 files changed, 115 insertions(+), 43 deletions(-) create mode 100644 web/control/components/Alerts/InfractionDay.js create mode 100644 web/control/components/Alerts/InfractionWeek.js diff --git a/common/utils/regulation/groupAlertsByDay.js b/common/utils/regulation/groupAlertsByDay.js index 976c7ef9..c9479d35 100644 --- a/common/utils/regulation/groupAlertsByDay.js +++ b/common/utils/regulation/groupAlertsByDay.js @@ -27,6 +27,7 @@ export const getAlertsGroupedByDay = observedInfractions => { }) => ({ ...(unit === PERIOD_UNITS.DAY && { day: date }), ...(unit === PERIOD_UNITS.WEEK && { week: date }), + unit, checked: isReported, reportable: isReportable, extra, @@ -62,6 +63,7 @@ export const getAlertsGroupedByDayFromRegulationComputationsByDay = regulationCo ...(breachedRegCheck.unit === PERIOD_UNITS.DAY && { day: timestamp }), + unit: breachedRegCheck.unit, extra, checked: false }; diff --git a/web/control/components/Alerts/AlertGroup.js b/web/control/components/Alerts/AlertGroup.js index e1efc3ea..41af5f97 100644 --- a/web/control/components/Alerts/AlertGroup.js +++ b/web/control/components/Alerts/AlertGroup.js @@ -12,6 +12,10 @@ import AccordionDetails from "@mui/material/AccordionDetails"; import { groupBy } from "lodash"; import { formatActivity } from "common/utils/businessTypes"; import { Description } from "../../../common/typography/Description"; +import { CONTROL_TYPES } from "../../../controller/utils/useReadControlData"; +import { InfractionDay } from "./InfractionDay"; +import { InfractionWeek } from "./InfractionWeek"; +import { PERIOD_UNITS } from "common/utils/regulation/periodUnitsEnum"; const useStyles = makeStyles(theme => { return { @@ -49,16 +53,23 @@ const useStyles = makeStyles(theme => { }); const getAlertsNumber = ( + controlType, alerts, isSanctionReportable, isReportingInfractions, readOnlyAlerts -) => - readOnlyAlerts || !isSanctionReportable - ? alerts.length - : isReportingInfractions - ? `${alerts.filter(alert => alert.checked).length} / ${alerts.length}` - : alerts.filter(alert => alert.checked).length; +) => { + if (readOnlyAlerts || !isSanctionReportable) { + return alerts.filter(alert => !!(alert.day || alert.week)).length; + } else if ( + isReportingInfractions && + controlType === CONTROL_TYPES.MOBILIC.label + ) { + return `${alerts.filter(alert => alert.checked).length} / ${alerts.length}`; + } else { + return alerts.filter(alert => alert.checked).length; + } +}; const isReportable = sanction => sanction.includes("NATINF"); @@ -70,6 +81,7 @@ const BusinessTypeTitle = ({ business }) => ( ); export function AlertGroup({ + controlType, alerts, infringementLabel, type, @@ -88,6 +100,7 @@ export function AlertGroup({ const isSanctionReportable = readOnlyAlerts ? true : isReportable(sanction); const alertsNumber = getAlertsNumber( + controlType, alerts, isSanctionReportable, isReportingInfractions, @@ -136,39 +149,69 @@ export function AlertGroup({
- {Object.entries(alertsGroupedByBusinessTypes).map( - ([businessId, alertsByBusiness]) => { - const firstAlert = alertsByBusiness[0]; - const { - description: alertDescription, - business: alertBusiness - } = firstAlert; - return ( - - {displayBusinessType && ( - - )} - {alertDescription} - - {alertsByBusiness.map((alert, index) => ( - - - - ))} - - - ); - } + {/* TODO refactor: extract in another component */} + {(controlType === CONTROL_TYPES.MOBILIC.label || + controlType === CONTROL_TYPES.NO_LIC.label) && + Object.entries(alertsGroupedByBusinessTypes).map( + ([businessId, alertsByBusiness]) => { + const firstAlert = alertsByBusiness[0]; + const { + description: alertDescription, + business: alertBusiness + } = firstAlert; + return ( + + {displayBusinessType && ( + + )} + {alertDescription} + + {alertsByBusiness.map((alert, index) => ( + + + + ))} + + + ); + } + )} + {controlType === CONTROL_TYPES.LIC_PAPIER.label && ( + <> + {alerts[0].description} + {alerts[0].unit === PERIOD_UNITS.DAY && ( + <> +

Sélectionnez la ou les journées concernées :

+ alert.day).filter(x => x)} + isReportingInfractions={isReportingInfractions} + onUpdateInfraction={onUpdateInfraction} + /> + + )} + {alerts[0].unit === PERIOD_UNITS.WEEK && ( + <> +

Sélectionnez la ou les semaines concernées :

+ alert.week).filter(x => x)} + isReportingInfractions={isReportingInfractions} + onUpdateInfraction={onUpdateInfraction} + /> + + )} + )}
diff --git a/web/control/components/Alerts/InfractionDay.js b/web/control/components/Alerts/InfractionDay.js new file mode 100644 index 00000000..6d1b55ea --- /dev/null +++ b/web/control/components/Alerts/InfractionDay.js @@ -0,0 +1,10 @@ +import React from "react"; + +export const InfractionDay = ({ + alert, + days, + isReportingInfractions, + onUpdateInfraction +}) => { + return
{JSON.stringify(days, null, 2)}
; +}; diff --git a/web/control/components/Alerts/InfractionWeek.js b/web/control/components/Alerts/InfractionWeek.js new file mode 100644 index 00000000..f4f601a6 --- /dev/null +++ b/web/control/components/Alerts/InfractionWeek.js @@ -0,0 +1,10 @@ +import React from "react"; + +export const InfractionWeek = ({ + alert, + weeks, + isReportingInfractions, + onUpdateInfraction +}) => { + return
{JSON.stringify(weeks, null, 2)}
; +}; diff --git a/web/control/components/UserReadAlerts.js b/web/control/components/UserReadAlerts.js index 196182e7..055f168d 100644 --- a/web/control/components/UserReadAlerts.js +++ b/web/control/components/UserReadAlerts.js @@ -76,7 +76,7 @@ export function UserReadAlerts({ return ( - {controlType === CONTROL_TYPES.MOBILIC && ( + {controlType === CONTROL_TYPES.MOBILIC.label && ( )} @@ -102,7 +102,7 @@ export function UserReadAlerts({ )}`} )} - {controlType === CONTROL_TYPES.MOBILIC && ( + {controlType === CONTROL_TYPES.MOBILIC.label && ( <> Infractions calculées par Mobilic @@ -123,6 +123,7 @@ export function UserReadAlerts({ > { From 57dbd20d1422bff016bc4a0a4a5e83e7b7b522c1 Mon Sep 17 00:00:00 2001 From: Sandrine Ricardo Date: Mon, 25 Nov 2024 14:21:47 +0100 Subject: [PATCH 16/32] feat(control): add blue border for reported infractions --- web/control/components/Alerts/AlertGroup.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/web/control/components/Alerts/AlertGroup.js b/web/control/components/Alerts/AlertGroup.js index 41af5f97..e7edac4d 100644 --- a/web/control/components/Alerts/AlertGroup.js +++ b/web/control/components/Alerts/AlertGroup.js @@ -16,6 +16,7 @@ import { CONTROL_TYPES } from "../../../controller/utils/useReadControlData"; import { InfractionDay } from "./InfractionDay"; import { InfractionWeek } from "./InfractionWeek"; import { PERIOD_UNITS } from "common/utils/regulation/periodUnitsEnum"; +import classNames from "classnames"; const useStyles = makeStyles(theme => { return { @@ -43,6 +44,10 @@ const useStyles = makeStyles(theme => { justifyContent: "center", fontWeight: "bold" }, + reportedAlert: { + borderColor: theme.palette.primary.main, + borderWidth: "2px" + }, reportableAlert: { backgroundColor: theme.palette.error.main }, @@ -99,6 +104,11 @@ export function AlertGroup({ const isSanctionReportable = readOnlyAlerts ? true : isReportable(sanction); + const isReported = React.useMemo( + () => alerts.filter(alert => alert.checked).length > 0, + [alerts] + ); + const alertsNumber = getAlertsNumber( controlType, alerts, @@ -117,7 +127,10 @@ export function AlertGroup({ expanded={open} onChange={(event, open_) => setOpen(open_)} variant="outlined" - className={classes.container} + className={classNames( + classes.container, + isReported ? classes.reportedAlert : "" + )} > }> {alertsNumber} From 782f45545689ff097b6f473426b86dc16facf5d2 Mon Sep 17 00:00:00 2001 From: Sandrine Ricardo Date: Tue, 26 Nov 2024 16:11:17 +0100 Subject: [PATCH 17/32] feat(control): add calendar to report day infractions --- package.json | 1 + web/control/components/Alerts/AlertGroup.js | 18 ++-- .../components/Alerts/InfractionDay.js | 99 ++++++++++++++++++- yarn.lock | 18 ++++ 4 files changed, 125 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 95d6bde1..7e0d8d89 100644 --- a/package.json +++ b/package.json @@ -85,6 +85,7 @@ "react-error-boundary": "^3.1.3", "react-minimal-pie-chart": "^8.2.0", "react-multi-carousel": "^2.8.2", + "react-multi-date-picker": "^4.5.2", "react-qr-reader": "^3.0.0-beta-1", "react-redux": "^7.2.0", "react-router-dom": "^5.3.3", diff --git a/web/control/components/Alerts/AlertGroup.js b/web/control/components/Alerts/AlertGroup.js index e7edac4d..0e7f9a38 100644 --- a/web/control/components/Alerts/AlertGroup.js +++ b/web/control/components/Alerts/AlertGroup.js @@ -16,6 +16,7 @@ import { CONTROL_TYPES } from "../../../controller/utils/useReadControlData"; import { InfractionDay } from "./InfractionDay"; import { InfractionWeek } from "./InfractionWeek"; import { PERIOD_UNITS } from "common/utils/regulation/periodUnitsEnum"; +import { unixToJSTimestamp } from "common/utils/time"; import classNames from "classnames"; const useStyles = makeStyles(theme => { @@ -204,15 +205,14 @@ export function AlertGroup({ <> {alerts[0].description} {alerts[0].unit === PERIOD_UNITS.DAY && ( - <> -

Sélectionnez la ou les journées concernées :

- alert.day).filter(x => x)} - isReportingInfractions={isReportingInfractions} - onUpdateInfraction={onUpdateInfraction} - /> - + unixToJSTimestamp(alert.day)) // TODO 835 convert in component + .filter(x => x)} + isReportingInfractions={isReportingInfractions} + onUpdateInfraction={onUpdateInfraction} + /> )} {alerts[0].unit === PERIOD_UNITS.WEEK && ( <> diff --git a/web/control/components/Alerts/InfractionDay.js b/web/control/components/Alerts/InfractionDay.js index 6d1b55ea..c3e779dd 100644 --- a/web/control/components/Alerts/InfractionDay.js +++ b/web/control/components/Alerts/InfractionDay.js @@ -1,4 +1,39 @@ -import React from "react"; +import React, { useState } from "react"; +import { Calendar } from "react-multi-date-picker"; +import { addDaysToDate, textualPrettyFormatDay } from "common/utils/time"; +import { Tag } from "@codegouvfr/react-dsfr/Tag"; + +const gregorian_fr = { + name: "gregorian_fr", + months: [ + ["Janvier", "Jan"], + ["Février", "Fév"], + ["Mars", "Mars"], + ["Avril", "Avr"], + ["Mai", "Mai"], + ["Juin", "Jun"], + ["Juillet", "Jul"], + ["Août", "Aou"], + ["Septembre", "Sep"], + ["Octobre", "Oct"], + ["Novembre", "Nov"], + ["Décembre", "Déc"] + ], + weekDays: [ + ["Samedi", "S"], + ["Dimanche", "D"], + ["Lundi", "L"], + ["Mardi", "M"], + ["Mercredi", "M"], + ["Jeudi", "J"], + ["Vendredi", "V"] + ], + digits: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], + meridiems: [ + ["AM", "am"], + ["PM", "pm"] + ] +}; export const InfractionDay = ({ alert, @@ -6,5 +41,65 @@ export const InfractionDay = ({ isReportingInfractions, onUpdateInfraction }) => { - return
{JSON.stringify(days, null, 2)}
; + const [values, setValues] = useState(days); // TODO 835 remove to use props instead + + const today = new Date(); + const minDate = addDaysToDate(new Date(), -28); + + const onSelectedDatesChange = values => { + console.log("onSelectedDatesChange = " + values); + setValues(values); + }; + + const onRemoveDate = v => { + console.log("onRemoveDate = " + v); + const copyValues = [...values]; + setValues(copyValues.filter(value => value !== v)); + }; + + return ( +
+ {isReportingInfractions && ( +

+ Sélectionnez la ou les journées concernées : +

+ )} + {isReportingInfractions && ( + // Documentation: https://shahabyazdi.github.io/react-multi-date-picker/ + + )} +
    + {values.map(date => ( +
  • + > 0, + true + )}` + }) + }} + > + {textualPrettyFormatDay((date / 1000) >> 0, true)} + +
  • + ))} +
+
+ ); }; diff --git a/yarn.lock b/yarn.lock index aa9305f2..6d84dc6c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12028,6 +12028,11 @@ react-clientside-effect@^1.2.6: dependencies: "@babel/runtime" "^7.12.13" +react-date-object@^2.1.8: + version "2.1.9" + resolved "https://registry.yarnpkg.com/react-date-object/-/react-date-object-2.1.9.tgz#9eb0f70b2b424e32bb437226fc5e435d1fd6a4f1" + integrity sha512-BHxD/quWOTo9fLKV/cfL/M31ePoj4a1JaJ/CnOf8Ndg3mrkh4x9wEMMkCfTrzduxDOgU8ZgR8uarhqI5G71sTg== + react-dev-utils@^12.0.0: version "12.0.1" resolved "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz" @@ -12075,6 +12080,11 @@ react-dropzone@^11.3.1: file-selector "^0.4.0" prop-types "^15.8.1" +react-element-popper@^2.1.6: + version "2.1.7" + resolved "https://registry.yarnpkg.com/react-element-popper/-/react-element-popper-2.1.7.tgz#924aac2dd8d8f0efa344987690fa462cab00e710" + integrity sha512-tuM2OxKlW32h+6uFSK6EENHPeZ2OGgOipHfOAl+VLWEv9/j3QkSGbD+ADX3A9uJlmq24i37n28RjJmAbGTfpEg== + react-error-boundary@^3.1.3: version "3.1.4" resolved "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz" @@ -12143,6 +12153,14 @@ react-multi-carousel@^2.8.2: resolved "https://registry.npmjs.org/react-multi-carousel/-/react-multi-carousel-2.8.2.tgz" integrity sha512-M9Y7DfAp8bA/r6yexttU6RLA7uyppje4c0ELRuCHZWswH+u7nr0uVP6qHNPjc4XGOEY1MYFOb5nBg7JvoKutuQ== +react-multi-date-picker@^4.5.2: + version "4.5.2" + resolved "https://registry.yarnpkg.com/react-multi-date-picker/-/react-multi-date-picker-4.5.2.tgz#d618c0d682efd2eb99c12eee3012f61368e2b427" + integrity sha512-FgWjZB3Z6IA6XpcWiLPk85PwcRUhOiYhKK42o5k672gD/n2I6rzPfQ8bUrldOIiF/Z7FfOCdH7a6FeubzqteLg== + dependencies: + react-date-object "^2.1.8" + react-element-popper "^2.1.6" + react-qr-reader@^3.0.0-beta-1: version "3.0.0-beta-1" resolved "https://registry.npmjs.org/react-qr-reader/-/react-qr-reader-3.0.0-beta-1.tgz" From ae103217cdf3aa80fd9e8fd5f0e886cbede45577 Mon Sep 17 00:00:00 2001 From: Tristan Gueguen Date: Tue, 26 Nov 2024 19:32:04 +0100 Subject: [PATCH 18/32] fix(calendar): center, box-shadow, border --- web/control/components/Alerts/InfractionDay.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/web/control/components/Alerts/InfractionDay.js b/web/control/components/Alerts/InfractionDay.js index c3e779dd..aba1b2bf 100644 --- a/web/control/components/Alerts/InfractionDay.js +++ b/web/control/components/Alerts/InfractionDay.js @@ -2,6 +2,8 @@ import React, { useState } from "react"; import { Calendar } from "react-multi-date-picker"; import { addDaysToDate, textualPrettyFormatDay } from "common/utils/time"; import { Tag } from "@codegouvfr/react-dsfr/Tag"; +import { makeStyles } from "@mui/styles"; +import { fr } from "@codegouvfr/react-dsfr"; const gregorian_fr = { name: "gregorian_fr", @@ -35,12 +37,23 @@ const gregorian_fr = { ] }; +const useStyles = makeStyles(theme => ({ + calendar: { + margin: "auto", + border: "1px solid", + borderColor: fr.colors.decisions.background.disabled.grey.default, + borderRadius: "0px", + boxShadow: "none" + } +})); + export const InfractionDay = ({ alert, days, isReportingInfractions, onUpdateInfraction }) => { + const classes = useStyles(); const [values, setValues] = useState(days); // TODO 835 remove to use props instead const today = new Date(); @@ -67,6 +80,7 @@ export const InfractionDay = ({ {isReportingInfractions && ( // Documentation: https://shahabyazdi.github.io/react-multi-date-picker/ Date: Tue, 26 Nov 2024 21:51:35 +0100 Subject: [PATCH 19/32] feat(lic-papier): can add and remove infractions from calendar --- web/control/components/Alerts/AlertGroup.js | 12 +-- .../components/Alerts/InfractionDay.js | 81 ++++++++++++------- web/control/components/UserReadAlerts.js | 4 + .../noQRCode/noLic/ControllerControlNoLic.js | 6 +- .../noLic/ControllerControlNoLicDrawer.js | 6 +- web/controller/utils/useReportInfractions.js | 59 +++++++++++++- 6 files changed, 128 insertions(+), 40 deletions(-) diff --git a/web/control/components/Alerts/AlertGroup.js b/web/control/components/Alerts/AlertGroup.js index 0e7f9a38..9d216d7d 100644 --- a/web/control/components/Alerts/AlertGroup.js +++ b/web/control/components/Alerts/AlertGroup.js @@ -16,7 +16,6 @@ import { CONTROL_TYPES } from "../../../controller/utils/useReadControlData"; import { InfractionDay } from "./InfractionDay"; import { InfractionWeek } from "./InfractionWeek"; import { PERIOD_UNITS } from "common/utils/regulation/periodUnitsEnum"; -import { unixToJSTimestamp } from "common/utils/time"; import classNames from "classnames"; const useStyles = makeStyles(theme => { @@ -96,6 +95,8 @@ export function AlertGroup({ setTab, isReportingInfractions, onUpdateInfraction, + onAddInfraction, + onRemoveInfraction, readOnlyAlerts, displayBusinessType = false, titleProps = {} @@ -206,12 +207,11 @@ export function AlertGroup({ {alerts[0].description} {alerts[0].unit === PERIOD_UNITS.DAY && ( unixToJSTimestamp(alert.day)) // TODO 835 convert in component - .filter(x => x)} + alerts={alerts} isReportingInfractions={isReportingInfractions} - onUpdateInfraction={onUpdateInfraction} + onAddInfraction={onAddInfraction} + onRemoveInfraction={onRemoveInfraction} + sanction={sanction} /> )} {alerts[0].unit === PERIOD_UNITS.WEEK && ( diff --git a/web/control/components/Alerts/InfractionDay.js b/web/control/components/Alerts/InfractionDay.js index aba1b2bf..142e49b2 100644 --- a/web/control/components/Alerts/InfractionDay.js +++ b/web/control/components/Alerts/InfractionDay.js @@ -1,6 +1,10 @@ -import React, { useState } from "react"; +import React, { useMemo } from "react"; import { Calendar } from "react-multi-date-picker"; -import { addDaysToDate, textualPrettyFormatDay } from "common/utils/time"; +import { + addDaysToDate, + textualPrettyFormatDay, + unixToJSTimestamp +} from "common/utils/time"; import { Tag } from "@codegouvfr/react-dsfr/Tag"; import { makeStyles } from "@mui/styles"; import { fr } from "@codegouvfr/react-dsfr"; @@ -48,26 +52,42 @@ const useStyles = makeStyles(theme => ({ })); export const InfractionDay = ({ - alert, - days, + alerts, isReportingInfractions, - onUpdateInfraction + onAddInfraction, + onRemoveInfraction, + sanction }) => { const classes = useStyles(); - const [values, setValues] = useState(days); // TODO 835 remove to use props instead + + const initialDays = useMemo( + () => alerts.map(alert => alert.day).filter(x => !!x), + [alerts] + ); + + const initialTimestamps = useMemo(() => initialDays.map(unixToJSTimestamp), [ + initialDays + ]); const today = new Date(); const minDate = addDaysToDate(new Date(), -28); const onSelectedDatesChange = values => { - console.log("onSelectedDatesChange = " + values); - setValues(values); + const newTimestamps = values + .map(dateString => { + const parsedDate = new Date(dateString); + return parsedDate.getTime(); + }) + .map(date => (date / 1000) >> 0) + .filter(ts => !initialDays.includes(ts)); + + for (const newTimestamp of newTimestamps) { + onAddInfraction(sanction, newTimestamp); + } }; - const onRemoveDate = v => { - console.log("onRemoveDate = " + v); - const copyValues = [...values]; - setValues(copyValues.filter(value => value !== v)); + const onRemoveDate = timestamp => { + onRemoveInfraction(sanction, timestamp); }; return ( @@ -81,7 +101,7 @@ export const InfractionDay = ({ // Documentation: https://shahabyazdi.github.io/react-multi-date-picker/ )}
    - {values.map(date => ( -
  • - > 0, - true - )}` - }) - }} - > - {textualPrettyFormatDay((date / 1000) >> 0, true)} - -
  • - ))} + {initialTimestamps + .map(ts => (ts / 1000) >> 0) + .map(ts => ( +
  • + onRemoveDate(ts), + "aria-label": `Retirer ${textualPrettyFormatDay(ts, true)}` + }) + }} + > + {textualPrettyFormatDay(ts, true)} + +
  • + ))}
); diff --git a/web/control/components/UserReadAlerts.js b/web/control/components/UserReadAlerts.js index 055f168d..f7e4c093 100644 --- a/web/control/components/UserReadAlerts.js +++ b/web/control/components/UserReadAlerts.js @@ -63,6 +63,8 @@ export function UserReadAlerts({ saveInfractions, cancelInfractions, onUpdateInfraction, + onAddInfraction, + onRemoveInfraction, reportedInfractionsLastUpdateTime, readOnlyAlerts, controlType @@ -128,6 +130,8 @@ export function UserReadAlerts({ setTab={setTab} isReportingInfractions={isReportingInfractions} onUpdateInfraction={onUpdateInfraction} + onAddInfraction={onAddInfraction} + onRemoveInfraction={onRemoveInfraction} readOnlyAlerts={readOnlyAlerts} titleProps={{ component: "h3" }} displayBusinessType={ diff --git a/web/controller/components/noQRCode/noLic/ControllerControlNoLic.js b/web/controller/components/noQRCode/noLic/ControllerControlNoLic.js index 01828ca2..478a6a9e 100644 --- a/web/controller/components/noQRCode/noLic/ControllerControlNoLic.js +++ b/web/controller/components/noQRCode/noLic/ControllerControlNoLic.js @@ -100,7 +100,9 @@ export function ControllerControlNoLic({ hasModifiedInfractions, saveInfractions, cancelInfractions, - onUpdateInfraction + onUpdateInfraction, + onAddInfraction, + onRemoveInfraction }) { const classes = useStyles(); const downloadBDC = useDownloadBDC(controlData.id); @@ -160,6 +162,8 @@ export function ControllerControlNoLic({ saveInfractions={saveInfractions} cancelInfractions={cancelInfractions} onUpdateInfraction={onUpdateInfraction} + onAddInfraction={onAddInfraction} + onRemoveInfraction={onRemoveInfraction} hasModifiedInfractions={hasModifiedInfractions} readOnlyAlerts={false} /> diff --git a/web/controller/components/noQRCode/noLic/ControllerControlNoLicDrawer.js b/web/controller/components/noQRCode/noLic/ControllerControlNoLicDrawer.js index af06d442..b1ce8d29 100644 --- a/web/controller/components/noQRCode/noLic/ControllerControlNoLicDrawer.js +++ b/web/controller/components/noQRCode/noLic/ControllerControlNoLicDrawer.js @@ -34,7 +34,9 @@ export function ControllerControlNoLicDrawer({ hasModifiedInfractions, saveInfractions, cancelInfractions, - onUpdateInfraction + onUpdateInfraction, + onAddInfraction, + onRemoveInfraction ] = useReportInfractions(controlData); return ( { setHasModifiedInfractions(true); }; + const onAddInfraction = (sanction, date) => { + let hasInsertedNewOne = false; + setObservedInfractions(currentObservedInfractions => + currentObservedInfractions.flatMap(infraction => { + if (infraction.sanction !== sanction) { + return [infraction]; + } + if (!infraction.date) { + return [{ ...infraction, date }]; + } + if (!hasInsertedNewOne) { + hasInsertedNewOne = true; + return [ + infraction, + { + ...infraction, + date + } + ]; + } else { + return [infraction]; + } + }) + ); + setHasModifiedInfractions(true); + }; + + const onRemoveInfraction = (sanction, date) => { + const isOnlyOne = + observedInfractions.filter(infraction => infraction.sanction === sanction) + .length === 1; + setObservedInfractions(currentObservedInfractions => + currentObservedInfractions.flatMap(infraction => { + if (infraction.sanction !== sanction) { + return [infraction]; + } + if (isOnlyOne) { + return [ + { + ...infraction, + date: null + } + ]; + } else { + if (infraction.date === date) { + return []; + } else { + return [infraction]; + } + } + }) + ); + setHasModifiedInfractions(true); + }; + const checkedAlertsNumber = React.useMemo( () => groupedAlerts @@ -153,6 +208,8 @@ export const useReportInfractions = controlData => { hasModifiedInfractions, saveInfractions, cancelInfractions, - onUpdateInfraction + onUpdateInfraction, + onAddInfraction, + onRemoveInfraction ]; }; From b3192815207c0c56397aa1e017db6aa623673bda Mon Sep 17 00:00:00 2001 From: Tristan Gueguen Date: Wed, 27 Nov 2024 14:48:31 +0100 Subject: [PATCH 20/32] feat(lic-papier): weekly alerts working, need refacto --- web/control/components/Alerts/AlertGroup.js | 8 +-- .../components/Alerts/InfractionDay.js | 5 +- .../components/Alerts/InfractionWeek.js | 65 +++++++++++++++++-- web/controller/utils/useReportInfractions.js | 14 ++-- 4 files changed, 76 insertions(+), 16 deletions(-) diff --git a/web/control/components/Alerts/AlertGroup.js b/web/control/components/Alerts/AlertGroup.js index 9d216d7d..c90587fa 100644 --- a/web/control/components/Alerts/AlertGroup.js +++ b/web/control/components/Alerts/AlertGroup.js @@ -216,12 +216,12 @@ export function AlertGroup({ )} {alerts[0].unit === PERIOD_UNITS.WEEK && ( <> -

Sélectionnez la ou les semaines concernées :

alert.week).filter(x => x)} + alerts={alerts} isReportingInfractions={isReportingInfractions} - onUpdateInfraction={onUpdateInfraction} + onAddInfraction={onAddInfraction} + onRemoveInfraction={onRemoveInfraction} + sanction={sanction} /> )} diff --git a/web/control/components/Alerts/InfractionDay.js b/web/control/components/Alerts/InfractionDay.js index 142e49b2..f6a133d5 100644 --- a/web/control/components/Alerts/InfractionDay.js +++ b/web/control/components/Alerts/InfractionDay.js @@ -8,6 +8,7 @@ import { import { Tag } from "@codegouvfr/react-dsfr/Tag"; import { makeStyles } from "@mui/styles"; import { fr } from "@codegouvfr/react-dsfr"; +import Stack from "@mui/material/Stack"; const gregorian_fr = { name: "gregorian_fr", @@ -91,7 +92,7 @@ export const InfractionDay = ({ }; return ( -
+ {isReportingInfractions && (

Sélectionnez la ou les journées concernées : @@ -133,6 +134,6 @@ export const InfractionDay = ({ ))} -

+ ); }; diff --git a/web/control/components/Alerts/InfractionWeek.js b/web/control/components/Alerts/InfractionWeek.js index f4f601a6..77d80e79 100644 --- a/web/control/components/Alerts/InfractionWeek.js +++ b/web/control/components/Alerts/InfractionWeek.js @@ -1,10 +1,65 @@ -import React from "react"; +import React, { useMemo } from "react"; +import Stack from "@mui/material/Stack"; +import { Checkbox } from "@codegouvfr/react-dsfr/Checkbox"; +import { startOfDay, textualPrettyFormatWeek } from "common/utils/time"; + +const getLastFourMondays = () => { + const mondays = []; + const today = new Date(); + let date = new Date(today); + + while (mondays.length < 4) { + if (date.getDay() === 1) { + mondays.push(new Date(date)); + } + date.setDate(date.getDate() - 1); + } + return mondays.map(startOfDay); +}; export const InfractionWeek = ({ - alert, - weeks, + alerts, + onAddInfraction, + onRemoveInfraction, isReportingInfractions, - onUpdateInfraction + sanction }) => { - return
{JSON.stringify(weeks, null, 2)}
; + const initialWeeks = useMemo( + () => alerts.map(alert => alert.week).filter(x => !!x), + [alerts] + ); + + const toggleInfraction = (date, checked) => { + if (checked) { + onAddInfraction(sanction, date); + } else { + onRemoveInfraction(sanction, date); + } + }; + return ( + + {isReportingInfractions && ( +

+ Sélectionnez la ou les semaines concernées : +

+ )} + {getLastFourMondays().map(monday => ( + toggleInfraction(monday, e.target.checked) + } + } + ]} + disabled={!isReportingInfractions} + /> + ))} +
+ ); }; diff --git a/web/controller/utils/useReportInfractions.js b/web/controller/utils/useReportInfractions.js index e932878c..42702ef8 100644 --- a/web/controller/utils/useReportInfractions.js +++ b/web/controller/utils/useReportInfractions.js @@ -50,9 +50,11 @@ export const useReportInfractions = controlData => { controlId: controlData?.id, reportedInfractions: observedInfractions .filter(infraction => infraction.isReported) - .map(({ date, sanction }) => ({ + .map(({ date, sanction, unit, type }) => ({ date, - sanction + sanction, + unit, + type })) }, { context: { nonPublicApi: true } } @@ -126,7 +128,7 @@ export const useReportInfractions = controlData => { return [infraction]; } if (!infraction.date) { - return [{ ...infraction, date }]; + return [{ ...infraction, date, isReported: true }]; } if (!hasInsertedNewOne) { hasInsertedNewOne = true; @@ -134,7 +136,8 @@ export const useReportInfractions = controlData => { infraction, { ...infraction, - date + date, + isReported: true } ]; } else { @@ -158,7 +161,8 @@ export const useReportInfractions = controlData => { return [ { ...infraction, - date: null + date: null, + isReported: false } ]; } else { From c9576469f017b6cc87a0bbe77862ece954a734be Mon Sep 17 00:00:00 2001 From: Tristan Gueguen Date: Wed, 27 Nov 2024 20:23:00 +0100 Subject: [PATCH 21/32] refacto(lic-papier): using a context instead of passing a lot of props to children components --- web/control/components/Alerts/AlertGroup.js | 24 +--- .../components/Alerts/InfractionDay.js | 14 +-- .../components/Alerts/InfractionWeek.js | 14 +-- web/control/components/RegulatoryAlert.js | 4 +- web/control/components/UserReadAlerts.js | 22 ++-- .../controlBulletin/ControlBulletinDrawer.js | 10 +- .../ControlBulletinFormStep3.js | 3 +- .../ControllerControlBulletin.js | 7 +- .../details/ControllerControlDetails.js | 115 ++++++++---------- .../details/ControllerControlDrawer.js | 44 +++---- .../menu/ControllerControlBottomMenu.js | 5 +- .../noQRCode/noLic/ControllerControlNoLic.js | 36 ++---- .../noLic/ControllerControlNoLicDrawer.js | 31 ----- web/controller/utils/contextInfractions.js | 16 +++ web/controller/utils/useReportInfractions.js | 4 +- 15 files changed, 140 insertions(+), 209 deletions(-) create mode 100644 web/controller/utils/contextInfractions.js diff --git a/web/control/components/Alerts/AlertGroup.js b/web/control/components/Alerts/AlertGroup.js index c90587fa..14b615e6 100644 --- a/web/control/components/Alerts/AlertGroup.js +++ b/web/control/components/Alerts/AlertGroup.js @@ -17,6 +17,7 @@ import { InfractionDay } from "./InfractionDay"; import { InfractionWeek } from "./InfractionWeek"; import { PERIOD_UNITS } from "common/utils/regulation/periodUnitsEnum"; import classNames from "classnames"; +import { useInfractions } from "../../../controller/utils/contextInfractions"; const useStyles = makeStyles(theme => { return { @@ -93,16 +94,13 @@ export function AlertGroup({ sanction, setPeriodOnFocus, setTab, - isReportingInfractions, - onUpdateInfraction, - onAddInfraction, - onRemoveInfraction, readOnlyAlerts, displayBusinessType = false, titleProps = {} }) { const [open, setOpen] = React.useState(false); const classes = useStyles(); + const { isReportingInfractions } = useInfractions(); const isSanctionReportable = readOnlyAlerts ? true : isReportable(sanction); @@ -191,8 +189,6 @@ export function AlertGroup({ isReportable={isSanctionReportable} setPeriodOnFocus={setPeriodOnFocus} setTab={setTab} - isReportingInfractions={isReportingInfractions} - onUpdateInfraction={onUpdateInfraction} readOnlyAlerts={readOnlyAlerts} /> @@ -206,23 +202,11 @@ export function AlertGroup({ <> {alerts[0].description} {alerts[0].unit === PERIOD_UNITS.DAY && ( - + )} {alerts[0].unit === PERIOD_UNITS.WEEK && ( <> - + )} diff --git a/web/control/components/Alerts/InfractionDay.js b/web/control/components/Alerts/InfractionDay.js index f6a133d5..04d52de7 100644 --- a/web/control/components/Alerts/InfractionDay.js +++ b/web/control/components/Alerts/InfractionDay.js @@ -9,6 +9,7 @@ import { Tag } from "@codegouvfr/react-dsfr/Tag"; import { makeStyles } from "@mui/styles"; import { fr } from "@codegouvfr/react-dsfr"; import Stack from "@mui/material/Stack"; +import { useInfractions } from "../../../controller/utils/contextInfractions"; const gregorian_fr = { name: "gregorian_fr", @@ -52,14 +53,13 @@ const useStyles = makeStyles(theme => ({ } })); -export const InfractionDay = ({ - alerts, - isReportingInfractions, - onAddInfraction, - onRemoveInfraction, - sanction -}) => { +export const InfractionDay = ({ alerts, sanction }) => { const classes = useStyles(); + const { + isReportingInfractions, + onAddInfraction, + onRemoveInfraction + } = useInfractions(); const initialDays = useMemo( () => alerts.map(alert => alert.day).filter(x => !!x), diff --git a/web/control/components/Alerts/InfractionWeek.js b/web/control/components/Alerts/InfractionWeek.js index 77d80e79..6ca7bb28 100644 --- a/web/control/components/Alerts/InfractionWeek.js +++ b/web/control/components/Alerts/InfractionWeek.js @@ -2,6 +2,7 @@ import React, { useMemo } from "react"; import Stack from "@mui/material/Stack"; import { Checkbox } from "@codegouvfr/react-dsfr/Checkbox"; import { startOfDay, textualPrettyFormatWeek } from "common/utils/time"; +import { useInfractions } from "../../../controller/utils/contextInfractions"; const getLastFourMondays = () => { const mondays = []; @@ -17,13 +18,12 @@ const getLastFourMondays = () => { return mondays.map(startOfDay); }; -export const InfractionWeek = ({ - alerts, - onAddInfraction, - onRemoveInfraction, - isReportingInfractions, - sanction -}) => { +export const InfractionWeek = ({ alerts, sanction }) => { + const { + isReportingInfractions, + onAddInfraction, + onRemoveInfraction + } = useInfractions(); const initialWeeks = useMemo( () => alerts.map(alert => alert.week).filter(x => !!x), [alerts] diff --git a/web/control/components/RegulatoryAlert.js b/web/control/components/RegulatoryAlert.js index eeffcdd4..f0d682ce 100644 --- a/web/control/components/RegulatoryAlert.js +++ b/web/control/components/RegulatoryAlert.js @@ -14,6 +14,7 @@ import { Link } from "../../common/LinkButton"; import { ALERT_TYPES } from "common/utils/regulation/alertTypes"; import Stack from "@mui/material/Stack"; import { Checkbox } from "@codegouvfr/react-dsfr/Checkbox"; +import { useInfractions } from "../../controller/utils/contextInfractions"; const formatDate = timestamp => { const date = new Date(timestamp); @@ -164,10 +165,9 @@ export function RegulatoryAlert({ isReportable, setPeriodOnFocus, setTab, - isReportingInfractions, - onUpdateInfraction, readOnlyAlerts }) { + const { isReportingInfractions, onUpdateInfraction } = useInfractions(); return ( {!readOnlyAlerts && isReportable && ( diff --git a/web/control/components/UserReadAlerts.js b/web/control/components/UserReadAlerts.js index f7e4c093..3593320c 100644 --- a/web/control/components/UserReadAlerts.js +++ b/web/control/components/UserReadAlerts.js @@ -16,6 +16,7 @@ import { DisplayBusinessTypes } from "./Alerts/BusinessTypesFromGroupedAlerts"; import { getBusinessTypesFromGroupedAlerts } from "../utils/businessTypesFromGroupedAlerts"; import { Description } from "../../common/typography/Description"; import { CONTROL_TYPES } from "../../controller/utils/useReadControlData"; +import { useInfractions } from "../../controller/utils/contextInfractions"; const useStyles = makeStyles(theme => ({ container: { @@ -56,20 +57,19 @@ export const WarningComputedAlerts = () => ( export function UserReadAlerts({ setTab, - groupedAlerts, - totalAlertsNumber, setPeriodOnFocus, - isReportingInfractions, - saveInfractions, - cancelInfractions, - onUpdateInfraction, - onAddInfraction, - onRemoveInfraction, - reportedInfractionsLastUpdateTime, readOnlyAlerts, controlType }) { const classes = useStyles(); + const { + groupedAlerts, + isReportingInfractions, + totalAlertsNumber, + reportedInfractionsLastUpdateTime, + saveInfractions, + cancelInfractions + } = useInfractions(); const businessTypes = React.useMemo( () => getBusinessTypesFromGroupedAlerts(groupedAlerts), @@ -128,10 +128,6 @@ export function UserReadAlerts({ controlType={controlType} setPeriodOnFocus={setPeriodOnFocus} setTab={setTab} - isReportingInfractions={isReportingInfractions} - onUpdateInfraction={onUpdateInfraction} - onAddInfraction={onAddInfraction} - onRemoveInfraction={onRemoveInfraction} readOnlyAlerts={readOnlyAlerts} titleProps={{ component: "h3" }} displayBusinessType={ diff --git a/web/controller/components/controlBulletin/ControlBulletinDrawer.js b/web/controller/components/controlBulletin/ControlBulletinDrawer.js index 0eed97a3..12dfca7a 100644 --- a/web/controller/components/controlBulletin/ControlBulletinDrawer.js +++ b/web/controller/components/controlBulletin/ControlBulletinDrawer.js @@ -4,6 +4,7 @@ import { makeStyles } from "@mui/styles"; import { ControllerControlBulletin } from "./ControllerControlBulletin"; import Box from "@mui/material/Box"; import { useModals } from "common/utils/modals"; +import { useInfractions } from "../../utils/contextInfractions"; const useStyles = makeStyles(theme => ({ missionDrawer: { @@ -16,13 +17,10 @@ export function ControlBulletinDrawer({ isOpen, onClose, controlData, - onSaveControlBulletin, - groupedAlerts, - saveInfractions, - onUpdateInfraction, - cancelInfractions + onSaveControlBulletin }) { const classes = useStyles(); + const { cancelInfractions, saveInfractions } = useInfractions(); const [mustConfirmBeforeClosing, setMustConfirmBeforeClosing] = useState( false ); @@ -65,9 +63,7 @@ export function ControlBulletinDrawer({ controlData={controlData} setMustConfirmBeforeClosing={setMustConfirmBeforeClosing} onSaveControlBulletin={onSaveControlBulletin} - groupedAlerts={groupedAlerts} saveInfractions={() => saveInfractions({ showSuccessMessage: false })} - onUpdateInfraction={onUpdateInfraction} /> diff --git a/web/controller/components/controlBulletin/ControlBulletinFormStep3.js b/web/controller/components/controlBulletin/ControlBulletinFormStep3.js index a0cfb34d..e10d317a 100644 --- a/web/controller/components/controlBulletin/ControlBulletinFormStep3.js +++ b/web/controller/components/controlBulletin/ControlBulletinFormStep3.js @@ -7,6 +7,7 @@ import ListItem from "@mui/material/ListItem"; import { AlertGroup } from "../../../control/components/Alerts/AlertGroup"; import { Input } from "../../../common/forms/Input"; import Notice from "../../../common/Notice"; +import { useInfractions } from "../../utils/contextInfractions"; export function ControlBulletinFormStep3({ controlType, @@ -15,9 +16,9 @@ export function ControlBulletinFormStep3({ grecoId, onUpdateGrecoId, controlCanBeDownloaded, - groupedAlerts, onUpdateInfraction }) { + const { groupedAlerts } = useInfractions(); return ( )} , - setIsEditingBC(true)} - controlData={controlData} - reportedInfractionsLastUpdateTime={reportedInfractionsLastUpdateTime} - isReportingInfractions={isReportingInfractions} - setIsReportingInfractions={setIsReportingInfractions} - groupedAlerts={groupedAlerts} - saveInfractions={saveInfractions} - cancelInfractions={cancelInfractions} - onUpdateInfraction={onUpdateInfraction} - hasModifiedInfractions={hasModifiedInfractions} - readOnlyAlerts={false} - />, - setIsEditingBC(false)} - controlData={controlData} - onSaveControlBulletin={newControlData => - setControlData(prevControlData => ({ - ...prevControlData, - ...newControlData - })) - } - groupedAlerts={groupedAlerts} - saveInfractions={saveInfractions} - onUpdateInfraction={onUpdateInfraction} - cancelInfractions={cancelInfractions} - /> - ]; + return ( + <> + + setIsEditingBC(true)} + controlData={controlData} + reportedInfractionsLastUpdateTime={reportedInfractionsLastUpdateTime} + isReportingInfractions={isReportingInfractions} + setIsReportingInfractions={setIsReportingInfractions} + groupedAlerts={groupedAlerts} + readOnlyAlerts={false} + /> + setIsEditingBC(false)} + controlData={controlData} + onSaveControlBulletin={newControlData => + setControlData(prevControlData => ({ + ...prevControlData, + ...newControlData + })) + } + /> + + ); } diff --git a/web/controller/components/details/ControllerControlDrawer.js b/web/controller/components/details/ControllerControlDrawer.js index 2c457545..572e7594 100644 --- a/web/controller/components/details/ControllerControlDrawer.js +++ b/web/controller/components/details/ControllerControlDrawer.js @@ -6,6 +6,7 @@ import { } from "../../utils/useReadControlData"; import { ControllerControlNoLicDrawer } from "../noQRCode/noLic/ControllerControlNoLicDrawer"; import { ControlDrawer } from "../../utils/ControlDrawer"; +import { InfractionsProvider } from "../../utils/contextInfractions"; export function ControllerControlDrawer({ controlId, controlType, onClose }) { const [controlData, setControlData] = useReadControlData( @@ -16,29 +17,30 @@ export function ControllerControlDrawer({ controlId, controlType, onClose }) { if (!controlData) { return null; } - if (controlType === CONTROL_TYPES.MOBILIC) { - return ( - - + {controlType === CONTROL_TYPES.MOBILIC ? ( + + + + ) : ( + - - ); - } else { - return ( - - ); - } + )} + + ); } diff --git a/web/controller/components/menu/ControllerControlBottomMenu.js b/web/controller/components/menu/ControllerControlBottomMenu.js index 1c3572da..c74eeed2 100644 --- a/web/controller/components/menu/ControllerControlBottomMenu.js +++ b/web/controller/components/menu/ControllerControlBottomMenu.js @@ -2,6 +2,7 @@ import React from "react"; import { makeStyles } from "@mui/styles"; import { ButtonsGroup } from "@codegouvfr/react-dsfr/ButtonsGroup"; import { Box } from "@mui/material"; +import { useInfractions } from "../../utils/contextInfractions"; const useStyles = makeStyles(theme => ({ textButton: { @@ -16,10 +17,10 @@ export function ControllerControlBottomMenu({ editBDC, downloadBDC, canDownloadBDC, - bdcAlreadyExisting, - totalAlertsNumber + bdcAlreadyExisting }) { const classes = useStyles(); + const { totalAlertsNumber } = useInfractions(); return ( diff --git a/web/controller/components/noQRCode/noLic/ControllerControlNoLic.js b/web/controller/components/noQRCode/noLic/ControllerControlNoLic.js index 478a6a9e..ec9bd58e 100644 --- a/web/controller/components/noQRCode/noLic/ControllerControlNoLic.js +++ b/web/controller/components/noQRCode/noLic/ControllerControlNoLic.js @@ -17,6 +17,7 @@ import { canDownloadBDC } from "../../../utils/controlBulletin"; import { TextWithBadge } from "../../../../common/TextWithBadge"; import { UserReadAlerts } from "../../../../control/components/UserReadAlerts"; import Box from "@mui/material/Box"; +import { useInfractions } from "../../../utils/contextInfractions"; const useStyles = makeStyles(theme => ({ middleTab: { @@ -87,25 +88,15 @@ const getTabs = alertNumber => [ } ]; -export function ControllerControlNoLic({ - controlType, - controlData, - editBDC, - reportedInfractionsLastUpdateTime, - groupedAlerts, - checkedAlertsNumber, - totalAlertsNumber, - isReportingInfractions, - setIsReportingInfractions, - hasModifiedInfractions, - saveInfractions, - cancelInfractions, - onUpdateInfraction, - onAddInfraction, - onRemoveInfraction -}) { +export function ControllerControlNoLic({ controlType, controlData, editBDC }) { const classes = useStyles(); const downloadBDC = useDownloadBDC(controlData.id); + const { + checkedAlertsNumber, + setIsReportingInfractions, + isReportingInfractions, + reportedInfractionsLastUpdateTime + } = useInfractions(); const TABS = getTabs(checkedAlertsNumber); const [tab, setTab] = React.useState(TABS[0].name); @@ -155,16 +146,6 @@ export function ControllerControlNoLic({ } @@ -183,7 +164,6 @@ export function ControllerControlNoLic({ downloadBDC={downloadBDC} canDownloadBDC={canDownloadBDC(controlData)} bdcAlreadyExisting={!!controlData.controlBulletinCreationTime} - totalAlertsNumber={totalAlertsNumber} /> )} diff --git a/web/controller/components/noQRCode/noLic/ControllerControlNoLicDrawer.js b/web/controller/components/noQRCode/noLic/ControllerControlNoLicDrawer.js index b1ce8d29..308838f3 100644 --- a/web/controller/components/noQRCode/noLic/ControllerControlNoLicDrawer.js +++ b/web/controller/components/noQRCode/noLic/ControllerControlNoLicDrawer.js @@ -3,7 +3,6 @@ import { ControllerControlHeader } from "../../details/ControllerControlHeader"; import { ControllerControlNoLic } from "./ControllerControlNoLic"; import { ControlBulletinDrawer } from "../../controlBulletin/ControlBulletinDrawer"; import { ControlDrawer } from "../../../utils/ControlDrawer"; -import { useReportInfractions } from "../../../utils/useReportInfractions"; import { canDownloadBDC } from "../../../utils/controlBulletin"; export function ControllerControlNoLicDrawer({ @@ -24,20 +23,6 @@ export function ControllerControlNoLicDrawer({ onClose(); }; - const [ - reportedInfractionsLastUpdateTime, - groupedAlerts, - checkedAlertsNumber, - totalAlertsNumber, - isReportingInfractions, - setIsReportingInfractions, - hasModifiedInfractions, - saveInfractions, - cancelInfractions, - onUpdateInfraction, - onAddInfraction, - onRemoveInfraction - ] = useReportInfractions(controlData); return ( ); diff --git a/web/controller/utils/contextInfractions.js b/web/controller/utils/contextInfractions.js new file mode 100644 index 00000000..8ad8450d --- /dev/null +++ b/web/controller/utils/contextInfractions.js @@ -0,0 +1,16 @@ +import React, { createContext, useContext } from "react"; +import { useReportInfractions } from "./useReportInfractions"; + +const InfractionsContext = createContext(null); + +export const useInfractions = () => useContext(InfractionsContext); + +export function InfractionsProvider({ controlData, children }) { + return ( + + {children} + + ); +} diff --git a/web/controller/utils/useReportInfractions.js b/web/controller/utils/useReportInfractions.js index 42702ef8..5c109781 100644 --- a/web/controller/utils/useReportInfractions.js +++ b/web/controller/utils/useReportInfractions.js @@ -202,7 +202,7 @@ export const useReportInfractions = controlData => { [groupedAlerts] ); - return [ + return { reportedInfractionsLastUpdateTime, groupedAlerts, checkedAlertsNumber, @@ -215,5 +215,5 @@ export const useReportInfractions = controlData => { onUpdateInfraction, onAddInfraction, onRemoveInfraction - ]; + }; }; From 4c04acb43ba192990121c64f687837b6aabf9bb1 Mon Sep 17 00:00:00 2001 From: Tristan Gueguen Date: Wed, 27 Nov 2024 20:49:49 +0100 Subject: [PATCH 22/32] feat(lic-papier): using control date for InfractionDay and InfractionWeek --- web/control/components/Alerts/AlertGroup.js | 13 +++++++++++-- web/control/components/Alerts/InfractionDay.js | 8 ++++---- web/control/components/Alerts/InfractionWeek.js | 17 +++++++++++------ web/control/components/UserReadAlerts.js | 2 ++ 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/web/control/components/Alerts/AlertGroup.js b/web/control/components/Alerts/AlertGroup.js index 14b615e6..07258a84 100644 --- a/web/control/components/Alerts/AlertGroup.js +++ b/web/control/components/Alerts/AlertGroup.js @@ -95,6 +95,7 @@ export function AlertGroup({ setPeriodOnFocus, setTab, readOnlyAlerts, + controlData, displayBusinessType = false, titleProps = {} }) { @@ -202,11 +203,19 @@ export function AlertGroup({ <> {alerts[0].description} {alerts[0].unit === PERIOD_UNITS.DAY && ( - + )} {alerts[0].unit === PERIOD_UNITS.WEEK && ( <> - + )} diff --git a/web/control/components/Alerts/InfractionDay.js b/web/control/components/Alerts/InfractionDay.js index 04d52de7..530eb8d2 100644 --- a/web/control/components/Alerts/InfractionDay.js +++ b/web/control/components/Alerts/InfractionDay.js @@ -53,7 +53,7 @@ const useStyles = makeStyles(theme => ({ } })); -export const InfractionDay = ({ alerts, sanction }) => { +export const InfractionDay = ({ alerts, sanction, controlData }) => { const classes = useStyles(); const { isReportingInfractions, @@ -70,8 +70,8 @@ export const InfractionDay = ({ alerts, sanction }) => { initialDays ]); - const today = new Date(); - const minDate = addDaysToDate(new Date(), -28); + const maxDate = new Date(unixToJSTimestamp(controlData.creationTime)); + const minDate = addDaysToDate(new Date(maxDate), -28); const onSelectedDatesChange = values => { const newTimestamps = values @@ -107,7 +107,7 @@ export const InfractionDay = ({ alerts, sanction }) => { multiple sort minDate={minDate} - maxDate={today} // TODO 835 use controlDate + maxDate={maxDate} highlightToday={false} weekStartDayIndex={1} headerOrder={["MONTH_YEAR", "LEFT_BUTTON", "RIGHT_BUTTON"]} diff --git a/web/control/components/Alerts/InfractionWeek.js b/web/control/components/Alerts/InfractionWeek.js index 6ca7bb28..93520a14 100644 --- a/web/control/components/Alerts/InfractionWeek.js +++ b/web/control/components/Alerts/InfractionWeek.js @@ -1,13 +1,16 @@ import React, { useMemo } from "react"; import Stack from "@mui/material/Stack"; import { Checkbox } from "@codegouvfr/react-dsfr/Checkbox"; -import { startOfDay, textualPrettyFormatWeek } from "common/utils/time"; +import { + startOfDay, + textualPrettyFormatWeek, + unixToJSTimestamp +} from "common/utils/time"; import { useInfractions } from "../../../controller/utils/contextInfractions"; -const getLastFourMondays = () => { +const getLastFourMondays = fromDate => { const mondays = []; - const today = new Date(); - let date = new Date(today); + let date = new Date(fromDate); while (mondays.length < 4) { if (date.getDay() === 1) { @@ -18,7 +21,7 @@ const getLastFourMondays = () => { return mondays.map(startOfDay); }; -export const InfractionWeek = ({ alerts, sanction }) => { +export const InfractionWeek = ({ alerts, sanction, controlData }) => { const { isReportingInfractions, onAddInfraction, @@ -43,7 +46,9 @@ export const InfractionWeek = ({ alerts, sanction }) => { Sélectionnez la ou les semaines concernées :

)} - {getLastFourMondays().map(monday => ( + {getLastFourMondays( + new Date(unixToJSTimestamp(controlData.creationTime)) + ).map(monday => ( ( export function UserReadAlerts({ setTab, + controlData, setPeriodOnFocus, readOnlyAlerts, controlType @@ -133,6 +134,7 @@ export function UserReadAlerts({ displayBusinessType={ businessTypes && businessTypes.length > 1 } + controlData={controlData} /> ))} From 4ec6d8c0bac20d4ce91114b7e1d41d49a1b5a160 Mon Sep 17 00:00:00 2001 From: Tristan Gueguen Date: Thu, 28 Nov 2024 11:31:24 +0100 Subject: [PATCH 23/32] Revert "feat(control): handle extra null in infractions" This reverts commit e302f7704e3cc82ad88055e3392afefa9c2065bd. --- web/control/components/RegulatoryAlert.js | 51 +++++++++++------------ 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/web/control/components/RegulatoryAlert.js b/web/control/components/RegulatoryAlert.js index f0d682ce..0c58f334 100644 --- a/web/control/components/RegulatoryAlert.js +++ b/web/control/components/RegulatoryAlert.js @@ -48,25 +48,25 @@ export function formatAlertText(alert, type) { switch (type) { case ALERT_TYPES.minimumDailyRest: { const maxBreakLengthInSeconds = - alert.extra?.breach_period_max_break_in_seconds; - return maxBreakLengthInSeconds ? ( + alert.extra.breach_period_max_break_in_seconds; + return ( Durée de la plus longue période de repos consécutif effectuée entre le{" "} {formatDate(alert.extra.breach_period_start)} et le{" "} {formatDate(alert.extra.breach_period_end)} :{" "} {formatTimer(maxBreakLengthInSeconds)} - ) : null; + ); } case ALERT_TYPES.maximumWorkedDaysInWeek: { - const maxBreakLengthInSeconds = alert.extra?.rest_duration_s; - const tooManyDays = alert.extra?.too_many_days; - const restDurationText = maxBreakLengthInSeconds ? ( + const maxBreakLengthInSeconds = alert.extra.rest_duration_s; + const tooManyDays = alert.extra.too_many_days; + const restDurationText = ( <> Durée du repos hebdomadaire :{" "} {formatTimer(maxBreakLengthInSeconds)}. - ) : null; + ); const tooManyDaysText = ( <>La semaine ne comporte aucune journée non travaillée. ); @@ -100,20 +100,20 @@ export function formatAlertText(alert, type) { } case ALERT_TYPES.maximumUninterruptedWorkTime: { const uninterruptedWorkTime = - alert.extra?.longest_uninterrupted_work_in_seconds; - return uninterruptedWorkTime ? ( + alert.extra.longest_uninterrupted_work_in_seconds; + return ( Durée du temps de travail ininterrompu constaté :{" "} {formatTimer(uninterruptedWorkTime)} entre le{" "} {formatDate(alert.extra.longest_uninterrupted_work_start)} et le{" "} {formatDate(alert.extra.longest_uninterrupted_work_end)} - ) : null; + ); } case ALERT_TYPES.minimumWorkDayBreak: { - const breakTimeInSeconds = alert.extra?.total_break_time_in_seconds; - const workTimeInSeconds = alert.extra?.work_range_in_seconds; - return breakTimeInSeconds && workTimeInSeconds ? ( + const breakTimeInSeconds = alert.extra.total_break_time_in_seconds; + const workTimeInSeconds = alert.extra.work_range_in_seconds; + return ( Durée du temps de pause :{" "} {formatMinutesFromSeconds(breakTimeInSeconds)} pour une période @@ -121,16 +121,12 @@ export function formatAlertText(alert, type) { le {formatDate(alert.extra.work_range_start)} et le{" "} {formatDate(alert.extra.work_range_end)} - ) : null; + ); } case ALERT_TYPES.maximumWorkDayTime: { - const { - nightWork, - work_range_in_seconds: workTime, - work_range_start, - work_range_end - } = alert.extra || {}; - return workTime && work_range_start && work_range_end ? ( + const nightWork = alert.extra.night_work; + const workTime = alert.extra.work_range_in_seconds; + return ( Temps de travail total effectué entre le{" "} {formatDate(alert.extra.work_range_start)} et le{" "} @@ -139,19 +135,22 @@ export function formatAlertText(alert, type) { {" : "} {formatTimer(workTime)} - ) : null; + ); } case ALERT_TYPES.maximumWorkInCalendarWeek: { - const { work_duration_in_seconds, work_range_start, work_range_end } = - alert.extra || {}; - return work_duration_in_seconds && work_range_start && work_range_end ? ( + const { + work_duration_in_seconds, + work_range_start, + work_range_end + } = alert.extra; + return ( Temps de travail total effectué entre le{" "} {formatDate(work_range_start)} et le {formatDate(work_range_end)} :{" "} {formatTimer(work_duration_in_seconds)} - ) : null; + ); } default: return ; From 8f36dde22f630dbb8eabd6ecd81eced1b2c40810 Mon Sep 17 00:00:00 2001 From: Tristan Gueguen Date: Thu, 28 Nov 2024 11:35:07 +0100 Subject: [PATCH 24/32] fix(lic-papier): display correct component based on control type --- web/control/components/Alerts/AlertGroup.js | 2 +- web/control/components/UserReadAlerts.js | 11 +++++------ .../components/details/ControllerControlDrawer.js | 2 +- web/controller/components/list/ControlsList.js | 2 +- .../noQRCode/noLic/ControllerControlNoLic.js | 1 - web/controller/utils/useReadControlData.js | 2 +- 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/web/control/components/Alerts/AlertGroup.js b/web/control/components/Alerts/AlertGroup.js index 07258a84..24392891 100644 --- a/web/control/components/Alerts/AlertGroup.js +++ b/web/control/components/Alerts/AlertGroup.js @@ -47,7 +47,7 @@ const useStyles = makeStyles(theme => { }, reportedAlert: { borderColor: theme.palette.primary.main, - borderWidth: "2px" + borderWidth: "1px" }, reportableAlert: { backgroundColor: theme.palette.error.main diff --git a/web/control/components/UserReadAlerts.js b/web/control/components/UserReadAlerts.js index 993de4ed..c766ede7 100644 --- a/web/control/components/UserReadAlerts.js +++ b/web/control/components/UserReadAlerts.js @@ -59,8 +59,7 @@ export function UserReadAlerts({ setTab, controlData, setPeriodOnFocus, - readOnlyAlerts, - controlType + readOnlyAlerts }) { const classes = useStyles(); const { @@ -79,7 +78,7 @@ export function UserReadAlerts({ return ( - {controlType === CONTROL_TYPES.MOBILIC.label && ( + {controlData.controlType === CONTROL_TYPES.MOBILIC.label && ( )} @@ -105,7 +104,7 @@ export function UserReadAlerts({ )}`} )} - {controlType === CONTROL_TYPES.MOBILIC.label && ( + {controlData.controlType === CONTROL_TYPES.MOBILIC.label && ( <> Infractions calculées par Mobilic @@ -126,7 +125,7 @@ export function UserReadAlerts({ >
) : ( - controlType === CONTROL_TYPES.MOBILIC && ( + controlData.controlType === CONTROL_TYPES.MOBILIC.label && ( - {controlType === CONTROL_TYPES.MOBILIC ? ( + {controlType === CONTROL_TYPES.MOBILIC.label ? ( { diff --git a/web/controller/utils/useReadControlData.js b/web/controller/utils/useReadControlData.js index dfca9dbf..72d10dd3 100644 --- a/web/controller/utils/useReadControlData.js +++ b/web/controller/utils/useReadControlData.js @@ -27,7 +27,7 @@ export const useReadControlData = (controlId, controlType) => { withLoadingScreen(async () => { await alerts.withApiErrorHandling(async () => { const apiResponse = await api.graphQlMutate( - controlType === CONTROL_TYPES.MOBILIC + controlType === CONTROL_TYPES.MOBILIC.label ? CONTROLLER_READ_CONTROL_DATA : CONTROLLER_READ_CONTROL_DATA_NO_LIC, { controlId }, From a277f6d20a1416d61615444615758053de38ac8b Mon Sep 17 00:00:00 2001 From: Tristan Gueguen Date: Thu, 28 Nov 2024 12:16:11 +0100 Subject: [PATCH 25/32] feat(lic-papier): style, sorting day/week infractions --- common/assets/styles/root.scss | 13 ++++++ .../components/Alerts/InfractionDay.js | 5 ++- .../components/Alerts/InfractionWeek.js | 43 ++++++++----------- 3 files changed, 33 insertions(+), 28 deletions(-) diff --git a/common/assets/styles/root.scss b/common/assets/styles/root.scss index 85ee2b90..62d7200e 100644 --- a/common/assets/styles/root.scss +++ b/common/assets/styles/root.scss @@ -475,4 +475,17 @@ video:not([href])[controls] { main { scroll-margin-top: 200px; +} + +.rmdp-day.rmdp-selected span:not(.highlight) { + background-color: #3965EA; + box-shadow: none; +} + +.rmdp-week-day { + color: #00000061; +} + +.rmdp-header-values { + font-weight: bold; } \ No newline at end of file diff --git a/web/control/components/Alerts/InfractionDay.js b/web/control/components/Alerts/InfractionDay.js index 530eb8d2..adc63727 100644 --- a/web/control/components/Alerts/InfractionDay.js +++ b/web/control/components/Alerts/InfractionDay.js @@ -111,13 +111,14 @@ export const InfractionDay = ({ alerts, sanction, controlData }) => { highlightToday={false} weekStartDayIndex={1} headerOrder={["MONTH_YEAR", "LEFT_BUTTON", "RIGHT_BUTTON"]} - monthYearSeparator="" // TODO 835 maybe use space + monthYearSeparator=" " locale={gregorian_fr} /> )} -
    +
      {initialTimestamps .map(ts => (ts / 1000) >> 0) + .sort() .map(ts => (
    • { } }; return ( - - {isReportingInfractions && ( -

      - Sélectionnez la ou les semaines concernées : -

      - )} - {getLastFourMondays( + ( - toggleInfraction(monday, e.target.checked) - } - } - ]} - disabled={!isReportingInfractions} - /> - ))} -
      + ) + .reverse() + .map(monday => ({ + label: textualPrettyFormatWeek(monday), + nativeInputProps: { + checked: initialWeeks.includes(monday), + onChange: e => toggleInfraction(monday, e.target.checked) + } + }))} + /> ); }; From 8db276fbdbe99e8a5fc9c67961592e4c446eb5d3 Mon Sep 17 00:00:00 2001 From: Sandrine Ricardo Date: Thu, 28 Nov 2024 12:37:32 +0100 Subject: [PATCH 26/32] feat(infractions): display no lic sanction first --- web/control/components/AlertsInHistory.js | 15 +++---- web/control/components/UserReadAlerts.js | 43 +++++++++---------- web/control/utils/sanctionComparator.js | 6 +++ .../ControlBulletinFormStep3.js | 27 ++++++------ 4 files changed, 44 insertions(+), 47 deletions(-) create mode 100644 web/control/utils/sanctionComparator.js diff --git a/web/control/components/AlertsInHistory.js b/web/control/components/AlertsInHistory.js index 8ba432ce..2d7c1f43 100644 --- a/web/control/components/AlertsInHistory.js +++ b/web/control/components/AlertsInHistory.js @@ -5,6 +5,7 @@ import List from "@mui/material/List"; import ListItem from "@mui/material/ListItem"; import { AlertCard } from "./Alerts/AlertGroup"; import { WarningComputedAlerts } from "./UserReadAlerts"; +import { sanctionComparator } from "../utils/sanctionComparator"; export function AlertsInHistory({ alertsInPeriod }) { return ( @@ -15,15 +16,11 @@ export function AlertsInHistory({ alertsInPeriod }) { > - {alertsInPeriod - .sort((alert1, alert2) => - alert1.sanction.localeCompare(alert2.sanction) - ) - .map(alert => ( - - - - ))} + {alertsInPeriod.sort(sanctionComparator).map(alert => ( + + + + ))} diff --git a/web/control/components/UserReadAlerts.js b/web/control/components/UserReadAlerts.js index c766ede7..371ebe99 100644 --- a/web/control/components/UserReadAlerts.js +++ b/web/control/components/UserReadAlerts.js @@ -17,6 +17,7 @@ import { getBusinessTypesFromGroupedAlerts } from "../utils/businessTypesFromGro import { Description } from "../../common/typography/Description"; import { CONTROL_TYPES } from "../../controller/utils/useReadControlData"; import { useInfractions } from "../../controller/utils/contextInfractions"; +import { sanctionComparator } from "../utils/sanctionComparator"; const useStyles = makeStyles(theme => ({ container: { @@ -114,29 +115,25 @@ export function UserReadAlerts({ )} {groupedAlerts?.length > 0 ? ( - {groupedAlerts - .sort((alert1, alert2) => - alert1.sanction.localeCompare(alert2.sanction) - ) - .map(group => ( - - 1 - } - controlData={controlData} - /> - - ))} + {groupedAlerts.sort(sanctionComparator).map(group => ( + + 1 + } + controlData={controlData} + /> + + ))} ) : ( diff --git a/web/control/utils/sanctionComparator.js b/web/control/utils/sanctionComparator.js new file mode 100644 index 00000000..d6d5faa0 --- /dev/null +++ b/web/control/utils/sanctionComparator.js @@ -0,0 +1,6 @@ +export const sanctionComparator = (alert1, alert2) => { + // Display "absence de LIC" first + if (alert1.sanction === "NATINF 23103") return -1; + if (alert2.sanction === "NATINF 23103") return 1; + return alert1.sanction.localeCompare(alert2.sanction); +}; diff --git a/web/controller/components/controlBulletin/ControlBulletinFormStep3.js b/web/controller/components/controlBulletin/ControlBulletinFormStep3.js index e10d317a..07831f78 100644 --- a/web/controller/components/controlBulletin/ControlBulletinFormStep3.js +++ b/web/controller/components/controlBulletin/ControlBulletinFormStep3.js @@ -8,6 +8,7 @@ import { AlertGroup } from "../../../control/components/Alerts/AlertGroup"; import { Input } from "../../../common/forms/Input"; import Notice from "../../../common/Notice"; import { useInfractions } from "../../utils/contextInfractions"; +import { sanctionComparator } from "../../../control/utils/sanctionComparator"; export function ControlBulletinFormStep3({ controlType, @@ -32,21 +33,17 @@ export function ControlBulletinFormStep3({ Infractions retenues {groupedAlerts?.length > 0 ? ( - {groupedAlerts - .sort((alert1, alert2) => - alert1.sanction.localeCompare(alert2.sanction) - ) - .map(group => ( - - - - ))} + {groupedAlerts.sort(sanctionComparator).map(group => ( + + + + ))} ) : ( From 39ae0cb5a5cf4a43918031cdafd17c16b3d82797 Mon Sep 17 00:00:00 2001 From: Sandrine Ricardo Date: Thu, 28 Nov 2024 12:49:47 +0100 Subject: [PATCH 27/32] feat(control): get control type from control data --- web/control/components/Alerts/AlertGroup.js | 9 ++++----- web/control/components/UserReadAlerts.js | 1 - .../controlBulletin/ControlBulletinFormStep3.js | 4 ++-- .../controlBulletin/ControllerControlBulletin.js | 2 +- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/web/control/components/Alerts/AlertGroup.js b/web/control/components/Alerts/AlertGroup.js index 24392891..9faee9df 100644 --- a/web/control/components/Alerts/AlertGroup.js +++ b/web/control/components/Alerts/AlertGroup.js @@ -87,7 +87,6 @@ const BusinessTypeTitle = ({ business }) => ( ); export function AlertGroup({ - controlType, alerts, infringementLabel, type, @@ -111,7 +110,7 @@ export function AlertGroup({ ); const alertsNumber = getAlertsNumber( - controlType, + controlData.controlType, alerts, isSanctionReportable, isReportingInfractions, @@ -165,8 +164,8 @@ export function AlertGroup({ {/* TODO refactor: extract in another component */} - {(controlType === CONTROL_TYPES.MOBILIC.label || - controlType === CONTROL_TYPES.NO_LIC.label) && + {(controlData.controlType === CONTROL_TYPES.MOBILIC.label || + controlData.controlType === CONTROL_TYPES.NO_LIC.label) && Object.entries(alertsGroupedByBusinessTypes).map( ([businessId, alertsByBusiness]) => { const firstAlert = alertsByBusiness[0]; @@ -199,7 +198,7 @@ export function AlertGroup({ ); } )} - {controlType === CONTROL_TYPES.LIC_PAPIER.label && ( + {controlData.controlType === CONTROL_TYPES.LIC_PAPIER.label && ( <> {alerts[0].description} {alerts[0].unit === PERIOD_UNITS.DAY && ( diff --git a/web/control/components/UserReadAlerts.js b/web/control/components/UserReadAlerts.js index 371ebe99..2686bbcd 100644 --- a/web/control/components/UserReadAlerts.js +++ b/web/control/components/UserReadAlerts.js @@ -122,7 +122,6 @@ export function UserReadAlerts({ > Date: Thu, 28 Nov 2024 13:20:21 +0100 Subject: [PATCH 28/32] feat(bdc): do not display not reported infractions for lic papier on 3rd step of bdc edition --- .../ControlBulletinFormStep3.js | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/web/controller/components/controlBulletin/ControlBulletinFormStep3.js b/web/controller/components/controlBulletin/ControlBulletinFormStep3.js index 3b6d415e..da197903 100644 --- a/web/controller/components/controlBulletin/ControlBulletinFormStep3.js +++ b/web/controller/components/controlBulletin/ControlBulletinFormStep3.js @@ -9,6 +9,7 @@ import { Input } from "../../../common/forms/Input"; import Notice from "../../../common/Notice"; import { useInfractions } from "../../utils/contextInfractions"; import { sanctionComparator } from "../../../control/utils/sanctionComparator"; +import { CONTROL_TYPES } from "../../utils/useReadControlData"; export function ControlBulletinFormStep3({ controlData, @@ -20,6 +21,19 @@ export function ControlBulletinFormStep3({ onUpdateInfraction }) { const { groupedAlerts } = useInfractions(); + + const groupedAlertsToDisplay = React.useMemo(() => { + if (controlData.controlType === CONTROL_TYPES.LIC_PAPIER.label) { + return ( + groupedAlerts.filter( + group => group.alerts.filter(alert => alert.checked).length > 0 + ) || [] + ); + } else { + return groupedAlerts; + } + }, [controlData, groupedAlerts]); + return ( Infractions retenues - {groupedAlerts?.length > 0 ? ( + {groupedAlertsToDisplay?.length > 0 ? ( - {groupedAlerts.sort(sanctionComparator).map(group => ( + {groupedAlertsToDisplay.sort(sanctionComparator).map(group => ( From 76cb7b1234e7eb19dba6056f457401a4260c8c7d Mon Sep 17 00:00:00 2001 From: Tristan Gueguen Date: Fri, 29 Nov 2024 11:03:27 +0100 Subject: [PATCH 29/32] feat(lic-papier): better size Calendar InfractionDay --- common/assets/styles/root.scss | 44 ++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/common/assets/styles/root.scss b/common/assets/styles/root.scss index 62d7200e..30040330 100644 --- a/common/assets/styles/root.scss +++ b/common/assets/styles/root.scss @@ -488,4 +488,48 @@ main { .rmdp-header-values { font-weight: bold; +} + +.rmdp-day, +.rmdp-week-day { + height:52px; + width:52px +} + +.rmdp-header { + font-size:1.125rem; +} + +.rmdp-arrow { + border:solid #00000061; + border-width:0 2px 2px 0; + height:10px; + width:10px +} + +.rmdp-arrow-container { + height:20px; + width:20px +} +.rmdp-arrow-container.disabled { + display: none; +} + +@media (max-height:450px),(max-width:450px) { + .rmdp-day, + .rmdp-week-day { + height:38px; + width:38px + } + .rmdp-header { + font-size:0.875rem; + } + .rmdp-arrow { + height:8px; + width:8px + } + .rmdp-arrow-container { + height:14px; + width:14px + } } \ No newline at end of file From 88b84be32a4bca61db1f4d826296795d0eb86ac5 Mon Sep 17 00:00:00 2001 From: Tristan Gueguen Date: Fri, 29 Nov 2024 11:39:02 +0100 Subject: [PATCH 30/32] fix(lic-papier): infractions edit mode in BDC. off when closing BDC --- .../controlBulletin/ControlBulletinFormStep3.js | 10 ++++++---- .../controlBulletin/ControllerControlBulletin.js | 7 ++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/web/controller/components/controlBulletin/ControlBulletinFormStep3.js b/web/controller/components/controlBulletin/ControlBulletinFormStep3.js index da197903..9fa3ad88 100644 --- a/web/controller/components/controlBulletin/ControlBulletinFormStep3.js +++ b/web/controller/components/controlBulletin/ControlBulletinFormStep3.js @@ -17,10 +17,9 @@ export function ControlBulletinFormStep3({ controlBulletin, grecoId, onUpdateGrecoId, - controlCanBeDownloaded, - onUpdateInfraction + controlCanBeDownloaded }) { - const { groupedAlerts } = useInfractions(); + const { groupedAlerts, setIsReportingInfractions } = useInfractions(); const groupedAlertsToDisplay = React.useMemo(() => { if (controlData.controlType === CONTROL_TYPES.LIC_PAPIER.label) { @@ -34,6 +33,10 @@ export function ControlBulletinFormStep3({ } }, [controlData, groupedAlerts]); + React.useEffect(() => { + setIsReportingInfractions(true); + }, []); + return ( diff --git a/web/controller/components/controlBulletin/ControllerControlBulletin.js b/web/controller/components/controlBulletin/ControllerControlBulletin.js index 310e03cb..4d7f1518 100644 --- a/web/controller/components/controlBulletin/ControllerControlBulletin.js +++ b/web/controller/components/controlBulletin/ControllerControlBulletin.js @@ -53,7 +53,6 @@ export function ControllerControlBulletin({ }) { const store = useStoreSyncedWithLocalStorage(); const controllerUserInfo = store.controllerInfo(); - const { onUpdateInfraction } = useInfractions(); const api = useApi(); const withLoadingScreen = useLoadingScreen(); const alerts = useSnackbarAlerts(); @@ -64,6 +63,7 @@ export function ControllerControlBulletin({ controllerUserInfo.grecoId || "" ); const [showErrors, setShowErrors] = React.useState(false); + const { setIsReportingInfractions } = useInfractions(); const controlCanBeDownloaded = React.useMemo(() => { return canDownloadBDC(controlData); @@ -128,6 +128,7 @@ export function ControllerControlBulletin({ alerts.success(STEPS[step].successMessage, "", 3000); } if (!STEPS[step + 1]) { + setIsReportingInfractions(false); onClose(true); } else { setStep(step + 1); @@ -245,10 +246,6 @@ export function ControllerControlBulletin({ grecoId={grecoId} onUpdateGrecoId={onUpdateGrecoId} controlCanBeDownloaded={controlCanBeDownloaded} - onUpdateInfraction={(...args) => { - setFieldUpdated(true); - onUpdateInfraction(...args); - }} /> )} Date: Fri, 29 Nov 2024 11:45:15 +0100 Subject: [PATCH 31/32] fix(lic-papier): disable edit mode infractions when closing control drawer --- web/controller/utils/ControlDrawer.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/web/controller/utils/ControlDrawer.js b/web/controller/utils/ControlDrawer.js index 09c2bad6..33818935 100644 --- a/web/controller/utils/ControlDrawer.js +++ b/web/controller/utils/ControlDrawer.js @@ -1,6 +1,7 @@ import React from "react"; import SwipeableDrawer from "@mui/material/SwipeableDrawer"; import { makeStyles } from "@mui/styles"; +import { useInfractions } from "./contextInfractions"; const useStyles = makeStyles(theme => ({ missionDrawer: { @@ -25,6 +26,15 @@ export function ControlDrawer({ } }, [isOpen, controlId]); + const _useInfractions = useInfractions(); + + const _onClose = () => { + if (_useInfractions && _useInfractions.setIsReportingInfractions) { + _useInfractions.setIsReportingInfractions(false); + } + onClose(); + }; + return ( {}} - onClose={onClose} + onClose={_onClose} PaperProps={{ className: classes.missionDrawer, sx: { From 816f3f5d7d63b80768bc6d8168cc62e4b0c1deb7 Mon Sep 17 00:00:00 2001 From: Tristan Gueguen Date: Fri, 29 Nov 2024 15:37:15 +0100 Subject: [PATCH 32/32] refacto(controls): use Control Context --- web/control/components/Alerts/AlertGroup.js | 23 +++++++----------- .../components/Alerts/InfractionDay.js | 20 ++++++++++++---- .../components/Alerts/InfractionWeek.js | 5 +++- web/control/components/UserReadAlerts.js | 24 ++++++++++--------- web/control/components/UserReadHistory.js | 3 ++- web/control/components/UserReadInfo.js | 5 ++-- web/control/components/UserReadTabs.js | 3 --- .../controlBulletin/ControlBulletinDrawer.js | 2 -- .../ControlBulletinFormStep3.js | 14 ++++------- .../ControllerControlBulletin.js | 10 ++------ .../details/ControllerControlDetails.js | 8 +------ .../details/ControllerControlDrawer.js | 21 ++++++++-------- .../details/ControllerControlExportMenu.js | 6 +++-- .../details/ControllerControlHeader.js | 18 ++++---------- .../details/ControllerControlNote.js | 8 ++++--- .../menu/ControllerControlBottomMenu.js | 10 ++++---- .../noQRCode/noLic/ControllerControlNoLic.js | 17 +++++-------- .../noLic/ControllerControlNoLicDrawer.js | 10 +------- .../ControllerControlNoLicInformations.js | 6 ++--- ...trollerControlNoLicInformationsEmployee.js | 4 +++- .../scanQRCode/ControllerScanQRCode.js | 2 +- web/controller/utils/contextControl.js | 16 +++++++++++++ web/controller/utils/useReadControlData.js | 19 ++++++++++++++- 23 files changed, 131 insertions(+), 123 deletions(-) create mode 100644 web/controller/utils/contextControl.js diff --git a/web/control/components/Alerts/AlertGroup.js b/web/control/components/Alerts/AlertGroup.js index 9faee9df..144625f0 100644 --- a/web/control/components/Alerts/AlertGroup.js +++ b/web/control/components/Alerts/AlertGroup.js @@ -18,6 +18,7 @@ import { InfractionWeek } from "./InfractionWeek"; import { PERIOD_UNITS } from "common/utils/regulation/periodUnitsEnum"; import classNames from "classnames"; import { useInfractions } from "../../../controller/utils/contextInfractions"; +import { useControl } from "../../../controller/utils/contextControl"; const useStyles = makeStyles(theme => { return { @@ -94,13 +95,13 @@ export function AlertGroup({ setPeriodOnFocus, setTab, readOnlyAlerts, - controlData, displayBusinessType = false, titleProps = {} }) { const [open, setOpen] = React.useState(false); const classes = useStyles(); const { isReportingInfractions } = useInfractions(); + const { controlType } = useControl(); const isSanctionReportable = readOnlyAlerts ? true : isReportable(sanction); @@ -110,7 +111,7 @@ export function AlertGroup({ ); const alertsNumber = getAlertsNumber( - controlData.controlType, + controlType, alerts, isSanctionReportable, isReportingInfractions, @@ -164,8 +165,8 @@ export function AlertGroup({ {/* TODO refactor: extract in another component */} - {(controlData.controlType === CONTROL_TYPES.MOBILIC.label || - controlData.controlType === CONTROL_TYPES.NO_LIC.label) && + {(controlType === CONTROL_TYPES.MOBILIC.label || + controlType === CONTROL_TYPES.NO_LIC.label) && Object.entries(alertsGroupedByBusinessTypes).map( ([businessId, alertsByBusiness]) => { const firstAlert = alertsByBusiness[0]; @@ -198,23 +199,15 @@ export function AlertGroup({ ); } )} - {controlData.controlType === CONTROL_TYPES.LIC_PAPIER.label && ( + {controlType === CONTROL_TYPES.LIC_PAPIER.label && ( <> {alerts[0].description} {alerts[0].unit === PERIOD_UNITS.DAY && ( - + )} {alerts[0].unit === PERIOD_UNITS.WEEK && ( <> - + )} diff --git a/web/control/components/Alerts/InfractionDay.js b/web/control/components/Alerts/InfractionDay.js index adc63727..70a62fe6 100644 --- a/web/control/components/Alerts/InfractionDay.js +++ b/web/control/components/Alerts/InfractionDay.js @@ -10,6 +10,7 @@ import { makeStyles } from "@mui/styles"; import { fr } from "@codegouvfr/react-dsfr"; import Stack from "@mui/material/Stack"; import { useInfractions } from "../../../controller/utils/contextInfractions"; +import { useControl } from "../../../controller/utils/contextControl"; const gregorian_fr = { name: "gregorian_fr", @@ -53,13 +54,14 @@ const useStyles = makeStyles(theme => ({ } })); -export const InfractionDay = ({ alerts, sanction, controlData }) => { +export const InfractionDay = ({ alerts, sanction }) => { const classes = useStyles(); const { isReportingInfractions, onAddInfraction, onRemoveInfraction } = useInfractions(); + const { controlData } = useControl(); const initialDays = useMemo( () => alerts.map(alert => alert.day).filter(x => !!x), @@ -74,17 +76,27 @@ export const InfractionDay = ({ alerts, sanction, controlData }) => { const minDate = addDaysToDate(new Date(maxDate), -28); const onSelectedDatesChange = values => { - const newTimestamps = values + const selectedTimestamps = values .map(dateString => { const parsedDate = new Date(dateString); return parsedDate.getTime(); }) - .map(date => (date / 1000) >> 0) - .filter(ts => !initialDays.includes(ts)); + .map(date => (date / 1000) >> 0); + + const newTimestamps = selectedTimestamps.filter( + ts => !initialDays.includes(ts) + ); for (const newTimestamp of newTimestamps) { onAddInfraction(sanction, newTimestamp); } + + const removedTimestamps = initialDays.filter( + ts => !selectedTimestamps.includes(ts) + ); + for (const removedTimestamp of removedTimestamps) { + onRemoveInfraction(sanction, removedTimestamp); + } }; const onRemoveDate = timestamp => { diff --git a/web/control/components/Alerts/InfractionWeek.js b/web/control/components/Alerts/InfractionWeek.js index 0585083c..73a7f66d 100644 --- a/web/control/components/Alerts/InfractionWeek.js +++ b/web/control/components/Alerts/InfractionWeek.js @@ -6,6 +6,7 @@ import { unixToJSTimestamp } from "common/utils/time"; import { useInfractions } from "../../../controller/utils/contextInfractions"; +import { useControl } from "../../../controller/utils/contextControl"; const getLastFourMondays = fromDate => { const mondays = []; @@ -20,12 +21,13 @@ const getLastFourMondays = fromDate => { return mondays.map(startOfDay); }; -export const InfractionWeek = ({ alerts, sanction, controlData }) => { +export const InfractionWeek = ({ alerts, sanction }) => { const { isReportingInfractions, onAddInfraction, onRemoveInfraction } = useInfractions(); + const { controlData } = useControl(); const initialWeeks = useMemo( () => alerts.map(alert => alert.week).filter(x => !!x), [alerts] @@ -40,6 +42,7 @@ export const InfractionWeek = ({ alerts, sanction, controlData }) => { }; return ( ({ container: { @@ -58,28 +59,30 @@ export const WarningComputedAlerts = () => ( export function UserReadAlerts({ setTab, - controlData, setPeriodOnFocus, - readOnlyAlerts + readOnlyAlerts, + groupedAlerts = undefined }) { const classes = useStyles(); const { - groupedAlerts, + groupedAlerts: infractionsGroupedAlerts, isReportingInfractions, totalAlertsNumber, reportedInfractionsLastUpdateTime, saveInfractions, cancelInfractions } = useInfractions(); + const { controlType } = useControl(); + const _groupedAlerts = groupedAlerts ?? infractionsGroupedAlerts; const businessTypes = React.useMemo( - () => getBusinessTypesFromGroupedAlerts(groupedAlerts), - [groupedAlerts] + () => getBusinessTypesFromGroupedAlerts(_groupedAlerts), + [_groupedAlerts] ); return ( - {controlData.controlType === CONTROL_TYPES.MOBILIC.label && ( + {controlType === CONTROL_TYPES.MOBILIC.label && ( )} @@ -105,7 +108,7 @@ export function UserReadAlerts({ )}`} )} - {controlData.controlType === CONTROL_TYPES.MOBILIC.label && ( + {controlType === CONTROL_TYPES.MOBILIC.label && ( <> Infractions calculées par Mobilic @@ -113,9 +116,9 @@ export function UserReadAlerts({ )} - {groupedAlerts?.length > 0 ? ( + {_groupedAlerts?.length > 0 ? ( - {groupedAlerts.sort(sanctionComparator).map(group => ( + {_groupedAlerts.sort(sanctionComparator).map(group => ( 1 } - controlData={controlData} /> ))} @@ -156,7 +158,7 @@ export function UserReadAlerts({ ) : ( - controlData.controlType === CONTROL_TYPES.MOBILIC.label && ( + controlType === CONTROL_TYPES.MOBILIC.label && ( ({ container: { @@ -61,9 +62,9 @@ export function UserReadInfo({ allowC1BExport = true, companyName, vehicleRegistrationNumber, - controlData, businesses }) { + const { controlData } = useControl() ?? {}; const [userName, setUserName] = React.useState(""); React.useEffect(() => { if (userInfo) { @@ -86,7 +87,7 @@ export function UserReadInfo({ {controlData && ( - + )} diff --git a/web/control/components/UserReadTabs.js b/web/control/components/UserReadTabs.js index 842eac2b..ac3fc911 100644 --- a/web/control/components/UserReadTabs.js +++ b/web/control/components/UserReadTabs.js @@ -9,7 +9,6 @@ import Container from "@mui/material/Container"; import { ControllerControlBottomMenu } from "../../controller/components/menu/ControllerControlBottomMenu"; import { currentControllerId } from "common/utils/cookie"; import { useDownloadBDC } from "../../controller/utils/useDownloadBDC"; -import { canDownloadBDC } from "../../controller/utils/controlBulletin"; import Box from "@mui/material/Box"; import Notice from "../../common/Notice"; @@ -147,8 +146,6 @@ export function UserReadTabs({ tabs, restoreScroll, ...props }) { updatedInfractions={!!props.reportedInfractionsLastUpdateTime} editBDC={props.openBulletinControl} downloadBDC={downloadBDC} - canDownloadBDC={canDownloadBDC(props.controlData)} - bdcAlreadyExisting={!!props.controlData.controlBulletinCreationTime} totalAlertsNumber={props.totalAlertsNumber} /> )} diff --git a/web/controller/components/controlBulletin/ControlBulletinDrawer.js b/web/controller/components/controlBulletin/ControlBulletinDrawer.js index 12dfca7a..23b4c1d2 100644 --- a/web/controller/components/controlBulletin/ControlBulletinDrawer.js +++ b/web/controller/components/controlBulletin/ControlBulletinDrawer.js @@ -16,7 +16,6 @@ const useStyles = makeStyles(theme => ({ export function ControlBulletinDrawer({ isOpen, onClose, - controlData, onSaveControlBulletin }) { const classes = useStyles(); @@ -60,7 +59,6 @@ export function ControlBulletinDrawer({ saveInfractions({ showSuccessMessage: false })} diff --git a/web/controller/components/controlBulletin/ControlBulletinFormStep3.js b/web/controller/components/controlBulletin/ControlBulletinFormStep3.js index 9fa3ad88..8e1dd7cb 100644 --- a/web/controller/components/controlBulletin/ControlBulletinFormStep3.js +++ b/web/controller/components/controlBulletin/ControlBulletinFormStep3.js @@ -10,16 +10,16 @@ import Notice from "../../../common/Notice"; import { useInfractions } from "../../utils/contextInfractions"; import { sanctionComparator } from "../../../control/utils/sanctionComparator"; import { CONTROL_TYPES } from "../../utils/useReadControlData"; +import { useControl } from "../../utils/contextControl"; export function ControlBulletinFormStep3({ - controlData, handleEditControlBulletin, controlBulletin, grecoId, - onUpdateGrecoId, - controlCanBeDownloaded + onUpdateGrecoId }) { const { groupedAlerts, setIsReportingInfractions } = useInfractions(); + const { controlData, canDownloadBDC } = useControl(); const groupedAlertsToDisplay = React.useMemo(() => { if (controlData.controlType === CONTROL_TYPES.LIC_PAPIER.label) { @@ -52,11 +52,7 @@ export function ControlBulletinFormStep3({ {groupedAlertsToDisplay.sort(sanctionComparator).map(group => ( - + ))} @@ -74,7 +70,7 @@ export function ControlBulletinFormStep3({ label="Observations" textArea /> - {!controlCanBeDownloaded && ( + {!canDownloadBDC && ( { - return canDownloadBDC(controlData); - }, [controlData]); + const { controlData } = useControl(); const onUpdateGrecoId = newGrecoId => { setGrecoId(newGrecoId); @@ -240,12 +236,10 @@ export function ControllerControlBulletin({ )} {step === 3 && ( )} setIsEditingBC(true)} - controlData={controlData} reportedInfractionsLastUpdateTime={reportedInfractionsLastUpdateTime} isReportingInfractions={isReportingInfractions} setIsReportingInfractions={setIsReportingInfractions} - groupedAlerts={groupedAlerts} readOnlyAlerts={false} /> { + const { controlData, setControlData, controlId, controlType } = useControl(); if (!controlData) { return null; @@ -34,7 +29,6 @@ export function ControllerControlDrawer({ controlId, controlType, onClose }) { ) : ( ); +}; +export function ControllerControlDrawer({ controlId, controlType, onClose }) { + return ( + + + + ); } diff --git a/web/controller/components/details/ControllerControlExportMenu.js b/web/controller/components/details/ControllerControlExportMenu.js index acf00ad5..dcfd1050 100644 --- a/web/controller/components/details/ControllerControlExportMenu.js +++ b/web/controller/components/details/ControllerControlExportMenu.js @@ -10,11 +10,13 @@ import { HTTP_QUERIES } from "common/utils/apiQueries"; import { useApi } from "common/utils/api"; import { useSnackbarAlerts } from "../../../common/Snackbar"; import { useModals } from "common/utils/modals"; +import { useControl } from "../../utils/contextControl"; -export function ControllerControlExportMenu({ controlId, canDownloadXml }) { +export function ControllerControlExportMenu() { const api = useApi(); const modals = useModals(); const alerts = useSnackbarAlerts(); + const { controlId, canDownloadBDC } = useControl(); const [exportMenuAnchorEl, setExportMenuAnchorEl] = React.useState(null); const isOpen = React.useMemo(() => !!exportMenuAnchorEl, [ @@ -75,7 +77,7 @@ export function ControllerControlExportMenu({ controlId, canDownloadXml }) { Export Excel { setExportMenuAnchorEl(null); alerts.withApiErrorHandling(async () => { diff --git a/web/controller/components/details/ControllerControlHeader.js b/web/controller/components/details/ControllerControlHeader.js index 3ce6fafd..2e1c312c 100644 --- a/web/controller/components/details/ControllerControlHeader.js +++ b/web/controller/components/details/ControllerControlHeader.js @@ -7,6 +7,7 @@ import Container from "@mui/material/Container"; import Box from "@mui/material/Box"; import { ControllerControlExportMenu } from "./ControllerControlExportMenu"; import { Button } from "@codegouvfr/react-dsfr/Button"; +import { useControl } from "../../utils/contextControl"; const useStyles = makeStyles(theme => ({ desktopHeaderContainer: { @@ -39,13 +40,12 @@ const useStyles = makeStyles(theme => ({ })); export function ControllerControlHeader({ - controlId, controlDate, onCloseDrawer, - canDownloadXml, enableExport = true }) { const classes = useStyles(); + const { controlId } = useControl(); const isOnDesktop = useIsWidthUp("md"); return isOnDesktop ? ( @@ -67,12 +67,7 @@ export function ControllerControlHeader({ Date et heure du contrôle : {prettyFormatDayHour(controlDate)} - {enableExport && ( - - )} + {enableExport && } ) : ( @@ -87,12 +82,7 @@ export function ControllerControlHeader({ > Fermer - {enableExport && ( - - )} + {enableExport && } ); diff --git a/web/controller/components/details/ControllerControlNote.js b/web/controller/components/details/ControllerControlNote.js index 90eee51c..9431fc4a 100644 --- a/web/controller/components/details/ControllerControlNote.js +++ b/web/controller/components/details/ControllerControlNote.js @@ -9,6 +9,7 @@ import { formatApiError } from "common/utils/errors"; import { useSnackbarAlerts } from "../../../common/Snackbar"; import { useApi } from "common/utils/api"; import { Button } from "@codegouvfr/react-dsfr/Button"; +import { useControl } from "../../utils/contextControl"; const useStyles = makeStyles(() => ({ addNoteButton: { @@ -19,17 +20,18 @@ const useStyles = makeStyles(() => ({ } })); -export function ControllerControlNote({ controlData }) { +export function ControllerControlNote() { const classes = useStyles(); const [isEditing, setIsEditing] = React.useState(false); - const [note, setNote] = React.useState(controlData.note); + const { controlData } = useControl(); + const [note, setNote] = React.useState(controlData.note || ""); const alerts = useSnackbarAlerts(); const api = useApi(); React.useEffect(() => { if (controlData) { - setNote(controlData.note); + setNote(controlData.note || ""); } }, [controlData]); diff --git a/web/controller/components/menu/ControllerControlBottomMenu.js b/web/controller/components/menu/ControllerControlBottomMenu.js index c74eeed2..9536e8fe 100644 --- a/web/controller/components/menu/ControllerControlBottomMenu.js +++ b/web/controller/components/menu/ControllerControlBottomMenu.js @@ -3,6 +3,7 @@ import { makeStyles } from "@mui/styles"; import { ButtonsGroup } from "@codegouvfr/react-dsfr/ButtonsGroup"; import { Box } from "@mui/material"; import { useInfractions } from "../../utils/contextInfractions"; +import { useControl } from "../../utils/contextControl"; const useStyles = makeStyles(theme => ({ textButton: { @@ -15,18 +16,17 @@ export function ControllerControlBottomMenu({ updatedInfractions, disabledReportInfractions, editBDC, - downloadBDC, - canDownloadBDC, - bdcAlreadyExisting + downloadBDC }) { const classes = useStyles(); const { totalAlertsNumber } = useInfractions(); + const { canDownloadBDC, bdcAlreadyExists } = useControl(); return ( ({ middleTab: { @@ -88,9 +88,11 @@ const getTabs = alertNumber => [ } ]; -export function ControllerControlNoLic({ controlType, controlData, editBDC }) { +export function ControllerControlNoLic({ editBDC }) { const classes = useStyles(); - const downloadBDC = useDownloadBDC(controlData.id); + + const { controlId } = useControl(); + const downloadBDC = useDownloadBDC(controlId); const { checkedAlertsNumber, setIsReportingInfractions, @@ -142,12 +144,7 @@ export function ControllerControlNoLic({ controlType, controlData, editBDC }) { className={`${classes.panel} ${tab !== t.name && classes.hiddenPanel}`} > - { - - } + {} ))} @@ -161,8 +158,6 @@ export function ControllerControlNoLic({ controlType, controlData, editBDC }) { disableReportInfractions={false} editBDC={editBDC} downloadBDC={downloadBDC} - canDownloadBDC={canDownloadBDC(controlData)} - bdcAlreadyExisting={!!controlData.controlBulletinCreationTime} /> )} diff --git a/web/controller/components/noQRCode/noLic/ControllerControlNoLicDrawer.js b/web/controller/components/noQRCode/noLic/ControllerControlNoLicDrawer.js index 308838f3..fe64c1f4 100644 --- a/web/controller/components/noQRCode/noLic/ControllerControlNoLicDrawer.js +++ b/web/controller/components/noQRCode/noLic/ControllerControlNoLicDrawer.js @@ -3,10 +3,8 @@ import { ControllerControlHeader } from "../../details/ControllerControlHeader"; import { ControllerControlNoLic } from "./ControllerControlNoLic"; import { ControlBulletinDrawer } from "../../controlBulletin/ControlBulletinDrawer"; import { ControlDrawer } from "../../../utils/ControlDrawer"; -import { canDownloadBDC } from "../../../utils/controlBulletin"; export function ControllerControlNoLicDrawer({ - controlType, controlData, setControlData, isOpen, @@ -41,17 +39,11 @@ export function ControllerControlNoLicDrawer({ } /> closeControl()} - canDownloadXml={canDownloadBDC(controlData)} enableExport={false} /> - + ); } diff --git a/web/controller/components/noQRCode/noLic/ControllerControlNoLicInformations.js b/web/controller/components/noQRCode/noLic/ControllerControlNoLicInformations.js index 30b11314..8ce60b9f 100644 --- a/web/controller/components/noQRCode/noLic/ControllerControlNoLicInformations.js +++ b/web/controller/components/noQRCode/noLic/ControllerControlNoLicInformations.js @@ -3,7 +3,7 @@ import Stack from "@mui/material/Stack"; import { ControllerControlNote as Notes } from "../../details/ControllerControlNote"; import { ControllerControlNoLicInformationsEmployee as InformationsEmployee } from "./ControllerControlNoLicInformationsEmployee"; -export function ControllerControlNoLicInformations({ controlData }) { +export function ControllerControlNoLicInformations() { return ( - - + + ); } diff --git a/web/controller/components/noQRCode/noLic/ControllerControlNoLicInformationsEmployee.js b/web/controller/components/noQRCode/noLic/ControllerControlNoLicInformationsEmployee.js index d1ea1b35..12e0a305 100644 --- a/web/controller/components/noQRCode/noLic/ControllerControlNoLicInformationsEmployee.js +++ b/web/controller/components/noQRCode/noLic/ControllerControlNoLicInformationsEmployee.js @@ -8,6 +8,7 @@ import DriveEtaIcon from "@mui/icons-material/DirectionsCar"; import BusinessIcon from "@mui/icons-material/Business"; import ListItemIcon from "@mui/material/ListItemIcon"; import { InfoItem } from "../../../../home/InfoField"; +import { useControl } from "../../../utils/contextControl"; const useStyles = makeStyles(theme => ({ sectionBody: { @@ -23,7 +24,8 @@ const useStyles = makeStyles(theme => ({ } })); -export function ControllerControlNoLicInformationsEmployee({ controlData }) { +export function ControllerControlNoLicInformationsEmployee() { + const { controlData } = useControl(); const classes = useStyles(); return ( diff --git a/web/controller/components/scanQRCode/ControllerScanQRCode.js b/web/controller/components/scanQRCode/ControllerScanQRCode.js index e962a805..c0bd72a6 100644 --- a/web/controller/components/scanQRCode/ControllerScanQRCode.js +++ b/web/controller/components/scanQRCode/ControllerScanQRCode.js @@ -116,7 +116,7 @@ export function ControllerScanQRCode() { history.push(CONTROLLER_ROUTE_PREFIX + "/home", { controlOnFocus: { id: controlResponse.id, - type: CONTROL_TYPES.MOBILIC + type: CONTROL_TYPES.MOBILIC.label } }); } catch (err) { diff --git a/web/controller/utils/contextControl.js b/web/controller/utils/contextControl.js new file mode 100644 index 00000000..a95195ef --- /dev/null +++ b/web/controller/utils/contextControl.js @@ -0,0 +1,16 @@ +import React, { createContext, useContext } from "react"; +import { useReadControlData } from "./useReadControlData"; + +const ControlContext = createContext(null); + +export const useControl = () => useContext(ControlContext); + +export function ControlProvider({ controlId, controlType, children }) { + return ( + + {children} + + ); +} diff --git a/web/controller/utils/useReadControlData.js b/web/controller/utils/useReadControlData.js index 72d10dd3..f4c22bc7 100644 --- a/web/controller/utils/useReadControlData.js +++ b/web/controller/utils/useReadControlData.js @@ -7,6 +7,7 @@ import { } from "common/utils/apiQueries"; import { useLoadingScreen } from "common/utils/loading"; import { useSnackbarAlerts } from "../../common/Snackbar"; +import { canDownloadBDC as _canDownloadBDC } from "./controlBulletin"; // Value AND label must match ControlType enum from API export const CONTROL_TYPES = { @@ -39,5 +40,21 @@ export const useReadControlData = (controlId, controlType) => { } }, [controlId]); - return [controlData, setControlData]; + const canDownloadBDC = React.useMemo(() => _canDownloadBDC(controlData), [ + controlData + ]); + + const bdcAlreadyExists = React.useMemo( + () => !!controlData?.controlBulletinCreationTime, + [controlData] + ); + + return { + controlData, + setControlData, + controlId, + controlType, + canDownloadBDC, + bdcAlreadyExists + }; };