feature/IO-3000-messaging-sockets-migrations2 -
- sync send - fix status events Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { CONVERSATION_LIST_QUERY, GET_CONVERSATION_DETAILS } from "../../graphql/conversations.queries";
|
||||
import { gql } from "@apollo/client";
|
||||
|
||||
export const registerMessagingHandlers = ({ socket, client }) => {
|
||||
if (!(socket && client)) return;
|
||||
@@ -14,8 +15,6 @@ export const registerMessagingHandlers = ({ socket, client }) => {
|
||||
|
||||
const fullConversation = {
|
||||
...newConversation,
|
||||
phone_num: newConversation.phone_num,
|
||||
id: newConversation.id,
|
||||
updated_at: newConversation.updated_at || new Date().toISOString(),
|
||||
unreadcnt: newConversation.unreadcnt || 0,
|
||||
archived: newConversation.archived || false,
|
||||
@@ -77,21 +76,43 @@ export const registerMessagingHandlers = ({ socket, client }) => {
|
||||
};
|
||||
|
||||
const handleMessageChanged = (message) => {
|
||||
// Find the message in the cache and update all fields dynamically
|
||||
client.cache.modify({
|
||||
id: client.cache.identify({
|
||||
__typename: "messages",
|
||||
id: message.id
|
||||
}),
|
||||
id: client.cache.identify({ __typename: "conversations", id: message.conversationid }),
|
||||
fields: {
|
||||
// Dynamically update all fields based on the incoming message object
|
||||
__typename: (existingType) => existingType || "messages", // Ensure __typename is preserved
|
||||
...Object.fromEntries(
|
||||
Object.entries(message).map(([key, value]) => [
|
||||
key,
|
||||
(cached) => (value !== undefined ? value : cached) // Update with new value or keep existing
|
||||
])
|
||||
)
|
||||
...(message.type === "status-changed" && {
|
||||
messages(existing = [], { readField }) {
|
||||
return existing.map((messageRef) => {
|
||||
// Match the message by ID
|
||||
if (readField("id", messageRef) === message.id) {
|
||||
const currentStatus = readField("status", messageRef);
|
||||
|
||||
// Prevent overwriting if the current status is already "delivered"
|
||||
if (currentStatus === "delivered") {
|
||||
return messageRef;
|
||||
}
|
||||
|
||||
// Update the existing message fields
|
||||
return client.cache.writeFragment({
|
||||
id: messageRef.__ref,
|
||||
fragment: gql`
|
||||
fragment UpdatedMessage on messages {
|
||||
id
|
||||
status
|
||||
conversationid
|
||||
__typename
|
||||
}
|
||||
`,
|
||||
data: {
|
||||
__typename: "messages",
|
||||
...message // Only update the fields provided in the message object
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return messageRef; // Keep other messages unchanged
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -113,6 +134,7 @@ export const registerMessagingHandlers = ({ socket, client }) => {
|
||||
client.cache.modify({
|
||||
id: cacheId,
|
||||
fields: {
|
||||
// This is a catch-all for just sending it fields off conversation
|
||||
...Object.fromEntries(
|
||||
Object.entries(fields).map(([key, value]) => [
|
||||
key,
|
||||
@@ -138,6 +160,30 @@ export const registerMessagingHandlers = ({ socket, client }) => {
|
||||
});
|
||||
};
|
||||
|
||||
const handleNewMessage = ({ conversationId, message }) => {
|
||||
client.cache.modify({
|
||||
id: client.cache.identify({ __typename: "conversations", id: conversationId }),
|
||||
fields: {
|
||||
messages(existing = []) {
|
||||
const newMessageRef = client.cache.writeFragment({
|
||||
data: message,
|
||||
fragment: gql`
|
||||
fragment NewMessage on messages {
|
||||
id
|
||||
body
|
||||
createdAt
|
||||
selectedMedia
|
||||
imexshopid
|
||||
}
|
||||
`
|
||||
});
|
||||
return [...existing, newMessageRef];
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
socket.on("new-message", handleNewMessage);
|
||||
socket.on("new-message-summary", handleNewMessageSummary);
|
||||
socket.on("new-message-detailed", handleNewMessageDetailed);
|
||||
socket.on("message-changed", handleMessageChanged);
|
||||
@@ -146,9 +192,9 @@ export const registerMessagingHandlers = ({ socket, client }) => {
|
||||
|
||||
export const unregisterMessagingHandlers = ({ socket }) => {
|
||||
if (!socket) return;
|
||||
socket.off("new-message");
|
||||
socket.off("new-message-summary");
|
||||
socket.off("new-message-detailed");
|
||||
socket.off("message-changed");
|
||||
socket.off("message-changed");
|
||||
socket.off("conversation-changed");
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LoadingOutlined, SendOutlined } from "@ant-design/icons";
|
||||
import { Input, Spin } from "antd";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import React, { useContext, useEffect, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
@@ -10,6 +10,7 @@ import { selectIsSending, selectMessage } from "../../redux/messaging/messaging.
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import ChatMediaSelector from "../chat-media-selector/chat-media-selector.component";
|
||||
import ChatPresetsComponent from "../chat-presets/chat-presets.component";
|
||||
import SocketContext from "../../contexts/SocketIO/socketContext.jsx";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -25,6 +26,8 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
function ChatSendMessageComponent({ conversation, bodyshop, sendMessage, isSending, message, setMessage }) {
|
||||
const inputArea = useRef(null);
|
||||
const [selectedMedia, setSelectedMedia] = useState([]);
|
||||
const { socket } = useContext(SocketContext);
|
||||
|
||||
useEffect(() => {
|
||||
inputArea.current.focus();
|
||||
}, [isSending, setMessage]);
|
||||
@@ -37,14 +40,22 @@ function ChatSendMessageComponent({ conversation, bodyshop, sendMessage, isSendi
|
||||
logImEXEvent("messaging_send_message");
|
||||
|
||||
if (selectedImages.length < 11) {
|
||||
sendMessage({
|
||||
const newMessage = {
|
||||
to: conversation.phone_num,
|
||||
body: message || "",
|
||||
messagingServiceSid: bodyshop.messagingservicesid,
|
||||
conversationid: conversation.id,
|
||||
selectedMedia: selectedImages,
|
||||
imexshopid: bodyshop.imexshopid
|
||||
});
|
||||
};
|
||||
sendMessage(newMessage);
|
||||
if (socket) {
|
||||
socket.emit("message-added", {
|
||||
conversationId: conversation.id,
|
||||
bodyshopId: bodyshop.id,
|
||||
message: newMessage
|
||||
});
|
||||
}
|
||||
setSelectedMedia(
|
||||
selectedMedia.map((i) => {
|
||||
return { ...i, isSelected: false };
|
||||
|
||||
@@ -36,7 +36,9 @@ exports.status = async (req, res) => {
|
||||
});
|
||||
|
||||
ioRedis.to(conversationRoom).emit("message-changed", {
|
||||
message
|
||||
...message,
|
||||
status: SmsStatus,
|
||||
type: "status-changed"
|
||||
});
|
||||
} else {
|
||||
logger.log("sms-status-update-warning", "WARN", "api", null, {
|
||||
@@ -80,21 +82,11 @@ exports.markConversationRead = async (req, res) => {
|
||||
|
||||
const broadcastRoom = getBodyshopRoom(bodyshopid);
|
||||
|
||||
const conversationRoom = getBodyshopConversationRoom({
|
||||
bodyshopId: bodyshopid,
|
||||
conversationId: conversationid
|
||||
});
|
||||
|
||||
ioRedis.to(broadcastRoom).emit("conversation-changed", {
|
||||
type: "conversation-marked-read",
|
||||
conversationId: conversationid
|
||||
});
|
||||
|
||||
ioRedis.to(conversationRoom).emit("message-changed", {
|
||||
type: "all-messages-marked-read",
|
||||
conversationId: conversationid
|
||||
});
|
||||
|
||||
res.status(200).json({ success: true, message: "Conversation marked as read." });
|
||||
} catch (error) {
|
||||
logger.log("conversation-mark-read-error", "ERROR", "api", null, {
|
||||
|
||||
@@ -178,6 +178,19 @@ const redisSocketEvents = ({
|
||||
}
|
||||
};
|
||||
|
||||
const messageAdded = ({ bodyshopId, conversationId, message }) => {
|
||||
try {
|
||||
const room = getBodyshopConversationRoom({ bodyshopId, conversationId });
|
||||
io.to(room).emit("new-message", message);
|
||||
} catch (error) {
|
||||
logger.log("Failed to handle new message", "error", "io-redis", null, {
|
||||
error: error.message,
|
||||
stack: error.stack
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
socket.on("message-added", messageAdded);
|
||||
socket.on("conversation-modified", conversationModified);
|
||||
socket.on("join-bodyshop-conversation", joinConversationRoom);
|
||||
socket.on("leave-bodyshop-conversation", leaveConversationRoom);
|
||||
|
||||
Reference in New Issue
Block a user