mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
feat: Création d'un profile selector [#37,#38]
This commit is contained in:
@ -9,7 +9,7 @@ class Profile(AbstractUser):
|
|||||||
|
|
||||||
USERNAME_FIELD = 'email'
|
USERNAME_FIELD = 'email'
|
||||||
REQUIRED_FIELDS = ('password', )
|
REQUIRED_FIELDS = ('password', )
|
||||||
|
roleIndexLoginDefault = models.IntegerField(default=0)
|
||||||
code = models.CharField(max_length=200, default="", blank=True)
|
code = models.CharField(max_length=200, default="", blank=True)
|
||||||
datePeremption = models.CharField(max_length=200, default="", blank=True)
|
datePeremption = models.CharField(max_length=200, default="", blank=True)
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ class ProfileSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Profile
|
model = Profile
|
||||||
fields = ['id', 'password', 'email', 'code', 'datePeremption', 'username', 'roles']
|
fields = ['id', 'password', 'email', 'code', 'datePeremption', 'username', 'roles', 'roleIndexLoginDefault']
|
||||||
extra_kwargs = {'password': {'write_only': True}}
|
extra_kwargs = {'password': {'write_only': True}}
|
||||||
|
|
||||||
def get_roles(self, obj):
|
def get_roles(self, obj):
|
||||||
|
|||||||
@ -54,6 +54,7 @@ class SessionView(APIView):
|
|||||||
'user': openapi.Schema(type=openapi.TYPE_OBJECT, properties={
|
'user': openapi.Schema(type=openapi.TYPE_OBJECT, properties={
|
||||||
'id': openapi.Schema(type=openapi.TYPE_INTEGER),
|
'id': openapi.Schema(type=openapi.TYPE_INTEGER),
|
||||||
'email': openapi.Schema(type=openapi.TYPE_STRING),
|
'email': openapi.Schema(type=openapi.TYPE_STRING),
|
||||||
|
'roleIndexLoginDefault': openapi.Schema(type=openapi.TYPE_INTEGER),
|
||||||
'roles': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Items(type=openapi.TYPE_OBJECT, properties={
|
'roles': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Items(type=openapi.TYPE_OBJECT, properties={
|
||||||
'role_type': openapi.Schema(type=openapi.TYPE_STRING),
|
'role_type': openapi.Schema(type=openapi.TYPE_STRING),
|
||||||
'establishment': openapi.Schema(type=openapi.TYPE_STRING)
|
'establishment': openapi.Schema(type=openapi.TYPE_STRING)
|
||||||
@ -65,18 +66,16 @@ class SessionView(APIView):
|
|||||||
)
|
)
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
token = request.META.get('HTTP_AUTHORIZATION', '').split('Bearer ')[-1]
|
token = request.META.get('HTTP_AUTHORIZATION', '').split('Bearer ')[-1]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
decoded_token = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256'])
|
decoded_token = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256'])
|
||||||
userid = decoded_token.get('user_id')
|
userid = decoded_token.get('user_id')
|
||||||
user = Profile.objects.get(id=userid)
|
user = Profile.objects.get(id=userid)
|
||||||
|
|
||||||
roles = ProfileRole.objects.filter(profile=user).values('role_type', 'establishment__name')
|
roles = ProfileRole.objects.filter(profile=user).values('role_type', 'establishment__name')
|
||||||
|
|
||||||
response_data = {
|
response_data = {
|
||||||
'user': {
|
'user': {
|
||||||
'id': user.id,
|
'id': user.id,
|
||||||
'email': user.email,
|
'email': user.email,
|
||||||
|
'roleIndexLoginDefault': user.roleIndexLoginDefault,
|
||||||
'roles': list(roles)
|
'roles': list(roles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,11 +156,10 @@ class LoginView(APIView):
|
|||||||
operation_description="Connexion utilisateur",
|
operation_description="Connexion utilisateur",
|
||||||
request_body=openapi.Schema(
|
request_body=openapi.Schema(
|
||||||
type=openapi.TYPE_OBJECT,
|
type=openapi.TYPE_OBJECT,
|
||||||
required=['email', 'password', 'role_type'],
|
required=['email', 'password'],
|
||||||
properties={
|
properties={
|
||||||
'email': openapi.Schema(type=openapi.TYPE_STRING),
|
'email': openapi.Schema(type=openapi.TYPE_STRING),
|
||||||
'password': openapi.Schema(type=openapi.TYPE_STRING),
|
'password': openapi.Schema(type=openapi.TYPE_STRING)
|
||||||
'role_type': openapi.Schema(type=openapi.TYPE_STRING)
|
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
responses={
|
responses={
|
||||||
@ -194,38 +192,15 @@ class LoginView(APIView):
|
|||||||
password=data.get('password'),
|
password=data.get('password'),
|
||||||
)
|
)
|
||||||
if user is not None:
|
if user is not None:
|
||||||
role_type = data.get('role_type')
|
# Vérifier si l'utilisateur a un role actif
|
||||||
primary_role = ProfileRole.objects.filter(profile=user, role_type=role_type, is_active=True).first()
|
has_active_role = ProfileRole.objects.filter(profile=user, is_active=True).first()
|
||||||
|
if not has_active_role:
|
||||||
if not primary_role:
|
|
||||||
return JsonResponse({"errorMessage": "Profil inactif"}, status=status.HTTP_401_UNAUTHORIZED)
|
return JsonResponse({"errorMessage": "Profil inactif"}, status=status.HTTP_401_UNAUTHORIZED)
|
||||||
|
|
||||||
login(request, user)
|
login(request, user)
|
||||||
user.save()
|
user.save()
|
||||||
retour = ''
|
retour = ''
|
||||||
|
access_token, refresh_token = makeToken(user)
|
||||||
# Récupérer tous les rôles de l'utilisateur avec le type spécifié
|
|
||||||
roles = ProfileRole.objects.filter(profile=user, role_type=role_type).values('role_type', 'establishment__id', 'establishment__name')
|
|
||||||
|
|
||||||
# Générer le JWT avec la bonne syntaxe datetime
|
|
||||||
access_payload = {
|
|
||||||
'user_id': user.id,
|
|
||||||
'email': user.email,
|
|
||||||
'roles': list(roles),
|
|
||||||
'type': 'access',
|
|
||||||
'exp': datetime.utcnow() + settings.SIMPLE_JWT['ACCESS_TOKEN_LIFETIME'],
|
|
||||||
'iat': datetime.utcnow(),
|
|
||||||
}
|
|
||||||
|
|
||||||
access_token = jwt.encode(access_payload, settings.SIMPLE_JWT['SIGNING_KEY'], algorithm=settings.SIMPLE_JWT['ALGORITHM'])
|
|
||||||
# Générer le Refresh Token (exp: 7 jours)
|
|
||||||
refresh_payload = {
|
|
||||||
'user_id': user.id,
|
|
||||||
'type': 'refresh',
|
|
||||||
'exp': datetime.utcnow() + settings.SIMPLE_JWT['REFRESH_TOKEN_LIFETIME'],
|
|
||||||
'iat': datetime.utcnow(),
|
|
||||||
}
|
|
||||||
refresh_token = jwt.encode(refresh_payload, settings.SIMPLE_JWT['SIGNING_KEY'], algorithm=settings.SIMPLE_JWT['ALGORITHM'])
|
|
||||||
|
|
||||||
return JsonResponse({
|
return JsonResponse({
|
||||||
'token': access_token,
|
'token': access_token,
|
||||||
@ -299,35 +274,10 @@ class RefreshJWTView(APIView):
|
|||||||
|
|
||||||
# Récupérer les informations utilisateur
|
# Récupérer les informations utilisateur
|
||||||
user = Profile.objects.get(id=payload['user_id'])
|
user = Profile.objects.get(id=payload['user_id'])
|
||||||
role_type = payload.get('role_type')
|
if not user:
|
||||||
|
return JsonResponse({'errorMessage': 'Utilisateur non trouvé'}, status=404)
|
||||||
|
|
||||||
# Récupérer le rôle principal de l'utilisateur
|
new_access_payload, new_refresh_token = makeToken(user)
|
||||||
primary_role = ProfileRole.objects.filter(profile=user, role_type=role_type, is_active=True).first()
|
|
||||||
|
|
||||||
if not primary_role:
|
|
||||||
return JsonResponse({'errorMessage': 'Profil inactif'}, status=400)
|
|
||||||
|
|
||||||
# Générer un nouveau Access Token avec les informations complètes
|
|
||||||
new_access_payload = {
|
|
||||||
'user_id': user.id,
|
|
||||||
'email': user.email,
|
|
||||||
'role_type': primary_role.get_role_type_display(),
|
|
||||||
'establishment': primary_role.establishment.id,
|
|
||||||
'type': 'access',
|
|
||||||
'exp': datetime.utcnow() + settings.SIMPLE_JWT['ACCESS_TOKEN_LIFETIME'],
|
|
||||||
'iat': datetime.utcnow(),
|
|
||||||
}
|
|
||||||
|
|
||||||
new_access_token = jwt.encode(new_access_payload, settings.SIMPLE_JWT['SIGNING_KEY'], algorithm=settings.SIMPLE_JWT['ALGORITHM'])
|
|
||||||
|
|
||||||
new_refresh_payload = {
|
|
||||||
'user_id': user.id,
|
|
||||||
'role_type': role_type,
|
|
||||||
'type': 'refresh',
|
|
||||||
'exp': datetime.utcnow() + settings.SIMPLE_JWT['REFRESH_TOKEN_LIFETIME'],
|
|
||||||
'iat': datetime.utcnow(),
|
|
||||||
}
|
|
||||||
new_refresh_token = jwt.encode(new_refresh_payload, settings.SIMPLE_JWT['SIGNING_KEY'], algorithm=settings.SIMPLE_JWT['ALGORITHM'])
|
|
||||||
|
|
||||||
return JsonResponse({'token': new_access_token, 'refresh': new_refresh_token}, status=200)
|
return JsonResponse({'token': new_access_token, 'refresh': new_refresh_token}, status=200)
|
||||||
|
|
||||||
@ -341,6 +291,38 @@ class RefreshJWTView(APIView):
|
|||||||
logger.error(f"Erreur inattendue: {str(e)}")
|
logger.error(f"Erreur inattendue: {str(e)}")
|
||||||
return JsonResponse({'errorMessage': f'Erreur inattendue: {str(e)}'}, status=400)
|
return JsonResponse({'errorMessage': f'Erreur inattendue: {str(e)}'}, status=400)
|
||||||
|
|
||||||
|
def makeToken(user):
|
||||||
|
"""
|
||||||
|
Fonction pour créer un token JWT pour l'utilisateur donné.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Récupérer tous les rôles de l'utilisateur actifs
|
||||||
|
roles = ProfileRole.objects.filter(profile=user, is_active=True).values('role_type', 'establishment__id', 'establishment__name')
|
||||||
|
|
||||||
|
# Générer le JWT avec la bonne syntaxe datetime
|
||||||
|
access_payload = {
|
||||||
|
'user_id': user.id,
|
||||||
|
'email': user.email,
|
||||||
|
'roleIndexLoginDefault':user.roleIndexLoginDefault,
|
||||||
|
'roles': list(roles),
|
||||||
|
'type': 'access',
|
||||||
|
'exp': datetime.utcnow() + settings.SIMPLE_JWT['ACCESS_TOKEN_LIFETIME'],
|
||||||
|
'iat': datetime.utcnow(),
|
||||||
|
}
|
||||||
|
|
||||||
|
access_token = jwt.encode(access_payload, settings.SIMPLE_JWT['SIGNING_KEY'], algorithm=settings.SIMPLE_JWT['ALGORITHM'])
|
||||||
|
# Générer le Refresh Token (exp: 7 jours)
|
||||||
|
refresh_payload = {
|
||||||
|
'user_id': user.id,
|
||||||
|
'type': 'refresh',
|
||||||
|
'exp': datetime.utcnow() + settings.SIMPLE_JWT['REFRESH_TOKEN_LIFETIME'],
|
||||||
|
'iat': datetime.utcnow(),
|
||||||
|
}
|
||||||
|
refresh_token = jwt.encode(refresh_payload, settings.SIMPLE_JWT['SIGNING_KEY'], algorithm=settings.SIMPLE_JWT['ALGORITHM'])
|
||||||
|
return access_token, refresh_token
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Erreur lors de la création du token: {str(e)}")
|
||||||
|
return None
|
||||||
|
|
||||||
@method_decorator(csrf_protect, name='dispatch')
|
@method_decorator(csrf_protect, name='dispatch')
|
||||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||||
|
|||||||
@ -131,7 +131,6 @@ export default function Layout({
|
|||||||
if (roleIndex === -1) {
|
if (roleIndex === -1) {
|
||||||
roleIndex = 0;
|
roleIndex = 0;
|
||||||
}
|
}
|
||||||
setCurrentRoleIndex(roleIndex);
|
|
||||||
const role = session.user.roles[roleIndex].role_type;
|
const role = session.user.roles[roleIndex].role_type;
|
||||||
setProfileRole(role);
|
setProfileRole(role);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import logger from '@/utils/logger';
|
|||||||
import { fetchRegisterForms } from '@/app/actions/subscriptionAction';
|
import { fetchRegisterForms } from '@/app/actions/subscriptionAction';
|
||||||
import { fetchUpcomingEvents } from '@/app/actions/planningAction';
|
import { fetchUpcomingEvents } from '@/app/actions/planningAction';
|
||||||
import { getSession } from 'next-auth/react';
|
import { getSession } from 'next-auth/react';
|
||||||
import { getCurrentRoleIndex } from '@/store/Store';
|
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||||
|
|
||||||
|
|
||||||
// Composant EventCard pour afficher les événements
|
// Composant EventCard pour afficher les événements
|
||||||
@ -42,14 +42,11 @@ export default function DashboardPage() {
|
|||||||
|
|
||||||
const [classes, setClasses] = useState([]);
|
const [classes, setClasses] = useState([]);
|
||||||
const [establishmentId, setEstablishmentId] = useState(null);
|
const [establishmentId, setEstablishmentId] = useState(null);
|
||||||
|
const { selectedEstablishmentId } = useEstablishment();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getSession()
|
getSession()
|
||||||
.then(session => {
|
.then(session => {
|
||||||
if (session && session.user) {
|
setEstablishmentId(selectedEstablishmentId);
|
||||||
const establishmentId = session.user.roles[getCurrentRoleIndex()].establishment__id;
|
|
||||||
setEstablishmentId(establishmentId);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
logger.error('Error fetching session:', err);
|
logger.error('Error fetching session:', err);
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
// src/components/Layout.js
|
// src/components/Layout.js
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import DropdownMenu from '@/components/DropdownMenu';
|
import DropdownMenu from '@/components/DropdownMenu';
|
||||||
|
import ProfileSelector from '@/components/ProfileSelector';
|
||||||
import { useRouter } from 'next/navigation'; // Ajout de l'importation
|
import { useRouter } from 'next/navigation'; // Ajout de l'importation
|
||||||
import { User, MessageSquare, LogOut, Settings, Home } from 'lucide-react'; // Ajout de l'importation de l'icône Home
|
import { User, MessageSquare, LogOut, Settings, Home } from 'lucide-react'; // Ajout de l'importation de l'icône Home
|
||||||
import Logo from '@/components/Logo'; // Ajout de l'importation du composant Logo
|
import Logo from '@/components/Logo'; // Ajout de l'importation du composant Logo
|
||||||
@ -11,11 +12,11 @@ import ProtectedRoute from '@/components/ProtectedRoute';
|
|||||||
import { disconnect } from '@/app/actions/authAction';
|
import { disconnect } from '@/app/actions/authAction';
|
||||||
import Popup from '@/components/Popup';
|
import Popup from '@/components/Popup';
|
||||||
import logger from '@/utils/logger';
|
import logger from '@/utils/logger';
|
||||||
import { useSession } from 'next-auth/react';
|
|
||||||
import { FE_USERS_LOGIN_URL } from '@/utils/Url';
|
|
||||||
import { getRightStr, RIGHTS } from '@/utils/rights';
|
import { getRightStr, RIGHTS } from '@/utils/rights';
|
||||||
import { getGravatarUrl } from '@/utils/gravatar';
|
import { getGravatarUrl } from '@/utils/gravatar';
|
||||||
|
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
|
import Footer from '@/components/Footer';
|
||||||
|
|
||||||
export default function Layout({
|
export default function Layout({
|
||||||
children,
|
children,
|
||||||
@ -23,11 +24,12 @@ export default function Layout({
|
|||||||
|
|
||||||
const router = useRouter(); // Définition de router
|
const router = useRouter(); // Définition de router
|
||||||
const [messages, setMessages] = useState([]);
|
const [messages, setMessages] = useState([]);
|
||||||
const { data: session, status } = useSession();
|
|
||||||
const [userId, setUserId] = useState(null);
|
|
||||||
const [user, setUser] = useState(null);
|
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [isPopupVisible, setIsPopupVisible] = useState(false);
|
const [isPopupVisible, setIsPopupVisible] = useState(false);
|
||||||
|
const { profileRole, user } = useEstablishment();
|
||||||
|
const softwareName = "N3WT School";
|
||||||
|
const softwareVersion = `${process.env.NEXT_PUBLIC_APP_VERSION}`;
|
||||||
|
|
||||||
|
|
||||||
const handleDisconnect = () => {
|
const handleDisconnect = () => {
|
||||||
setIsPopupVisible(true);
|
setIsPopupVisible(true);
|
||||||
@ -38,40 +40,13 @@ export default function Layout({
|
|||||||
disconnect();
|
disconnect();
|
||||||
};
|
};
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (status === 'loading') return;
|
|
||||||
// if (!session) {
|
|
||||||
// router.push(`${FE_USERS_LOGIN_URL}`);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const userIdFromSession = session.user.id;
|
|
||||||
// setUserId(userIdFromSession);
|
|
||||||
// setIsLoading(true);
|
|
||||||
// fetchMessages(userId)
|
|
||||||
// .then(data => {
|
|
||||||
// if (data) {
|
|
||||||
// setMessages(data);
|
|
||||||
// }
|
|
||||||
// logger.debug('Success :', data);
|
|
||||||
// })
|
|
||||||
// .catch(error => {
|
|
||||||
// logger.error('Error fetching data:', error);
|
|
||||||
// })
|
|
||||||
// .finally(() => {
|
|
||||||
// setIsLoading(false);
|
|
||||||
// });
|
|
||||||
// }, [userId]);
|
|
||||||
|
|
||||||
// if (isLoading) {
|
|
||||||
// return <div>Loading...</div>;
|
|
||||||
// }
|
|
||||||
const dropdownItems = [
|
const dropdownItems = [
|
||||||
{
|
{
|
||||||
type: 'info',
|
type: 'info',
|
||||||
content: (
|
content: (
|
||||||
<div className="px-4 py-2">
|
<div className="px-4 py-2">
|
||||||
<div className="font-medium">{user?.email || 'Utilisateur'}</div>
|
<div className="font-medium">{user?.email || 'Utilisateur'}</div>
|
||||||
<div className="text-xs text-gray-400">{getRightStr(user?.roles[0]?.role_type) || ''}</div>
|
<div className="text-xs text-gray-400">{getRightStr(profileRole) || ''}</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -91,11 +66,14 @@ const dropdownItems = [
|
|||||||
<ProtectedRoute requiredRight={RIGHTS.PARENT}>
|
<ProtectedRoute requiredRight={RIGHTS.PARENT}>
|
||||||
<div className="flex flex-col min-h-screen bg-gray-50">
|
<div className="flex flex-col min-h-screen bg-gray-50">
|
||||||
{/* Entête */}
|
{/* Entête */}
|
||||||
<header className="bg-white border-b border-gray-200 px-4 py-2 md:px-8 md:py-4 flex items-center justify-between fixed top-0 left-0 right-0 z-10">
|
<header className="h-16 bg-white border-b border-gray-200 px-4 md:px-8 py-4 flex items-center justify-between fixed top-0 left-0 right-0 z-10">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Logo className="h-6 w-6 md:h-8 md:w-8" /> {/* Utilisation du composant Logo */}
|
<div className="border-b border-gray-200 ">
|
||||||
|
<ProfileSelector
|
||||||
<div className="text-lg md:text-xl font-semibold">Accueil</div>
|
className="w-64 border-r"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="text-lg md:text-xl p-2 font-semibold">Accueil</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-2 md:space-x-4">
|
<div className="flex items-center space-x-2 md:space-x-4">
|
||||||
<button
|
<button
|
||||||
@ -116,6 +94,7 @@ const dropdownItems = [
|
|||||||
<span className="absolute top-0 right-0 block h-2 w-2 rounded-full bg-emerald-600"></span>
|
<span className="absolute top-0 right-0 block h-2 w-2 rounded-full bg-emerald-600"></span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
buttonContent={<Image
|
buttonContent={<Image
|
||||||
src={getGravatarUrl(user?.email)}
|
src={getGravatarUrl(user?.email)}
|
||||||
@ -135,6 +114,8 @@ const dropdownItems = [
|
|||||||
<div className="pt-16 md:pt-20 p-4 md:p-8 flex-1"> {/* Ajout de flex-1 pour utiliser toute la hauteur disponible */}
|
<div className="pt-16 md:pt-20 p-4 md:p-8 flex-1"> {/* Ajout de flex-1 pour utiliser toute la hauteur disponible */}
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
{/* Footer responsive */}
|
||||||
|
<Footer softwareName={softwareName} softwareVersion={softwareVersion} />
|
||||||
</div>
|
</div>
|
||||||
<Popup
|
<Popup
|
||||||
visible={isPopupVisible}
|
visible={isPopupVisible}
|
||||||
|
|||||||
@ -7,51 +7,33 @@ import StatusLabel from '@/components/StatusLabel';
|
|||||||
import { FE_PARENTS_EDIT_INSCRIPTION_URL } from '@/utils/Url';
|
import { FE_PARENTS_EDIT_INSCRIPTION_URL } from '@/utils/Url';
|
||||||
import { fetchChildren } from '@/app/actions/subscriptionAction';
|
import { fetchChildren } from '@/app/actions/subscriptionAction';
|
||||||
import logger from '@/utils/logger';
|
import logger from '@/utils/logger';
|
||||||
import { useSession } from 'next-auth/react';
|
|
||||||
import { FE_USERS_LOGIN_URL } from '@/utils/Url';
|
|
||||||
import { useEstablishment } from '@/context/EstablishmentContext';
|
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||||
|
import ProfileSelector from '@/components/ProfileSelector';
|
||||||
|
|
||||||
export default function ParentHomePage() {
|
export default function ParentHomePage() {
|
||||||
const [children, setChildren] = useState([]);
|
const [children, setChildren] = useState([]);
|
||||||
const { data: session, status } = useSession();
|
|
||||||
const [userId, setUserId] = useState(null);
|
const [userId, setUserId] = useState(null);
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const [establishments, setEstablishments] = useState([]);
|
const { user, setProfileRole, selectedEstablishmentId, setSelectedEstablishmentId, establishments } = useEstablishment();
|
||||||
const { selectedEstablishmentId, setSelectedEstablishmentId } = useEstablishment();
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (status === 'loading') return;
|
const userIdFromSession = user.user_id;
|
||||||
|
|
||||||
if (!session || !session.user) {
|
|
||||||
router.push(`${FE_USERS_LOGIN_URL}`);
|
|
||||||
} else {
|
|
||||||
const userIdFromSession = session.user.user_id;
|
|
||||||
setUserId(userIdFromSession);
|
setUserId(userIdFromSession);
|
||||||
|
|
||||||
const userEstablishments = session.user.roles.map(role => ({
|
|
||||||
id: role.establishment__id,
|
|
||||||
name: role.establishment__name,
|
|
||||||
role_type: role.role_type
|
|
||||||
}));
|
|
||||||
setEstablishments(userEstablishments);
|
|
||||||
|
|
||||||
if (!selectedEstablishmentId && userEstablishments.length > 0) {
|
|
||||||
setSelectedEstablishmentId(userEstablishments[0].id);
|
|
||||||
}
|
|
||||||
console.log(selectedEstablishmentId)
|
console.log(selectedEstablishmentId)
|
||||||
fetchChildren(userIdFromSession, selectedEstablishmentId).then(data => {
|
fetchChildren(userIdFromSession, selectedEstablishmentId).then(data => {
|
||||||
setChildren(data);
|
setChildren(data);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}, [status, session, selectedEstablishmentId]);
|
}, [ selectedEstablishmentId]);
|
||||||
|
|
||||||
const handleEstablishmentChange = (e) => {
|
const handleEstablishmentChange = (e) => {
|
||||||
const establishmentId = parseInt(e.target.value, 10);
|
const establishmentId = parseInt(e.target.value, 10);
|
||||||
setSelectedEstablishmentId(establishmentId);
|
setSelectedEstablishmentId(establishmentId);
|
||||||
|
const role = establishments.find(est => est.id === establishmentId)?.role_type;
|
||||||
|
setProfileRole(role);
|
||||||
};
|
};
|
||||||
|
|
||||||
function handleEdit(eleveId) {
|
function handleEdit(eleveId) {
|
||||||
// Logique pour éditer le dossier de l'élève
|
// Logique pour éditer le dossier de l'élève
|
||||||
logger.debug(`Edit dossier for student id: ${eleveId}`);
|
logger.debug(`Edit dossier for student id: ${eleveId}`);
|
||||||
@ -107,22 +89,6 @@ export default function ParentHomePage() {
|
|||||||
<Users className="h-6 w-6 text-emerald-600" />
|
<Users className="h-6 w-6 text-emerald-600" />
|
||||||
Enfants
|
Enfants
|
||||||
</h2>
|
</h2>
|
||||||
{establishments.length > 1 && (
|
|
||||||
<div className="mb-4">
|
|
||||||
<label className="block text-gray-700 text-sm font-bold mb-2">Sélectionnez un établissement :</label>
|
|
||||||
<select
|
|
||||||
value={selectedEstablishmentId}
|
|
||||||
onChange={handleEstablishmentChange}
|
|
||||||
className="block w-full mt-1 p-2 border border-gray-300 rounded-md"
|
|
||||||
>
|
|
||||||
{establishments.map((establishment, index) => (
|
|
||||||
<option key={`${establishment.id}-${index}`} value={establishment.id}>
|
|
||||||
{establishment.name}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="overflow-x-auto">
|
<div className="overflow-x-auto">
|
||||||
<Table
|
<Table
|
||||||
data={children}
|
data={children}
|
||||||
|
|||||||
@ -9,16 +9,16 @@ import Button from '@/components/Button'; // Importez le composant Button
|
|||||||
import { User, KeySquare } from 'lucide-react'; // Importez directement les icônes nécessaires
|
import { User, KeySquare } from 'lucide-react'; // Importez directement les icônes nécessaires
|
||||||
import {
|
import {
|
||||||
FE_USERS_NEW_PASSWORD_URL,
|
FE_USERS_NEW_PASSWORD_URL,
|
||||||
FE_ADMIN_SUBSCRIPTIONS_URL,
|
getRedirectUrlFromRole
|
||||||
FE_PARENTS_HOME_URL
|
|
||||||
} from '@/utils/Url';
|
} from '@/utils/Url';
|
||||||
import { login } from '@/app/actions/authAction';
|
import { login } from '@/app/actions/authAction';
|
||||||
import { getSession } from 'next-auth/react';
|
import { getSession } from 'next-auth/react';
|
||||||
import { useCsrfToken } from '@/context/CsrfContext'; // Importez le hook useCsrfToken
|
import { useCsrfToken } from '@/context/CsrfContext'; // Importez le hook useCsrfToken
|
||||||
import logger from '@/utils/logger';
|
import logger from '@/utils/logger';
|
||||||
import ProfileSelector from '@/components/ProfileSelector'; // Importez le composant ProfileSelector
|
|
||||||
import { RIGHTS } from '@/utils/rights';
|
|
||||||
import { setCurrentRoleIndex } from '@/store/Store';
|
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
@ -26,8 +26,7 @@ export default function Page() {
|
|||||||
const [errorMessage, setErrorMessage] = useState("");
|
const [errorMessage, setErrorMessage] = useState("");
|
||||||
const [userFieldError, setUserFieldError] = useState("")
|
const [userFieldError, setUserFieldError] = useState("")
|
||||||
const [passwordFieldError, setPasswordFieldError] = useState("")
|
const [passwordFieldError, setPasswordFieldError] = useState("")
|
||||||
const [selectedProfile, setSelectedProfile] = useState(1); // Par défaut, sélectionnez ADMIN
|
const { setUser } = useEstablishment();
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -37,14 +36,15 @@ export default function Page() {
|
|||||||
return data.errorMessage === ""
|
return data.errorMessage === ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function handleFormLogin(formData) {
|
function handleFormLogin(formData) {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setErrorMessage("");
|
setErrorMessage("");
|
||||||
|
|
||||||
login({
|
login({
|
||||||
email: formData.get('login'),
|
email: formData.get('login'),
|
||||||
password: formData.get('password'),
|
password: formData.get('password')
|
||||||
role_type: selectedProfile
|
|
||||||
}).then(result => {
|
}).then(result => {
|
||||||
logger.debug('Sign In Result', result);
|
logger.debug('Sign In Result', result);
|
||||||
|
|
||||||
@ -58,18 +58,16 @@ export default function Page() {
|
|||||||
}
|
}
|
||||||
const user = session.user;
|
const user = session.user;
|
||||||
logger.debug('User Session:', user);
|
logger.debug('User Session:', user);
|
||||||
|
setUser(session.user);
|
||||||
const roles = user.roles.filter(role => role.role_type === selectedProfile);
|
if (session.user.roles && session.user.roles.length > 0) {
|
||||||
if (roles.length > 0) {
|
let roleIndex = 0;
|
||||||
// Redirection en fonction du rôle
|
if( session.user.roles.length > session.user.roleIndexLoginDefault){
|
||||||
// Ne pas désactiver le loader avant la redirection
|
roleIndex = session.user.roleIndexLoginDefault;
|
||||||
const currentRoleIndex = 0;
|
}
|
||||||
setCurrentRoleIndex(currentRoleIndex);
|
const role = session.user.roles[roleIndex].role_type;
|
||||||
const role = roles[currentRoleIndex].role_type;
|
const url = getRedirectUrlFromRole(role);
|
||||||
if (role === RIGHTS.ADMIN || role === RIGHTS.TEACHER) {
|
if (url) {
|
||||||
router.push(FE_ADMIN_SUBSCRIPTIONS_URL);
|
router.push(url);
|
||||||
} else if (role === RIGHTS.PARENT) {
|
|
||||||
router.push(FE_PARENTS_HOME_URL);
|
|
||||||
} else {
|
} else {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
setErrorMessage('Type de rôle non géré');
|
setErrorMessage('Type de rôle non géré');
|
||||||
@ -104,7 +102,6 @@ export default function Page() {
|
|||||||
<DjangoCSRFToken csrfToken={csrfToken} />
|
<DjangoCSRFToken csrfToken={csrfToken} />
|
||||||
<InputTextIcon name="login" type="text" IconItem={User} label="Identifiant" placeholder="Identifiant" errorMsg={userFieldError} className="w-full mb-5" />
|
<InputTextIcon name="login" type="text" IconItem={User} label="Identifiant" placeholder="Identifiant" errorMsg={userFieldError} className="w-full mb-5" />
|
||||||
<InputTextIcon name="password" type="password" IconItem={KeySquare} label="Mot de passe" placeholder="Mot de passe" errorMsg={passwordFieldError} className="w-full mb-5" />
|
<InputTextIcon name="password" type="password" IconItem={KeySquare} label="Mot de passe" placeholder="Mot de passe" errorMsg={passwordFieldError} className="w-full mb-5" />
|
||||||
<ProfileSelector selectedProfile={selectedProfile} setSelectedProfile={setSelectedProfile} />
|
|
||||||
<div className="input-group mb-4">
|
<div className="input-group mb-4">
|
||||||
</div>
|
</div>
|
||||||
<label className="text-red-500">{errorMessage}</label>
|
<label className="text-red-500">{errorMessage}</label>
|
||||||
|
|||||||
@ -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 (
|
return (
|
||||||
<div className="flex space-x-4">
|
<div className={`relative ${className}`}>
|
||||||
<button
|
<DropdownMenu
|
||||||
type="button"
|
buttonContent={
|
||||||
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'}`}
|
<div className="h-16 flex items-center gap-2 cursor-pointer px-4 bg-white">
|
||||||
onClick={() => setSelectedProfile(1)}
|
<div className="flex-1">
|
||||||
>
|
<div className="font-bold text-left">{getRightStr(selectedEstablishment?.role_type) || ''}</div>
|
||||||
ADMINISTRATEUR
|
<div className="text-sm text-gray-500 text-left">
|
||||||
</button>
|
{selectedEstablishment?.name || 'Sélectionnez un établissement'}
|
||||||
<button
|
</div>
|
||||||
type="button"
|
</div>
|
||||||
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'}`}
|
{/* Icône ChevronDown avec rotation conditionnelle */}
|
||||||
onClick={() => setSelectedProfile(0)}
|
<ChevronDown
|
||||||
>
|
className={`w-5 h-5 transition-transform duration-200 ${
|
||||||
PROFESSEUR
|
dropdownOpen ? 'rotate-180' : 'rotate-0'
|
||||||
</button>
|
}`}
|
||||||
<button
|
/>
|
||||||
type="button"
|
</div>
|
||||||
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)}
|
items={establishments.map(establishment => ({
|
||||||
>
|
type: 'item',
|
||||||
PARENT
|
label: (
|
||||||
</button>
|
<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>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,33 +1,33 @@
|
|||||||
import React, { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useSession } from 'next-auth/react';
|
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||||
import Loader from '@/components/Loader'; // Importez le composant Loader
|
import { FE_USERS_LOGIN_URL,getRedirectUrlFromRole } from '@/utils/Url';
|
||||||
import { FE_USERS_LOGIN_URL } from '@/utils/Url';
|
|
||||||
|
|
||||||
const ProtectedRoute = ({ children, requiredRight }) => {
|
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
|
const { user, profileRole } = useEstablishment();
|
||||||
if (status === 'loading') {
|
const router = useRouter();
|
||||||
return <Loader />;
|
const hasRequiredRight = (profileRole === requiredRight);
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifier si l'utilisateur a au moins un rôle correspondant au 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
|
// Autoriser l'affichage si authentifié et rôle correct
|
||||||
return session ? children : null;
|
return hasRequiredRight ? children : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ProtectedRoute;
|
export default ProtectedRoute;
|
||||||
@ -1,7 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useEstablishment } from '@/context/EstablishmentContext';
|
import ProfileSelector from '@/components/ProfileSelector';
|
||||||
|
|
||||||
const SidebarItem = ({ icon: Icon, text, active, url, onClick }) => (
|
const SidebarItem = ({ icon: Icon, text, active, url, onClick }) => (
|
||||||
<div
|
<div
|
||||||
@ -15,9 +15,9 @@ const SidebarItem = ({ icon: Icon, text, active, url, onClick }) => (
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
function Sidebar({ establishments, currentPage, items, onCloseMobile, onEstablishmentChange }) {
|
function Sidebar({ currentPage, items, onCloseMobile, onEstablishmentChange }) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { selectedEstablishmentId, setSelectedEstablishmentId, setProfileRole } = useEstablishment();
|
|
||||||
const [selectedItem, setSelectedItem] = useState(currentPage);
|
const [selectedItem, setSelectedItem] = useState(currentPage);
|
||||||
|
|
||||||
useEffect(() => {
|
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 (
|
return (
|
||||||
<div className="w-64 bg-white border-r h-full border-gray-200 py-6 px-4">
|
<div className="w-64 bg-white border-r h-full border-gray-200">
|
||||||
<div className="flex items-center mb-8 px-2">
|
<div className="border-b border-gray-200 ">
|
||||||
<select
|
<ProfileSelector
|
||||||
value={selectedEstablishmentId || ''}
|
onEstablishmentChange={onEstablishmentChange}
|
||||||
onChange={handleEstablishmentChange}
|
className="border-none"
|
||||||
className="form-select block w-full mt-1"
|
/>
|
||||||
>
|
|
||||||
{establishments.map(establishment => (
|
|
||||||
<option key={establishment.id} value={establishment.id}>
|
|
||||||
{establishment.name}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
|
<nav className="space-y-1 px-4 py-6">
|
||||||
<nav className="space-y-1">
|
|
||||||
{items.map((item) => (
|
{items.map((item) => (
|
||||||
<SidebarItem
|
<SidebarItem
|
||||||
key={item.id}
|
key={item.id}
|
||||||
|
|||||||
@ -1,37 +1,41 @@
|
|||||||
import React, { createContext, useContext, useState, useEffect } from 'react';
|
import React, { createContext, useContext, useState, useEffect } from 'react';
|
||||||
import { useSession } from 'next-auth/react';
|
|
||||||
import logger from '@/utils/logger';
|
import logger from '@/utils/logger';
|
||||||
|
|
||||||
const EstablishmentContext = createContext();
|
const EstablishmentContext = createContext();
|
||||||
|
|
||||||
export const EstablishmentProvider = ({ children }) => {
|
export const EstablishmentProvider = ({ children }) => {
|
||||||
const { data: session, status } = useSession();
|
|
||||||
const [selectedEstablishmentId, setSelectedEstablishmentId] = useState(null);
|
const [selectedEstablishmentId, setSelectedEstablishmentId] = useState(null);
|
||||||
const [profileRole, setProfileRole] = useState(null);
|
const [profileRole, setProfileRole] = useState(null);
|
||||||
const [establishments, setEstablishments] = useState([]);
|
const [establishments, setEstablishments] = useState([]);
|
||||||
const [user, setUser] = useState(null);
|
const [user, setUser] = useState(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (status === 'loading') return; // Attendre que le statut de la session soit défini
|
if (user) {
|
||||||
|
logger.debug('Establishments User= ', user);
|
||||||
if (session && session.user) {
|
// Au changement de l'utilisateur on sette par défaut le premier établissement
|
||||||
setUser(session.user);
|
// et le premier rôle
|
||||||
const userEstablishments = session.user.roles.map(role => ({
|
const userEstablishments = user.roles.map(role => ({
|
||||||
id: role.establishment__id,
|
id: role.establishment__id,
|
||||||
name: role.establishment__name,
|
name: role.establishment__name,
|
||||||
role_type: role.role_type
|
role_type: role.role_type
|
||||||
}));
|
}));
|
||||||
setEstablishments(userEstablishments);
|
setEstablishments(userEstablishments);
|
||||||
// Sélectionner l'établissement depuis la session ou le premier établissement par défaut
|
logger.debug('Establishments', user.roleIndexLoginDefault);
|
||||||
|
let roleIndexDefault = 0;
|
||||||
|
user.roleIndexLoginDefault;
|
||||||
|
// Sélectionner l'établissement au login par défaut
|
||||||
|
if (userEstablishments.length > user.roleIndexLoginDefault) {
|
||||||
|
roleIndexDefault = user.roleIndexLoginDefault;
|
||||||
|
}
|
||||||
if (userEstablishments.length > 0) {
|
if (userEstablishments.length > 0) {
|
||||||
setSelectedEstablishmentId(userEstablishments[0].id);
|
setSelectedEstablishmentId(userEstablishments[roleIndexDefault].id);
|
||||||
setProfileRole(userEstablishments[0].role_type);
|
setProfileRole(userEstablishments[roleIndexDefault].role_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [session, status]);
|
}, [user]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EstablishmentContext.Provider value={{ selectedEstablishmentId, setSelectedEstablishmentId, profileRole, setProfileRole, establishments, user }}>
|
<EstablishmentContext.Provider value={{ selectedEstablishmentId, setSelectedEstablishmentId, profileRole, setProfileRole, establishments, setUser, user }}>
|
||||||
{children}
|
{children}
|
||||||
</EstablishmentContext.Provider>
|
</EstablishmentContext.Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
import { createContext, useContext, useEffect, useState } from 'react';
|
import { createContext, useContext, useEffect, useState } from 'react';
|
||||||
import { createPlanning, fetchEvents, fetchPlannings, updatePlanning, createEvent, deleteEvent, updateEvent } from '@/app/actions/planningAction';
|
import { createPlanning, fetchEvents, fetchPlannings, updatePlanning, createEvent, deleteEvent, updateEvent } from '@/app/actions/planningAction';
|
||||||
import { useCsrfToken } from './CsrfContext';
|
import { useCsrfToken } from './CsrfContext';
|
||||||
import { ESTABLISHMENT_ID } from '@/utils/Url';
|
|
||||||
import logger from '@/utils/logger';
|
import logger from '@/utils/logger';
|
||||||
|
import { useSession } from 'next-auth/react';
|
||||||
|
import { useEstablishment }from '@/context/EstablishmentContext';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -27,13 +28,15 @@ export function PlanningProvider({ children }) {
|
|||||||
const [currentDate, setCurrentDate] = useState(new Date());
|
const [currentDate, setCurrentDate] = useState(new Date());
|
||||||
const [viewType, setViewType] = useState('week'); // Changer 'month' en 'week'
|
const [viewType, setViewType] = useState('week'); // Changer 'month' en 'week'
|
||||||
const [hiddenSchedules, setHiddenSchedules] = useState([]);
|
const [hiddenSchedules, setHiddenSchedules] = useState([]);
|
||||||
|
const { selectedEstablishmentId } = useEstablishment();
|
||||||
|
|
||||||
const csrfToken = useCsrfToken();
|
const csrfToken = useCsrfToken();
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
|
|
||||||
fetchPlannings().then((data) => {
|
fetchPlannings().then((data) => {
|
||||||
setSchedules(data)
|
setSchedules(data)
|
||||||
setSelectedSchedule(data[0].id);
|
if(data.length > 0){
|
||||||
|
setSelectedSchedule(data[0].id);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
fetchEvents().then((data)=>{
|
fetchEvents().then((data)=>{
|
||||||
setEvents(data);
|
setEvents(data);
|
||||||
@ -47,9 +50,6 @@ export function PlanningProvider({ children }) {
|
|||||||
createEvent(newEvent).then((data) => {
|
createEvent(newEvent).then((data) => {
|
||||||
setEvents((prevEvents) => [...prevEvents, data]);
|
setEvents((prevEvents) => [...prevEvents, data]);
|
||||||
});
|
});
|
||||||
console.log('newEvent',newEvent);
|
|
||||||
|
|
||||||
//dssetEvents((prevEvents) => [...prevEvents, newEvent]);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUpdateEvent = (id, updatedEvent) => {
|
const handleUpdateEvent = (id, updatedEvent) => {
|
||||||
@ -69,10 +69,8 @@ export function PlanningProvider({ children }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const addSchedule = (newSchedule) => {
|
const addSchedule = (newSchedule) => {
|
||||||
//FIXME:Gerenr lestablshment
|
|
||||||
logger.debug('newSchedule',newSchedule);
|
logger.debug('newSchedule',newSchedule);
|
||||||
newSchedule.establishment = ESTABLISHMENT_ID;
|
newSchedule.establishment = selectedEstablishmentId;
|
||||||
|
|
||||||
createPlanning(newSchedule,csrfToken).then((data) => {
|
createPlanning(newSchedule,csrfToken).then((data) => {
|
||||||
setSchedules((prevSchedules) => [...prevSchedules, data]);
|
setSchedules((prevSchedules) => [...prevSchedules, data]);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -11,15 +11,13 @@ const options = {
|
|||||||
name: 'Credentials',
|
name: 'Credentials',
|
||||||
credentials: {
|
credentials: {
|
||||||
email: { label: 'Email', type: 'email' },
|
email: { label: 'Email', type: 'email' },
|
||||||
password: { label: 'Password', type: 'password' },
|
password: { label: 'Password', type: 'password' }
|
||||||
role_type: { label: 'Role Type', type: 'text' }
|
|
||||||
},
|
},
|
||||||
authorize: async (credentials, req) => {
|
authorize: async (credentials, req) => {
|
||||||
try {
|
try {
|
||||||
const data = {
|
const data = {
|
||||||
email: credentials.email,
|
email: credentials.email,
|
||||||
password: credentials.password,
|
password: credentials.password
|
||||||
role_type: credentials.role_type
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const user = await getJWT(data);
|
const user = await getJWT(data);
|
||||||
@ -87,14 +85,15 @@ const options = {
|
|||||||
},
|
},
|
||||||
async session({ session, token }) {
|
async session({ session, token }) {
|
||||||
if (token && token?.token) {
|
if (token && token?.token) {
|
||||||
const { user_id, email, roles } = jwt_decode.decode(token.token);
|
const { user_id, email, roles, roleIndexLoginDefault } = jwt_decode.decode(token.token);
|
||||||
session.user = {
|
session.user = {
|
||||||
...session.user,
|
...session.user,
|
||||||
token: token.token,
|
token: token.token,
|
||||||
refresh: token.refresh,
|
refresh: token.refresh,
|
||||||
user_id: user_id,
|
user_id: user_id,
|
||||||
email: email,
|
email: email,
|
||||||
roles: roles
|
roles: roles,
|
||||||
|
roleIndexLoginDefault : roleIndexLoginDefault
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return session;
|
return session;
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
|
|
||||||
// Current Role Index
|
|
||||||
// Cette fonction permet de stocker et l'index du rôle actuel dans le localStorage
|
|
||||||
export function setCurrentRoleIndex(currentRoleIndex){
|
|
||||||
localStorage.setItem('currentRoleIndex', currentRoleIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getCurrentRoleIndex(){
|
|
||||||
const currentRoleIndex = localStorage.getItem('currentRoleIndex');
|
|
||||||
return currentRoleIndex? currentRoleIndex : 0;
|
|
||||||
}
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
|
import { RIGHTS } from '@/utils/rights';
|
||||||
export const BASE_URL = process.env.NEXT_PUBLIC_API_URL;
|
export const BASE_URL = process.env.NEXT_PUBLIC_API_URL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//URL-Back-End
|
//URL-Back-End
|
||||||
|
|
||||||
// GESTION DocuSeal
|
// GESTION DocuSeal
|
||||||
@ -106,3 +106,22 @@ export const FE_PARENTS_EDIT_INSCRIPTION_URL = `/parents/editInscription`
|
|||||||
export const FE_API_DOCUSEAL_GENERATE_TOKEN = `/api/docuseal/generateToken`
|
export const FE_API_DOCUSEAL_GENERATE_TOKEN = `/api/docuseal/generateToken`
|
||||||
export const FE_API_DOCUSEAL_CLONE_URL = `/api/docuseal/cloneTemplate`
|
export const FE_API_DOCUSEAL_CLONE_URL = `/api/docuseal/cloneTemplate`
|
||||||
export const FE_API_DOCUSEAL_DOWNLOAD_URL = `/api/docuseal/downloadTemplate`
|
export const FE_API_DOCUSEAL_DOWNLOAD_URL = `/api/docuseal/downloadTemplate`
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fonction pour obtenir l'URL de redirection en fonction du rôle
|
||||||
|
* @param {RIGHTS} role
|
||||||
|
* @returns {string|null} L'URL de redirection ou null si le rôle n'est pas géré
|
||||||
|
*/
|
||||||
|
export function getRedirectUrlFromRole(role) {
|
||||||
|
switch (role) {
|
||||||
|
case RIGHTS.ADMIN:
|
||||||
|
return FE_ADMIN_SUBSCRIPTIONS_URL;
|
||||||
|
case RIGHTS.TEACHER:
|
||||||
|
return FE_ADMIN_SUBSCRIPTIONS_URL;
|
||||||
|
case RIGHTS.PARENT:
|
||||||
|
return FE_PARENTS_HOME_URL;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user