diff --git a/.env b/.env index fc25010..871e4c5 100644 --- a/.env +++ b/.env @@ -1,6 +1,7 @@ REACT_APP_TAB_TITLE=Gepafin REACT_APP_API_EXECUTION_ADDRESS=https://api-dev-gepafin.memento.credit/v1 REACT_APP_API_ADDRESS=https://api-dev-gepafin.memento.credit +REACT_APP_API_ADDRESS_WS=https://api-dev-gepafin.memento.credit/wss REACT_APP_LOGO_FILENAME=gepafin-logo.svg REACT_APP_FAVICON_FILENAME=gepafin-favicon.ico REACT_APP_HUB_ID=p4lk3bcx1RStqTaIVVbXs diff --git a/package.json b/package.json index e58a0a4..0783782 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "@emotion/styled": "11.13.0", "@number-flow/react": "0.4.2", "@sentry/browser": "^8.42.0", + "@stomp/stompjs": "^7.0.0", "@tanstack/react-table": "^8.20.5", "@wordpress/i18n": "5.8.0", "@wordpress/react-i18n": "4.8.0", @@ -36,6 +37,7 @@ "react-hook-form": "7.53.0", "react-router-dom": "6.26.2", "react-scripts": "5.0.1", + "sockjs-client": "^1.6.1", "validate.js": "0.13.1", "zustand": "4.5.4", "zustand-x": "3.0.4" diff --git a/src/components/NotificationsSidebar/index.js b/src/components/NotificationsSidebar/index.js index 7e1d919..31b00e5 100644 --- a/src/components/NotificationsSidebar/index.js +++ b/src/components/NotificationsSidebar/index.js @@ -1,6 +1,8 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { __ } from '@wordpress/i18n'; import { head, isEmpty, pathOr } from 'ramda'; +import SockJS from 'sockjs-client'; +import { Stomp } from '@stomp/stompjs'; // store import { storeGet, useStore } from '../../store'; @@ -18,6 +20,8 @@ import { TabPanel, TabView } from 'primereact/tabview'; import NotificationItem from './components/NotificationItem'; import NotificationItemChosen from './components/NotificationItemChosen'; +const socketUrl = process.env.REACT_APP_API_ADDRESS_WS; + const NotificationsSidebar = () => { const chosenCompanyId = useStore().main.chosenCompanyId(); const userData = useStore().main.userData(); @@ -27,6 +31,10 @@ const NotificationsSidebar = () => { const [notifications, setNotifications] = useState([]); const [notificationsRead, setNotificationsRead] = useState([]); const [chosenMsg, setChosenMsg] = useState({}); + const socket = useRef(null); + const stomp = useRef(null); + const [currentSubscription, setCurrentSubscription] = useState(null); + const [isConnected, setIsConnected] = useState(false); // Handle tab change const handleTabChange = (e) => { @@ -61,7 +69,13 @@ const NotificationsSidebar = () => { const userData = storeGet.main.userData(); const role = pathOr('', ['role', 'roleType'], userData); - if (userData.id && chosenCompanyId !== 0 && role === 'ROLE_BENEFICIARY') { + if (currentSubscription) { + console.log('UNsubscribed') + currentSubscription.unsubscribe(); + setCurrentSubscription(null); + } + + if (isConnected && userData.id && chosenCompanyId !== 0 && role === 'ROLE_BENEFICIARY') { setLoading(true); NotificationService.getNotifications( userData.id, @@ -72,7 +86,10 @@ const NotificationsSidebar = () => { ['companyId', chosenCompanyId] ] ); - } else if (userData.id && role !== 'ROLE_BENEFICIARY') { + if (socket.current) { + subscribeTo(`/topic/notifications_user_${userData.id}_company_${chosenCompanyId}`) + } + } else if (isConnected && userData.id && role !== 'ROLE_BENEFICIARY') { setLoading(true); NotificationService.getNotifications( userData.id, @@ -82,6 +99,9 @@ const NotificationsSidebar = () => { ['status', status] ] ); + if (socket.current) { + subscribeTo(`/topic/notifications_user_${userData.id}`) + } } } @@ -127,9 +147,72 @@ const NotificationsSidebar = () => { set404FromErrorResponse(resp); } + const connectWebSocket = () => { + socket.current = new SockJS(socketUrl); + stomp.current = Stomp.over(socket.current); + + stomp.current.configure({ + debug: function(str) { + //console.log(str); + }, + reconnectDelay: 5000, + heartbeatIncoming: 20000, + heartbeatOutgoing: 20000 + }); + + stomp.current.connect( + {}, + () => { + // connected + console.log('Websocket connected'); + setIsConnected(true); + }, + (error) => { + console.error('WebSocket Connection Error:', error); + setIsConnected(false); + setTimeout(connectWebSocket, 5000); + } + ); + }; + + const subscribeTo = (topic) => { + console.log('subscribeTo', topic) + const subscription = stomp.current.subscribe( + topic, + (message) => { + try { + const notification = JSON.parse(message.body); + console.log('notification', notification) + //setNotifications(prev => [notification, ...prev]); + } catch (error) { + console.error('Error parsing notification:', error); + } + } + ); + + setCurrentSubscription(subscription); + } + useEffect(() => { fetchMessages(); - }, [chosenCompanyId, userData.id]); + }, [chosenCompanyId, userData.id, isConnected]); + + useEffect(() => { + connectWebSocket(); + + return () => { + if (currentSubscription) { + currentSubscription.unsubscribe(); + setCurrentSubscription(null); + } + + if (stomp.current) { + stomp.current.disconnect(() => { + console.log('WebSocket Disconnected'); + }); + } + }; + }, []); return ( <>