diff --git a/client/src/components/chat-affix/registerMessagingSocketHandlers.js b/client/src/components/chat-affix/registerMessagingSocketHandlers.js
index 44b79c3b3..ab4473e97 100644
--- a/client/src/components/chat-affix/registerMessagingSocketHandlers.js
+++ b/client/src/components/chat-affix/registerMessagingSocketHandlers.js
@@ -1,35 +1,45 @@
import { CONVERSATION_LIST_QUERY, GET_CONVERSATION_DETAILS } from "../../graphql/conversations.queries";
import { gql } from "@apollo/client";
+const logLocal = (message, ...args) => {
+ if (import.meta.env.PROD) {
+ return;
+ }
+ console.log(`==================== ${message} ====================`);
+ console.dir({ ...args });
+};
+
export const registerMessagingHandlers = ({ socket, client }) => {
if (!(socket && client)) return;
const handleNewMessageSummary = (message) => {
const { conversationId, newConversation, existingConversation, isoutbound } = message;
+ logLocal("handleNewMessageSummary", message);
+
if (!existingConversation && newConversation?.phone_num) {
const queryResults = client.cache.readQuery({
query: CONVERSATION_LIST_QUERY,
variables: { offset: 0 }
});
-
- const fullConversation = {
- ...newConversation,
- updated_at: newConversation.updated_at || new Date().toISOString(),
- unreadcnt: newConversation.unreadcnt || 0,
- archived: newConversation.archived || false,
- label: newConversation.label || null,
- job_conversations: newConversation.job_conversations || [],
- messages_aggregate: newConversation.messages_aggregate || {
- aggregate: { count: isoutbound ? 0 : 1 }
- }
- };
-
client.cache.writeQuery({
query: CONVERSATION_LIST_QUERY,
variables: { offset: 0 },
data: {
- conversations: [fullConversation, ...(queryResults?.conversations || [])]
+ conversations: [
+ {
+ ...newConversation,
+ updated_at: newConversation.updated_at || new Date().toISOString(),
+ unreadcnt: newConversation.unreadcnt || 0,
+ archived: newConversation.archived || false,
+ label: newConversation.label || null,
+ job_conversations: newConversation.job_conversations || [],
+ messages_aggregate: newConversation.messages_aggregate || {
+ aggregate: { count: isoutbound ? 0 : 1 }
+ }
+ },
+ ...(queryResults?.conversations || [])
+ ]
}
});
} else {
@@ -51,9 +61,12 @@ export const registerMessagingHandlers = ({ socket, client }) => {
});
}
};
+
const handleNewMessageDetailed = (message) => {
const { conversationId, newMessage } = message;
+ logLocal("handleNewMessageDetailed", message);
+
// Append the new message to the conversation's message list
const queryResults = client.cache.readQuery({
query: GET_CONVERSATION_DETAILS,
@@ -76,6 +89,10 @@ export const registerMessagingHandlers = ({ socket, client }) => {
};
const handleMessageChanged = (message) => {
+ if (!message) return;
+
+ logLocal("handleMessageChanged", message);
+
client.cache.modify({
id: client.cache.identify({ __typename: "conversations", id: message.conversationid }),
fields: {
@@ -118,8 +135,12 @@ export const registerMessagingHandlers = ({ socket, client }) => {
};
const handleConversationChanged = (data) => {
+ if (!data) return;
+
const { conversationId, type, job_conversations, ...fields } = data;
+ logLocal("handleConversationChanged", data);
+
// Identify the conversation in the Apollo cache
const cacheId = client.cache.identify({
__typename: "conversations",
@@ -161,23 +182,60 @@ export const registerMessagingHandlers = ({ socket, client }) => {
};
const handleNewMessage = ({ conversationId, message }) => {
+ if (!conversationId || !message.id || !message.text) {
+ return;
+ }
+
+ logLocal("handleNewMessage", { conversationId, message });
+
client.cache.modify({
id: client.cache.identify({ __typename: "conversations", id: conversationId }),
fields: {
messages(existing = []) {
+ // Ensure that the `message` object matches the schema
const newMessageRef = client.cache.writeFragment({
- data: message,
+ data: {
+ __typename: "messages",
+ id: message.id,
+ body: message.text,
+ selectedMedia: message.image_path || [],
+ imexshopid: message.userid,
+ status: message.status,
+ created_at: message.created_at,
+ read: message.read
+ },
fragment: gql`
fragment NewMessage on messages {
id
body
- createdAt
selectedMedia
imexshopid
+ status
+ created_at
+ read
}
`
});
- return [...existing, newMessageRef];
+
+ // Prevent duplicates by checking if the message already exists
+ const isDuplicate = existing.some(
+ (msgRef) =>
+ client.cache.readFragment({
+ id: msgRef.__ref,
+ fragment: gql`
+ fragment CheckMessage on messages {
+ id
+ }
+ `
+ })?.id === message.id
+ );
+
+ // We already have it, so return the existing list
+ if (isDuplicate) {
+ return existing;
+ }
+
+ return [...existing, newMessageRef]; // Add the new message reference
}
}
});
diff --git a/client/src/components/chat-archive-button/chat-archive-button.component.jsx b/client/src/components/chat-archive-button/chat-archive-button.component.jsx
index 755e8f514..f7ed348c1 100644
--- a/client/src/components/chat-archive-button/chat-archive-button.component.jsx
+++ b/client/src/components/chat-archive-button/chat-archive-button.component.jsx
@@ -1,21 +1,31 @@
import { useMutation } from "@apollo/client";
import { Button } from "antd";
-import React, { useState } from "react";
+import React, { useContext, useState } from "react";
import { useTranslation } from "react-i18next";
import { TOGGLE_CONVERSATION_ARCHIVE } from "../../graphql/conversations.queries";
+import SocketContext from "../../contexts/SocketIO/socketContext.jsx";
-export default function ChatArchiveButton({ conversation }) {
+export default function ChatArchiveButton({ conversation, bodyshop }) {
const [loading, setLoading] = useState(false);
const { t } = useTranslation();
const [updateConversation] = useMutation(TOGGLE_CONVERSATION_ARCHIVE);
+ const { socket } = useContext(SocketContext);
+
const handleToggleArchive = async () => {
setLoading(true);
- await updateConversation({
- variables: { id: conversation.id, archived: !conversation.archived },
- refetchQueries: ["CONVERSATION_LIST_QUERY"]
+ const updatedConversation = await updateConversation({
+ variables: { id: conversation.id, archived: !conversation.archived }
});
+ if (socket) {
+ socket.emit("conversation-modified", {
+ conversationId: conversation.id,
+ bodyshopId: bodyshop.id,
+ archived: updatedConversation.data.update_conversations_by_pk.archived
+ });
+ }
+
setLoading(false);
};
diff --git a/client/src/components/chat-conversation-title/chat-conversation-title.component.jsx b/client/src/components/chat-conversation-title/chat-conversation-title.component.jsx
index 243f699a0..7754ea347 100644
--- a/client/src/components/chat-conversation-title/chat-conversation-title.component.jsx
+++ b/client/src/components/chat-conversation-title/chat-conversation-title.component.jsx
@@ -18,7 +18,7 @@ export default function ChatConversationTitle({ conversation, bodyshop }) {
bodyshop={bodyshop}
/>
-
+
);
}
diff --git a/client/src/components/chat-conversation/chat-conversation.container.jsx b/client/src/components/chat-conversation/chat-conversation.container.jsx
index 0fb60aea4..613d96288 100644
--- a/client/src/components/chat-conversation/chat-conversation.container.jsx
+++ b/client/src/components/chat-conversation/chat-conversation.container.jsx
@@ -26,7 +26,6 @@ export function ChatConversationContainer({ bodyshop, selectedConversation }) {
fetchPolicy: "network-only",
nextFetchPolicy: "network-only"
});
-
const { socket } = useContext(SocketContext);
useEffect(() => {
diff --git a/client/src/components/chat-send-message/chat-send-message.component.jsx b/client/src/components/chat-send-message/chat-send-message.component.jsx
index 2ea90322e..e86531ee4 100644
--- a/client/src/components/chat-send-message/chat-send-message.component.jsx
+++ b/client/src/components/chat-send-message/chat-send-message.component.jsx
@@ -50,10 +50,11 @@ function ChatSendMessageComponent({ conversation, bodyshop, sendMessage, isSendi
};
sendMessage(newMessage);
if (socket) {
+ const lastMessage = conversation.messages?.[conversation.messages.length - 1]; // Get the last message
socket.emit("message-added", {
conversationId: conversation.id,
bodyshopId: bodyshop.id,
- message: newMessage
+ message: lastMessage
});
}
setSelectedMedia(
diff --git a/server/sms/status.js b/server/sms/status.js
index bfdeb5ed2..51d2f7ecb 100644
--- a/server/sms/status.js
+++ b/server/sms/status.js
@@ -15,6 +15,11 @@ exports.status = async (req, res) => {
} = req;
try {
+ // Ignore status 'queued'
+ if (SmsStatus === "queued") {
+ return res.status(200).json({ message: "Status 'queued' disregarded." });
+ }
+
// Update message status in the database
const response = await client.request(queries.UPDATE_MESSAGE_STATUS, {
msid: SmsSid,
@@ -47,6 +52,7 @@ exports.status = async (req, res) => {
warning: "No message returned from the database update."
});
}
+
res.sendStatus(200);
} catch (error) {
logger.log("sms-status-update-error", "ERROR", "api", null, {
diff --git a/server/web-sockets/redisSocketEvents.js b/server/web-sockets/redisSocketEvents.js
index 33faab361..a8e753f2f 100644
--- a/server/web-sockets/redisSocketEvents.js
+++ b/server/web-sockets/redisSocketEvents.js
@@ -181,7 +181,7 @@ const redisSocketEvents = ({
const messageAdded = ({ bodyshopId, conversationId, message }) => {
try {
const room = getBodyshopConversationRoom({ bodyshopId, conversationId });
- io.to(room).emit("new-message", message);
+ io.to(room).emit("new-message", { message, conversationId });
} catch (error) {
logger.log("Failed to handle new message", "error", "io-redis", null, {
error: error.message,