Skip to content

Commit

Permalink
Merge pull request #601 from MTES-MCT/feat/lic-papier
Browse files Browse the repository at this point in the history
Feat/lic papier
  • Loading branch information
tristan-gueguen authored Nov 29, 2024
2 parents e292ef5 + c403792 commit 1207a3a
Show file tree
Hide file tree
Showing 51 changed files with 1,434 additions and 838 deletions.
57 changes: 57 additions & 0 deletions common/assets/styles/root.scss
Original file line number Diff line number Diff line change
Expand Up @@ -475,4 +475,61 @@ 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;
}

.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
}
}
2 changes: 2 additions & 0 deletions common/utils/apiFragments.js
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ export const CONTROL_BULLETIN_FRAGMENT = gql`
licenseCopyNumber
observation
isVehicleImmobilized
businessType
}
`;

Expand All @@ -269,6 +270,7 @@ export const CONTROL_DATA_FRAGMENT = gql`
userLastName
controlBulletinCreationTime
vehicleRegistrationNumber
isDayPageFilled
note
nbReportedInfractions
controlBulletin {
Expand Down
6 changes: 6 additions & 0 deletions common/utils/apiQueries.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -1890,6 +1894,8 @@ export const CONTROLLER_SAVE_CONTROL_BULLETIN = gql`
licenseCopyNumber: $licenseCopyNumber
isVehicleImmobilized: $isVehicleImmobilized
observation: $observation
businessType: $businessType
isDayPageFilled: $isDayPageFilled
) {
...ControlData
controlBulletin {
Expand Down
2 changes: 2 additions & 0 deletions common/utils/regulation/groupAlertsByDay.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -62,6 +63,7 @@ export const getAlertsGroupedByDayFromRegulationComputationsByDay = regulationCo
...(breachedRegCheck.unit === PERIOD_UNITS.DAY && {
day: timestamp
}),
unit: breachedRegCheck.unit,
extra,
checked: false
};
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
150 changes: 150 additions & 0 deletions web/common/forms/BirthDate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
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 !== "" &&
(year < MIN_BIRTH_DATE_YEAR || year > MAX_BIRTH_DATE_YEAR)
) {
setYearState("error");
hasError = true;
} else {
setYearState("default");
}
if (month !== "" && (month < 1 || month > 12)) {
setMonthState("error");
hasError = true;
} else {
setMonthState("default");
}
if (day !== "" && (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 (
<fieldset
role="group"
aria-labelledby="date-naissance-salarie"
aria-describedby="date-naissance-salarie-error"
className={classNames(
"fr-fieldset",
dateState === "error" ? "fr-input-group--error" : ""
)}
style={{ alignItems: "flex-start" }}
>
<legend className="fr-fieldset__legend" id="date-naissance-salarie">
{label}
</legend>
<div className="fr-fieldset__element fr-fieldset__element--inline fr-fieldset__element--number">
<Input
nativeInputProps={{
value: day,
onChange: e => 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&nbsp;: 14."
/>
</div>
<div className="fr-fieldset__element fr-fieldset__element--inline fr-fieldset__element--number">
<Input
nativeInputProps={{
value: month,
onChange: e => setMonth(e.target.value),
onBlur: onValidateBirthDate,
type: "number",
inputMode: "numeric"
}}
label="Mois"
hintText="Entre 1 et 12"
required
state={monthState}
stateRelatedMessage="Mois invalide. Exemple&nbsp;: 12."
/>
</div>
<div className="fr-fieldset__element fr-fieldset__element--inline fr-fieldset__element--inline-grow fr-fieldset__element--year">
<Input
nativeInputProps={{
value: year,
onChange: e => setYear(e.target.value),
onBlur: onValidateBirthDate,
type: "number",
inputMode: "numeric"
}}
label="Année"
hintText="Exemple&nbsp;: 1984"
required
state={yearState}
stateRelatedMessage="Année invalide&nbsp;: elle doit être comprise entre 1924 et 2006. Exemple : 1990."
/>
</div>
{dateState === "error" && (
<p id="date-naissance-salarie-error" className="fr-error-text">
Date invalide&nbsp;: ce jour n'existe pas.
</p>
)}
</fieldset>
);
}
20 changes: 20 additions & 0 deletions web/common/forms/SirenFieldset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from "react";

export const SirenFieldset = ({
labelAnnuaire = "Annuaire des entreprises",
children
}) => (
<fieldset className="fr-fieldset" aria-label="Identifiant entreprise">
<div className="fr-fieldset__element">{children}</div>
<div className="fr-mt-n1v fr-fieldset__element">
<a
className="fr-link"
target="_blank"
rel="noopener noreferrer"
href="https://annuaire-entreprises.data.gouv.fr/"
>
{labelAnnuaire}
</a>
</div>
</fieldset>
);
28 changes: 28 additions & 0 deletions web/common/utils/siren.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export function sirenValidationErrorMessage(siren) {
if (!siren) {
return "Veuillez compléter ce champ.";
}
if (siren.length !== 9 || !/^\d+$/.test(siren)) {
return "Ce numéro SIREN n'est pas valide. Le numéro SIREN est composé de 9 chiffres.";
}

// The last digit of the 9-digit siren must be the Luhn checksum of the 8 firsts
// The following implementation is inspired from https://simplycalc.com/luhn-source.php

let luhnSum = 0;
for (let i = 8; i >= 0; i--) {
let digit = parseInt(siren.charAt(i));
if (i % 2 === 1) {
digit *= 2;
}
if (digit > 9) {
digit -= 9;
}
luhnSum += digit;
}
const validSiren = luhnSum % 10 === 0;
if (!validSiren) {
return "Ce numéro SIREN n'est pas valide. Vérifiez le numéro auprès de l'entreprise ou de la personne qui vous l'a transmis.";
}
return null;
}
Loading

0 comments on commit 1207a3a

Please sign in to comment.