From 8dc753ee39b206e1a70d3e565876fc6377005fc3 Mon Sep 17 00:00:00 2001 From: yassinedorbozgithub Date: Tue, 28 Jan 2025 11:16:23 +0100 Subject: [PATCH] fix: apply feedback updates --- frontend/src/contexts/auth.context.tsx | 14 ------ frontend/src/hooks/entities/auth-hooks.ts | 4 +- frontend/src/hooks/useBroadcastChannel.ts | 46 +++++++++--------- widget/src/hooks/useBroadcastChannel.ts | 57 +++++++++++++++++++++++ widget/src/providers/ChatProvider.tsx | 15 +++++- 5 files changed, 95 insertions(+), 41 deletions(-) create mode 100644 widget/src/hooks/useBroadcastChannel.ts diff --git a/frontend/src/contexts/auth.context.tsx b/frontend/src/contexts/auth.context.tsx index a3d27ace..a2faf186 100644 --- a/frontend/src/contexts/auth.context.tsx +++ b/frontend/src/contexts/auth.context.tsx @@ -21,11 +21,6 @@ import { Progress } from "@/app-components/displays/Progress"; import { useLogout } from "@/hooks/entities/auth-hooks"; import { useApiClient } from "@/hooks/useApiClient"; import { CURRENT_USER_KEY, PUBLIC_PATHS } from "@/hooks/useAuth"; -import { - EBCEvent, - ETabMode, - useBroadcastChannel, -} from "@/hooks/useBroadcastChannel"; import { useTranslate } from "@/hooks/useTranslate"; import { RouterType } from "@/services/types"; import { IUser } from "@/types/user.types"; @@ -64,9 +59,6 @@ export const AuthProvider = ({ children }: AuthProviderProps): JSX.Element => { i18n.changeLanguage(lang); }; const { mutate: logoutSession } = useLogout(); - const { mode, value } = useBroadcastChannel({ - channelName: "websocket-session", - }); const logout = async () => { updateLanguage(publicRuntimeConfig.lang.default); logoutSession(); @@ -115,12 +107,6 @@ export const AuthProvider = ({ children }: AuthProviderProps): JSX.Element => { setIsReady(true); }, []); - useEffect(() => { - if (value === EBCEvent.LOGOUT_END_SESSION && mode === ETabMode.SECONDARY) { - router.reload(); - } - }, [value, mode, router]); - if (!isReady || isLoading) return ; return ( diff --git a/frontend/src/hooks/entities/auth-hooks.ts b/frontend/src/hooks/entities/auth-hooks.ts index 8dd9d783..fb78fed4 100755 --- a/frontend/src/hooks/entities/auth-hooks.ts +++ b/frontend/src/hooks/entities/auth-hooks.ts @@ -59,9 +59,7 @@ export const useLogout = ( const { logoutRedirection } = useLogoutRedirection(); const { toast } = useToast(); const { t } = useTranslate(); - const { send } = useBroadcastChannel({ - channelName: "websocket-session", - }); + const { send } = useBroadcastChannel(); return useMutation({ ...options, diff --git a/frontend/src/hooks/useBroadcastChannel.ts b/frontend/src/hooks/useBroadcastChannel.ts index 66a30582..beba882d 100644 --- a/frontend/src/hooks/useBroadcastChannel.ts +++ b/frontend/src/hooks/useBroadcastChannel.ts @@ -6,7 +6,7 @@ * 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file). */ -import { useEffect, useMemo, useState } from "react"; +import { useEffect, useRef, useState } from "react"; export enum ETabMode { PRIMARY = "primary", @@ -17,38 +17,40 @@ export enum EBCEvent { LOGOUT_END_SESSION = "logout-end-session", } -export const useBroadcastChannel = ({ - channelName, - initialValue, -}: { - channelName: string; - initialValue?: EBCEvent; -}) => { +export const useBroadcastChannel = ( + channelName: string = "main-broadcast-channel", + initialValue?: EBCEvent, +) => { + const channelRef = useRef(null); const [value, setValue] = useState(initialValue); const [mode, setMode] = useState(ETabMode.PRIMARY); - const channel = useMemo( - () => new BroadcastChannel(channelName), - [channelName], - ); useEffect(() => { - channel.onmessage = (event) => { - if (mode === ETabMode.PRIMARY) { - setValue(event.data); - setMode(ETabMode.SECONDARY); - } - }; + channelRef.current = new BroadcastChannel(channelName); + }, [channelName]); - channel.postMessage(initialValue); + useEffect(() => { + if (channelRef.current) { + channelRef.current.addEventListener("message", (event) => { + if (mode === ETabMode.PRIMARY) { + setValue(event.data); + setMode(ETabMode.SECONDARY); + } + }); + channelRef.current.postMessage(initialValue); + } return () => { - channel.close(); + if (channelRef.current?.onmessage) { + channelRef.current.onmessage = null; + } + channelRef.current?.close(); }; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [channel, channelName, initialValue]); + }, [channelName, initialValue]); const send = (data: EBCEvent) => { - channel.postMessage(data); + channelRef.current?.postMessage(data); }; return { mode, value, send }; diff --git a/widget/src/hooks/useBroadcastChannel.ts b/widget/src/hooks/useBroadcastChannel.ts new file mode 100644 index 00000000..beba882d --- /dev/null +++ b/widget/src/hooks/useBroadcastChannel.ts @@ -0,0 +1,57 @@ +/* + * Copyright © 2025 Hexastack. All rights reserved. + * + * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: + * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. + * 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file). + */ + +import { useEffect, useRef, useState } from "react"; + +export enum ETabMode { + PRIMARY = "primary", + SECONDARY = "secondary", +} + +export enum EBCEvent { + LOGOUT_END_SESSION = "logout-end-session", +} + +export const useBroadcastChannel = ( + channelName: string = "main-broadcast-channel", + initialValue?: EBCEvent, +) => { + const channelRef = useRef(null); + const [value, setValue] = useState(initialValue); + const [mode, setMode] = useState(ETabMode.PRIMARY); + + useEffect(() => { + channelRef.current = new BroadcastChannel(channelName); + }, [channelName]); + + useEffect(() => { + if (channelRef.current) { + channelRef.current.addEventListener("message", (event) => { + if (mode === ETabMode.PRIMARY) { + setValue(event.data); + setMode(ETabMode.SECONDARY); + } + }); + channelRef.current.postMessage(initialValue); + } + + return () => { + if (channelRef.current?.onmessage) { + channelRef.current.onmessage = null; + } + channelRef.current?.close(); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [channelName, initialValue]); + + const send = (data: EBCEvent) => { + channelRef.current?.postMessage(data); + }; + + return { mode, value, send }; +}; diff --git a/widget/src/providers/ChatProvider.tsx b/widget/src/providers/ChatProvider.tsx index f24795cd..eefb0937 100644 --- a/widget/src/providers/ChatProvider.tsx +++ b/widget/src/providers/ChatProvider.tsx @@ -6,7 +6,6 @@ * 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file). */ - import React, { createContext, ReactNode, @@ -17,6 +16,11 @@ import React, { useState, } from "react"; +import { + EBCEvent, + ETabMode, + useBroadcastChannel, +} from "../hooks/useBroadcastChannel"; import { StdEventType } from "../types/chat-io-messages.types"; import { Direction, @@ -188,6 +192,7 @@ const ChatProvider: React.FC<{ defaultConnectionState?: ConnectionState; children: ReactNode; }> = ({ wantToConnect, defaultConnectionState = 0, children }) => { + const { mode, value } = useBroadcastChannel(); const config = useConfig(); const settings = useSettings(); const { screen, setScreen } = useWidget(); @@ -269,7 +274,7 @@ const ChatProvider: React.FC<{ content_type: QuickReplyType.text, text: qr.title, payload: qr.payload, - } as ISuggestion), + }) as ISuggestion, ), ); } else { @@ -419,6 +424,12 @@ const ChatProvider: React.FC<{ // eslint-disable-next-line react-hooks/exhaustive-deps }, [settings.avatarUrl]); + useEffect(() => { + if (value === EBCEvent.LOGOUT_END_SESSION && mode === ETabMode.SECONDARY) { + socketCtx.socket.disconnect(); + } + }, [value, mode]); + const contextValue: ChatContextType = { participants, setParticipants,