import { useNavigate } from "react-router-dom"; import { BellIcon } from "@primer/octicons-react"; import { useAppSelector, useUserDetails } from "@renderer/hooks"; import { useCallback, useEffect, useMemo, useState, useRef } from "react"; import { useTranslation } from "react-i18next"; import SteamLogo from "@renderer/assets/steam-logo.svg?react"; import { Avatar } from "../avatar/avatar"; import { AuthPage } from "@shared"; import { logger } from "@renderer/logger"; import type { NotificationCountResponse } from "@types"; import "./sidebar-profile.scss"; export function SidebarProfile() { const navigate = useNavigate(); const { t } = useTranslation("sidebar"); const { userDetails } = useUserDetails(); const { gameRunning } = useAppSelector((state) => state.gameRunning); const [notificationCount, setNotificationCount] = useState(0); const apiNotificationCountRef = useRef(0); const hasFetchedInitialCount = useRef(false); const fetchLocalNotificationCount = useCallback(async () => { try { const localCount = await window.electron.getLocalNotificationsCount(); setNotificationCount(localCount + apiNotificationCountRef.current); } catch (error) { logger.error("Failed to fetch local notification count", error); } }, []); const fetchApiNotificationCount = useCallback(async () => { try { const response = await window.electron.hydraApi.get( "/profile/notifications/count", { needsAuth: true } ); apiNotificationCountRef.current = response.count; } catch { // Ignore API errors } fetchLocalNotificationCount(); }, [fetchLocalNotificationCount]); // Initial fetch on mount (only once) useEffect(() => { fetchLocalNotificationCount(); }, [fetchLocalNotificationCount]); // Fetch API count when user logs in (only if not already fetched) useEffect(() => { if (userDetails && !hasFetchedInitialCount.current) { hasFetchedInitialCount.current = true; fetchApiNotificationCount(); } else if (!userDetails) { hasFetchedInitialCount.current = false; apiNotificationCountRef.current = 0; fetchLocalNotificationCount(); } }, [userDetails, fetchApiNotificationCount, fetchLocalNotificationCount]); useEffect(() => { const unsubscribe = window.electron.onLocalNotificationCreated(() => { fetchLocalNotificationCount(); }); return () => unsubscribe(); }, [fetchLocalNotificationCount]); useEffect(() => { const handleNotificationsChange = () => { fetchLocalNotificationCount(); }; window.addEventListener("notificationsChanged", handleNotificationsChange); return () => { window.removeEventListener( "notificationsChanged", handleNotificationsChange ); }; }, [fetchLocalNotificationCount]); useEffect(() => { const unsubscribe = window.electron.onSyncNotificationCount( (notification) => { apiNotificationCountRef.current = notification.notificationCount; fetchLocalNotificationCount(); } ); return () => unsubscribe(); }, [fetchLocalNotificationCount]); const handleProfileClick = () => { if (userDetails === null) { window.electron.openAuthWindow(AuthPage.SignIn); return; } navigate(`/profile/${userDetails.id}`); }; const notificationsButton = useMemo(() => { return ( ); }, [t, notificationCount, navigate]); const gameRunningDetails = () => { if (!userDetails || !gameRunning) return null; if (gameRunning.iconUrl) { return ( {gameRunning.title} ); } return ; }; return (
{notificationsButton}
); }