Skip to content

Commit

Permalink
Mise en place du formulaire candidature d'un conseiller
Browse files Browse the repository at this point in the history
  • Loading branch information
NerOcrO committed Jun 27, 2024
1 parent e3c87d6 commit d69ebc9
Show file tree
Hide file tree
Showing 13 changed files with 360 additions and 18 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Continuous Integration

on: pull_request

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
cache: npm
node-version-file: package.json
- name: Install modules
run: npm i
- name: Lint
run: npm run lint

tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
cache: npm
node-version-file: package.json
- name: Install modules
run: npm i
- name: Lint
run: npm run test
17 changes: 0 additions & 17 deletions .github/workflows/eslint.yml

This file was deleted.

2 changes: 1 addition & 1 deletion public/styles-5.22.0.css

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Carte from './views/Carte';
import CarteCoordinateur from './views/coordination-territoriale/CarteCoordinateur';
import Formation from './views/formation';
import DonneesPersonnelles from './views/donnees-personnelles';
import PageCandidatureConseiller from './views/candidature-conseiller/PageCandidatureConseiller';

const RedirectCarto = () => {
const { permanence } = useParams();
Expand All @@ -37,6 +38,7 @@ function App() {
<Router>
<Routes>
<Route path="/accueil" element={<GestionHash />}/>
<Route path="/nouveau-formulaire-conseiller" element={<PageCandidatureConseiller />}/>
<Route path="/kit-communication" element={<KitCommunication />}/>
<Route path="/donnees-personnelles" element={<DonneesPersonnelles />}/>
<Route path="/mentions-legales" element={<MentionsLegales />}/>
Expand Down
15 changes: 15 additions & 0 deletions src/views/candidature-conseiller/CandidatureConseiller.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.cc-section {
border: 1px solid var(--grey-900-175);
}

.cc-titre {
color: var(--blue-france-sun-113-625);
}

.cc-obligatoire {
color: var(--error-425-625);
}

.cc-bold {
font-weight: 900;
}
27 changes: 27 additions & 0 deletions src/views/candidature-conseiller/CandidatureConseiller.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';
import Sommaire from './Sommaire';
import InformationsDeContact from './InformationsDeContact';
import SituationEtExperience from './SituationEtExperience';
import './CandidatureConseiller.css';

export default function CandidatureConseiller() {
return (
<div className="fr-container fr-mt-5w fr-mb-5w">
<div className="fr-grid-row">
<div className="fr-col-4">
<Sommaire />
</div>
<div className="fr-col-8">
<h1 className="cc-titre fr-mb-5w">Je veux devenir conseiller numérique</h1>
<form aria-label="Candidature conseiller">
<InformationsDeContact />
<SituationEtExperience />
<button className="fr-btn" type="submit">
Envoyer votre candidature
</button>
</form>
</div>
</div>
</div>
);
}
115 changes: 115 additions & 0 deletions src/views/candidature-conseiller/CandidatureConseiller.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { render, screen, within } from '@testing-library/react';
import { describe, expect, it } from 'vitest';
import CandidatureConseiller from './CandidatureConseiller';

export const textMatcher = wording => (_, element) => {
return element?.textContent === wording;
};

describe('candidature conseiller', () => {
describe('étant un candidat', () => {
it('quand j’affiche le formulaire alors le titre et le menu s’affiche', () => {
// WHEN
render(<CandidatureConseiller />);

// THEN
const titre = screen.getByRole('heading', { level: 1, name: 'Je veux devenir conseiller numérique' });
expect(titre).toBeInTheDocument();

const navigation = screen.getByRole('navigation', { name: 'Sommaire' });
const menu = within(navigation).getByRole('list');
const menuItems = within(menu).getAllByRole('listitem');

const informationsDeContact = within(menuItems[0]).getByRole('link', { name: 'Vos informations de contact' });
expect(informationsDeContact).toHaveAttribute('href', '#informationsDeContact');

const situationEtExperience = within(menuItems[1]).getByRole('link', { name: 'Votre situation et expérience' });
expect(situationEtExperience).toHaveAttribute('href', '#situtationEtExperience');

const votreDisponibilite = within(menuItems[2]).getByRole('link', { name: 'Votre disponibilité' });
expect(votreDisponibilite).toHaveAttribute('href', '#votreDisponibilite');

const votreMotivation = within(menuItems[3]).getByRole('link', { name: 'Votre motivation' });
expect(votreMotivation).toHaveAttribute('href', '#votreDisponibilite');
});
});

it('quand j’affiche le formulaire alors l’étape "Vos informations de contact" est affiché', () => {
// WHEN
render(<CandidatureConseiller />);

// THEN
const formulaire = screen.getByRole('form', { name: 'Candidature conseiller' });
const etapeInformationsDeContact = within(formulaire).getByRole('group', { name: 'Vos informations de contact' });
expect(etapeInformationsDeContact).toHaveAttribute('id', 'informationsDeContact');

const champsObligatoires = within(etapeInformationsDeContact).getByText(textMatcher('Les champs avec * sont obligatoires.'), { selector: 'p' });
expect(champsObligatoires).toBeInTheDocument();

const prenom = within(etapeInformationsDeContact).getByLabelText('Prénom *');
expect(prenom).toHaveAttribute('type', 'text');
expect(prenom).toBeRequired();

const nom = within(etapeInformationsDeContact).getByLabelText('Nom *');
expect(nom).toHaveAttribute('type', 'text');
expect(nom).toBeRequired();

const email = within(etapeInformationsDeContact).getByLabelText('Adresse e-mail * Format attendu : [email protected]');
expect(email).toHaveAttribute('type', 'email');
expect(email).toBeRequired();

const telephone = within(etapeInformationsDeContact).getByLabelText('Téléphone Format attendu : 0122334455');
expect(telephone).toHaveAttribute('type', 'text');

const habitation = within(etapeInformationsDeContact).getByLabelText('Votre lieu d’habitation Saississez le nom ou le code postal de votre commune.');
expect(habitation).toHaveAttribute('type', 'text');
});

it('quand j’affiche le formulaire alors l’étape "Votre situation et expérience" est affiché', () => {
// WHEN
render(<CandidatureConseiller />);

// THEN
const formulaire = screen.getByRole('form', { name: 'Candidature conseiller' });
const situationEtExperience = within(formulaire).getByRole('group', { name: 'Votre situation et expérience' });
expect(situationEtExperience).toHaveAttribute('id', 'situationEtExperience');

const champsObligatoires = within(situationEtExperience).getByText(textMatcher('Les champs avec * sont obligatoires.'), { selector: 'p' });
expect(champsObligatoires).toBeInTheDocument();

const situation = within(situationEtExperience).getByText(textMatcher('Êtes-vous actuellement dans l’une des situations suivantes ? *'), { selector: 'p' });
expect(situation).toBeInTheDocument();

const demandeurEmploi = screen.getByRole('checkbox', { name: 'Demandeur d’emploi' });
expect(demandeurEmploi).toBeInTheDocument();

const enEmploi = screen.getByRole('checkbox', { name: 'En emploi' });
expect(enEmploi).toBeInTheDocument();

const enFormation = screen.getByRole('checkbox', { name: 'En formation' });
expect(enFormation).toBeInTheDocument();

const diplome = screen.getByRole('checkbox', { name: 'Diplômé dans le secteur de la médiation numérique (formation certifiante ou non)' });
expect(diplome).toBeInTheDocument();

const experienceProfessionnelle = within(situationEtExperience).getByText(
textMatcher('Avez-vous une expérience professionnelle de médiation numérique ? *'),
{ selector: 'p' }
);
expect(experienceProfessionnelle).toBeInTheDocument();

const sousTitreExperienceProfessionnelle = within(situationEtExperience).getByText(
textMatcher('Accompagnement de personnes vers l’autonomie dans leurs usages de technologies, services et médias numériques.'),
{ selector: 'p' }
);
expect(sousTitreExperienceProfessionnelle).toBeInTheDocument();

const oui = screen.getByRole('radio', { name: 'Oui' });
expect(oui).toBeRequired();
expect(oui).toHaveAttribute('name', 'experienceProfessionnelle');

const non = screen.getByRole('radio', { name: 'Non' });
expect(non).toBeRequired();
expect(non).toHaveAttribute('name', 'experienceProfessionnelle');
});
});
20 changes: 20 additions & 0 deletions src/views/candidature-conseiller/Checkbox.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';
import PropTypes from 'prop-types';

export default function Checkbox({ children, id }) {
return (
<div className="fr-fieldset__element">
<div className="fr-checkbox-group">
<input id={id} type="checkbox" />
<label className="fr-label" htmlFor={id}>
{children}
</label>
</div>
</div>
);
}

Checkbox.propTypes = {
children: PropTypes.node,
id: PropTypes.string,
};
40 changes: 40 additions & 0 deletions src/views/candidature-conseiller/InformationsDeContact.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react';
import Input from './Input';

export default function InformationsDeContact() {
return (
<fieldset className="fr-border cc-section fr-p-3w fr-mb-3w" id="informationsDeContact">
<legend className="fr-h5">Vos informations de contact</legend>
<p className="fr-text--sm fr-hint-text">Les champs avec <span className="cc-obligatoire">*</span> sont obligatoires.</p>
<hr />
<Input
id="prenom"
>
Prénom <span className="cc-obligatoire">*</span>
</Input>
<Input
id="nom"
>
Nom <span className="cc-obligatoire">*</span>
</Input>
<Input
id="email"
type="email"
>
Adresse e-mail <span className="cc-obligatoire">*</span> <span className="fr-hint-text">Format attendu : [email protected]</span>
</Input>
<Input
id="telephone"
isRequired={false}
>
Téléphone <span className="fr-hint-text">Format attendu : 0122334455</span>
</Input>
<Input
id="lieuHabitation"
isRequired={false}
>
Votre lieu d’habitation <span className="fr-hint-text">Saississez le nom ou le code postal de votre commune.</span>
</Input>
</fieldset>
);
}
20 changes: 20 additions & 0 deletions src/views/candidature-conseiller/Input.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';
import PropTypes from 'prop-types';

export default function Input({ children, id, isRequired = true, type = 'text' }) {
return (
<div className="fr-fieldset__element">
<div className="fr-input-group">
<label className="fr-label" htmlFor={id}>{children}</label>
<input className="fr-input" type={type} id={id} required={isRequired} />
</div>
</div>
);
}

Input.propTypes = {
children: PropTypes.node,
id: PropTypes.string,
isRequired: PropTypes.bool,
type: PropTypes.string,
};
12 changes: 12 additions & 0 deletions src/views/candidature-conseiller/PageCandidatureConseiller.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import Header from '../../components/Header';
import CandidatureConseiller from './CandidatureConseiller';

export default function PageCandidatureConseiller() {
return (
<>
<Header />
<CandidatureConseiller />
</>
);
}
48 changes: 48 additions & 0 deletions src/views/candidature-conseiller/SituationEtExperience.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from 'react';
import Checkbox from './Checkbox';

export default function SituationEtExperience() {
return (
<fieldset className="fr-border cc-section fr-p-3w fr-mb-3w" id="situationEtExperience">
<legend className="fr-h5">Votre situation et expérience</legend>
<p className="fr-text--sm fr-hint-text">Les champs avec <span className="cc-obligatoire">*</span> sont obligatoires.</p>
<hr />
<p className="fr-mb-3w cc-bold">
Êtes-vous actuellement dans l’une des situations suivantes ? <span className="cc-obligatoire">*</span>
</p>
<Checkbox id="demandeurEmploi">
Demandeur d’emploi
</Checkbox>
<Checkbox id="enEmploi">
En emploi
</Checkbox>
<Checkbox id="enFormation">
En formation
</Checkbox>
<Checkbox id="diplome">
Diplômé dans le secteur de la médiation numérique (formation certifiante ou non)
</Checkbox>
<hr />
<p className="fr-mb-3w cc-bold">
Avez-vous une expérience professionnelle de médiation numérique ? <span className="cc-obligatoire">*</span>
</p>
<p className="fr-text--sm fr-hint-text">Accompagnement de personnes vers l’autonomie dans leurs usages de technologies, services et médias numériques.</p>
<div className="fr-fieldset__element">
<div className="fr-radio-group">
<input type="radio" id="oui" name="experienceProfessionnelle" required />
<label className="fr-label" htmlFor="oui">
Oui
</label>
</div>
</div>
<div className="fr-fieldset__element">
<div className="fr-radio-group">
<input type="radio" id="non" name="experienceProfessionnelle" required />
<label className="fr-label" htmlFor="non">
Non
</label>
</div>
</div>
</fieldset>
);
}
Loading

0 comments on commit d69ebc9

Please sign in to comment.