import { useApolloClient, useQuery } from "@apollo/client"; import axios from "axios"; import React, { useCallback, useContext, useEffect, useState } from "react"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import SocketContext from "../../contexts/SocketIO/socketContext"; import { GET_CONVERSATION_DETAILS } from "../../graphql/conversations.queries"; import { selectSelectedConversation } from "../../redux/messaging/messaging.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors"; import ChatConversationComponent from "./chat-conversation.component"; const mapStateToProps = createStructuredSelector({ selectedConversation: selectSelectedConversation, bodyshop: selectBodyshop }); export function ChatConversationContainer({ bodyshop, selectedConversation }) { const client = useApolloClient(); const { socket } = useContext(SocketContext); const [markingAsReadInProgress, setMarkingAsReadInProgress] = useState(false); const { loading: convoLoading, error: convoError, data: convoData } = useQuery(GET_CONVERSATION_DETAILS, { variables: { conversationId: selectedConversation }, fetchPolicy: "network-only", nextFetchPolicy: "network-only" }); const updateCacheWithReadMessages = useCallback( (conversationId, messageIds) => { if (!conversationId || !messageIds || messageIds.length === 0) return; // Mark individual messages as read messageIds.forEach((messageId) => { client.cache.modify({ id: client.cache.identify({ __typename: "messages", id: messageId }), fields: { read() { return true; // Mark message as read } } }); }); // Update aggregate unread count for the conversation client.cache.modify({ id: client.cache.identify({ __typename: "conversations", id: conversationId }), fields: { messages_aggregate(existingAggregate) { return { ...existingAggregate, aggregate: { ...existingAggregate.aggregate, count: 0 // No unread messages remaining } }; } } }); }, [client.cache] ); // Handle WebSocket events useEffect(() => { if (!socket || !socket.connected) return; const handleConversationChange = (data) => { if (data.type === "conversation-marked-read") { const { conversationId, messageIds } = data; console.log("Conversation change received:", data); updateCacheWithReadMessages(conversationId, messageIds); } }; socket.on("conversation-changed", handleConversationChange); return () => { socket.off("conversation-changed", handleConversationChange); }; }, [socket, client, updateCacheWithReadMessages]); // Handle joining/leaving conversation useEffect(() => { if (!socket || !socket.connected) return; socket.emit("join-bodyshop-conversation", { bodyshopId: bodyshop.id, conversationId: selectedConversation }); return () => { socket.emit("leave-bodyshop-conversation", { bodyshopId: bodyshop.id, conversationId: selectedConversation }); }; }, [selectedConversation, bodyshop, socket]); // Handle marking conversation as read const handleMarkConversationAsRead = async () => { if (!convoData || !selectedConversation || markingAsReadInProgress) return; const conversation = convoData.conversations_by_pk; if (!conversation) { console.warn(`No data found for conversation ID: ${selectedConversation}`); return; } const unreadMessageIds = conversation.messages ?.filter((message) => !message.read && !message.isoutbound) .map((message) => message.id); if (unreadMessageIds?.length > 0) { setMarkingAsReadInProgress(true); try { const payload = { conversation, imexshopid: bodyshop?.imexshopid, bodyshopid: bodyshop?.id }; console.log("Marking conversation as read:", payload); await axios.post("/sms/markConversationRead", payload); // Update local cache updateCacheWithReadMessages(selectedConversation, unreadMessageIds); } catch (error) { console.error("Error marking conversation as read:", error.response?.data || error.message); } finally { setMarkingAsReadInProgress(false); } } }; return ( ); } export default connect(mapStateToProps, null)(ChatConversationContainer);