feature/IO-3000-Migrate-MSG-to-Sockets - Progress Checkpoint
Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
@@ -4,15 +4,19 @@ import { createStructuredSelector } from "reselect";
|
|||||||
import { selectSelectedConversation } from "../../redux/messaging/messaging.selectors";
|
import { selectSelectedConversation } from "../../redux/messaging/messaging.selectors";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import ChatConversationComponent from "./chat-conversation.component";
|
import ChatConversationComponent from "./chat-conversation.component";
|
||||||
import axios from "axios";
|
|
||||||
import SocketContext from "../../contexts/SocketIO/socketContext.jsx";
|
import SocketContext from "../../contexts/SocketIO/socketContext.jsx";
|
||||||
|
import { updateUnreadCount } from "../../redux/messaging/messaging.actions.js";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
selectedConversation: selectSelectedConversation,
|
selectedConversation: selectSelectedConversation,
|
||||||
bodyshop: selectBodyshop
|
bodyshop: selectBodyshop
|
||||||
});
|
});
|
||||||
|
|
||||||
export function ChatConversationContainer({ bodyshop, selectedConversation }) {
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
updateUnreadCounts: (data) => dispatch(updateUnreadCount(data.conversationId, data.unreadcnt))
|
||||||
|
});
|
||||||
|
|
||||||
|
export function ChatConversationContainer({ bodyshop, selectedConversation, updateUnreadCounts }) {
|
||||||
const { socket } = useContext(SocketContext);
|
const { socket } = useContext(SocketContext);
|
||||||
const [conversationDetails, setConversationDetails] = useState({});
|
const [conversationDetails, setConversationDetails] = useState({});
|
||||||
const [messages, setMessages] = useState([]);
|
const [messages, setMessages] = useState([]);
|
||||||
@@ -36,26 +40,34 @@ export function ChatConversationContainer({ bodyshop, selectedConversation }) {
|
|||||||
setMessages((prevMessages) => [...prevMessages, message]);
|
setMessages((prevMessages) => [...prevMessages, message]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on("unread-count-updated", (data) => {
|
||||||
|
updateUnreadCounts(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("conversation-list-updated", (data) => {
|
||||||
|
setConversationDetails(data.conversation);
|
||||||
|
setMessages(data.messages);
|
||||||
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
socket.emit("leave-conversation", selectedConversation);
|
socket.emit("leave-conversation", selectedConversation);
|
||||||
socket.off("conversation-details");
|
socket.off("conversation-details");
|
||||||
socket.off("new-message");
|
socket.off("new-message");
|
||||||
|
socket.off("unread-count-updated");
|
||||||
|
socket.off("conversation-list-updated");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}, [socket, selectedConversation]);
|
}, [socket, selectedConversation, updateUnreadCounts]);
|
||||||
|
|
||||||
// Mark messages as read
|
// Mark messages as read
|
||||||
const handleMarkConversationAsRead = async () => {
|
const handleMarkConversationAsRead = async () => {
|
||||||
if (messages.some((msg) => !msg.read) && !markingAsReadInProgress) {
|
if (messages.some((msg) => !msg.read) && !markingAsReadInProgress) {
|
||||||
setMarkingAsReadInProgress(true);
|
setMarkingAsReadInProgress(true);
|
||||||
|
|
||||||
// Emit a WebSocket event to mark messages as read
|
// Emit a WebSocket event to mark messages as read
|
||||||
socket.emit("mark-as-read", { conversationId: selectedConversation });
|
socket.emit("mark-as-read", {
|
||||||
|
conversationId: selectedConversation,
|
||||||
// Fallback to an API call to update the read status in the database
|
imexshopid: bodyshop.imexshopid,
|
||||||
await axios.post("/sms/markConversationRead", {
|
bodyshopId: bodyshop.id
|
||||||
conversationid: selectedConversation,
|
|
||||||
imexshopid: bodyshop.imexshopid
|
|
||||||
});
|
});
|
||||||
|
|
||||||
setMarkingAsReadInProgress(false);
|
setMarkingAsReadInProgress(false);
|
||||||
@@ -76,4 +88,4 @@ export function ChatConversationContainer({ bodyshop, selectedConversation }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(ChatConversationContainer);
|
export default connect(mapStateToProps, mapDispatchToProps)(ChatConversationContainer);
|
||||||
|
|||||||
@@ -81,13 +81,13 @@ const useSocket = (bodyshop) => {
|
|||||||
dispatch({ type: "ADD_MESSAGE", payload: data.message });
|
dispatch({ type: "ADD_MESSAGE", payload: data.message });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleReadUpdated = ({ conversationId }) => {
|
// const handleReadUpdated = ({ conversationId }) => {
|
||||||
dispatch({ type: "UPDATE_UNREAD_COUNT", payload: conversationId });
|
// dispatch({ type: "UPDATE_UNREAD_COUNT", payload: conversationId });
|
||||||
};
|
// };
|
||||||
|
|
||||||
socketInstance.on("messaging-list", handleMessagingList);
|
socketInstance.on("messaging-list", handleMessagingList);
|
||||||
socketInstance.on("new-message", handleNewMessage);
|
socketInstance.on("new-message", handleNewMessage);
|
||||||
socketInstance.on("read-updated", handleReadUpdated);
|
// socketInstance.on("mark-as-read", handleReadUpdated);
|
||||||
socketInstance.on("connect", handleConnect);
|
socketInstance.on("connect", handleConnect);
|
||||||
socketInstance.on("reconnect", handleReconnect);
|
socketInstance.on("reconnect", handleReconnect);
|
||||||
socketInstance.on("connect_error", handleConnectionError);
|
socketInstance.on("connect_error", handleConnectionError);
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ export function Manage({ conflict, bodyshop, alerts, setAlerts }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fetchAlerts();
|
fetchAlerts();
|
||||||
}, []);
|
}, [setAlerts]);
|
||||||
|
|
||||||
// Use useEffect to watch for new alerts
|
// Use useEffect to watch for new alerts
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -52,12 +52,12 @@ export const addMessage = (message) => ({
|
|||||||
|
|
||||||
// Add a Conversation to the list of conversations
|
// Add a Conversation to the list of conversations
|
||||||
export const addConversation = (conversation) => ({
|
export const addConversation = (conversation) => ({
|
||||||
type: "ADD_CONVERSATION",
|
type: MessagingActionTypes.ADD_CONVERSATION,
|
||||||
payload: conversation
|
payload: conversation
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update unread count for a conversation (e.g., after marking messages as read)
|
// Update unread count for a conversation (e.g., after marking messages as read)
|
||||||
export const updateUnreadCount = (conversationId) => ({
|
export const updateUnreadCount = (conversationId, unreadCount) => ({
|
||||||
type: MessagingActionTypes.UPDATE_UNREAD_COUNT,
|
type: MessagingActionTypes.UPDATE_UNREAD_COUNT,
|
||||||
payload: conversationId
|
payload: { conversationId, unreadCount }
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const INITIAL_STATE = {
|
|||||||
message: null,
|
message: null,
|
||||||
conversations: [], // Holds the list of conversations
|
conversations: [], // Holds the list of conversations
|
||||||
messages: [], // Holds the list of messages for the selected conversation
|
messages: [], // Holds the list of messages for the selected conversation
|
||||||
unreadCount: 0,
|
unreadcnt: 0,
|
||||||
searchingForConversation: false
|
searchingForConversation: false
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -83,12 +83,21 @@ const messagingReducer = (state = INITIAL_STATE, action) => {
|
|||||||
conversations: {
|
conversations: {
|
||||||
...state.conversations,
|
...state.conversations,
|
||||||
conversations: state.conversations.conversations.map((conversation) =>
|
conversations: state.conversations.conversations.map((conversation) =>
|
||||||
conversation.id === action.payload
|
conversation.id === action.payload.conversationId
|
||||||
? { ...conversation, unreadcnt: 0 } // Reset unread count for the selected conversation
|
? { ...conversation, unreadcnt: action.payload.unreadcnt } // Update unread count to the value in the payload
|
||||||
: conversation
|
: conversation
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
unreadCount: Math.max(state.unreadCount - 1, 0) // Ensure unreadCount does not go below zero
|
unreadcnt: Math.max(
|
||||||
|
state.conversations.conversations.reduce(
|
||||||
|
(total, conversation) =>
|
||||||
|
conversation.id === action.payload.conversationId
|
||||||
|
? total + action.payload.unreadcnt
|
||||||
|
: total + conversation.unreadcnt,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
0
|
||||||
|
) // Recalculate the global unreadcnt based on all conversations
|
||||||
};
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
const { admin } = require("../firebase/firebase-handler");
|
const { admin } = require("../firebase/firebase-handler");
|
||||||
const { MARK_MESSAGES_AS_READ, GET_CONVERSATIONS, GET_CONVERSATION_DETAILS } = require("../graphql-client/queries");
|
const { MARK_MESSAGES_AS_READ, GET_CONVERSATIONS, GET_CONVERSATION_DETAILS } = require("../graphql-client/queries");
|
||||||
const logger = require("../utils/logger");
|
|
||||||
const { phone } = require("phone");
|
const { phone } = require("phone");
|
||||||
const { client: gqlClient } = require("../graphql-client/graphql-client");
|
const { client: gqlClient } = require("../graphql-client/graphql-client");
|
||||||
const queries = require("../graphql-client/queries");
|
const queries = require("../graphql-client/queries");
|
||||||
@@ -151,7 +150,6 @@ const redisSocketEvents = ({
|
|||||||
const conversations = await client.request(GET_CONVERSATIONS, { bodyshopId: bodyshopUUID });
|
const conversations = await client.request(GET_CONVERSATIONS, { bodyshopId: bodyshopUUID });
|
||||||
socket.emit("messaging-list", { conversations });
|
socket.emit("messaging-list", { conversations });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.dir(error);
|
|
||||||
logger.log("error", "Failed to fetch conversations", error);
|
logger.log("error", "Failed to fetch conversations", error);
|
||||||
socket.emit("error", { message: "Failed to fetch conversations" });
|
socket.emit("error", { message: "Failed to fetch conversations" });
|
||||||
}
|
}
|
||||||
@@ -171,19 +169,35 @@ const redisSocketEvents = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const markAsRead = async ({ conversationId, userId }) => {
|
const markAsRead = async ({ conversationId, userId, imexshopid, bodyshopId }) => {
|
||||||
try {
|
try {
|
||||||
await client.request(MARK_MESSAGES_AS_READ, { conversationId, userId });
|
await client.request(MARK_MESSAGES_AS_READ, { conversationId, userId });
|
||||||
io.to(`conversation-${conversationId}`).emit("read-updated", { conversationId });
|
|
||||||
|
// Fetch the updated unread count for this conversation
|
||||||
|
const conversations = await client.request(GET_CONVERSATIONS, { bodyshopId });
|
||||||
|
|
||||||
|
// Emit the updated unread count to all clients
|
||||||
|
const room = `conversation-${conversationId}`;
|
||||||
|
io.to(room).emit("messaging-list", { conversations });
|
||||||
|
|
||||||
|
admin.messaging().send({
|
||||||
|
topic: `${imexshopid}-messaging`,
|
||||||
|
data: {
|
||||||
|
type: "messaging-mark-conversation-read",
|
||||||
|
conversationid: conversationId || ""
|
||||||
|
}
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.log("error", "Failed to mark messages as read", error);
|
logger.log("Failed to mark messages as read", "error", null, null, {
|
||||||
|
message: error.message,
|
||||||
|
stack: error.stack
|
||||||
|
});
|
||||||
socket.emit("error", { message: "Failed to mark messages as read" });
|
socket.emit("error", { message: "Failed to mark messages as read" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const sendMessage = (data) => {
|
const sendMessage = (data) => {
|
||||||
const { to, messagingServiceSid, body, conversationid, selectedMedia, imexshopid, user } = data;
|
const { to, messagingServiceSid, body, conversationid, selectedMedia, imexshopid, user } = data;
|
||||||
console.dir({ data });
|
|
||||||
logger.log("sms-outbound", "DEBUG", user.email, null, {
|
logger.log("sms-outbound", "DEBUG", user.email, null, {
|
||||||
messagingServiceSid: messagingServiceSid,
|
messagingServiceSid: messagingServiceSid,
|
||||||
to: phone(to).phoneNumber,
|
to: phone(to).phoneNumber,
|
||||||
@@ -217,7 +231,6 @@ const redisSocketEvents = ({
|
|||||||
gqlClient
|
gqlClient
|
||||||
.request(queries.INSERT_MESSAGE, { msg: newMessage, conversationid })
|
.request(queries.INSERT_MESSAGE, { msg: newMessage, conversationid })
|
||||||
.then((r2) => {
|
.then((r2) => {
|
||||||
//console.log("Responding GQL Message ID", JSON.stringify(r2));
|
|
||||||
logger.log("sms-outbound-success", "DEBUG", user.email, null, {
|
logger.log("sms-outbound-success", "DEBUG", user.email, null, {
|
||||||
msid: message.sid,
|
msid: message.sid,
|
||||||
conversationid
|
conversationid
|
||||||
|
|||||||
Reference in New Issue
Block a user