feat: mise en place de la messagerie [#17]

This commit is contained in:
Luc SORIGNET
2025-05-26 13:24:42 +02:00
parent e2df29d851
commit d37145b73e
64 changed files with 13113 additions and 853 deletions

View File

@ -3,7 +3,6 @@ import React, { useState, useEffect } from 'react';
import Sidebar from '@/components/Sidebar';
import { usePathname } from 'next/navigation';
import { useTranslations } from 'next-intl';
import Image from 'next/image';
import {
LayoutDashboard,
FileText,
@ -13,11 +12,8 @@ import {
Calendar,
Settings,
LogOut,
Menu,
X,
Mail,
MessageSquare,
} from 'lucide-react';
import DropdownMenu from '@/components/DropdownMenu';
import Popup from '@/components/Popup';
import {
@ -86,7 +82,7 @@ export default function Layout({ children }) {
id: 'messagerie',
name: t('messagerie'),
url: FE_ADMIN_MESSAGERIE_URL,
icon: Mail,
icon: MessageSquare,
},
settings: {
id: 'settings',

View File

@ -1,5 +1,5 @@
'use client';
import React from 'react';
import React, { useEffect } from 'react';
import SidebarTabs from '@/components/SidebarTabs';
import EmailSender from '@/components/Admin/EmailSender';
import InstantMessaging from '@/components/Admin/InstantMessaging';
@ -26,11 +26,8 @@ export default function MessageriePage({ csrfToken }) {
];
return (
<div className="flex h-full w-full">
<SidebarTabs
tabs={tabs}
onTabChange={(tabId) => logger.debug(`Onglet actif : ${tabId}`)}
/>
<div className="h-full flex flex-col p-0 m-0">
<SidebarTabs tabs={tabs} />
</div>
);
}

View File

@ -1,31 +1,64 @@
'use client';
// src/components/Layout.js
import React, { useState } from 'react';
import ProfileSelector from '@/components/ProfileSelector';
import { useRouter } from 'next/navigation'; // Ajout de l'importation
import { MessageSquare, LogOut, Settings, Home } from 'lucide-react'; // Ajout de l'importation de l'icône Home
import React, { useState, useEffect } from 'react';
import Sidebar from '@/components/Sidebar';
import { useRouter, usePathname } from 'next/navigation';
import { MessageSquare, Settings, Home, Menu } from 'lucide-react';
import {
FE_PARENTS_HOME_URL,
FE_PARENTS_MESSAGERIE_URL,
FE_PARENTS_SETTINGS_URL,
} from '@/utils/Url'; // Ajout de l'importation de l'URL de la page d'accueil parent
} from '@/utils/Url';
import ProtectedRoute from '@/components/ProtectedRoute';
import { disconnect } from '@/app/actions/authAction';
import Popup from '@/components/Popup';
import logger from '@/utils/logger';
import { getRightStr, RIGHTS } from '@/utils/rights';
import { RIGHTS } from '@/utils/rights';
import { useEstablishment } from '@/context/EstablishmentContext';
import Footer from '@/components/Footer';
export default function Layout({ children }) {
const router = useRouter(); // Définition de router
const [messages, setMessages] = useState([]);
const router = useRouter();
const pathname = usePathname();
const [isPopupVisible, setIsPopupVisible] = useState(false);
const { profileRole, user, clearContext } = useEstablishment();
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
const { clearContext } = useEstablishment();
const softwareName = 'N3WT School';
const softwareVersion = `${process.env.NEXT_PUBLIC_APP_VERSION}`;
// Vérifier si on est sur la page messagerie
const isMessagingPage = pathname?.includes('/messagerie');
// Configuration des éléments de la sidebar pour les parents
const sidebarItems = [
{
id: 'home',
name: 'Accueil',
url: FE_PARENTS_HOME_URL,
icon: Home,
},
{
id: 'messagerie',
name: 'Messagerie',
url: FE_PARENTS_MESSAGERIE_URL,
icon: MessageSquare,
},
{
id: 'settings',
name: 'Paramètres',
url: FE_PARENTS_SETTINGS_URL,
icon: Settings,
},
];
// Déterminer la page actuelle pour la sidebar
const getCurrentPage = () => {
if (pathname?.includes('/messagerie')) return 'messagerie';
if (pathname?.includes('/settings')) return 'settings';
return 'home';
};
const currentPage = getCurrentPage();
const handleDisconnect = () => {
setIsPopupVisible(true);
};
@ -35,52 +68,63 @@ export default function Layout({ children }) {
disconnect();
clearContext();
};
const toggleSidebar = () => {
setIsSidebarOpen(!isSidebarOpen);
};
useEffect(() => {
// Fermer la sidebar quand on change de page sur mobile
setIsSidebarOpen(false);
}, [pathname]);
return (
<ProtectedRoute requiredRight={RIGHTS.PARENT}>
<div className="flex flex-col min-h-screen bg-gray-50">
{/* 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">
<div className="flex items-center space-x-2">
{/* Suppression du menu profil parent */}
{/* Bouton hamburger pour mobile */}
<button
onClick={toggleSidebar}
className="fixed top-4 left-4 z-40 p-2 rounded-md bg-white shadow-lg border border-gray-200 md:hidden"
>
<Menu size={20} />
</button>
<div className="text-lg md:text-xl p-2 font-semibold">Accueil</div>
</div>
<div className="flex items-center space-x-2 md:space-x-4">
<button
className="p-1 md:p-2 rounded-full hover:bg-gray-200"
onClick={() => {
router.push(FE_PARENTS_HOME_URL);
}}
>
<Home className="h-5 w-5 md:h-6 md:w-6" />
</button>
<div className="relative">
<button
className="p-1 md:p-2 rounded-full hover:bg-gray-200"
onClick={() => {
router.push(FE_PARENTS_MESSAGERIE_URL);
}}
>
<MessageSquare className="h-5 w-5 md:h-6 md:w-6" />
</button>
{messages.length > 0 && (
<span className="absolute top-0 right-0 block h-2 w-2 rounded-full bg-emerald-600"></span>
)}
</div>
<ProfileSelector className="w-64 border-b border-gray-200 " />
{/* Suppression du DropdownMenu profil parent */}
</div>
</header>
{/* Content */}
<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}
</div>
{/* Footer responsive */}
<Footer softwareName={softwareName} softwareVersion={softwareVersion} />
{/* Sidebar */}
<div
className={`absolute top-0 bottom-0 left-0 z-30 w-64 bg-white border-r border-gray-200 box-border ${
isSidebarOpen ? 'block' : 'hidden md:block'
}`}
>
<Sidebar
currentPage={currentPage}
items={sidebarItems}
onCloseMobile={toggleSidebar}
/>
</div>
{/* Overlay for mobile */}
{isSidebarOpen && (
<div
className="fixed inset-0 bg-black bg-opacity-50 z-20 md:hidden"
onClick={toggleSidebar}
/>
)}
{/* Main container */}
<div
className={`absolute overflow-auto bg-gradient-to-br from-emerald-50 via-sky-50 to-emerald-100 top-0 bottom-16 left-0 md:left-64 right-0 ${!isMessagingPage ? 'p-4 md:p-8' : ''}`}
>
{children}
</div>
{/* Footer */}
<Footer softwareName={softwareName} softwareVersion={softwareVersion} />
<Popup
isOpen={isPopupVisible}
message="Êtes-vous sûr(e) de vouloir vous déconnecter ?"
onConfirm={confirmDisconnect}
onCancel={() => setIsPopupVisible(false)}
/>
</ProtectedRoute>
);
}

View File

@ -1,15 +1,28 @@
'use client';
import React, { useEffect, useState } from 'react';
import Chat from '@/components/Chat';
import React from 'react';
import InstantChat from '@/components/Chat/InstantChat';
import { useEstablishment } from '@/context/EstablishmentContext';
export default function MessageriePage() {
const { user, selectedEstablishmentId } = useEstablishment();
if (!user) return <div>Chargement...</div>;
if (!user?.user_id || !selectedEstablishmentId) {
return (
<div className="flex items-center justify-center h-full w-full">
<div className="text-center">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900 mx-auto mb-4"></div>
<p className="text-gray-600">Chargement de la messagerie...</p>
</div>
</div>
);
}
return (
<Chat userProfileId={user.id} establishmentId={selectedEstablishmentId} />
<div className="h-full flex flex-col">
<InstantChat
userProfileId={user.user_id}
establishmentId={selectedEstablishmentId}
/>
</div>
);
}