181 lines
6.0 KiB
JavaScript
181 lines
6.0 KiB
JavaScript
import {
|
|
InfoCircleOutlined,
|
|
MessageOutlined,
|
|
ShrinkOutlined,
|
|
SyncOutlined,
|
|
} from "@ant-design/icons";
|
|
import { useLazyQuery, useSubscription } from "@apollo/client";
|
|
import { Badge, Card, Col, Row, Space, Tag, Tooltip, Typography } from "antd";
|
|
import React, { useCallback, useEffect, useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { connect } from "react-redux";
|
|
import { createStructuredSelector } from "reselect";
|
|
import {
|
|
CONVERSATION_LIST_QUERY,
|
|
CONVERSATION_LIST_SUBSCRIPTION,
|
|
UNREAD_CONVERSATION_COUNT_SUBSCRIPTION,
|
|
} from "../../graphql/conversations.queries";
|
|
import { toggleChatVisible } from "../../redux/messaging/messaging.actions";
|
|
import {
|
|
selectChatVisible,
|
|
selectSelectedConversation,
|
|
} from "../../redux/messaging/messaging.selectors";
|
|
import ChatConversationListComponent from "../chat-conversation-list/chat-conversation-list.component";
|
|
import ChatConversationContainer from "../chat-conversation/chat-conversation.container";
|
|
import ChatNewConversation from "../chat-new-conversation/chat-new-conversation.component";
|
|
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
|
import "./chat-popup.styles.scss";
|
|
|
|
const mapStateToProps = createStructuredSelector({
|
|
selectedConversation: selectSelectedConversation,
|
|
chatVisible: selectChatVisible,
|
|
});
|
|
const mapDispatchToProps = (dispatch) => ({
|
|
toggleChatVisible: () => dispatch(toggleChatVisible()),
|
|
});
|
|
|
|
export function ChatPopupComponent({
|
|
chatVisible,
|
|
selectedConversation,
|
|
toggleChatVisible,
|
|
}) {
|
|
const { t } = useTranslation();
|
|
const [pollInterval, setpollInterval] = useState(0);
|
|
|
|
const { data: unreadData } = useSubscription(
|
|
UNREAD_CONVERSATION_COUNT_SUBSCRIPTION
|
|
);
|
|
|
|
const [
|
|
getConversations,
|
|
{ loading, data, called, refetch, fetchMore, subscribeToMore },
|
|
] = useLazyQuery(CONVERSATION_LIST_QUERY, {
|
|
fetchPolicy: "network-only",
|
|
nextFetchPolicy: "network-only",
|
|
skip: !chatVisible,
|
|
});
|
|
|
|
const fcmToken = sessionStorage.getItem("fcmtoken");
|
|
|
|
useEffect(() => {
|
|
if (fcmToken) {
|
|
setpollInterval(0);
|
|
} else {
|
|
setpollInterval(60000);
|
|
}
|
|
}, [fcmToken]);
|
|
|
|
useEffect(() => {
|
|
if (called && chatVisible)
|
|
getConversations({
|
|
variables: {
|
|
offset: 0,
|
|
},
|
|
});
|
|
}, [chatVisible, called, getConversations]);
|
|
|
|
const loadMoreConversations = useCallback(() => {
|
|
if (data)
|
|
fetchMore({
|
|
variables: {
|
|
offset: data.conversations.length,
|
|
},
|
|
});
|
|
}, [data, fetchMore]);
|
|
|
|
const unreadCount = unreadData?.messages_aggregate.aggregate.count || 0;
|
|
|
|
return (
|
|
<Badge count={unreadCount}>
|
|
<Card size="small">
|
|
{chatVisible ? (
|
|
<div className="chat-popup">
|
|
<Space align="center">
|
|
<Typography.Title level={4}>
|
|
{t("messaging.labels.messaging")}
|
|
</Typography.Title>
|
|
<ChatNewConversation />
|
|
<Tooltip title={t("messaging.labels.recentonly")}>
|
|
<InfoCircleOutlined />
|
|
</Tooltip>
|
|
<SyncOutlined
|
|
style={{ cursor: "pointer" }}
|
|
onClick={() => refetch()}
|
|
/>
|
|
{pollInterval > 0 && (
|
|
<Tag color="yellow">{t("messaging.labels.nopush")}</Tag>
|
|
)}
|
|
</Space>
|
|
<ShrinkOutlined
|
|
onClick={() => toggleChatVisible()}
|
|
style={{ position: "absolute", right: ".5rem", top: ".5rem" }}
|
|
/>
|
|
|
|
<Row gutter={[8, 8]} className="chat-popup-content">
|
|
<Col span={8} sm={8} xs={selectedConversation && 0}>
|
|
{loading ? (
|
|
<LoadingSpinner />
|
|
) : (
|
|
<ChatConversationListComponent
|
|
conversationList={data ? data.conversations : []}
|
|
loadMoreConversations={loadMoreConversations}
|
|
subscribeToMoreConversations={() =>
|
|
subscribeToMore({
|
|
document: CONVERSATION_LIST_SUBSCRIPTION,
|
|
variables: { offset: 0 },
|
|
updateQuery: (prev, { subscriptionData }) => {
|
|
if (
|
|
!subscriptionData.data ||
|
|
subscriptionData.data.conversations.length === 0
|
|
)
|
|
return prev;
|
|
|
|
let conversations = [...prev.conversations];
|
|
const newConversations =
|
|
subscriptionData.data.conversations;
|
|
|
|
for (const conversation of newConversations) {
|
|
const index = conversations.findIndex(
|
|
(prevConversation) =>
|
|
prevConversation.id === conversation.id
|
|
);
|
|
|
|
if (index !== -1) {
|
|
conversations.splice(index, 1);
|
|
conversations.unshift(conversation);
|
|
|
|
continue;
|
|
}
|
|
|
|
conversations.unshift(conversation);
|
|
}
|
|
|
|
return Object.assign({}, prev, {
|
|
conversations: conversations,
|
|
});
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
)}
|
|
</Col>
|
|
<Col span={16}>
|
|
{selectedConversation ? <ChatConversationContainer /> : null}
|
|
</Col>
|
|
</Row>
|
|
</div>
|
|
) : (
|
|
<div
|
|
onClick={() => toggleChatVisible()}
|
|
style={{ cursor: "pointer" }}
|
|
>
|
|
<MessageOutlined />
|
|
<strong>{t("messaging.labels.messaging")}</strong>
|
|
</div>
|
|
)}
|
|
</Card>
|
|
</Badge>
|
|
);
|
|
}
|
|
export default connect(mapStateToProps, mapDispatchToProps)(ChatPopupComponent);
|