Skip to content

Commit

Permalink
Ajout d'erreur sur les inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
Alezco committed Nov 25, 2024
1 parent b77f7a5 commit 734893c
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 18 deletions.
30 changes: 26 additions & 4 deletions src/components/commun/Input.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
import React from 'react';
import PropTypes from 'prop-types';

export default function Input({ children, id, isRequired = true, autoComplete = 'on', testId = '', type = 'text',
pattern, onChange, list, min, disabled, isLoading, ariaBusy, value, maxlength }) {
export default function Input({
children,
id,
isRequired = true,
autoComplete = 'on',
testId = '',
type = 'text',
pattern,
onChange,
list,
min,
disabled,
isLoading,
ariaBusy,
value,
maxlength,
error,
}) {
return (
<div className="fr-fieldset__element">
<div className="fr-input-group">
<div className={`fr-input-group${error ? ' fr-input-group--error' : ''}`}>
<label className="fr-label" htmlFor={id}>{children}</label>
<input
className="fr-input"
Expand All @@ -29,6 +45,11 @@ export default function Input({ children, id, isRequired = true, autoComplete =
<div className="fr-spinner fr-spinner--sm" aria-label="Chargement..."></div>
</div>
)}
{error && (
<p id="text-input-error-desc-error" className="fr-error-text">
{error}
</p>
)}
</div>
</div>
);
Expand All @@ -49,5 +70,6 @@ Input.propTypes = {
ariaBusy: PropTypes.bool,
value: PropTypes.string,
testId: PropTypes.string,
maxlength: PropTypes.string
maxlength: PropTypes.string,
error: PropTypes.string
};
10 changes: 8 additions & 2 deletions src/components/commun/ZoneDeTexte.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import React from 'react';
import PropTypes from 'prop-types';

export default function ZoneDeTexte({ children, id, isRequired = true, maxlength = "2500" }) {
export default function ZoneDeTexte({ children, id, isRequired = true, maxlength = '2500', error }) {
return (
<div className="fr-input-group">
<div className={`fr-input-group${error ? ' fr-input-group--error' : ''}`}>
<label className="fr-label" htmlFor={id}>
{children}
</label>
<textarea className="fr-input" id={id} name={id} required={isRequired} maxLength={maxlength}></textarea>
{error && (
<p id="text-input-error-desc-error" className="fr-error-text">
{error}
</p>
)}
</div>
);
}
Expand All @@ -17,4 +22,5 @@ ZoneDeTexte.propTypes = {
id: PropTypes.string,
isRequired: PropTypes.bool,
maxlength: PropTypes.string,
error: PropTypes.string,
};
12 changes: 9 additions & 3 deletions src/views/candidature-conseiller/AddressChooser.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@ import React, { useState } from 'react';
import Input from '../../components/commun/Input';
import { useGeoApi } from './useGeoApi';
import { debounce } from './debounce';
import PropTypes from 'prop-types';

export default function AddressChooser() {
export default function AddressChooser({ error }) {
const { searchByName, villes } = useGeoApi();
const [codeCommune, setCodeCommune] = useState('');

return (
<>
<Input
autoComplete= "off"
autoComplete="off"
id="lieuHabitation"
list="resultatsRecherche"
error={error}
onChange={debounce(async event => {
searchByName(event.target.value);
const codeCommune = await villes.find(({ codesPostaux, nom }) =>
Expand All @@ -23,7 +25,7 @@ export default function AddressChooser() {
Votre lieu d’habitation <span className="cc-obligatoire">*</span>{' '}
<span className="fr-hint-text">Saississez le nom ou le code postal de votre commune.</span>
</Input>
<Input type="hidden" id="lieuHabitationCodeCommune" value={codeCommune} testId="lieuHabitationCodeCommune-hidden"/>
<Input type="hidden" id="lieuHabitationCodeCommune" value={codeCommune} testId="lieuHabitationCodeCommune-hidden" />
<datalist id="resultatsRecherche">
{villes?.map(({ codesPostaux, nom }, key) => (
<option value={`${codesPostaux[0]} ${nom}`} key={key}>
Expand All @@ -34,3 +36,7 @@ export default function AddressChooser() {
</>
);
}

AddressChooser.propTypes = {
error: PropTypes.bool
};
22 changes: 17 additions & 5 deletions src/views/candidature-conseiller/CandidatureConseiller.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useRef } from 'react';
import SommaireConseiller from './SommaireConseiller';
import InformationsDeContact from './InformationsDeContact';
import SituationEtExperience from './SituationEtExperience';
Expand All @@ -25,8 +25,10 @@ export default function CandidatureConseiller() {
const [dateDisponibilite, setDateDisponibilite] = useState('');
const [isSituationValid, setIsSituationValid] = useState(true);
const [validationError, setValidationError] = useState('');
const [errors, setErrors] = useState({});
const [widgetId, setWidgetId] = useState(null);
const { buildConseillerData, creerCandidatureConseiller } = useApiAdmin();
const ref = useRef(null);

const navigate = useNavigate();
useScrollToSection();
Expand All @@ -44,6 +46,14 @@ export default function CandidatureConseiller() {
return demandeurEmploi || enEmploi || enFormation || diplome;
};

const checkValidity = () => {
const formData = new FormData(ref.current);
const keys = Array.from(formData.keys());
const formElements = keys.map(key => document.getElementById(key)).filter(key => key !== null);
const errors = formElements.map(formElement => ({ [formElement.id]: formElement.validationMessage }));
setErrors(Object.assign({}, ...errors));
};

const validerLaCandidature = async event => {
event.preventDefault();

Expand Down Expand Up @@ -89,16 +99,18 @@ export default function CandidatureConseiller() {
<form
aria-label="Candidature conseiller"
onSubmit={validerLaCandidature}
onInput={checkValidity}
ref={ref}
>
<InformationsDeContact />
<InformationsDeContact errors={errors} />
<SituationEtExperience isSituationValid={isSituationValid} />
<Disponibilite setDateDisponibilite={setDateDisponibilite} />
<Motivation />
<Motivation errors={errors} />
<EnResume dateDisponibilite={dateDisponibilite} />
<div className="fr-mt-2w fr-mb-2w">
<Captcha setWidgetId={setWidgetId} widgetId={widgetId}/>
<Captcha setWidgetId={setWidgetId} widgetId={widgetId} />
</div>
<button className="fr-btn cc-envoyer" type="submit">
<button className="fr-btn cc-envoyer" type="submit" onClick={checkValidity}>
Envoyer votre candidature
</button>
</form>
Expand Down
13 changes: 11 additions & 2 deletions src/views/candidature-conseiller/InformationsDeContact.jsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
import React from 'react';
import Input from '../../components/commun/Input';
import AddressChooser from './AddressChooser';
import PropTypes from 'prop-types';

export default function InformationsDeContact() {
export default function InformationsDeContact({ errors }) {
return (
<fieldset className="fr-border cc-section fr-p-3w fr-mb-3w" id="informations-de-contact">
<legend className="fr-h5">Vos informations de contact</legend>
<hr />
<Input
id="prenom"
error={errors.prenom}
>
Prénom <span className="cc-obligatoire">*</span>
</Input>
<Input
id="nom"
error={errors.nom}
>
Nom <span className="cc-obligatoire">*</span>
</Input>
<Input
id="email"
type="email"
error={errors.email}
>
Adresse électronique <span className="cc-obligatoire">*</span> <span className="fr-hint-text">Format attendu : [email protected]</span>
</Input>
Expand All @@ -28,10 +32,15 @@ export default function InformationsDeContact() {
type="tel"
pattern="([+][0-9]{11,12})|([0-9]{10})"
isRequired={false}
error={errors.telephone}
>
Téléphone <span className="fr-hint-text">Format attendu : 0122334455 ou +33122334455</span>
</Input>
<AddressChooser />
<AddressChooser error={errors.lieuHabitation}/>
</fieldset>
);
}

InformationsDeContact.propTypes = {
errors: PropTypes.object
};
9 changes: 7 additions & 2 deletions src/views/candidature-conseiller/Motivation.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import React from 'react';
import ZoneDeTexte from '../../components/commun/ZoneDeTexte';
import PropTypes from 'prop-types';

export default function Motivation() {
export default function Motivation({ errors }) {
return (
<fieldset className="fr-border cc-section fr-p-3w fr-mb-3w" id="votre-motivation">
<legend className="fr-h5" id="titreMotivation">Votre motivation</legend>
<p className="fr-text--sm fr-hint-text">
En quelques lignes, décrivez votre motivation personnelle pour devenir conseiller numérique et{' '}
aider les personnes à devenir autonomes dans l’utilisation des outils numériques.
</p>
<ZoneDeTexte id="motivation">
<ZoneDeTexte id="motivation" error={errors.motivation}>
Votre message <span className="cc-obligatoire">*</span> <span className="fr-hint-text">Limité à 2500 caractères</span>
</ZoneDeTexte>
</fieldset>
);
}

Motivation.propTypes = {
errors: PropTypes.object
};

0 comments on commit 734893c

Please sign in to comment.