Files
SAE-BUT2-frontend/src/components/Header/Header.jsx
T

197 lines
8.1 KiB
React

import { Link, NavLink } from "react-router";
import {useContext, useEffect, useRef, useState} from "react";
import styles from "./Header.module.css"
import getUserNotifications from "../../utils/notifications/getUserNotifications.js";
import deleteNotificationUser from "../../utils/notifications/deleteNotificationUser.js";
import initEcho from "../../utils/echo/initEcho.js"
import readNotifications from "../../utils/notifications/readNotifications.js";
import { userCreatedListener } from "../../utils/echo/listeners/userCreatedListener";
import { userNotificationsListener } from "../../utils/echo/listeners/userNotificationsListener.js";
import NotificationCard from "../NotificationCard/NotificationCard.jsx";
import { EventContext } from "../../contexts/Events/EventContext.js";
import {AuthContext} from "../../contexts/Auth/AuthContext.js";
import { PendingMembersContext } from "../../contexts/PendingMembers/PendingMembersContext";
function Header() {
const { update, user } = useContext(AuthContext);
const { updateEvent } = useContext(EventContext);
const [notificationMenu, setnotificationMenu] = useState(false);
const [unreadNotification, setunreadNotification] = useState(false);
const [mobileMenu, setMobileMenu] = useState(false);
const [notifications, setNotifications] = useState([]);
const notificationRef = useRef(null);
const { updatePendingMembers } = useContext(PendingMembersContext);
useEffect(() => {
updateEvent();
let echoInstance = null;
let channelsToLeave = [];
async function initializeHeader() {
try {
const notifData = await getUserNotifications();
const data = notifData || [];
setNotifications(data);
const hasUnread = data.some(n => n.pivot && n.pivot.unread === 1);
setunreadNotification(hasUnread);
const echo = initEcho();
echoInstance = echo;
const activeChannels = [
userCreatedListener(echo, user, setNotifications, setunreadNotification, updatePendingMembers),
userNotificationsListener(echo, user, setNotifications, setunreadNotification),
];
channelsToLeave = activeChannels.filter(name => name !== null);
} catch (err) {
console.error("Erreur initialisation Header:", err);
}
}
initializeHeader();
const handleClickOutside = (event) => {
if (
notificationRef.current &&
!notificationRef.current.contains(event.target) &&
!event.target.closest(`.${styles.bellBtn}`)
) {
setnotificationMenu(false);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
if (echoInstance) {
channelsToLeave.forEach(chan => echoInstance.leave(chan));
}
};
}, []);
const toggleNotificationMenu = async () => {
try {
setnotificationMenu(!notificationMenu);
if (unreadNotification) {
const result = await readNotifications();
if (result) {
setunreadNotification(false);
update();
}
}
} catch (err) {
console.error('Erreur pour ouvrir/fermer le menu de notifications :', err);
}
}
async function deleteNotification(notificationId) {
try {
const result = await deleteNotificationUser(notificationId);
if (result) {
setNotifications(prev => prev.filter(n => n.id !== notificationId));
update();
}
} catch (err) {
console.error('Erreur suppression notification :', err);
}
}
return (
<div className={styles.headerContainer}>
<header className={`${styles.header} glassCard`}>
<nav className={`${mobileMenu ? styles.inactiveHeaderContent : styles.activeHeaderContent}`}>
<div className={styles.headerLeftContent}>
<NavLink className={styles.logoLink} to="/">
<img src="/logo.png" alt="logo" className={styles.logo} />
</NavLink>
<div className={styles.navLinks}>
<NavLink to="/" className={({ isActive }) => isActive ? styles.activeLink : styles.link}>
Accueil
</NavLink>
<NavLink to="/events" className={({ isActive }) => isActive ? styles.activeLink : styles.link}>
Evènements
</NavLink>
<NavLink to="/volunteers" className={({ isActive }) => isActive ? styles.activeLink : styles.link}>
Bénévoles
</NavLink>
{user?.isAdmin && (
<NavLink to="/admin" className={({ isActive }) => isActive ? styles.activeLink : styles.link}>
Administration
</NavLink>
)}
</div>
</div>
<div className={styles.headerRightContent}>
<button
className={`${styles.bellBtn} ${notificationMenu ? styles.activeBellBtn : ""}`}
onClick={() => {toggleNotificationMenu();}}
>
<img className={styles.notificationsImg} src="/bell.svg" alt="notifications"/>
{unreadNotification && <span className={styles.notificationBadge}></span>}
</button>
<Link to="/profile" className={styles.profileLink}>
<img className={styles.profileImg} src="/person.svg" alt="profile"/>
</Link>
</div>
</nav>
<nav className={`${mobileMenu ? styles.activeMobileMenu : styles.inactiveMobileMenu}`}>
<NavLink to="/" className={({ isActive }) => isActive ? styles.activeLink : styles.link}>
Accueil
</NavLink>
<NavLink to="/events" className={({ isActive }) => isActive ? styles.activeLink : styles.link}>
Evènements
</NavLink>
<NavLink to="/volunteers" className={({ isActive }) => isActive ? styles.activeLink : styles.link}>
Bénévoles
</NavLink>
{user?.isAdmin && (
<NavLink to="/admin" className={({ isActive }) => isActive ? styles.activeLink : styles.link}>
Administration
</NavLink>
)}
</nav>
<button
className={`${styles.burgerBtn} ${mobileMenu ? styles.activeBurgerBtn : ""}`}
onClick={() => setMobileMenu(!mobileMenu)}
>
<div className={styles.burgerBar}></div>
<div className={styles.burgerBar}></div>
<div className={styles.burgerBar}></div>
</button>
</header>
<div
ref={notificationRef}
className={`${styles.notificationDiv} glassCard ${notificationMenu ? styles.activeNotificationDiv : ""}`}
>
{notifications.length === 0 ? (
<p className={styles.notification}>Vous n'avez aucune notification !</p>
) : (
<NotificationCard notifications={notifications} deleteNotification={deleteNotification} />
)}
</div>
</div>
);
}
export default Header;