删除 useReducer 的 ConversationContext, Action, Reducer, Provider

dev/chat
Lei OT 2 years ago
parent c6ed93acd1
commit be24c964e0

@ -5,104 +5,6 @@ import { parseRenderMessageList } from '@/lib/msgUtils';
const API_HOST = 'https://p9axztuwd7x8a7.mycht.cn/whatsapp_callback'; 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 () => { export const fetchTemplates = async () => {
const data = await fetchJSON(`${API_HOST}/listtemplates`); const data = await fetchJSON(`${API_HOST}/listtemplates`);
const canUseTemplates = (data?.result?.items || []) const canUseTemplates = (data?.result?.items || [])

@ -3,7 +3,6 @@ import ReactDOM from 'react-dom/client'
import { createBrowserRouter, RouterProvider } from 'react-router-dom'; import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import { AuthContext } from '@/stores/AuthContext' import { AuthContext } from '@/stores/AuthContext'
import { ThemeContext } from '@/stores/ThemeContext' import { ThemeContext } from '@/stores/ThemeContext'
import ConversationProvider from '@/views/Conversations/ConversationProvider'
import AuthApp from '@/views/AuthApp' import AuthApp from '@/views/AuthApp'
import Standlone from '@/views/Standlone' import Standlone from '@/views/Standlone'
import OrderFollow from '@/views/OrderFollow' import OrderFollow from '@/views/OrderFollow'
@ -43,9 +42,7 @@ ReactDOM.createRoot(document.getElementById('root')).render(
// <React.StrictMode> // <React.StrictMode>
<ThemeContext.Provider value={{ colorPrimary: '#1ba784', borderRadius: 4 }}> <ThemeContext.Provider value={{ colorPrimary: '#1ba784', borderRadius: 4 }}>
<AuthContext.Provider value={{ loginUser: { userId: 354, username: '廖一军', accountList: [{OPI_Code:'LYJ'}, {OPI_Code:'LYJAH'}, {OPI_Code:'LYJGH'}] } }}> <AuthContext.Provider value={{ loginUser: { userId: 354, username: '廖一军', accountList: [{OPI_Code:'LYJ'}, {OPI_Code:'LYJAH'}, {OPI_Code:'LYJGH'}] } }}>
{/* <ConversationProvider> */}
<RouterProvider router={router} fallbackElement={() => <div>Loading...</div>} /> <RouterProvider router={router} fallbackElement={() => <div>Loading...</div>} />
{/* </ConversationProvider> */}
</AuthContext.Provider> </AuthContext.Provider>
</ThemeContext.Provider> </ThemeContext.Provider>
// </React.StrictMode> // </React.StrictMode>

@ -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;

@ -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;

@ -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);

@ -1,102 +0,0 @@
import { useContext, useReducer, useEffect } from 'react';
import { ConversationStateContext, ConversationDispatchContext } from '@/stores/ConversationContext';
import ConversationReducer from '@/reducers/ConversationReducer';
import {
initWebsocket,
updateWebsocketState,
updateWebsocketRetrytimes,
addError,
fetchConversationsList,
fetchTemplates,
receivedConversationList,
receivedTemplates,
updateMessageItem,
receivedNewMessage,
} from '@/actions/ConversationActions';
import initialState from '@/records/ConversationState';
import { AuthContext } from '@/stores/AuthContext';
import { RealTimeAPI } from '@/lib/realTimeAPI';
import { receivedMsgTypeMapped } from '@/lib/msgUtils';
import { isEmpty } from '@/utils/utils';
// const WS_URL = 'ws://202.103.68.144:8888/whatever/';
// const WS_URL = 'ws://120.79.9.217:10022/whatever/';
const WS_URL = 'wss://p9axztuwd7x8a7.mycht.cn/whatsapp_callback'; // prod:
const ConversationProvider = ({ children }) => {
const { loginUser } = useContext(AuthContext);
const { userId } = loginUser;
const [state, dispatch] = useReducer(ConversationReducer, { ...initialState, websocket: null });
console.log('ConversationProvider', state, dispatch);
// useEffect(() => {
// console.log('invoke provider');
// const realtimeAPI = new RealTimeAPI(
// {
// url: `${WS_URL}?opisn=${userId || ''}&_spam=${Date.now().toString()}`,
// protocol: 'WhatsApp',
// },
// () => {dispatch(updateWebsocketState(true)); dispatch(updateWebsocketRetrytimes(0));},
// () => dispatch(updateWebsocketState(false)),
// (n) => dispatch(updateWebsocketRetrytimes(n))
// );
// realtimeAPI.onError(() => dispatch(addError('Error')));
// realtimeAPI.onMessage(handleMessage);
// realtimeAPI.onCompletion(() => dispatch(addError('Connection broken')));
// dispatch(initWebsocket(realtimeAPI));
// return () => {
// realtimeAPI.disconnect();
// };
// }, []);
// useEffect(() => {
// fetchConversationsList({ opisn: userId }).then((data) => {
// dispatch(receivedConversationList(data));
// });
// fetchTemplates().then((data) => dispatch(receivedTemplates(data)));
// return () => {};
// }, []);
const handleMessage = (data) => {
console.log('handleMessage------------------');
console.log(data);
const { errcode, errmsg, result } = data;
if (!result) {
return false;
}
let resultType = result?.action || result.type;
if (errcode !== 0) {
// addError('Error Connecting to Server');
resultType = 'error';
}
console.log(resultType, 'result.type');
const msgObj = receivedMsgTypeMapped[resultType].getMsg(result);
const msgRender = receivedMsgTypeMapped[resultType].contentToRender(msgObj);
const msgUpdate = receivedMsgTypeMapped[resultType].contentToUpdate(msgObj);
console.log('msgRender msgUpdate', msgRender, msgUpdate);
if (['whatsapp.message.updated', 'message', 'error'].includes(resultType)) {
dispatch(updateMessageItem(msgUpdate));
// return false;
}
if (!isEmpty(msgRender)) {
dispatch(receivedNewMessage(msgRender.conversationid, msgRender));
}
console.log('handleMessage*******************');
};
// return <ConversationContext.Provider value={{ ...state, dispatch }}>{children}</ConversationContext.Provider>;
return (
<ConversationStateContext.Provider value={{ ...state }}>
<ConversationDispatchContext.Provider value={dispatch}>{children}</ConversationDispatchContext.Provider>
</ConversationStateContext.Provider>
);
};
export default ConversationProvider;
Loading…
Cancel
Save