From 22cf54f3139ff6e88c01998f5b39434696ff7abe Mon Sep 17 00:00:00 2001 From: Lei OT Date: Tue, 20 Feb 2024 14:57:21 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=A2=E5=8D=95=E8=BF=9B=E5=85=A5=E4=BC=9A?= =?UTF-8?q?=E8=AF=9D,=20=E8=8E=B7=E5=8F=96=E6=96=B0=E4=BC=9A=E8=AF=9D?= =?UTF-8?q?=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions/ConversationActions.js | 105 +----------- src/lib/msgUtils.js | 15 +- src/main.jsx | 5 +- src/records/ConversationState.js | 18 -- src/reducers/ConversationReducer.js | 156 ------------------ src/stores/ConversationContext.js | 12 -- src/stores/ConversationStore.js | 7 +- src/views/Conversations/ChatWindow.jsx | 42 ++++- .../Components/ConversationsList.jsx | 39 ++--- .../Conversations/Components/Messages.jsx | 41 ++--- .../Components/MessagesHeader.jsx | 2 +- .../Conversations/ConversationProvider.jsx | 102 ------------ tailwind.config.js | 5 +- 13 files changed, 103 insertions(+), 446 deletions(-) delete mode 100644 src/records/ConversationState.js delete mode 100644 src/reducers/ConversationReducer.js delete mode 100644 src/stores/ConversationContext.js delete mode 100644 src/views/Conversations/ConversationProvider.jsx diff --git a/src/actions/ConversationActions.js b/src/actions/ConversationActions.js index 79d391b..1be1b28 100644 --- a/src/actions/ConversationActions.js +++ b/src/actions/ConversationActions.js @@ -5,104 +5,6 @@ import { parseRenderMessageList } from '@/lib/msgUtils'; const API_HOST = 'https://p9axztuwd7x8a7.mycht.cn/whatsapp_callback'; -const NAME_SPACE = 'CONVERSATION/'; -export const initWebsocket = (socket) => ({ - type: NAME_SPACE + 'INIT_WEBSOCKET', - payload: socket, -}); -export const closeWebsocket0 = () => ({ - type: NAME_SPACE + 'CLOSE_WEBSOCKET', - payload: null, -}); -export const updateWebsocketState = (v) => ({ - type: NAME_SPACE + 'MODIFY_WEBSOCKET_STATE', - payload: v, -}); -export const updateWebsocketRetrytimes = (v) => ({ - type: NAME_SPACE + 'MODIFY_WEBSOCKET_RETRYTIMES', - payload: v, -}); - -export const receivedNewMessage = (targetId, message) => ({ - type: NAME_SPACE + 'RECEIVED_NEW_MESSAGE', - payload: { - targetId, - message, - }, -}); -export const sentNewMessage = (message) => ({ - type: NAME_SPACE + 'SENT_NEW_MESSAGE', - payload: { - targetId: message.conversationid, - message, - }, -}); - -export const addError = (error) => { - return { - type: NAME_SPACE + 'ADD_ERROR', - payload: error, - }; -}; - -export const receivedTemplates = (data) => ({ - type: NAME_SPACE + 'SET_TEMPLATE_LIST', - payload: data, -}); - -export const receivedConversationList = (data) => { - return { - type: NAME_SPACE + 'SET_CONVERSATION_LIST', - payload: data, - }; -}; -export const addConversationList = (data) => { - return { - type: NAME_SPACE + 'ADD_TO_CONVERSATIONS_LIST', - payload: data, - }; -}; -export const delConversationitem = (data) => { - return { - type: NAME_SPACE + 'DEL_CONVERSATIONS_ITEM', - payload: data, - }; -}; -// export const updateConversationListItemNew = (message) => ({ -// type: NAME_SPACE + 'UPDATE_CONVERSATION_LIST_ITEM_NEW', -// payload: message, -// }); - -export const receivedCustomerProfile = (data) => ({ - type: NAME_SPACE + 'SET_CUSTOMER_ORDER_PROFILE', - payload: data, -}); -/** - * @deprecated 在更新list时操作 - */ -export const setActiveConversations = (obj) => ({ - type: NAME_SPACE + 'SET_ACTIVE_CONVERSATIONS', - payload: obj, -}); -export const setCurrentConversation = (obj) => ({ - type: NAME_SPACE + 'SET_CURRENT_CONVERSATION', - payload: obj, -}); -export const updateMessageItem = (message) => ({ - type: NAME_SPACE + 'UPDATE_SENT_MESSAGE_ITEM', - payload: message, -}); -export const receivedMessageList = (targetId, data) => ({ - type: NAME_SPACE + 'RECEIVED_MESSAGE_LIST', - payload: { targetId, data }, -}) -export const setReplyTo = (data) => { - return { - type: NAME_SPACE + 'SET_REFERENCE_MSG', - payload: data, - }; -}; - export const fetchTemplates = async () => { const data = await fetchJSON(`${API_HOST}/listtemplates`); const canUseTemplates = (data?.result?.items || []) @@ -128,6 +30,13 @@ export const fetchCustomerProfile = async (colisn) => { return data; }; +export const fetchOrderConversationsList = async (params) => { + const { errcode, result: data } = await fetchJSON(`${API_HOST}/getorderconversation`, params); + if (errcode !== 0) return []; + const list = data.map((ele) => ({ ...ele, customer_name: ele.whatsapp_name.trim() })); + return list; +}; + export const fetchConversationItemClose = async (body) => { const getParams = body ? new URLSearchParams(body).toString() : ''; const { result } = await fetchJSON(`${API_HOST}/closeconversation?${getParams}`); diff --git a/src/lib/msgUtils.js b/src/lib/msgUtils.js index 50c8ed6..8e06764 100644 --- a/src/lib/msgUtils.js +++ b/src/lib/msgUtils.js @@ -207,7 +207,7 @@ export const whatsappMsgTypeMapped = { unsupported: { type: 'system', data: (msg) => ({ text: 'Message type is currently not supported.' }) }, reaction: { type: 'text', - data: (msg) => ({ id: msg.wamid, text: msg.reaction?.emoji || msg.reaction?.text?.body || 'Reaction', reply: { message: '{content}', title: 'React from' } }), // todo: + data: (msg) => ({ id: msg.wamid, text: msg.reaction?.emoji || msg.reaction?.text?.body || 'Reaction', reply: { message: '{content}', title: 'React from', titleColor: '#1ba784' } }), // todo: }, document: { type: 'file', @@ -244,6 +244,16 @@ export const parseRenderMessageItem = (msg) => { whatsapp_name: msg?.customerProfile?.name || '', whatsapp_phone_number: msg.from, whatsapp_msg_type: msg.type, + ...(isEmpty(msg.context) + ? {} + : { + reply: { + message: `${msg.context.id}`, // todo: msg.context.text?.body || msg.context.text, + title: msg?.customerProfile?.name || msg.from, + titleColor: "#128c7e", + }, + origin: msg.context, + }), }; }; /** @@ -275,7 +285,8 @@ export const parseRenderMessageList = (messages, conversationid = null) => { : { reply: { message: msg.messageorigin_AsJOSN.text?.body || msg.messageorigin_AsJOSN.text, - title: msg.messageorigin_AsJOSN.senderName || msg.messageorigin_AsJOSN.from + title: msg.messageorigin_AsJOSN.senderName || '@', // msg.messageorigin_AsJOSN.from + titleColor: "#128c7e", }, origin: msg.messageorigin_AsJOSN, }), diff --git a/src/main.jsx b/src/main.jsx index 8f72496..e63a94d 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -3,7 +3,6 @@ import ReactDOM from 'react-dom/client' import { createBrowserRouter, RouterProvider } from 'react-router-dom'; import { AuthContext } from '@/stores/AuthContext' import { ThemeContext } from '@/stores/ThemeContext' -import ConversationProvider from '@/views/Conversations/ConversationProvider' import AuthApp from '@/views/AuthApp' import Standlone from '@/views/Standlone' import OrderFollow from '@/views/OrderFollow' @@ -43,9 +42,7 @@ ReactDOM.createRoot(document.getElementById('root')).render( // - {/* */} -
Loading...
} /> - {/*
*/} +
Loading...
} />
//
diff --git a/src/records/ConversationState.js b/src/records/ConversationState.js deleted file mode 100644 index 0a150bd..0000000 --- a/src/records/ConversationState.js +++ /dev/null @@ -1,18 +0,0 @@ -const initialState = { - websocket: null, - websocketOpened: null, - websocketRetrying: null, - websocketRetrytimes: null, - - errors: [], // 错误信息 - - conversationsList: [], // 对话列表 - templates: [], - customerOrderProfile: {}, - - activeConversations: {}, // 激活的对话的消息列表: { [conversationId]: [] } - currentConversation: {}, // 当前对话 - - referenceMsg: {}, -}; -export default initialState; diff --git a/src/reducers/ConversationReducer.js b/src/reducers/ConversationReducer.js deleted file mode 100644 index 357a0d8..0000000 --- a/src/reducers/ConversationReducer.js +++ /dev/null @@ -1,156 +0,0 @@ -import initialState from '@/records/ConversationState'; - -const NAME_SPACE = 'CONVERSATION/'; - -const ConversationReducer = (state = initialState, action) => { - switch (action.type) { - case NAME_SPACE + 'INIT_WEBSOCKET': - return { ...state, websocket: action.payload }; - case NAME_SPACE + 'MODIFY_WEBSOCKET_STATE': - return { ...state, websocketOpened: action.payload, }; - case NAME_SPACE + 'MODIFY_WEBSOCKET_RETRYTIMES': - return { ...state, websocketRetrytimes: action.payload, websocketRetrying: action.payload > 0 }; - - case NAME_SPACE + 'SET_CONVERSATION_LIST':{ - const conversationsMapped = action.payload.reduce((r, v) => ({ ...r, [`${v.sn}`]: [] }), {}); - return { ...state, conversationsList: action.payload, activeConversations: conversationsMapped }; - } - case NAME_SPACE + 'ADD_TO_CONVERSATIONS_LIST':{ - const { activeConversations } = state; - const conversationsIds = Object.keys(activeConversations); - const newConversations = action.payload.filter((conversation) => !conversationsIds.includes(`${conversation.sn}`)); - const newConversationsMapped = newConversations.reduce((r, v) => ({ ...r, [`${v.sn}`]: [] }), {}); - - return { - ...state, - conversationsList: [...newConversations, ...state.conversationsList], - activeConversations: { ...activeConversations, ...newConversationsMapped }, - }; - } - case NAME_SPACE + 'DEL_CONVERSATIONS_ITEM': { - const { conversationsList, activeConversations, currentConversation, customerOrderProfile } = state; - const targetId = action.payload.sn; - const targetIndex = conversationsList.findIndex((ele) => String(ele.sn) === String(targetId)); - conversationsList.splice(targetIndex, 1); - return { - ...state, - conversationsList: [...conversationsList], - activeConversations: { ...activeConversations, [`${targetId}`]: [] }, - currentConversation: {}, - customerOrderProfile: {}, - }; - } - - case NAME_SPACE + 'SET_TEMPLATE_LIST': - return { ...state, templates: action.payload }; - - case NAME_SPACE + 'SET_CUSTOMER_ORDER_PROFILE': - return { ...state, customerOrderProfile: action.payload }; - - case NAME_SPACE + 'SET_CURRENT_CONVERSATION': { - // 清空未读 - const { conversationsList } = state; - const targetId = action.payload.sn; - const targetIndex = conversationsList.findIndex((ele) => String(ele.sn) === String(targetId)); - targetIndex !== -1 ? conversationsList.splice(targetIndex, 1, { - ...conversationsList[targetIndex], - unread_msg_count: 0, - }) : null; - - return { ...state, currentConversation: action.payload, conversationsList: [...conversationsList] }; - } - case NAME_SPACE + 'SET_ACTIVE_CONVERSATIONS': { - const { activeConversations } = state; - return { ...state, activeConversations: { ...activeConversations, ...action.payload } }; - } - case NAME_SPACE + 'UPDATE_SENT_MESSAGE_ITEM': { - console.log('UPDATE_SENT_MESSAGE_ITEM-----------------------------------------------------------------', action); - // 更新会话中的消息 - const { activeConversations, conversationsList, } = state; - const message = action.payload; - const targetId = message.conversationid; - const targetMsgs = (activeConversations[String(targetId)] || []).map((ele) => { - // 更新状态 - // * 已读的不再更新状态, 有时候投递结果在已读之后返回 - if (ele.id === ele.actionId && ele.actionId === message.actionId) { - return { ...ele, id: message.id, status: ele.status === 'read' ? ele.status : message.status, dateString: message.dateString }; - } else if (ele.id === message.id) { - return { ...ele, id: message.id, status: ele.status === 'read' ? ele.status : message.status, dateString: message.dateString }; - } - return ele; - }); - // 显示会话中其他客户端发送的消息 - const targetMsgsIds = targetMsgs.map((ele) => ele.id); - if ( ! targetMsgsIds.includes(message.id)) { - targetMsgs.push(message); - } - - // 更新列表的时间 - if (message.type !== 'error') { - const targetIndex = conversationsList.findIndex((ele) => String(ele.sn) === String(targetId)); - conversationsList.splice(targetIndex, 1, { - ...conversationsList[targetIndex], - last_received_time: message.date, - }); - } - - return { - ...state, - activeConversations: { ...state.activeConversations, [String(targetId)]: targetMsgs }, - conversationsList: [...conversationsList], - }; - } - case NAME_SPACE + 'RECEIVED_MESSAGE_LIST': { - const { targetId, data } = action.payload; - return { - ...state, - activeConversations: { ...state.activeConversations, [String(targetId)]: data }, - }; - } - case NAME_SPACE + 'SENT_NEW_MESSAGE': - case NAME_SPACE + 'RECEIVED_NEW_MESSAGE': { - const { activeConversations, conversationsList, currentConversation } = state; - const { targetId, message } = action.payload; - const targetMsgs = activeConversations[String(targetId)] || []; - const targetIndex = conversationsList.findIndex((ele) => String(ele.sn) === String(targetId)); - const newConversation = - targetId !== -1 - ? { - ...conversationsList[targetIndex], - last_received_time: message.date, - unread_msg_count: - String(targetId) !== String(currentConversation.sn) && message.sender !== 'me' - ? conversationsList[targetIndex].unread_msg_count + 1 - : conversationsList[targetIndex].unread_msg_count, - } - : { - ...message, - sn: targetId, - last_received_time: message.date, - unread_msg_count: message.sender === 'me' ? 0 : 1, - }; - conversationsList.splice(targetIndex, 1); - conversationsList.unshift(newConversation); - return { - ...state, - activeConversations: { ...activeConversations, [String(targetId)]: [...targetMsgs, message] }, - conversationsList: [...conversationsList], - currentConversation: { - ...state.currentConversation, - last_received_time: String(targetId) === String(currentConversation.sn) ? message.date : currentConversation.last_received_time, - }, - }; - } - case NAME_SPACE + 'SET_REFERENCE_MSG': - return {...state, referenceMsg: action.payload}; - case NAME_SPACE + 'ADD_ERROR': { - console.log('add error', state.errors, action.payload); - const prelist = state.errors || []; - return { ...state, errors: [...prelist, action.payload] }; - } - default: - // throw new Error(`Unknown action: ${action.type}`); - return state; - } -}; -export default ConversationReducer; diff --git a/src/stores/ConversationContext.js b/src/stores/ConversationContext.js deleted file mode 100644 index dca607c..0000000 --- a/src/stores/ConversationContext.js +++ /dev/null @@ -1,12 +0,0 @@ -import {createContext, useContext} from 'react'; - -export const ConversationContext = createContext(); - -export const useConversationContext = () => useContext(ConversationContext); - - -export const ConversationStateContext = createContext(); -export const ConversationDispatchContext = createContext(); - -export const useConversationState = () => useContext(ConversationStateContext); -export const useConversationDispatch = () => useContext(ConversationDispatchContext); diff --git a/src/stores/ConversationStore.js b/src/stores/ConversationStore.js index 27b73a9..22e55d0 100644 --- a/src/stores/ConversationStore.js +++ b/src/stores/ConversationStore.js @@ -122,6 +122,9 @@ export const conversationSlice = (set, get) => ({ conversationsList: [], currentConversation: {}, + /** + * @deprecated + */ setConversationsList: (conversationsList) => { const conversationsMapped = conversationsList.reduce((r, v) => ({ ...r, [`${v.sn}`]: [] }), {}); return set({ conversationsList, activeConversations: conversationsMapped }); @@ -251,10 +254,10 @@ export const useConversationStore = create(devtools((set, get) => ({ // side effects fetchInitialData: async (userId) => { olog('fetch init'); - const { setConversationsList, setTemplates } = get(); + const { addToConversationList, setTemplates } = get(); const conversationsList = await fetchConversationsList({ opisn: userId }); - setConversationsList(conversationsList); + addToConversationList(conversationsList); const templates = await fetchTemplates(); setTemplates(templates); diff --git a/src/views/Conversations/ChatWindow.jsx b/src/views/Conversations/ChatWindow.jsx index 1ac93d3..76dcda7 100644 --- a/src/views/Conversations/ChatWindow.jsx +++ b/src/views/Conversations/ChatWindow.jsx @@ -1,5 +1,6 @@ -import { useEffect } from 'react'; -import { Layout, Spin } from 'antd'; +import { useEffect, useState } from 'react'; +import { Layout, Spin, Button } from 'antd'; +import { RightCircleOutlined, RightOutlined, MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons'; // import { useParams, useNavigate } from 'react-router-dom'; import MessagesHeader from './Components/MessagesHeader'; import Messages from './Components/Messages'; @@ -27,31 +28,56 @@ const ChatWindow = () => { return () => {}; }, []); + const [collapsedLeft, setCollapsedLeft] = useState(false); + const [collapsedRight, setCollapsedRight] = useState(false); return ( - - + + { + console.log('xxxxxxxxxxxxxxxxxxxxxx', broken); + }} + trigger={null}> -
+
+
- +
-