feature/IO-3000-Migrate-MSG-to-Sockets - Progress Checkpoint

Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
Dave Richer
2024-11-19 08:52:07 -08:00
parent 03ae7bb160
commit bed87174d4
7 changed files with 64 additions and 61 deletions

View File

@@ -12,8 +12,6 @@ export default function ChatConversationComponent({ subState, conversation, mess
if (loading) return <LoadingSkeleton />; if (loading) return <LoadingSkeleton />;
if (error) return <AlertComponent message={error.message} type="error" />; if (error) return <AlertComponent message={error.message} type="error" />;
console.dir(conversation);
return ( return (
<div <div
className="chat-conversation" className="chat-conversation"

View File

@@ -5,18 +5,15 @@ import { selectSelectedConversation } from "../../redux/messaging/messaging.sele
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 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
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({});
updateUnreadCounts: (data) => dispatch(updateUnreadCount(data.conversationId, data.unreadcnt))
});
export function ChatConversationContainer({ bodyshop, selectedConversation, updateUnreadCounts }) { export function ChatConversationContainer({ bodyshop, selectedConversation }) {
const { socket } = useContext(SocketContext); const { socket } = useContext(SocketContext);
const [conversationDetails, setConversationDetails] = useState({}); const [conversationDetails, setConversationDetails] = useState({});
const [messages, setMessages] = useState([]); const [messages, setMessages] = useState([]);
@@ -40,10 +37,6 @@ export function ChatConversationContainer({ bodyshop, selectedConversation, upda
setMessages((prevMessages) => [...prevMessages, message]); setMessages((prevMessages) => [...prevMessages, message]);
}); });
socket.on("unread-count-updated", (data) => {
updateUnreadCounts(data);
});
socket.on("conversation-list-updated", (data) => { socket.on("conversation-list-updated", (data) => {
setConversationDetails(data.conversation); setConversationDetails(data.conversation);
setMessages(data.messages); setMessages(data.messages);
@@ -53,11 +46,10 @@ export function ChatConversationContainer({ bodyshop, selectedConversation, upda
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.off("conversation-list-updated");
}; };
} }
}, [socket, selectedConversation, updateUnreadCounts]); }, [socket, selectedConversation]);
// Mark messages as read // Mark messages as read
const handleMarkConversationAsRead = async () => { const handleMarkConversationAsRead = async () => {

View File

@@ -47,14 +47,12 @@ const useSocket = (bodyshop) => {
}; };
const handleConnect = () => { const handleConnect = () => {
console.log("Socket connected:", socketInstance.id);
socketInstance.emit("join-bodyshop-room", bodyshop.id); socketInstance.emit("join-bodyshop-room", bodyshop.id);
setClientId(socketInstance.id); setClientId(socketInstance.id);
store.dispatch(setWssStatus("connected")); store.dispatch(setWssStatus("connected"));
}; };
const handleReconnect = (attempt) => { const handleReconnect = (attempt) => {
console.log(`Socket reconnected after ${attempt} attempts`);
store.dispatch(setWssStatus("connected")); store.dispatch(setWssStatus("connected"));
}; };
@@ -64,7 +62,6 @@ const useSocket = (bodyshop) => {
}; };
const handleDisconnect = () => { const handleDisconnect = () => {
console.log("Socket disconnected");
store.dispatch(setWssStatus("disconnected")); store.dispatch(setWssStatus("disconnected"));
}; };
@@ -81,13 +78,8 @@ const useSocket = (bodyshop) => {
dispatch({ type: "ADD_MESSAGE", payload: data.message }); dispatch({ type: "ADD_MESSAGE", payload: data.message });
}; };
// const handleReadUpdated = ({ 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("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);

View File

