mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-29 07:53:23 +00:00
fix: Suppression de la top bar admin [#34]
This commit is contained in:
@ -37,6 +37,7 @@ import { getGravatarUrl } from '@/utils/gravatar';
|
|||||||
import Footer from '@/components/Footer';
|
import Footer from '@/components/Footer';
|
||||||
import { getRightStr, RIGHTS } from '@/utils/rights';
|
import { getRightStr, RIGHTS } from '@/utils/rights';
|
||||||
import { useEstablishment } from '@/context/EstablishmentContext';
|
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||||
|
import ProfileSelector from '@/components/ProfileSelector';
|
||||||
|
|
||||||
export default function Layout({ children }) {
|
export default function Layout({ children }) {
|
||||||
const t = useTranslations('sidebar');
|
const t = useTranslations('sidebar');
|
||||||
@ -150,34 +151,6 @@ export default function Layout({ children }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ProtectedRoute requiredRight={[RIGHTS.ADMIN, RIGHTS.TEACHER]}>
|
<ProtectedRoute requiredRight={[RIGHTS.ADMIN, RIGHTS.TEACHER]}>
|
||||||
{/* Topbar */}
|
|
||||||
<header className="absolute top-0 left-64 right-0 h-16 bg-white border-b border-gray-200 px-4 md:px-8 flex items-center justify-between z-10 box-border">
|
|
||||||
<div className="flex items-center">
|
|
||||||
<button
|
|
||||||
className="mr-4 md:hidden text-gray-600 hover:text-gray-900"
|
|
||||||
onClick={toggleSidebar}
|
|
||||||
aria-label="Toggle menu"
|
|
||||||
>
|
|
||||||
{isSidebarOpen ? <X size={24} /> : <Menu size={24} />}
|
|
||||||
</button>
|
|
||||||
<div className="text-lg md:text-xl font-semibold">{headerTitle}</div>
|
|
||||||
</div>
|
|
||||||
<DropdownMenu
|
|
||||||
buttonContent={
|
|
||||||
<Image
|
|
||||||
src={getGravatarUrl(user?.email)}
|
|
||||||
alt="Profile"
|
|
||||||
className="w-8 h-8 rounded-full cursor-pointer"
|
|
||||||
width={32}
|
|
||||||
height={32}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
items={dropdownItems}
|
|
||||||
buttonClassName=""
|
|
||||||
menuClassName="absolute right-0 mt-2 w-64 bg-white border border-gray-200 rounded shadow-lg"
|
|
||||||
/>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
{/* Sidebar */}
|
{/* Sidebar */}
|
||||||
<div
|
<div
|
||||||
className={`absolute top-0 bottom-0 left-0 z-30 w-64 bg-white border-r border-gray-200 box-border ${
|
className={`absolute top-0 bottom-0 left-0 z-30 w-64 bg-white border-r border-gray-200 box-border ${
|
||||||
@ -201,12 +174,11 @@ export default function Layout({ children }) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Main container */}
|
{/* Main container */}
|
||||||
<div className="absolute overflow-auto bg-gradient-to-br from-emerald-50 via-sky-50 to-emerald-100 top-16 bottom-16 left-64 right-0">
|
<div className="absolute overflow-auto bg-gradient-to-br from-emerald-50 via-sky-50 to-emerald-100 top-0 bottom-16 left-64 right-0">
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
|
|
||||||
<Footer softwareName={softwareName} softwareVersion={softwareVersion} />
|
<Footer softwareName={softwareName} softwareVersion={softwareVersion} />
|
||||||
|
|
||||||
<Popup
|
<Popup
|
||||||
|
|||||||
@ -1,25 +1,21 @@
|
|||||||
'use client';
|
'use client';
|
||||||
// src/components/Layout.js
|
// src/components/Layout.js
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState } from 'react';
|
||||||
import DropdownMenu from '@/components/DropdownMenu';
|
|
||||||
import ProfileSelector from '@/components/ProfileSelector';
|
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 { 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 {
|
import {
|
||||||
FE_PARENTS_HOME_URL,
|
FE_PARENTS_HOME_URL,
|
||||||
FE_PARENTS_MESSAGERIE_URL,
|
FE_PARENTS_MESSAGERIE_URL,
|
||||||
FE_PARENTS_SETTINGS_URL,
|
FE_PARENTS_SETTINGS_URL,
|
||||||
} from '@/utils/Url'; // Ajout de l'importation de l'URL de la page d'accueil parent
|
} from '@/utils/Url'; // Ajout de l'importation de l'URL de la page d'accueil parent
|
||||||
import { fetchMessages } from '@/app/actions/messagerieAction';
|
|
||||||
import ProtectedRoute from '@/components/ProtectedRoute';
|
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 { getRightStr, RIGHTS } from '@/utils/rights';
|
import { getRightStr, RIGHTS } from '@/utils/rights';
|
||||||
import { getGravatarUrl } from '@/utils/gravatar';
|
|
||||||
import { useEstablishment } from '@/context/EstablishmentContext';
|
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||||
import Image from 'next/image';
|
|
||||||
import Footer from '@/components/Footer';
|
import Footer from '@/components/Footer';
|
||||||
|
|
||||||
export default function Layout({ children }) {
|
export default function Layout({ children }) {
|
||||||
@ -39,46 +35,14 @@ export default function Layout({ children }) {
|
|||||||
disconnect();
|
disconnect();
|
||||||
clearContext();
|
clearContext();
|
||||||
};
|
};
|
||||||
|
|
||||||
const dropdownItems = [
|
|
||||||
{
|
|
||||||
type: 'info',
|
|
||||||
content: (
|
|
||||||
<div className="px-4 py-2">
|
|
||||||
<div className="font-medium">{user?.email || 'Utilisateur'}</div>
|
|
||||||
<div className="text-xs text-gray-400">
|
|
||||||
{getRightStr(profileRole) || ''}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'separator',
|
|
||||||
content: <hr className="my-2 border-gray-200" />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Settings',
|
|
||||||
icon: Settings,
|
|
||||||
onClick: () => {
|
|
||||||
router.push(FE_PARENTS_SETTINGS_URL);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'item',
|
|
||||||
label: 'Déconnexion',
|
|
||||||
onClick: handleDisconnect,
|
|
||||||
icon: LogOut,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
return (
|
return (
|
||||||
<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="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">
|
<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">
|
||||||
<div className="border-b border-gray-200 ">
|
{/* Suppression du menu profil parent */}
|
||||||
<ProfileSelector className="w-64 border-r" />
|
|
||||||
</div>
|
|
||||||
<div className="text-lg md:text-xl p-2 font-semibold">Accueil</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">
|
||||||
@ -86,17 +50,16 @@ export default function Layout({ children }) {
|
|||||||
className="p-1 md:p-2 rounded-full hover:bg-gray-200"
|
className="p-1 md:p-2 rounded-full hover:bg-gray-200"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
router.push(FE_PARENTS_HOME_URL);
|
router.push(FE_PARENTS_HOME_URL);
|
||||||
}} // Utilisation de router pour revenir à l'accueil parent
|
}}
|
||||||
>
|
>
|
||||||
<Home className="h-5 w-5 md:h-6 md:w-6" />
|
<Home className="h-5 w-5 md:h-6 md:w-6" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<button
|
<button
|
||||||
className="p-1 md:p-2 rounded-full hover:bg-gray-200"
|
className="p-1 md:p-2 rounded-full hover:bg-gray-200"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
router.push(FE_PARENTS_MESSAGERIE_URL);
|
router.push(FE_PARENTS_MESSAGERIE_URL);
|
||||||
}} // Utilisation de router
|
}}
|
||||||
>
|
>
|
||||||
<MessageSquare className="h-5 w-5 md:h-6 md:w-6" />
|
<MessageSquare className="h-5 w-5 md:h-6 md:w-6" />
|
||||||
</button>
|
</button>
|
||||||
@ -104,21 +67,8 @@ export default function Layout({ children }) {
|
|||||||
<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>
|
||||||
|
<ProfileSelector className="w-64 border-b border-gray-200 " />
|
||||||
<DropdownMenu
|
{/* Suppression du DropdownMenu profil parent */}
|
||||||
buttonContent={
|
|
||||||
<Image
|
|
||||||
src={getGravatarUrl(user?.email)}
|
|
||||||
alt="Profile"
|
|
||||||
className="w-8 h-8 rounded-full cursor-pointer"
|
|
||||||
width={32}
|
|
||||||
height={32}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
items={dropdownItems}
|
|
||||||
buttonClassName=""
|
|
||||||
menuClassName="absolute right-0 mt-2 w-64 bg-white border border-gray-200 rounded shadow-lg"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
@ -131,12 +81,6 @@ export default function Layout({ children }) {
|
|||||||
{/* Footer responsive */}
|
{/* Footer responsive */}
|
||||||
<Footer softwareName={softwareName} softwareVersion={softwareVersion} />
|
<Footer softwareName={softwareName} softwareVersion={softwareVersion} />
|
||||||
</div>
|
</div>
|
||||||
<Popup
|
|
||||||
visible={isPopupVisible}
|
|
||||||
message="Êtes-vous sûr(e) de vouloir vous déconnecter ?"
|
|
||||||
onConfirm={confirmDisconnect}
|
|
||||||
onCancel={() => setIsPopupVisible(false)}
|
|
||||||
/>
|
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import Chat from '@/components/Chat';
|
import Chat from '@/components/Chat';
|
||||||
import { useSession } from '@/context/SessionContext';
|
|
||||||
import { useEstablishment } from '@/context/EstablishmentContext';
|
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||||
|
|
||||||
export default function MessageriePage() {
|
export default function MessageriePage() {
|
||||||
const { user } = useSession(); // Doit fournir l'id du parent connecté
|
const { user, selectedEstablishmentId } = useEstablishment();
|
||||||
const { selectedEstablishmentId } = useEstablishment();
|
|
||||||
|
|
||||||
if (!user) return <div>Chargement...</div>;
|
if (!user) return <div>Chargement...</div>;
|
||||||
|
|
||||||
|
|||||||
@ -20,14 +20,17 @@ const Popup = ({
|
|||||||
{/* Overlay noir semi-transparent */}
|
{/* Overlay noir semi-transparent */}
|
||||||
<div
|
<div
|
||||||
className="fixed inset-0 bg-black bg-opacity-60 transition-opacity z-[9998]"
|
className="fixed inset-0 bg-black bg-opacity-60 transition-opacity z-[9998]"
|
||||||
onClick={() => setIsOpen(false)}
|
onClick={() => {
|
||||||
|
if (setIsOpen) setIsOpen(false);
|
||||||
|
else if (onCancel) onCancel();
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className={`relative bg-white p-4 sm:p-6 rounded-xl shadow-2xl w-full max-w-xs sm:max-w-md ${popupClassName ? popupClassName : ''}`}
|
className={`relative bg-white p-4 sm:p-6 rounded-xl shadow-2xl w-full max-w-xs sm:max-w-md ${popupClassName ? popupClassName : ''}`}
|
||||||
style={{ zIndex: 9999 }}
|
style={{ zIndex: 9999 }}
|
||||||
>
|
>
|
||||||
{/* Titre ou message */}
|
{/* Titre ou message */}
|
||||||
<div className="mb-6">
|
<div className="mb-6 text-center">
|
||||||
{isStringMessage
|
{isStringMessage
|
||||||
? messageLines.map((line, index) => (
|
? messageLines.map((line, index) => (
|
||||||
<p key={index} className="text-gray-800 text-base">
|
<p key={index} className="text-gray-800 text-base">
|
||||||
@ -37,12 +40,13 @@ const Popup = ({
|
|||||||
: message}
|
: message}
|
||||||
</div>
|
</div>
|
||||||
{/* Boutons d'action */}
|
{/* Boutons d'action */}
|
||||||
<div className="flex justify-end space-x-4">
|
<div className="flex justify-center space-x-4 mt-8">
|
||||||
{!uniqueConfirmButton && (
|
{!uniqueConfirmButton && (
|
||||||
<button
|
<button
|
||||||
className="px-4 py-2 bg-gray-200 text-gray-800 rounded-lg hover:bg-gray-300 focus:outline-none transition"
|
className="px-4 py-2 bg-gray-200 text-gray-800 rounded-lg hover:bg-gray-300 focus:outline-none transition"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsOpen(false);
|
if (setIsOpen) setIsOpen(false);
|
||||||
|
else if (onCancel) onCancel();
|
||||||
if (onCancel) onCancel();
|
if (onCancel) onCancel();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -52,7 +56,8 @@ const Popup = ({
|
|||||||
<button
|
<button
|
||||||
className="px-4 py-2 bg-emerald-500 text-white rounded-lg hover:bg-emerald-600 focus:outline-none transition"
|
className="px-4 py-2 bg-emerald-500 text-white rounded-lg hover:bg-emerald-600 focus:outline-none transition"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsOpen(false);
|
if (setIsOpen) setIsOpen(false);
|
||||||
|
else if (onConfirm) onConfirm();
|
||||||
if (onConfirm) onConfirm();
|
if (onConfirm) onConfirm();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -1,8 +1,13 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState, useContext } from 'react';
|
||||||
|
import { LogOut } from 'lucide-react';
|
||||||
|
import { disconnect } from '@/app/actions/authAction';
|
||||||
|
import { getGravatarUrl } from '@/utils/gravatar';
|
||||||
import { useEstablishment } from '@/context/EstablishmentContext';
|
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||||
import DropdownMenu from '@/components/DropdownMenu';
|
import DropdownMenu from '@/components/DropdownMenu';
|
||||||
|
import { usePopup } from '@/context/PopupContext';
|
||||||
import { getRightStr } from '@/utils/rights';
|
import { getRightStr } from '@/utils/rights';
|
||||||
import { ChevronDown } from 'lucide-react'; // Import de l'icône
|
import { ChevronDown } from 'lucide-react'; // Import de l'icône
|
||||||
|
import Image from 'next/image'; // Import du composant Image
|
||||||
|
|
||||||
const ProfileSelector = ({ onRoleChange, className = '' }) => {
|
const ProfileSelector = ({ onRoleChange, className = '' }) => {
|
||||||
const {
|
const {
|
||||||
@ -14,6 +19,7 @@ const ProfileSelector = ({ onRoleChange, className = '' }) => {
|
|||||||
user,
|
user,
|
||||||
} = useEstablishment();
|
} = useEstablishment();
|
||||||
const [dropdownOpen, setDropdownOpen] = useState(false);
|
const [dropdownOpen, setDropdownOpen] = useState(false);
|
||||||
|
const { showPopup } = usePopup();
|
||||||
|
|
||||||
const handleRoleChange = (roleId) => {
|
const handleRoleChange = (roleId) => {
|
||||||
// Pas bon quand on a plusieur role pour le même établissement
|
// Pas bon quand on a plusieur role pour le même établissement
|
||||||
@ -28,52 +34,96 @@ const ProfileSelector = ({ onRoleChange, className = '' }) => {
|
|||||||
setDropdownOpen(false); // Fermer le menu après sélection
|
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
|
const handleDisconnect = () => {
|
||||||
if (
|
setDropdownOpen(false);
|
||||||
!establishments ||
|
setTimeout(() => {
|
||||||
establishments.length === 0 ||
|
showPopup &&
|
||||||
establishments.length === 1
|
showPopup(
|
||||||
) {
|
'Êtes-vous sûr(e) de vouloir vous déconnecter ?',
|
||||||
return null;
|
() => disconnect(),
|
||||||
}
|
undefined
|
||||||
|
);
|
||||||
|
}, 150);
|
||||||
|
};
|
||||||
|
|
||||||
const selectedEstablishment = establishments.find(
|
const selectedEstablishment = establishments.find(
|
||||||
(est) => est.role_id === selectedRoleId
|
(est) => est.role_id === selectedRoleId
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Suppression du tronquage JS, on utilise uniquement CSS
|
||||||
|
const isSingleRole = establishments && establishments.length === 1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`relative ${className}`}>
|
<div className={`relative ${className}`}>
|
||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
buttonContent={
|
buttonContent={
|
||||||
<div className="h-16 flex items-center gap-2 cursor-pointer px-4 bg-white">
|
<div className="h-16 flex items-center gap-2 cursor-pointer px-4 bg-white">
|
||||||
<div className="flex-1">
|
<Image
|
||||||
<div className="font-bold text-left">
|
src={getGravatarUrl(user?.email)}
|
||||||
|
alt="Profile"
|
||||||
|
className="w-8 h-8 rounded-full mr-2"
|
||||||
|
width={32}
|
||||||
|
height={32}
|
||||||
|
/>
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<div
|
||||||
|
className="font-bold text-left truncate max-w-full"
|
||||||
|
title={user?.email}
|
||||||
|
>
|
||||||
|
{user?.email}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="text-sm text-gray-500 text-left truncate max-w-full"
|
||||||
|
title={`${getRightStr(selectedEstablishment?.role_type) || ''}${selectedEstablishment?.name ? ', ' + selectedEstablishment.name : ''}`}
|
||||||
|
>
|
||||||
{getRightStr(selectedEstablishment?.role_type) || ''}
|
{getRightStr(selectedEstablishment?.role_type) || ''}
|
||||||
</div>
|
{selectedEstablishment?.name
|
||||||
<div className="text-sm text-gray-500 text-left">
|
? `, ${selectedEstablishment.name}`
|
||||||
{selectedEstablishment?.name || 'Sélectionnez un établissement'}
|
: ''}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Icône ChevronDown avec rotation conditionnelle */}
|
|
||||||
<ChevronDown
|
<ChevronDown
|
||||||
className={`w-5 h-5 transition-transform duration-200 ${
|
className={`w-5 h-5 transition-transform duration-200 ${dropdownOpen ? 'rotate-180' : 'rotate-0'}`}
|
||||||
dropdownOpen ? 'rotate-180' : 'rotate-0'
|
|
||||||
}`}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
items={establishments.map((establishment) => ({
|
items={
|
||||||
|
isSingleRole
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
label: 'Déconnexion',
|
||||||
|
onClick: handleDisconnect,
|
||||||
|
icon: LogOut,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
...establishments.map((establishment) => ({
|
||||||
type: 'item',
|
type: 'item',
|
||||||
label: (
|
label: (
|
||||||
<div className="text-left">
|
<div className="text-left">
|
||||||
<div className="font-bold">
|
<div className="font-bold">
|
||||||
{getRightStr(establishment.role_type)}
|
{getRightStr(establishment.role_type)}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-gray-500">{establishment.name}</div>
|
<div className="text-sm text-gray-500">
|
||||||
|
{establishment.name}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
onClick: () => handleRoleChange(establishment.role_id),
|
onClick: () => handleRoleChange(establishment.role_id),
|
||||||
}))}
|
})),
|
||||||
|
{
|
||||||
|
type: 'separator',
|
||||||
|
content: <hr className="my-2 border-gray-200" />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
label: 'Déconnexion',
|
||||||
|
onClick: handleDisconnect,
|
||||||
|
icon: LogOut,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
buttonClassName="w-full"
|
buttonClassName="w-full"
|
||||||
menuClassName="absolute mt-2 w-full bg-white border border-gray-200 rounded shadow-lg z-10"
|
menuClassName="absolute mt-2 w-full bg-white border border-gray-200 rounded shadow-lg z-10"
|
||||||
dropdownOpen={dropdownOpen}
|
dropdownOpen={dropdownOpen}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { ClassesProvider } from '@/context/ClassesContext';
|
|||||||
import { DndProvider } from 'react-dnd';
|
import { DndProvider } from 'react-dnd';
|
||||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||||
import logger from '@/utils/logger';
|
import logger from '@/utils/logger';
|
||||||
|
import { PopupProvider } from '@/context/PopupContext';
|
||||||
|
|
||||||
export default function Providers({ children, messages, locale, session }) {
|
export default function Providers({ children, messages, locale, session }) {
|
||||||
if (!locale) {
|
if (!locale) {
|
||||||
@ -22,9 +23,11 @@ export default function Providers({ children, messages, locale, session }) {
|
|||||||
<CsrfProvider>
|
<CsrfProvider>
|
||||||
<EstablishmentProvider>
|
<EstablishmentProvider>
|
||||||
<ClassesProvider>
|
<ClassesProvider>
|
||||||
|
<PopupProvider>
|
||||||
<NextIntlClientProvider messages={messages} locale={locale}>
|
<NextIntlClientProvider messages={messages} locale={locale}>
|
||||||
{children}
|
{children}
|
||||||
</NextIntlClientProvider>
|
</NextIntlClientProvider>
|
||||||
|
</PopupProvider>
|
||||||
</ClassesProvider>
|
</ClassesProvider>
|
||||||
</EstablishmentProvider>
|
</EstablishmentProvider>
|
||||||
</CsrfProvider>
|
</CsrfProvider>
|
||||||
|
|||||||
43
Front-End/src/context/PopupContext.js
Normal file
43
Front-End/src/context/PopupContext.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import React, { createContext, useContext, useState, useCallback } from 'react';
|
||||||
|
import Popup from '@/components/Popup';
|
||||||
|
|
||||||
|
const PopupContext = createContext();
|
||||||
|
|
||||||
|
export const PopupProvider = ({ children }) => {
|
||||||
|
const [popupState, setPopupState] = useState({
|
||||||
|
visible: false,
|
||||||
|
message: '',
|
||||||
|
onConfirm: null,
|
||||||
|
onCancel: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
const showPopup = useCallback((message, onConfirm, onCancel) => {
|
||||||
|
setPopupState({
|
||||||
|
visible: true,
|
||||||
|
message,
|
||||||
|
onConfirm: () => {
|
||||||
|
setPopupState((prev) => ({ ...prev, visible: false }));
|
||||||
|
if (onConfirm) onConfirm();
|
||||||
|
},
|
||||||
|
onCancel: () => {
|
||||||
|
setPopupState((prev) => ({ ...prev, visible: false }));
|
||||||
|
if (onCancel) onCancel();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PopupContext.Provider value={{ showPopup }}>
|
||||||
|
<Popup
|
||||||
|
isOpen={popupState.visible}
|
||||||
|
message={popupState.message}
|
||||||
|
onConfirm={popupState.onConfirm}
|
||||||
|
onCancel={popupState.onCancel}
|
||||||
|
popupClassName="fixed z-[9999] inset-0 flex items-center justify-center"
|
||||||
|
/>
|
||||||
|
{children}
|
||||||
|
</PopupContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usePopup = () => useContext(PopupContext);
|
||||||
Reference in New Issue
Block a user