Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Conformation email structure #219

Merged
merged 5 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ function App() {
const PageCandidatureStructure = lazy(() => import('./views/candidature-structure/PageCandidatureStructure'));
const PageCandidatureCoordinateur = lazy(() => import('./views/candidature-coordinateur/PageCandidatureCoordinateur'));
const PageCandidatureValidee = lazy(() => import('./views/candidature-validee/PageCandidatureValidee'));
const PageConfirmationEmailCandidature = lazy(() => import('./views/confirmation-email-candidature/PageConfirmationEmailCandidature'));
const PageConfirmationEmailCandidatureConseiller =
lazy(() => import('./views/confirmation-email-candidature-conseiller/PageConfirmationEmailCandidatureConseiller'));
const PageConfirmationEmailCandidatureStructure =
lazy(() => import('./views/confirmation-email-candidature-structure/PageConfirmationEmailCandidatureStructure'));

return (
<div className="App">
Expand All @@ -52,7 +55,8 @@ function App() {
<Route path="/nouveau-formulaire-structure" element={<PageCandidatureStructure />}/>
<Route path="/nouveau-formulaire-coordinateur" element={<PageCandidatureCoordinateur />}/>
<Route path="/candidature-validee" element={<PageCandidatureValidee />}/>
<Route path="/candidature-confirmer/:token" element={<PageConfirmationEmailCandidature />}/>
<Route path="/candidature-confirmer-conseiller/:token" element={<PageConfirmationEmailCandidatureConseiller />}/>
<Route path="/candidature-confirmer-structure/:token" element={<PageConfirmationEmailCandidatureStructure />}/>
<Route path="/kit-communication" element={<KitCommunication />}/>
<Route path="/donnees-personnelles" element={<DonneesPersonnelles />}/>
<Route path="/mentions-legales" element={<MentionsLegales />}/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import { useApiConfirmationEmailCandidature } from './useApiConfirmationEmailCandidature';
import { useApiConfirmationEmailCandidatureConseiller } from './useApiConfirmationEmailCandidatureConseiller';


export default function CandidatureValidee() {
export default function ConfirmationEmailCandidatureConseiller() {
const [reponseStatusConfirmation, setReponseStatusConfirmation] = useState(null);
const { actionConfirmationEmailCandidature } = useApiConfirmationEmailCandidature();
const { actionConfirmationEmailCandidatureConseiller } = useApiConfirmationEmailCandidatureConseiller();
const { token } = useParams();

useEffect(() => {
window.scrollTo({ top: 0, behavior: 'smooth' });
}, []);
const ClickBoutonConfirmer = async () => {
const response = await actionConfirmationEmailCandidature(token);
const response = await actionConfirmationEmailCandidatureConseiller(token);
setReponseStatusConfirmation(response.status);
};
return (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import Header from '../../components/Header';
import ConfirmationEmailCandidatureConseiller from './ConfirmationEmailCandidatureConseiller';

export default function PageConfirmationEmailCandidatureConseiller() {
return (
<>
<Header />
<ConfirmationEmailCandidatureConseiller />
</>
);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { render, act, screen, fireEvent } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';
import ConfirmationEmailCandidature from './ConfirmationEmailCandidature';
import ConfirmationEmailCandidature from './ConfirmationEmailCandidatureConseiller';

vi.mock('react-router-dom', () => ({
useParams: () => ({ token: '1' }),
Expand All @@ -10,7 +10,6 @@ describe('confirmation Email', () => {
it('quand j’affiche la page de confirmation de l’email validée alors le titre et les informations de la page s’affichent', () => {
// WHEN
render(<ConfirmationEmailCandidature />);
vi.spyOn(window, 'scrollTo').mockImplementation();

// THEN
const titre = screen.getByRole('heading', { level: 1, name: 'Confirmation de l’enregistrement de votre candidature' });
Expand All @@ -25,22 +24,21 @@ describe('confirmation Email', () => {
expect(envoyer).toBeInTheDocument();
});

it('quand l’utilisateur clique sur le bouton et que le lien est valide alors un message success s’affiche', async () => {
it('quand l’utilisateur clique sur le bouton et que le lien est valide alors un message de succès s’affiche', async () => {
// WHEN
vi.spyOn(window, 'scrollTo').mockImplementation();
render(<ConfirmationEmailCandidature />);
vi.stubGlobal('fetch', vi.fn(
() => ({ status: 200, json: async () => Promise.resolve({}) }))
);
render(<ConfirmationEmailCandidature />);

const envoyer = screen.getByRole('button', { name: 'Confirmer' });
expect(envoyer).toBeInTheDocument();
// eslint-disable-next-line testing-library/no-unnecessary-act
await act(() => {
fireEvent.click(envoyer);
});
expect(envoyer).not.toBeInTheDocument();
// THEN
expect(envoyer).not.toBeInTheDocument();
const titre = screen.getByRole('heading', { level: 1, name: 'Confirmation de l’enregistrement de votre candidature' });
expect(titre).toBeInTheDocument();

Expand All @@ -53,14 +51,13 @@ describe('confirmation Email', () => {
const messageError403 = screen.queryByText('Impossible de valider l’email, le lien a expiré ou est invalide.', { selector: 'p' });
expect(messageError403).not.toBeInTheDocument();

const messageErrorGenerale = screen.queryByText('Une erreur s’est produite veuillez réessayer plus tard.', { selector: 'p' });
expect(messageErrorGenerale).not.toBeInTheDocument();
const messageErreurGenerale = screen.queryByText('Une erreur s’est produite veuillez réessayer plus tard.', { selector: 'p' });
expect(messageErreurGenerale).not.toBeInTheDocument();
});

it('quand l’utilisateur clique sur le bouton et que le lien est invalide alors un message d’erreur s’affiche', async () => {

// GIVEN
vi.spyOn(window, 'scrollTo').mockImplementation();
vi.stubGlobal('fetch', vi.fn(
() => ({ status: 403, json: async () => Promise.resolve({}) }))
);
Expand All @@ -87,12 +84,12 @@ describe('confirmation Email', () => {
const messageSuccess = screen.queryByText('Votre email a été confirmé et votre inscription est maintenant active.' +
' Vous serez contacté par mail ou par téléphone si une structure est intéressée par votre profil.', { selector: 'p' });
expect(messageSuccess).not.toBeInTheDocument();
const messageErrorGenerale = screen.queryByText('Une erreur s’est produite veuillez réessayer plus tard.', { selector: 'p' });
expect(messageErrorGenerale).not.toBeInTheDocument();
const messageErreurGenerale = screen.queryByText('Une erreur s’est produite veuillez réessayer plus tard.', { selector: 'p' });
expect(messageErreurGenerale).not.toBeInTheDocument();
});


it('quand l’utilisateur clique sur le bouton et qu’une erreur innatendu se produit alors un message d’erreur s’affiche', async () => {
it('quand l’utilisateur clique sur le bouton et qu’une erreur innatendue se produit alors un message d’erreur s’affiche', async () => {
// GIVEN
vi.stubGlobal('fetch', vi.fn(
() => ({ status: 500, json: async () => Promise.resolve({}) }))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@

export const useApiConfirmationEmailCandidature = () => {
export const useApiConfirmationEmailCandidatureConseiller = () => {


const actionConfirmationEmailCandidature = async token => {
const actionConfirmationEmailCandidatureConseiller = async token => {
const baseUrl = import.meta.env.VITE_APP_API_URL;
const requestOptions = {
method: 'PATCH',
Expand All @@ -15,5 +15,5 @@ export const useApiConfirmationEmailCandidature = () => {
}
};

return { actionConfirmationEmailCandidature };
return { actionConfirmationEmailCandidatureConseiller };
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import { useApiConfirmationEmailCandidatureStructure } from './useApiConfirmationEmailCandidatureStructure';

export default function ConfirmationEmailCandidatureStructure() {
const [reponseStatusConfirmation, setReponseStatusConfirmation] = useState(null);
const { actionConfirmationEmailCandidatureStructure } = useApiConfirmationEmailCandidatureStructure();
const { token } = useParams();

useEffect(() => {
window.scrollTo({ top: 0, behavior: 'smooth' });
}, []);
const confirmerEmailCandidatureStructure = async () => {
const response = await actionConfirmationEmailCandidatureStructure(token);
setReponseStatusConfirmation(response.status);
};
return (
<div className="fr-container fr-p-10w cv-contenu">
<h1 className="fr-mb-5w cv-titre">Confirmation de l’enregistrement de votre candidature</h1>
{reponseStatusConfirmation === 200 && <div className="fr-alert fr-alert--success fr-alert--sm">
<p>Votre email a été confirmé et votre inscription est maintenant active.
Vous recevrez un mail d’activation de votre espace structure lorsque votre candidature aura été validée.</p>
</div>}
{reponseStatusConfirmation === 403 && <div className="fr-alert fr-alert--error fr-alert--sm">
<p>Impossible de valider l’email, le lien a expiré ou est invalide.</p>
</div>}
{reponseStatusConfirmation >= 400 && reponseStatusConfirmation !== 403 && <div className="rf-alert fr-alert--error fr-alert--sm">
<p>Une erreur s’est produite veuillez réessayer plus tard.</p>
</div>}
{!reponseStatusConfirmation && <>
<p>
Appuyez sur le bouton pour confirmer votre email
</p>
<button onClick={confirmerEmailCandidatureStructure} className="fr-btn fr-btn--secondary">
Confirmer
</button>
</>}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import Header from '../../components/Header';
import ConfirmationEmailCandidatureStructure from './ConfirmationEmailCandidatureStructure';

export default function PageConfirmationEmailCandidatureStructure() {
return (
<>
<Header />
<ConfirmationEmailCandidatureStructure />
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { render, act, screen, fireEvent } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';
import ConfirmationEmailCandidatureStructure from './ConfirmationEmailCandidatureStructure';

vi.mock('react-router-dom', () => ({
useParams: () => ({ token: '1' }),
}));

describe('confirmation Email', () => {
it('quand j’affiche la page de confirmation de l’email validée alors le titre et les informations de la page s’affichent', () => {
// WHEN
render(<ConfirmationEmailCandidatureStructure />);

// THEN
const titre = screen.getByRole('heading', { level: 1, name: 'Confirmation de l’enregistrement de votre candidature' });
expect(titre).toBeInTheDocument();

const indication = screen.getByText('Appuyez sur le bouton pour confirmer votre email',
{ selector: 'p' }
);
expect(indication).toBeInTheDocument();

const envoyer = screen.getByRole('button', { name: 'Confirmer' });
expect(envoyer).toBeInTheDocument();
});

it('quand l’utilisateur clique sur le bouton et que le lien est valide alors un message de succès s’affiche', async () => {
// WHEN
vi.stubGlobal('fetch', vi.fn(
() => ({ status: 200, json: async () => Promise.resolve({}) }))
);
render(<ConfirmationEmailCandidatureStructure />);

const envoyer = screen.getByRole('button', { name: 'Confirmer' });
expect(envoyer).toBeInTheDocument();
// eslint-disable-next-line testing-library/no-unnecessary-act
await act(() => {
fireEvent.click(envoyer);
});
expect(envoyer).not.toBeInTheDocument();
// THEN
const titre = screen.getByRole('heading', { level: 1, name: 'Confirmation de l’enregistrement de votre candidature' });
expect(titre).toBeInTheDocument();

const messageSucess = screen.getByText('Votre email a été confirmé et votre inscription est maintenant active.' +
' Vous recevrez un mail d’activation de votre espace structure lorsque votre candidature aura été validée.',
{ selector: 'p' }
);
expect(messageSucess).toBeInTheDocument();

const messageError403 = screen.queryByText('Impossible de valider l’email, le lien a expiré ou est invalide.', { selector: 'p' });
expect(messageError403).not.toBeInTheDocument();

const messageErreurGenerale = screen.queryByText('Une erreur s’est produite veuillez réessayer plus tard.', { selector: 'p' });
expect(messageErreurGenerale).not.toBeInTheDocument();
});

it('quand l’utilisateur clique sur le bouton et que le lien est invalide alors un message d’erreur s’affiche', async () => {

// GIVEN
vi.stubGlobal('fetch', vi.fn(
() => ({ status: 403, json: async () => Promise.resolve({}) }))
);
// WHEN
render(<ConfirmationEmailCandidatureStructure />);

// THEN
const envoyer = screen.getByRole('button', { name: 'Confirmer' });
expect(envoyer).toBeInTheDocument();
// eslint-disable-next-line testing-library/no-unnecessary-act
await act(() => {
fireEvent.click(envoyer);
});
expect(envoyer).not.toBeInTheDocument();
// THEN
const titre = screen.getByRole('heading', { level: 1, name: 'Confirmation de l’enregistrement de votre candidature' });
expect(titre).toBeInTheDocument();

const messageError = screen.getByText('Impossible de valider l’email, le lien a expiré ou est invalide.',
{ selector: 'p' }
);
expect(messageError).toBeInTheDocument();

const messageSuccess = screen.queryByText('Votre email a été confirmé et votre inscription est maintenant active.' +
' Vous recevrez un mail d’activation de votre espace structure lorsque votre candidature aura été validée.', { selector: 'p' });
expect(messageSuccess).not.toBeInTheDocument();
const messageErreurGenerale = screen.queryByText('Une erreur s’est produite veuillez réessayer plus tard.', { selector: 'p' });
expect(messageErreurGenerale).not.toBeInTheDocument();
});


it('quand l’utilisateur clique sur le bouton et qu’une erreur innatendue se produit alors un message d’erreur s’affiche', async () => {
// GIVEN
vi.stubGlobal('fetch', vi.fn(
() => ({ status: 500, json: async () => Promise.resolve({}) }))
);
// WHEN
render(<ConfirmationEmailCandidatureStructure />);

// THEN
const envoyer = screen.getByRole('button', { name: 'Confirmer' });
expect(envoyer).toBeInTheDocument();
// eslint-disable-next-line testing-library/no-unnecessary-act
await act(() => {
fireEvent.click(envoyer);
});
expect(envoyer).not.toBeInTheDocument();
// THEN
const titre = screen.getByRole('heading', { level: 1, name: 'Confirmation de l’enregistrement de votre candidature' });
expect(titre).toBeInTheDocument();

const messageError = screen.getByText('Une erreur s’est produite veuillez réessayer plus tard.',
{ selector: 'p' }
);
expect(messageError).toBeInTheDocument();

const messageError403 = screen.queryByText('Impossible de valider l’email, le lien a expiré ou est invalide.', { selector: 'p' });
expect(messageError403).not.toBeInTheDocument();

const messageSuccess = screen.queryByText('Votre email a été confirmé et votre inscription est maintenant active.' +
' Vous recevrez un mail d’activation de votre espace structure lorsque votre candidature aura été validée.', { selector: 'p' });
expect(messageSuccess).not.toBeInTheDocument();

});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export const useApiConfirmationEmailCandidatureStructure = () => {

const actionConfirmationEmailCandidatureStructure = async token => {
const baseUrl = import.meta.env.VITE_APP_API_URL;
const requestOptions = {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
};
try {
return await fetch(`${baseUrl}/confirmation-email-inscription-structure/${token}`, requestOptions);
} catch (error) {
return error;
}
};

return { actionConfirmationEmailCandidatureStructure };
};

This file was deleted.