From 2a65cb50259d4ddb96b4c2ec87c1495c11790c6a Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Wed, 5 Mar 2025 17:28:32 -0500 Subject: [PATCH] IO-3166-Global-Notifications-Part-2 - Checkpoint --- .../components/header/header.component.jsx | 41 +++- .../notification-center.component.jsx | 12 +- client/src/contexts/SocketIO/useSocket.jsx | 29 ++- client/src/graphql/notifications.queries.js | 6 + docker-compose-cluster.yml | 223 ++++++++++++++++++ hasura/metadata/tables.yaml | 22 ++ nginx-websocket.conf | 45 ++++ server/graphql-client/queries.js | 1 + server/routes/miscellaneousRoutes.js | 13 + 9 files changed, 368 insertions(+), 24 deletions(-) create mode 100644 docker-compose-cluster.yml create mode 100644 nginx-websocket.conf diff --git a/client/src/components/header/header.component.jsx b/client/src/components/header/header.component.jsx index 8399634ba..9ba708a38 100644 --- a/client/src/components/header/header.component.jsx +++ b/client/src/components/header/header.component.jsx @@ -1,6 +1,6 @@ import { Badge, Layout, Menu, Spin } from "antd"; import { useTranslation } from "react-i18next"; -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { Link } from "react-router-dom"; @@ -95,7 +95,8 @@ function Header({ const { t } = useTranslation(); const { isConnected, scenarioNotificationsOn } = useSocket(); const [notificationVisible, setNotificationVisible] = useState(false); - + const baseTitleRef = useRef(document.title || ""); + const lastSetTitleRef = useRef(""); const userAssociationId = bodyshop?.associations?.[0]?.id; const { @@ -123,6 +124,40 @@ function Header({ } }, [isConnected, unreadLoading, refetchUnread, userAssociationId]); + // Keep The unread count in the title. + useEffect(() => { + const updateTitle = () => { + const currentTitle = document.title; + // Check if the current title differs from what we last set + if (currentTitle !== lastSetTitleRef.current) { + // Extract base title by removing any unread count prefix + const baseTitleMatch = currentTitle.match(/^\(\d+\)\s*(.*)$/); + baseTitleRef.current = baseTitleMatch ? baseTitleMatch[1] : currentTitle; + } + + // Apply unread count to the base title + const newTitle = unreadCount > 0 ? `(${unreadCount}) ${baseTitleRef.current}` : baseTitleRef.current; + + // Only update if the title has changed to avoid unnecessary DOM writes + if (document.title !== newTitle) { + document.title = newTitle; + lastSetTitleRef.current = newTitle; // Store what we set + } + }; + + // Initial update + updateTitle(); + + // Poll every 100ms to catch child component changes + const interval = setInterval(updateTitle, 100); + + // Cleanup + return () => { + clearInterval(interval); + document.title = baseTitleRef.current; // Reset to base title on unmount + }; + }, [unreadCount]); // Re-run when unreadCount changes + const handleNotificationClick = (e) => { setNotificationVisible(!notificationVisible); if (handleMenuClick) handleMenuClick(e); @@ -656,7 +691,7 @@ function Header({ icon: unreadLoading ? ( ) : ( - + ), diff --git a/client/src/components/notification-center/notification-center.component.jsx b/client/src/components/notification-center/notification-center.component.jsx index c7e6d4f58..7d3506605 100644 --- a/client/src/components/notification-center/notification-center.component.jsx +++ b/client/src/components/notification-center/notification-center.component.jsx @@ -1,11 +1,12 @@ import { Virtuoso } from "react-virtuoso"; -import { Alert, Badge, Button, Space, Spin, Switch, Tooltip, Typography } from "antd"; +import { Badge, Button, Space, Spin, Switch, Tooltip, Typography } from "antd"; import { CheckCircleFilled, CheckCircleOutlined, EyeFilled, EyeOutlined } from "@ant-design/icons"; import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; import "./notification-center.styles.scss"; import day from "../../utils/day.js"; import { forwardRef } from "react"; +import { DateTimeFormat } from "../../utils/DateFormatter.jsx"; const { Text, Title } = Typography; @@ -52,11 +53,7 @@ const NotificationCenterComponent = forwardRef( {t("notifications.labels.ro-number", { ro_number: notification.roNumber })} - + {day(notification.created_at).fromNow()} @@ -83,7 +80,6 @@ const NotificationCenterComponent = forwardRef(
- {" "} {showUnreadOnly ? ( ) : ( @@ -94,7 +90,7 @@ const NotificationCenterComponent = forwardRef(