fix: re-subscribe on ws reconnect

This commit is contained in:
Mohamed Marrouchi 2025-01-22 19:34:11 +01:00
parent dee2eb5c81
commit 2b433ef755
3 changed files with 40 additions and 7 deletions

View File

@ -1,11 +1,12 @@
/* /*
* Copyright © 2024 Hexastack. All rights reserved. * Copyright © 2025 Hexastack. All rights reserved.
* *
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 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. * 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). * 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, { import React, {
SyntheticEvent, SyntheticEvent,
useCallback, useCallback,
@ -75,7 +76,7 @@ const UserSubscription: React.FC = () => {
}); });
setMessages(messages); setMessages(messages);
setParticipants([ setParticipants([
...participants, participants[0],
{ {
id: profile.foreign_id, id: profile.foreign_id,
foreign_id: profile.foreign_id, foreign_id: profile.foreign_id,

View File

@ -1,11 +1,12 @@
/* /*
* Copyright © 2024 Hexastack. All rights reserved. * Copyright © 2025 Hexastack. All rights reserved.
* *
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 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. * 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). * 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, { import React, {
createContext, createContext,
ReactNode, ReactNode,
@ -268,7 +269,7 @@ const ChatProvider: React.FC<{
content_type: QuickReplyType.text, content_type: QuickReplyType.text,
text: qr.title, text: qr.title,
payload: qr.payload, payload: qr.payload,
}) as ISuggestion, } as ISuggestion),
), ),
); );
} else { } else {
@ -308,11 +309,17 @@ const ChatProvider: React.FC<{
async (firstName?: string, lastName?: string) => { async (firstName?: string, lastName?: string) => {
try { try {
setConnectionState(2); setConnectionState(2);
const queryParams: Record<string, string> =
firstName && lastName
? { first_name: firstName, last_name: lastName }
: {};
const { body } = await socketCtx.socket.get<{ const { body } = await socketCtx.socket.get<{
messages: TMessage[]; messages: TMessage[];
profile: ISubscriber; profile: ISubscriber;
}>( }>(
`/webhook/${config.channel}/?first_name=${firstName}&last_name=${lastName}`, `/webhook/${config.channel}/?${new URLSearchParams(
queryParams,
).toString()}`,
); );
localStorage.setItem("profile", JSON.stringify(body.profile)); localStorage.setItem("profile", JSON.stringify(body.profile));
@ -332,7 +339,7 @@ const ChatProvider: React.FC<{
}), }),
); );
setParticipants([ setParticipants([
...participants, participants[0],
{ {
id: body.profile.foreign_id, id: body.profile.foreign_id,
foreign_id: body.profile.foreign_id, foreign_id: body.profile.foreign_id,
@ -382,6 +389,24 @@ const ChatProvider: React.FC<{
if (screen === "chat" && connectionState === ConnectionState.connected) { if (screen === "chat" && connectionState === ConnectionState.connected) {
handleSubscription(); handleSubscription();
} }
// When user loses internet connection, on reconnect
// we will need to subscribe him again (join the io room)
const reSubscribe = () => {
const item = localStorage.getItem("profile");
if (item) {
const profile = JSON.parse(item) as ISubscriber;
handleSubscription(profile.first_name, profile.last_name);
}
};
socketCtx.socket.io.on("reconnect", reSubscribe);
return () => {
socketCtx.socket.io.off("reconnect", reSubscribe);
};
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, []); }, []);

View File

@ -1,11 +1,12 @@
/* /*
* Copyright © 2024 Hexastack. All rights reserved. * Copyright © 2025 Hexastack. All rights reserved.
* *
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 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. * 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). * 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 { io, ManagerOptions, Socket, SocketOptions } from "socket.io-client"; import { io, ManagerOptions, Socket, SocketOptions } from "socket.io-client";
import { Config } from "../types/config.types"; import { Config } from "../types/config.types";
@ -56,6 +57,8 @@ export class SocketIoClient {
private config: SocketIoClientConfig; private config: SocketIoClientConfig;
public id: string;
constructor( constructor(
apiUrl: string, apiUrl: string,
socketConfig: SocketIoClientConfig, socketConfig: SocketIoClientConfig,
@ -72,6 +75,10 @@ export class SocketIoClient {
this.init(handlers); this.init(handlers);
} }
get io() {
return this.socket.io;
}
/** /**
* Initializes the socket client and sets up event handlers. * Initializes the socket client and sets up event handlers.
* @param handlers Event handlers for connection, disconnection, and connection errors * @param handlers Event handlers for connection, disconnection, and connection errors