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

Nouvelle page des gestion des membres d'une collectivité #3227

Merged
merged 36 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
98f4f1d
Ajoute un utilitaire d'envoi de mails
marc-rutkowski May 30, 2024
33fab09
Ajoute un utilitaire de vérification de l'utilisateur courant
marc-rutkowski May 30, 2024
1582e55
Ajoute un utilitaire de vérification de l'origine d'une requête
marc-rutkowski May 30, 2024
fc941eb
Ajoute les autorisations CORS dans le module auth.
marc-rutkowski May 30, 2024
fd38d1e
Ajoute le endpoint d'envoi des emails d'invitation
marc-rutkowski May 30, 2024
d811954
Ajoute l'envoi du mail lors de l'invitation d'un membre dans la colle…
marc-rutkowski May 30, 2024
f7d3cd8
Ajout de la modale d'envoi d'une invitation dans le plan de tracking
marc-rutkowski May 30, 2024
d03ce1a
Ajoute la modale d'envoi d'une invitation
marc-rutkowski May 30, 2024
e4d64d7
Raccorde la nouvelle modale d'invitation d'un membre dans la collecti…
marc-rutkowski May 30, 2024
f730900
Supprime les anciens fichiers
marc-rutkowski May 30, 2024
bd12735
Met à jour les storyshots
marc-rutkowski May 30, 2024
eabe62c
Change les tests e2e pour tester l'envoi des invitations à rejoindre …
marc-rutkowski May 30, 2024
5a1c0bb
Ajoute l'id d'invitation dans la rpc collectivite_membres
marc-rutkowski May 30, 2024
c2576bf
Change le typage de la liste des membres
marc-rutkowski May 30, 2024
fed0b12
Ajoute la pagination dans la page Gestion des membres
marc-rutkowski May 30, 2024
82eada0
Ajoute une fonction pour renvoyer une invitation
marc-rutkowski May 30, 2024
ddf438a
Met à jour la page Gestion des membres (WIP)
marc-rutkowski May 30, 2024
210da01
Remplace les modales de confirmation de la page Membres
marc-rutkowski Jun 4, 2024
289155f
Remplace l'affichage des lignes du tableau des Membres
marc-rutkowski Jun 4, 2024
1bfdc2c
Supprime des anciens fichiers
marc-rutkowski Jun 4, 2024
2d235a8
Change les tests e2e de la page Membres
marc-rutkowski Jun 4, 2024
8beb6cb
Rassemble des définitions d'étapes de test
marc-rutkowski Jun 4, 2024
1a9176e
Ajoute un scénario mettant en évidence le problème de la suppression …
marc-rutkowski Jun 4, 2024
ed1e9f4
Répare la suppression d'un utilisateur pré-existant à son rattachemen…
marc-rutkowski Jun 4, 2024
fdc1643
Renommage
marc-rutkowski Jun 4, 2024
9c16bd5
Utilise la fonction mutualisée pour l'envoi des invitations
marc-rutkowski Jun 4, 2024
ac8723f
Sépare les fonctions d'affichage des notifications "toast"
marc-rutkowski Jun 4, 2024
00ec5e0
Affiche la notification appropriée lors de l'ajout d'un membre à la c…
marc-rutkowski Jun 4, 2024
79615fa
Rétabli le test de la notification lors de l'ajout d'un membre à la c…
marc-rutkowski Jun 4, 2024
53be45b
Ajoute un peu de documentation dans le module auth.
marc-rutkowski Jun 5, 2024
952077e
Ajuste l'objet du mail d'invitation
marc-rutkowski Jun 5, 2024
094938e
Ajuste le template du mail d'invitation
marc-rutkowski Jun 5, 2024
9372dd4
Améliore l'affichage des notifications suite à l'envoi d'une invitati…
marc-rutkowski Jun 6, 2024
373891c
Envoi un email dans le cas du rattachement à une collectivité d'un ut…
marc-rutkowski Jun 6, 2024
6400881
Ajoute l'email associé à l'invitation lors de la redirection afin que…
marc-rutkowski Jun 6, 2024
878b23f
Change le rendu du bouton CTA dans les mails transactionnels
marc-rutkowski Jun 6, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
exports[`Storyshots app/Layout/Header Connected 1`] = `
<header
className="fr-header"
id="app-header"
role="banner"
>
<div
Expand Down Expand Up @@ -496,6 +497,7 @@ exports[`Storyshots app/Layout/Header Connected 1`] = `
exports[`Storyshots app/Layout/Header Connected Visite 1`] = `
<header
className="fr-header"
id="app-header"
role="banner"
>
<div
Expand Down Expand Up @@ -930,6 +932,7 @@ exports[`Storyshots app/Layout/Header Connected Visite 1`] = `
exports[`Storyshots app/Layout/Header Connected Visite Support 1`] = `
<header
className="fr-header"
id="app-header"
role="banner"
>
<div
Expand Down Expand Up @@ -1423,6 +1426,7 @@ exports[`Storyshots app/Layout/Header Connected Visite Support 1`] = `
exports[`Storyshots app/Layout/Header Not Connected 1`] = `
<header
className="fr-header"
id="app-header"
role="banner"
>
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ exports[`Storyshots app/Layout Exemple 1`] = `
>
<header
className="fr-header"
id="app-header"
role="banner"
>
<div
Expand Down
19 changes: 14 additions & 5 deletions app.territoiresentransitions.react/src/app/Redirector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const Redirector = () => {
const {pathname} = useLocation();
const {isConnected, user} = useAuth();
const {data: DCP, isLoading: isLoadingDCP} = useDCP(user?.id);
const {invitationId, consume} = useInvitationState();
const {invitationId, invitationEmail, consume} = useInvitationState();
const userCollectivites = useOwnedCollectivites();
const isLandingConnected = isConnected && pathname === '/'; // L'utilisateur est connecté et arrive sur '/'.

Expand Down Expand Up @@ -53,10 +53,19 @@ export const Redirector = () => {
});
} else if (!isConnected && !consume) {
// si déconnecté on redirige sur la page "créer un compte"
const signUpPathFromInvitation = getAuthPaths(
document.location.hostname,
`${document.location.href}?consume=1`
).signUp;
const signUpPathFromInvitation = new URL(
getAuthPaths(
document.location.hostname,
`${document.location.href}?consume=1`
).signUp
);
// ajoute l'email associé à l'invitation afin que le formulaire soit pré-rempli
if (invitationEmail) {
signUpPathFromInvitation.searchParams.append(
'email',
invitationEmail
);
}

document.location.replace(signUpPathFromInvitation);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,23 @@ import {
useCurrentCollectivite,
} from 'core-logic/hooks/useCurrentCollectivite';
import {useUpdateCollectiviteMembre} from 'app/pages/collectivite/Users/useUpdateCollectiviteMembre';
import {useCollectiviteMembres} from 'app/pages/collectivite/Users/useCollectiviteMembres';
import {
PAGE_SIZE,
useCollectiviteMembres,
} from 'app/pages/collectivite/Users/useCollectiviteMembres';
import {useRemoveFromCollectivite} from 'app/pages/collectivite/Users/useRemoveFromCollectivite';
import {
Membre,
TRemoveFromCollectivite,
TUpdateMembre,
} from 'app/pages/collectivite/Users/types';
import MembreListTable from 'app/pages/collectivite/Users/components/MembreListTable';
import InvitationForm from 'app/pages/collectivite/Users/components/InvitationForm';
import {
AddUserToCollectiviteRequest,
AddUserToCollectiviteResponse,
useAddUserToCollectivite,
} from 'app/pages/collectivite/Users/useAddUserToCollectivite';
import {useAddUserToCollectivite} from 'app/pages/collectivite/Users/useAddUserToCollectivite';
import {Button, Modal, Pagination} from '@tet/ui';
import {Invite} from 'app/pages/collectivite/Users/components/Invite';
import {useBaseToast} from 'core-logic/hooks/useBaseToast';
import {useEffect, useState} from 'react';
import {useSendInvitation} from 'app/pages/collectivite/Users/useSendInvitation';

export type MembresProps = {
membres: Membre[];
Expand All @@ -27,9 +30,6 @@ export type MembresProps = {
currentUser: UserData;
updateMembre: TUpdateMembre;
removeFromCollectivite: TRemoveFromCollectivite;
addUser: (request: AddUserToCollectiviteRequest) => void;
addUserResponse: AddUserToCollectiviteResponse | null;
resetAddUser: () => void;
};

/**
Expand All @@ -43,19 +43,66 @@ export const Membres = ({
currentUser,
updateMembre,
removeFromCollectivite,
addUser,
addUserResponse,
resetAddUser,
}: MembresProps) => {
const canViewInvitation =
collectivite.niveau_acces === 'admin' ||
collectivite.niveau_acces === 'edition';
const {niveau_acces} = collectivite;
const canInvite = niveau_acces === 'admin' || niveau_acces === 'edition';
const {data, mutate: addUser} = useAddUserToCollectivite(
collectivite,
currentUser
);
const {data: sendData, mutate: sendInvitation} = useSendInvitation(
collectivite,
currentUser
);
const {setToast, renderToast} = useBaseToast();

// affichage des notifications après l'ajout ou l'envoi de l'invitation
useEffect(() => {
if (!data) return;
if (data.added) {
setToast(
'success',
'Nouveau membre ajouté avec succès à la collectivité !'
);
} else if (data.invitationId) {
setToast('success', mailSentMessage(collectivite, data));
} else if (data.error) {
setToast('info', data.error);
}
}, [data?.added, data?.error]);

// affichage de la notification après le renvoi d'une invitation
useEffect(() => {
if (sendData?.sent) {
setToast('success', mailSentMessage(collectivite, sendData));
} else if (sendData?.error) {
setToast('error', sendData.error);
}
}, [sendData?.sent, sendData?.email, sendData?.error]);

return (
<main data-test="Users" className="fr-container mt-9 mb-16">
<h1 className="mb-10 lg:mb-14 lg:text-center">Gestion des membres</h1>
<h1 className="mb-10 lg:mb-14 lg:text-center flex flex-row justify-between">
Gestion des membres
{canInvite && (
<Modal
title="Inviter un membre"
render={({close}) => (
<Invite
niveauAcces={niveau_acces}
onCancel={close}
onSubmit={data => {
addUser(data);
close();
}}
/>
)}
>
<Button data-test="invite">Inviter un membre</Button>
</Modal>
)}
</h1>

<h2 className="">Liste des membres</h2>
<MembreListTable
currentUserId={currentUser.id}
currentUserAccess={
Expand All @@ -65,53 +112,59 @@ export const Membres = ({
isLoading={isLoading}
updateMembre={updateMembre}
removeFromCollectivite={removeFromCollectivite}
sendInvitation={sendInvitation}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pour comprendre, dans quel cas on veut pouvoir envoyer l'invitation seule, hors du processus d'ajout d'un membre à la collectivité ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C'est pour le bouton "renvoyer l'invitation".

/>

{canViewInvitation && (
<>
<h2 className="mt-12">Invitation</h2>
<p className="italic text-gray-500">
Tous les champs sont obligatoires
</p>
<InvitationForm
addUser={addUser}
addUserResponse={addUserResponse}
resetAddUser={resetAddUser}
currentUser={currentUser}
currentCollectivite={collectivite}
/>
</>
)}
{renderToast()}
</main>
);
};

// formate le message affiché après l'envoi d'un email
const mailSentMessage = (
collectivite: CurrentCollectivite,
data: {email: string}
): string =>
`L'invitation à rejoindre la collectivité ${collectivite.nom} a bien été envoyée à ${data.email}`;

const MembresConnected = () => {
const auth = useAuth();
const user = auth.user;
const collectivite_id = useCollectiviteId();
const collectivite = useCurrentCollectivite();

const {membres, isLoading: isMemberLoading} = useCollectiviteMembres();
const [page, setPage] = useState(1);
const {data, isLoading} = useCollectiviteMembres(page);
const {updateMembre} = useUpdateCollectiviteMembre();
const {removeFromCollectivite} = useRemoveFromCollectivite();
const {addUser, addUserResponse, resetAddUser} = useAddUserToCollectivite();

if (!user?.id || !collectivite_id || !collectivite) return null;

const {membres, count} = data;

return (
<Membres
addUser={addUser}
addUserResponse={addUserResponse}
resetAddUser={resetAddUser}
currentUser={user}
membres={membres}
collectivite={collectivite}
updateMembre={updateMembre}
removeFromCollectivite={removeFromCollectivite}
isLoading={isMemberLoading}
/>
<>
<Membres
currentUser={user}
membres={membres}
collectivite={collectivite}
updateMembre={updateMembre}
removeFromCollectivite={removeFromCollectivite}
isLoading={isLoading}
/>
{count > PAGE_SIZE && (
<Pagination
className="self-center"
selectedPage={page}
nbOfPages={Math.ceil(count / PAGE_SIZE)}
onChange={selectedPage => {
setPage(selectedPage);
document.getElementById('app-header')?.scrollIntoView();
}}
/>
)}
</>
);
};

export default MembresConnected;

Loading
Loading