You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Global-sales/src/views/Conversations/Online/ConversationsList.jsx

385 lines
14 KiB
React

import React, { useEffect, useState, useRef, useCallback } from 'react';
import { useParams, useNavigate, useLocation } from 'react-router-dom';
import { App, Input, Button, Empty, Tooltip, List } from 'antd';
import { PlusOutlined, LoadingOutlined, HistoryOutlined, FireOutlined,AudioTwoTone } from '@ant-design/icons';
import { fetchConversationsList, fetchOrderConversationsList, CONVERSATION_PAGE_SIZE } from '@/actions/ConversationActions';
import ConversationsNewItem from './ConversationsNewItem';
import { debounce, flush, isEmpty, isNotEmpty, pick } from '@/utils/commons';
import useConversationStore from '@/stores/ConversationStore';
import useAuthStore from '@/stores/AuthStore';
// import { useOrderStore, OrderLabelDefaultOptions, OrderStatusDefaultOptions } from "@/stores/OrderStore";
import { useVisibilityState } from '@/hooks/useVisibilityState';
import ChatListItem from './Components/ChatListItem';
import ChatListFilter from './Components/ChatListFilter';
import useStyleStore from '@/stores/StyleStore';
import dayjs from 'dayjs';
import { DATETIME_FORMAT } from '@/config';
/**
* []
*/
const Conversations = () => {
const { message } = App.useApp();
const [mobile] = useStyleStore((state) => [state.mobile]);
const routerReplace = mobile === false ? true : false; // : true;
const routePrefix = mobile === false ? `/order/chat` : `/m/chat`;
const { state: orderRow } = useLocation();
const { coli_guest_WhatsApp, guest_email } = orderRow || {};
const { order_sn } = useParams();
const navigate = useNavigate();
const userId = useAuthStore((state) => state.loginUser.userId);
const initialState = useConversationStore((state) => state.initialState);
// const [customerDetail] = useOrderStore((s) => [s.customerDetail])
const [currentConversation, setCurrentConversation, updateCurrentConversation] = useConversationStore((state) => [state.currentConversation, state.setCurrentConversation, state.updateCurrentConversation]);
const [topList, pageList, conversationsList] = useConversationStore((state) => [state.topList, state.pageList, state.conversationsList]);
const [conversationsListLoading, setConversationsListLoading] = useConversationStore((state) => [state.conversationsListLoading, state.setConversationsListLoading]);
const addToConversationList = useConversationStore((state) => state.addToConversationList);
const setConversationsList = useConversationStore((state) => state.setConversationsList);
const isVisible = useVisibilityState();
const [{ search: searchContent, loadNextPage, ...filterState }, setSearchContent, setFilter] = useConversationStore((state) => [state.filter, state.setFilterSearch, state.setFilter])
const [activeList, setActiveList] = useState(true);
const [currentLoading, setCurrentLoading] = useState(false);
const [shouldFetchCList, setShouldFetchCList] = useState(true);
/**
*
*/
let refreshing = false;
async function refreshConversationList(current='', append=false) {
// console.log('invoke -- refreshConversationList', current, conversationsListLoading, refreshing);
if (refreshing !== false) {
return false;
}
refreshing = true;
// setConversationsListLoading(mobile !== undefined ? true : false);
setConversationsListLoading(true);
setCurrentLoading(current==='');
const [otypeC, v] = filterState.otype ? filterState.otype.split('@') : [];
const otypeV = v ? parseInt(v) : '';
const searchParams = {
keyword: searchContent,
tags: filterState.tags.join(','),
olabel: otypeC === 'label' ? otypeV : '',
ostate: otypeC === 'state' ? otypeV : '',
intour: otypeC === 'intour' ? otypeV : '',
istoday: otypeC === 'istoday' ? otypeV : '',
session_enable: activeList ? 1 : 0,
lastpagetime: current ?
dayjs(current).add(1, 'minutes').format('YYYY-MM-DDTHH:mm:ss')
: append
? filterState.lastpagetime
: '',
lastactivetime: filterState.lastactivetime,
}
const _list = await fetchConversationsList({ ...searchParams, opisn: userId });
// const _list = DebounceFetchList({ ...searchParams, opisn: userId });
if (current) {
addToConversationList(_list, 'next');
} else if (append === false) {
7 months ago
// 搜索时, 清空列表
setConversationsList(_list)
} else {
addToConversationList(_list, 'next');
}
const pageTimeArr = flush(_list.map(item => item.lasttime));
const _lasttime = pageTimeArr.pop()
setFilter({
lastpagetime: _lasttime || '',
loadNextPage: !(_list.length === 0 || _list.length < CONVERSATION_PAGE_SIZE),
// ...((_list.length === 0 || _list.length < CONVERSATION_PAGE_SIZE) ? {
// lastactivetime: dayjs(filterState.lastactivetime).subtract(6, 'months').format(DATETIME_FORMAT),
// } : {}),
});
refreshing = false;
setConversationsListLoading(false);
setCurrentLoading(false);
}
useEffect(() => {
// console.log('effect []');
7 months ago
if (mobile !== false) {
setCurrentConversation({});
} else
if (order_sn ) {
setCurrentConversation({ coli_sn: Number(order_sn), sn: null })
// updateCurrentConversation({ coli_sn: Number(order_sn) });
}
return () => {};
}, []);
// useEffect(() => {
// if (order_sn && shouldFetchCList) {
// setCurrentConversation({ coli_sn: Number(order_sn) })
// // updateCurrentConversation({ coli_sn: Number(order_sn) });
// } else {
// // setCurrentConversation({ coli_sn: order_sn })
// }
// return () => {}
// }, [order_sn])
useEffect(() => {
// console.log('effect isVisible', isVisible);
if (isVisible && initialState) {
refreshConversationList(new Date()); // 无感刷新, 不显示上面的loading,
}
return () => {};
}, [isVisible]);
useEffect(() => {
// console.log('effect activeList');
if (isVisible && initialState) {
refreshConversationList(); // 显示loading
}
return () => {};
}, [activeList]);
const [dataSource, setDataSource] = useState(conversationsList);
const [listUpdateFlag, setListUpdateFlag] = useState();
const [switchToC, setSwitchToC] = useState({});
useEffect(() => {
setDataSource([...topList, ...pageList]);
// setDataSource(activeList ? conversationsList: closedConversationsList);
return () => {};
}, [conversationsList, topList, pageList, listUpdateFlag, currentConversation.unread_msg_count]);
let orderChatRefreshing = false;
useEffect(() => {
// console.log('first', isEmpty(currentConversation.sn) , order_sn , shouldFetchCList , initialState)
// isEmpty(currentConversation.sn) &&
if (order_sn && shouldFetchCList && initialState) {
getOrderConversationList(order_sn)
}
return () => {}
}, [order_sn, shouldFetchCList, initialState])
const getOrderConversationList = async (colisn) => {
if (orderChatRefreshing !== false) {
return false;
}
orderChatRefreshing = true;
const { whatsapp_phone_number } = switchToC;
const whatsappID = coli_guest_WhatsApp || whatsapp_phone_number || '';
const _email = guest_email || '';
// if (isEmpty(conversationsList)) {
// return false;
// }
let findCurrentOrderChats;
let findCurrentIndex;
let findCurrent;
// let findCurrentOrderChats = conversationsList.filter((item) => `${item.coli_sn}` === `${colisn}`);
// 使用opisn + whatsappID 判断, 解决订单修改whatsappID号码之后获取新会话, 登录账号此处省略
if (!isEmpty(whatsappID) || !isEmpty(_email)) {
findCurrentOrderChats = conversationsList.filter(
(item) => `${item.coli_sn}` === `${colisn}` && (`${item.whatsapp_phone_number}` === `${whatsappID}` || `${item.channels?.email}` === `${_email}`)
)
findCurrentIndex = isEmpty(findCurrentOrderChats) ? -1 : 0; // findCurrentOrderChats.length-1;
findCurrent = findCurrentOrderChats[findCurrentIndex];
if (findCurrentIndex !== -1) {
addToConversationList(findCurrentOrderChats, 'top');
} else // if (!isEmpty(whatsappID))
{
try {
setShouldFetchCList(false);
const data = await fetchOrderConversationsList({ opisn: userId, colisn: colisn, whatsappid: whatsappID, email: _email });
if (!isEmpty(data)) {
addToConversationList(data);
findCurrentIndex = 0; // data.length-1; // data.lastIndexOf((item) => item.coli_sn === Number(colisn));
findCurrent = data[findCurrentIndex];
} else {
// findCurrentIndex = conversationsList.findIndex((item) => item.coli_sn === Number(colisn)); // data.findIndex((item) => item.sn === currentConversation.sn);
}
} catch (error) {
// message.warning('获取订单会话失败')
}
}
}
else {
// if (isEmpty(whatsappID) && findCurrentIndex === undefined) {
// 刷新页面
findCurrentIndex = conversationsList.findIndex((item) => `${item.coli_sn}` === `${colisn}`);
findCurrent = conversationsList[findCurrentIndex];
}
orderChatRefreshing = false;
if (findCurrentIndex >= 0) {
setCurrentConversation(findCurrent);
return findCurrent;
} else {
// reset chat window
// setCurrentConversation({ sn: '', customer_name: '', coli_sn: order_sn });
return false;
}
};
const onSwitchConversation = async (item) => {
setCurrentConversation(item);
setShouldFetchCList(false);
if (isEmpty(item.coli_sn)) {
navigate(routePrefix, { replace: true });
} else {
setSwitchToC(item);
setShouldFetchCList(false);
navigate(`${routePrefix}/${item.coli_sn}`, { replace: routerReplace });
}
// if (!isEmpty(item.coli_sn)) {
// setSwitchToC(item);
// setShouldFetchCList(false);
// navigate(`/order/chat/${item.coli_sn}`, { replace: true });
// } else {
// navigate(`/order/chat`, { replace: true });
// }
// switchConversation(item);
};
const searchInputRef = useRef(null);
const [newChatModalVisible, setNewChatModalVisible] = useState(false);
const [editingChat, setEditingChat] = useState({});
// const closedVisible = closedConversationsList.length > 0;
const toggleClosedConversationsList = () => {
setActiveList(!activeList);
setCurrentConversation({});
};
const [searchInput, setSearchInput] = useState(searchContent);
return (
<div className='flex flex-col h-inherit'>
<div className='flex gap-1 items-center'>
<Button
onClick={() => {
setNewChatModalVisible(true)
setEditingChat({})
}}
icon={<PlusOutlined />}
type={'primary'}
ghost
shape={'circle'}
size='small'
/>
<Input.Search
className=''
ref={searchInputRef}
allowClear
value={searchInput}
onChange={(e) => {
setSearchInput(e.target.value)
// setTabCnt(-1)
// setTabSelectedConversation({})
}}
// onKeyDown={(e) => {
// if (e.key === 'Tab') {
// e.preventDefault()
// const _this = tabCnt >= dataSource.length - 1 ? 0 : tabCnt + 1
// setTabCnt(_this)
// setTabSelectedConversation(dataSource[_this])
// }
// }}
onPressEnter={(e) => {
// searchInputRef.current.blur()
setSearchContent(e.target.value)
// onSwitchConversation(dataSource[tabCnt < 0 ? 0 : tabCnt])
// setTabCnt(-1)
// setTabSelectedConversation({})
return false
}}
onSearch={(v, e, { source }) => setSearchContent(v)}
placeholder={`名称/号码/订单号${conversationsListLoading ? '...' : ''}`}
// addonBefore={filterTag}
// addonBefore={<FilterOutlined />}
// enterButton={'Filter'}
/>
7 months ago
{/* TODO 这个在完成搜索历史会话后去掉,待讨论查询规则 */}
{conversationsListLoading ? (
<div className='text-center py-1 px-2'>
<LoadingOutlined className='text-orange-400 ' />
</div>
) :
<Tooltip key={'conversation-list'} title={activeList ? '🗂已处理' : '活跃会话'}>
<Button onClick={toggleClosedConversationsList} icon={activeList ? '🗂' : '📌'} type='text' />
</Tooltip>
}
{mobile && (
<AudioTwoTone className='px-2'
onClick={() => {
navigate(`/callcenter/call`)
}}
/>
)}
</div>
<ChatListFilter key='chat-list-filter'
onFilterChange={(d) => {
refreshConversationList()
}}
activeList={activeList}
/>
<div className='flex-1 overflow-x-hidden overflow-y-auto relative'>
{/* {mobile && conversationsListLoading && dataSource.length === 0 ? ( */}
<List
itemLayout='vertical'
dataSource={dataSource}
loadMore={
<div className='text-center pt-3 mb-3 h-8 leading-8 '>
{!conversationsListLoading && loadNextPage ? (
<Button onClick={() => refreshConversationList(false, true)} size='small'>load more</Button>
) : null}
{conversationsListLoading && <LoadingOutlined className='text-primary ' />}
</div>
}
renderItem={(item, index) => (
<ChatListItem
key={item.sn}
{...{
item,
refreshConversationList,
setListUpdateFlag,
onSwitchConversation,
setNewChatModalVisible,
setEditingChat,
conversationsListLoading,
}}
/>
)}
/>
</div>
<ConversationsNewItem
initialValues={{ ...editingChat, is_current_order: false }}
open={newChatModalVisible}
onCreate={() => setNewChatModalVisible(false)}
onCancel={() => setNewChatModalVisible(false)}
/>
</div>
)
};
export default Conversations;