@@ -6,8 +6,10 @@ const INITIAL_STATE = {
isSending: false, isSending: false,
error: null, error: null,
message: null, message: null,
conversations: [], // Holds the list of conversations conversations: {
messages: [], // Holds the list of messages for the selected conversation conversations: []
},
messages: [],
unreadcnt: 0, unreadcnt: 0,
searchingForConversation: false searchingForConversation: false
}; };
@@ -72,34 +74,19 @@ const messagingReducer = (state = INITIAL_STATE, action) => {
}; };
case MessagingActionTypes.ADD_CONVERSATION: case MessagingActionTypes.ADD_CONVERSATION:
return {
...state,
conversations: [...state.conversations, action.payload]
};
case MessagingActionTypes.UPDATE_UNREAD_COUNT:
return { return {
...state, ...state,
conversations: { conversations: {
...state.conversations, ...state.conversations,
conversations: state.conversations.conversations.map((conversation) => conversations: [
conversation.id === action.payload.conversationId ...(state.conversations.conversations || []),
? { ...conversation, unreadcnt: action.payload.unreadcnt } // Update unread count to the value in the payload {
: conversation ...action.payload, // Ensure all fields from payload are included
) messages_aggregate: action.payload.messages_aggregate || { aggregate: { count: 0 } }
}, }
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:
return state; return state;
} }

View File

@@ -87,6 +87,21 @@ mutation RECEIVE_MESSAGE($msg: [messages_insert_input!]!) {
updated_at updated_at
unreadcnt unreadcnt
phone_num phone_num
label
job_conversations {
job {
id
ro_number
ownr_fn
ownr_ln
ownr_co_nm
}
}
messages_aggregate {
aggregate {
count
}
}
} }
conversationid conversationid
created_at created_at

View File

@@ -63,18 +63,28 @@ exports.receive = async (req, res) => {
// Insert new conversation and message // Insert new conversation and message
const insertresp = await client.request(queries.RECEIVE_MESSAGE, { msg: newMessage }); const insertresp = await client.request(queries.RECEIVE_MESSAGE, { msg: newMessage });
const createdConversation = insertresp.insert_conversations.returning[0]; // Safely access conversation and message
const message = insertresp.insert_messages.returning[0]; const createdConversation = insertresp?.insert_messages?.returning?.[0]?.conversation || null;
const message = insertresp?.insert_messages?.returning?.[0] || {
text: "",
image: false,
image_path: []
};
if (!createdConversation) {
throw new Error("Conversation data is missing from the response.");
}
// Emit new conversation event
ioRedis.to(getBodyshopRoom(response.bodyshops[0].id)).emit("new-conversation", { ioRedis.to(getBodyshopRoom(response.bodyshops[0].id)).emit("new-conversation", {
conversation: createdConversation, conversation: {
message: { ...createdConversation,
...message, messages_aggregate: {
text: message.text || "", aggregate: {
image: message.image || false, count: 1 // Adjust dynamically based on your logic or default to 0
image_path: message.image_path || [] }
} }
},
message
}); });
logger.log("sms-inbound-success", "DEBUG", "api", null, { logger.log("sms-inbound-success", "DEBUG", "api", null, {
@@ -99,6 +109,7 @@ exports.receive = async (req, res) => {
} }
} else if (response.bodyshops[0].conversations.length === 1) { } else if (response.bodyshops[0].conversations.length === 1) {
// Add to the existing conversation // Add to the existing conversation
// conversation UPDATED
newMessage.conversationid = response.bodyshops[0].conversations[0].id; newMessage.conversationid = response.bodyshops[0].conversations[0].id;
} else { } else {
// Duplicate phone error // Duplicate phone error

View File

@@ -140,11 +140,6 @@ const redisSocketEvents = ({
}; };
// Messaging Events // Messaging Events
const registerMessagingEvents = (socket) => { const registerMessagingEvents = (socket) => {
const broadcastNewMessage = async (message) => {
const room = `conversation-${message.conversationId}`;
io.to(room).emit("new-message", message);
};
const openMessaging = async (bodyshopUUID) => { const openMessaging = async (bodyshopUUID) => {
try { try {
const conversations = await client.request(GET_CONVERSATIONS, { bodyshopId: bodyshopUUID }); const conversations = await client.request(GET_CONVERSATIONS, { bodyshopId: bodyshopUUID });
@@ -282,6 +277,19 @@ const redisSocketEvents = ({
} }
}; };
const leaveConversation = (conversationId) => {
try {
const room = `conversation-${conversationId}`;
socket.leave(room);
// Optionally notify the client
socket.emit("conversation-left", { conversationId });
} catch (error) {
socket.emit("error", { message: "Failed to leave conversation" });
}
};
socket.on("leave-conversation", leaveConversation);
socket.on("send-message", sendMessage); socket.on("send-message", sendMessage);
socket.on("mark-as-read", markAsRead); socket.on("mark-as-read", markAsRead);
socket.on("join-conversation", joinConversation); socket.on("join-conversation", joinConversation);