feat: Création d'un profile selector [#37,#38]

This commit is contained in:
Luc SORIGNET
2025-04-12 16:07:30 +02:00
parent 4c2e2f8756
commit 89b01b79db
16 changed files with 237 additions and 286 deletions

View File

@ -1,29 +1,65 @@
import React from 'react';
import React, { useState } from 'react';
import { useEstablishment } from '@/context/EstablishmentContext';
import DropdownMenu from '@/components/DropdownMenu';
import { getRightStr } from '@/utils/rights';
import { ChevronDown } from 'lucide-react'; // Import de l'icône
const ProfileSelector = ({ onEstablishmentChange, className = '' }) => {
const { establishments, selectedEstablishmentId, setSelectedEstablishmentId, setProfileRole } = useEstablishment();
const [dropdownOpen, setDropdownOpen] = useState(false);
const handleEstablishmentChange = (establishmentId) => {
setSelectedEstablishmentId(establishmentId);
const role = establishments.find(est => est.id === establishmentId)?.role_type;
setProfileRole(role);
if (onEstablishmentChange) {
onEstablishmentChange(establishmentId);
}
setDropdownOpen(false); // Fermer le menu après sélection
};
// Si on a pas de rôle ou un seul rôle, on n'affiche pas le sélecteur
if (!establishments || establishments.length === 0 || establishments.length === 1) {
return null;
}
const selectedEstablishment = establishments.find(est => est.id === selectedEstablishmentId);
const ProfileSelector = ({ selectedProfile, setSelectedProfile }) => {
return (
<div className="flex space-x-4">
<button
type="button"
className={`px-4 py-2 rounded-lg shadow-md focus:outline-none focus:ring-2 focus:ring-blue-300 ${selectedProfile === 1 ? 'bg-blue-500 text-white ring-2 ring-blue-500' : 'bg-gray-200'}`}
onClick={() => setSelectedProfile(1)}
>
ADMINISTRATEUR
</button>
<button
type="button"
className={`px-4 py-2 rounded-lg shadow-md focus:outline-none focus:ring-2 focus:ring-blue-300 ${selectedProfile === 0 ? 'bg-blue-500 text-white ring-2 ring-blue-500' : 'bg-gray-200'}`}
onClick={() => setSelectedProfile(0)}
>
PROFESSEUR
</button>
<button
type="button"
className={`px-4 py-2 rounded-lg shadow-md focus:outline-none focus:ring-2 focus:ring-blue-300 ${selectedProfile === 2 ? 'bg-blue-500 text-white ring-2 ring-blue-500' : 'bg-gray-200'}`}
onClick={() => setSelectedProfile(2)}
>
PARENT
</button>
<div className={`relative ${className}`}>
<DropdownMenu
buttonContent={
<div className="h-16 flex items-center gap-2 cursor-pointer px-4 bg-white">
<div className="flex-1">
<div className="font-bold text-left">{getRightStr(selectedEstablishment?.role_type) || ''}</div>
<div className="text-sm text-gray-500 text-left">
{selectedEstablishment?.name || 'Sélectionnez un établissement'}
</div>
</div>
{/* Icône ChevronDown avec rotation conditionnelle */}
<ChevronDown
className={`w-5 h-5 transition-transform duration-200 ${
dropdownOpen ? 'rotate-180' : 'rotate-0'
}`}
/>
</div>
}
items={establishments.map(establishment => ({
type: 'item',
label: (
<div className="text-left">
<div className="font-bold">{getRightStr(establishment.role_type)}</div>
<div className="text-sm text-gray-500">{establishment.name}</div>
</div>
),
onClick: () => handleEstablishmentChange(establishment.id),
}))}
buttonClassName="w-full"
menuClassName="absolute mt-2 w-full bg-white border border-gray-200 rounded shadow-lg z-10"
dropdownOpen={dropdownOpen}
setDropdownOpen={setDropdownOpen}
/>
</div>
);
};

View File

@ -1,33 +1,33 @@
import React, { useEffect } from 'react';
import { useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { useSession } from 'next-auth/react';
import Loader from '@/components/Loader'; // Importez le composant Loader
import { FE_USERS_LOGIN_URL } from '@/utils/Url';
import { useEstablishment } from '@/context/EstablishmentContext';
import { FE_USERS_LOGIN_URL,getRedirectUrlFromRole } from '@/utils/Url';
const ProtectedRoute = ({ children, requiredRight }) => {
const { data: session, status } = useSession({
required: true,
onUnauthenticated() {
router.push(`${FE_USERS_LOGIN_URL}`);
}
});
const router = useRouter();
// Ne vérifier que si le statut est définitif
if (status === 'loading') {
return <Loader />;
}
const { user, profileRole } = useEstablishment();
const router = useRouter();
const hasRequiredRight = (profileRole === requiredRight);
// Vérifier si l'utilisateur a au moins un rôle correspondant au requiredRight
const hasRequiredRight = session?.user?.roles?.some(role => role.role_type === requiredRight);
useEffect(() => {
if(user){
// Vérifier si l'utilisateur a le droit requis mais pas le bon role on le redirige la page d'accueil associé au role
if (!hasRequiredRight) {
const redirectUrl = getRedirectUrlFromRole(profileRole);
router.push(`${redirectUrl}`);
}
}else{
// User non authentifié
router.push(`${FE_USERS_LOGIN_URL}`);
}
}, [profileRole]);
if (session && requiredRight && !hasRequiredRight) {
router.push(`${FE_USERS_LOGIN_URL}`);
return null;
}
// Autoriser l'affichage si authentifié et rôle correct
return session ? children : null;
return hasRequiredRight ? children : null;
};
export default ProtectedRoute;

View File

@ -1,7 +1,7 @@
'use client'
import React, { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { useEstablishment } from '@/context/EstablishmentContext';
import ProfileSelector from '@/components/ProfileSelector';
const SidebarItem = ({ icon: Icon, text, active, url, onClick }) => (
<div
@ -15,9 +15,9 @@ const SidebarItem = ({ icon: Icon, text, active, url, onClick }) => (
</div>
);
function Sidebar({ establishments, currentPage, items, onCloseMobile, onEstablishmentChange }) {
function Sidebar({ currentPage, items, onCloseMobile, onEstablishmentChange }) {
const router = useRouter();
const { selectedEstablishmentId, setSelectedEstablishmentId, setProfileRole } = useEstablishment();
const [selectedItem, setSelectedItem] = useState(currentPage);
useEffect(() => {
@ -32,31 +32,15 @@ function Sidebar({ establishments, currentPage, items, onCloseMobile, onEstablis
}
};
const handleEstablishmentChange = (e) => {
const establishmentId = parseInt(e.target.value, 10);
setSelectedEstablishmentId(establishmentId);
const role = establishments.find(est => est.id === establishmentId)?.role_type;
setProfileRole(role);
onEstablishmentChange(establishmentId);
};
return (
<div className="w-64 bg-white border-r h-full border-gray-200 py-6 px-4">
<div className="flex items-center mb-8 px-2">
<select
value={selectedEstablishmentId || ''}
onChange={handleEstablishmentChange}
className="form-select block w-full mt-1"
>
{establishments.map(establishment => (
<option key={establishment.id} value={establishment.id}>
{establishment.name}
</option>
))}
</select>
<div className="w-64 bg-white border-r h-full border-gray-200">
<div className="border-b border-gray-200 ">
<ProfileSelector
onEstablishmentChange={onEstablishmentChange}
className="border-none"
/>
</div>
<nav className="space-y-1">
<nav className="space-y-1 px-4 py-6">
{items.map((item) => (
<SidebarItem
key={item.id}