Skip to content

Commit

Permalink
Merge pull request #1015 from parlemonde/ft/VIL-483
Browse files Browse the repository at this point in the history
Ft/vil 483
  • Loading branch information
SimNed authored Dec 5, 2024
2 parents 88958ad + 7f2237c commit 42eae5e
Show file tree
Hide file tree
Showing 10 changed files with 175 additions and 85 deletions.
2 changes: 2 additions & 0 deletions server/controllers/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,8 @@ userController.put({ path: '/:id', userType: UserType.OBSERVATOR }, async (req:
user.countryCode = valueOrDefault(data.countryCode, user.countryCode);
user.avatar = valueOrDefault(data.avatar, user.avatar) || null;
user.displayName = valueOrDefault(data.displayName, user.displayName) || null;
user.firstname = valueOrDefault(data.firstname, user.firstname);
user.lastname = valueOrDefault(data.lastname, user.lastname);
user.firstLogin = valueOrDefault(data.firstLogin, user.firstLogin);
if (req.user !== undefined && req.user.type <= UserType.ADMIN) {
user.type = valueOrDefault(data.type, user.type);
Expand Down
26 changes: 26 additions & 0 deletions src/components/PasswordMessagesDisplayer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';

interface PasswordMessagesDisplayerProps {
isErrors: boolean;
badLengthMessage: string;
missingDigitsMessage: string;
}

const PasswordMessagesDisplayer = ({ isErrors, badLengthMessage, missingDigitsMessage }: PasswordMessagesDisplayerProps) => {
const passwordRequirementsMessage = '12 lettres minimum, une majuscule, une minusucle, un caractère spécial et un chiffre';
return isErrors ? (
<>
{badLengthMessage.length > 0 && (
<>
{badLengthMessage}
<br />
</>
)}
{missingDigitsMessage}
</>
) : (
<>{passwordRequirementsMessage}</>
);
};

export default PasswordMessagesDisplayer;
52 changes: 47 additions & 5 deletions src/components/WelcomeModal/FirstPhase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React from 'react';

import KeyboardArrowLeft from '@mui/icons-material/KeyboardArrowLeft';
import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight';
import { Checkbox } from '@mui/material';
import { Checkbox, Typography } from '@mui/material';
import Button from '@mui/material/Button';
import MobileStepper from '@mui/material/MobileStepper';

Expand Down Expand Up @@ -63,7 +63,7 @@ export const FirstPhase = () => {
};

const updateUser = async () => {
if (!newUser.city || !newUser.address || !newUser.pseudo || !newUser.school || !newUser.email || !newUser.postalCode) {
if (!newUser.firstname || !newUser.lastname || !newUser.school || !newUser.level || !newUser.address || !newUser.city || !newUser.postalCode) {
return;
}
setIsLoading(true);
Expand All @@ -75,6 +75,8 @@ export const FirstPhase = () => {
address: newUser.address,
pseudo: newUser.pseudo,
email: newUser.email,
firstname: newUser.firstname,
lastname: newUser.lastname,
firstLogin: 1,
displayName: newUser.displayName || '',
};
Expand Down Expand Up @@ -159,7 +161,17 @@ export const FirstPhase = () => {
color={currentStep === 2 || currentStep === 4 ? 'primary' : 'inherit'}
variant={currentStep === 2 || currentStep === 4 ? 'contained' : 'text'}
sx={currentStep === 2 || currentStep === 4 ? undefined : defaultTextButtonStyle}
disabled={(currentStep === 3 && (!newUser.city || !newUser.address || !newUser.postalCode)) || (currentStep === 2 && !cguChecked)}
disabled={
(currentStep === 3 &&
(!newUser.firstname ||
!newUser.lastname ||
!newUser.school ||
!newUser.level ||
!newUser.address ||
!newUser.city ||
!newUser.postalCode)) ||
(currentStep === 2 && !cguChecked)
}
onClick={() => {
if (currentStep === 3) {
getNewUserPosition().catch();
Expand Down Expand Up @@ -269,6 +281,36 @@ export const FirstPhase = () => {
</div>
<div style={{ display: 'flex', alignItems: 'stretch' }}>
<div style={{ flex: 1, marginRight: '1rem', minWidth: 0 }}>
<Typography variant="h3" mx={1} mb={2}>
Professionnel de l&apos;éducation
</Typography>
<PanelInput
value={newUser.lastname || ''}
defaultValue={'non renseignée'}
label="Nom : "
placeholder="Nom : "
hasError={!newUser.lastname}
isEditMode
isRequired
onChange={(lastname) => {
setNewUser((u) => ({ ...u, lastname }));
}}
/>
<PanelInput
value={newUser.firstname || ''}
defaultValue={'non renseignée'}
label="Prénom : "
placeholder="Prénom : "
hasError={!newUser.firstname}
isEditMode
isRequired
onChange={(firstname) => {
setNewUser((u) => ({ ...u, firstname }));
}}
/>
<Typography variant="h3" mx={1} my={2}>
Établissement
</Typography>
<PanelInput
value={newUser.school || ''}
defaultValue={'non renseignée'}
Expand Down Expand Up @@ -333,10 +375,10 @@ export const FirstPhase = () => {
<PanelInput value={user.country.name} defaultValue={''} label="Pays :" placeholder="Pays" isEditMode={false} />
)}
<PanelInput
style={{ marginTop: '2rem' }}
style={{ marginTop: '1rem' }}
value={newUser.displayName || ''}
defaultValue={'non renseigné'}
label="Nom affiché : "
label="Pseudo : "
placeholder={getUserDisplayName({ ...user, ...newUser, type: user?.type }, false)}
isEditMode
onChange={(displayName) => {
Expand Down
4 changes: 3 additions & 1 deletion src/components/mon-compte/PanelInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ interface PanelInputProps {
placeholder?: string;
isRequired?: boolean;
isEditMode?: boolean;
isBold?: boolean;
errorMsg?: string;
helperText?: string;
hasError?: boolean;
Expand All @@ -26,6 +27,7 @@ export const PanelInput = ({
placeholder = '',
isRequired = false,
isEditMode = true,
isBold = false,
errorMsg,
helperText,
type = 'text',
Expand All @@ -36,7 +38,7 @@ export const PanelInput = ({
}: PanelInputProps) => {
return (
<div style={{ margin: '0.5rem', display: 'inline-flex', alignItems: 'flex-start', ...style }}>
<label className="text text--bold" style={{ flexShrink: 0 }}>
<label className={`text ${isBold ? 'text--bold' : ''}`} style={{ flexShrink: 0 }}>
{label}
{isRequired && <span style={{ color: 'red' }}>*</span>}
</label>
Expand Down
49 changes: 15 additions & 34 deletions src/pages/inscription.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useRouter } from 'next/router';
import React, { useEffect, useRef, useState } from 'react';
import React, { useEffect, useState } from 'react';

import Visibility from '@mui/icons-material/Visibility';
import VisibilityOff from '@mui/icons-material/VisibilityOff';
Expand All @@ -8,10 +8,12 @@ import { Box, Button, Checkbox, FormControlLabel, Grid, IconButton, InputAdornme
import LanguageFilter from 'src/components/LanguageFilter';
import { Modal } from 'src/components/Modal';
import { ParentsCGU } from 'src/components/ParentsCGU';
import PasswordMessagesDisplayer from 'src/components/PasswordMessagesDisplayer';
import { useLanguages } from 'src/services/useLanguages';
import { useUserRequests } from 'src/services/useUsers';
import ArrowBack from 'src/svg/arrow_back.svg';
import Logo from 'src/svg/logo_1village_famille.svg';
import { invalidPasswordMessageBuilder } from 'src/utils/invalidPasswordMessageBuilder';
import { UserType } from 'types/user.type';
import type { UserForm } from 'types/user.type';

Expand All @@ -22,7 +24,7 @@ const Inscription = () => {
const [lastname, setLastname] = useState<string>('');
const [isLastnameValid, setIsLastnameValid] = useState<boolean>(true);
const [password, setPassword] = useState<string>('');
const passwordMessageRef = useRef<string>('');
const [passwordMessages, setPasswordMessages] = useState<{ badLength: string; missingDigits: string }>({ badLength: '', missingDigits: '' });
const [confirmPassword, setConfirmPassword] = useState<string>('');
const [isPasswordValid, setIsPasswordValid] = useState<boolean>(true);
const [isPasswordMatch, setIsPasswordMatch] = useState<boolean>(true);
Expand Down Expand Up @@ -56,38 +58,13 @@ const Inscription = () => {
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;

if (password !== '') {
passwordMessageRef.current = '';
setIsPasswordValid(false);

if (!password.match(/\d/)) {
passwordMessageRef.current = 'Le mot de passe doit contenir un chiffre';
}
if (!password.match(/[A-Z]/)) {
if (passwordMessageRef.current) {
passwordMessageRef.current += ' et ';
}
passwordMessageRef.current += ' une lettre majuscule';
}
if (password.length < 8) {
if (passwordMessageRef.current) {
passwordMessageRef.current += ' et ';
}
passwordMessageRef.current += 'faire au moins 8 caractères';
}

if (!password.match(/\d/) || !password.match(/[A-Z]/) || password.length < 8) {
setIsPasswordValid(false);
} else {
setIsPasswordValid(true);
}
const invalidPasswordMessage = invalidPasswordMessageBuilder(password);
setPasswordMessages({ badLength: invalidPasswordMessage.badLengthMessage, missingDigits: invalidPasswordMessage.missingDigitMessage });
setIsPasswordValid(invalidPasswordMessage.badLengthMessage === '' && invalidPasswordMessage.missingDigitMessage === '');
}

if (confirmPassword !== '') {
if (password !== confirmPassword) {
setIsPasswordMatch(false);
} else {
setIsPasswordMatch(true);
}
setIsPasswordMatch(password === confirmPassword);
}

if (email !== '') {
Expand Down Expand Up @@ -194,8 +171,6 @@ const Inscription = () => {
setIsConfirmationPasswordVisible(!isConfirmationPasswordVisible);
};

const passwordMessage = passwordMessageRef.current;

return (
<Grid
container
Expand Down Expand Up @@ -352,7 +327,13 @@ const Inscription = () => {
}}
type={isPasswordVisible === false ? 'password' : 'text'}
error={isPasswordValid === false}
helperText={isPasswordValid === true ? '8 lettres minimum, une majuscule et un chiffre' : passwordMessage}
helperText={
<PasswordMessagesDisplayer
isErrors={!isPasswordValid}
badLengthMessage={passwordMessages.badLength}
missingDigitsMessage={passwordMessages.missingDigits}
/>
}
InputLabelProps={{ shrink: true }}
onChange={(event) => {
setPassword(event.target.value);
Expand Down
8 changes: 7 additions & 1 deletion src/pages/mon-compte.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ const Presentation = () => {
label="École :"
placeholder="Nom de votre école"
isEditMode={editMode === 0}
isBold
onChange={(school) => {
setNewUser((u) => (!u ? u : { ...u, school }));
}}
Expand All @@ -287,6 +288,7 @@ const Presentation = () => {
label="Niveau de la classe :"
placeholder="Niveau de votre classe"
isEditMode={editMode === 0}
isBold
onChange={(level) => {
setNewUser((u) => (!u ? u : { ...u, level }));
}}
Expand All @@ -297,6 +299,7 @@ const Presentation = () => {
label="Adresse de l'école :"
placeholder="Adresse"
isEditMode={editMode === 0}
isBold
onChange={(address) => {
setNewUser((u) => (!u ? u : { ...u, address }));
}}
Expand All @@ -307,6 +310,7 @@ const Presentation = () => {
label="Ville :"
placeholder="Ville"
isEditMode={editMode === 0}
isBold
onChange={(city) => {
setNewUser((u) => (!u ? u : { ...u, city }));
}}
Expand All @@ -317,16 +321,18 @@ const Presentation = () => {
label="Code postal :"
placeholder="Code postal"
isEditMode={editMode === 0}
isBold
onChange={(postalCode) => {
setNewUser((u) => (!u ? u : { ...u, postalCode }));
}}
/>
<PanelInput
value={newUser.displayName || ''}
defaultValue={getUserDisplayName(user, false, true)}
label="Nom affiché sur vos publications :"
label="Pseudo :"
placeholder={getUserDisplayName(user, false, true)}
isEditMode={editMode === 0}
isBold
onChange={(displayName) => {
setNewUser((u) => (!u ? u : { ...u, displayName }));
}}
Expand Down
21 changes: 12 additions & 9 deletions src/pages/reset-password.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { axiosRequest } from 'src/utils/axiosRequest';

const errorMessages = {
0: `Une erreur inconnue s'est produite`,
1: `L'email renseignée est incorrect`,
1: `Veuillez renseigner une adresse mail valide`,
};

const ResetPassword: React.FunctionComponent = () => {
Expand All @@ -20,14 +20,21 @@ const ResetPassword: React.FunctionComponent = () => {
const [isSuccess, setIsSuccess] = React.useState<boolean>(false);
const [loading, setLoading] = React.useState<boolean>(false);

const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;

const handleEmailInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setEmail(event.target.value);
setErrorCode(-1);
};

const submit = async (event: React.FormEvent) => {
event.preventDefault();
setErrorCode(-1);

if (!emailRegex.test(email)) {
setErrorCode(1);
return;
}

setLoading(true);
const response = await axiosRequest({
method: 'POST',
Expand All @@ -37,8 +44,8 @@ const ResetPassword: React.FunctionComponent = () => {
},
});
setLoading(false);
if (response.error) {
setErrorCode(response.status === 400 ? 1 : 0);
if (response.status === 400) {
setErrorCode(0);
} else {
setTimeout(() => {
setIsSuccess(true);
Expand Down Expand Up @@ -144,8 +151,6 @@ const ResetPassword: React.FunctionComponent = () => {
<Box width="90%" maxWidth="350px" margin="0 auto">
<Typography margin="0 auto" align="left">
Veuillez renseigner l&apos;email lié à votre compte.
<br />
Nous vous enverrons un email avec un lien qui vous permettra de réinitialiser votre mot de passe.
</Typography>

<Box
Expand Down Expand Up @@ -201,9 +206,7 @@ const ResetPassword: React.FunctionComponent = () => {
) : (
<Box textAlign="center" display="block" height="fit-content">
<PelicoSouriant style={{ width: '100%', maxWidth: '250px', maxHeight: '250px', cursor: 'pointer' }} />
<div>Un email vient de vous être envoyé à l&apos;adresse donnée</div>
<br />
<div>Vous allez être redirigé(e) vers la page de connexion...</div>
<div>Si cette adresse e-mail est enregistrée, nous y avons envoyé les instructions afin de réinitialiser votre mot de passe.</div>
</Box>
)}
</Grid>
Expand Down
Loading

0 comments on commit 42eae5e

Please sign in to comment.