152 lines
4.8 KiB
JavaScript
152 lines
4.8 KiB
JavaScript
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 (
|
|
<ChatConversationComponent
|
|
subState={[convoLoading, convoError]}
|
|
conversation={convoData ? convoData.conversations_by_pk : {}}
|
|
messages={convoData ? convoData.conversations_by_pk.messages : []}
|
|
handleMarkConversationAsRead={handleMarkConversationAsRead}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export default connect(mapStateToProps, null)(ChatConversationContainer);
|