rename
parent
3f56f5034d
commit
63965ffd69
@ -1,67 +0,0 @@
|
||||
// websocketLib.js
|
||||
import { WebSocketSubject } from 'rxjs/webSocket';
|
||||
import { retryWhen, delay, take, catchError } from 'rxjs/operators';
|
||||
|
||||
class WebSocketLib {
|
||||
constructor(url, authToken, protocol) {
|
||||
this.url = url;
|
||||
this.authToken = authToken;
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
connect() {
|
||||
this.socket$ = new WebSocketSubject({
|
||||
url: this.url,
|
||||
protocol: this.protocol, // Use protocol for message type
|
||||
openObserver: {
|
||||
next: () => {
|
||||
console.log('Connection established');
|
||||
// Send authentication message as soon as connection is established
|
||||
this.socket$.next({ event: 'authenticate', token: this.authToken });
|
||||
},
|
||||
},
|
||||
closeObserver: {
|
||||
next: () => {
|
||||
console.log('Connection closed');
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
this.socket$
|
||||
.pipe(
|
||||
retryWhen(errors =>
|
||||
errors.pipe(
|
||||
delay(1000), // Retry connection every 1 second
|
||||
take(10), // Maximum of 10 retries
|
||||
catchError(error => new Error(`Failed to reconnect: ${error}`)) // Throw error after 10 failed retries
|
||||
)
|
||||
)
|
||||
)
|
||||
.subscribe(
|
||||
msg => console.log('Received message:', msg),
|
||||
err => console.error('Received error:', err),
|
||||
() => console.log('Connection closed')
|
||||
);
|
||||
}
|
||||
|
||||
sendMessage(message) {
|
||||
if (!this.socket$) {
|
||||
console.error('Must connect to WebSocket server before sending a message');
|
||||
return;
|
||||
}
|
||||
|
||||
this.socket$.next({ type: 'message', content: message });
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
if (!this.socket$) {
|
||||
console.error('Must connect to WebSocket server before disconnecting');
|
||||
return;
|
||||
}
|
||||
|
||||
this.socket$.complete();
|
||||
this.socket$ = null;
|
||||
}
|
||||
}
|
||||
|
||||
export default WebSocketLib;
|
@ -1,334 +0,0 @@
|
||||
import { createContext, useContext, useState, useEffect, useRef } from 'react';
|
||||
import { receivedMsgTypeMapped, sentMsgTypeMapped } from '@/lib/msgUtils';
|
||||
import { groupBy, isEmpty, pick } from '@/utils/utils';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
export const ConversationContext = createContext();
|
||||
export const useConversationContext = () => useContext(ConversationContext);
|
||||
export async function fetchJSON(url, data) {
|
||||
let params = '';
|
||||
let ifp = '';
|
||||
if (data) {
|
||||
params = new URLSearchParams(data).toString();
|
||||
ifp = params ? '?' : ifp;
|
||||
}
|
||||
ifp = url.includes('?') ? '' : ifp;
|
||||
const host = /^https?:\/\//i.test(url) ? '' : ''; // HT_HOST;
|
||||
const response = await fetch(`${host}${url}${ifp}${params}`);
|
||||
return await response.json();
|
||||
}
|
||||
export async function postJSON(url, obj) {
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(obj),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('fetch error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
// const API_HOST = 'http://202.103.68.144:8888';
|
||||
const API_HOST = 'https://p9axztuwd7x8a7.mycht.cn/whatsapp_server';
|
||||
|
||||
export const useConversations = ({loginUser, realtimeAPI}) => {
|
||||
const { userId } = loginUser;
|
||||
|
||||
const [errors, setErrors] = useState([]);
|
||||
const [messages, setMessages] = useState([]); // active conversation
|
||||
const [activeConversations, setActiveConversations] = useState({}); // all active conversation
|
||||
const [currentID, setCurrentID] = useState();
|
||||
const [conversationsList, setConversationsList] = useState([]); // open conversations
|
||||
const [currentConversation, setCurrentConversation] = useState({ sn: '', customer_name: '', coli_sn: '' });
|
||||
const currentConversationRef = useRef(currentConversation);
|
||||
useEffect(() => {
|
||||
currentConversationRef.current = currentConversation;
|
||||
}, [currentConversation]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log(errors, 'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee');
|
||||
|
||||
return () => {};
|
||||
}, [errors])
|
||||
|
||||
useEffect(() => {
|
||||
realtimeAPI.onError(addError.bind(null, 'Error'));
|
||||
realtimeAPI.onMessage(handleMessage);
|
||||
realtimeAPI.onCompletion(addError.bind(null, 'Not Connected to Server'));
|
||||
realtimeAPI.keepAlive(); // Ping Server
|
||||
|
||||
// Cleanup function to remove the event listeners when the component is unmounted
|
||||
return () => {
|
||||
realtimeAPI.disconnect();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
getConversationsList(); // todo: 和刷新订单会话页面有冲突
|
||||
getTemplates();
|
||||
return () => {};
|
||||
}, []);
|
||||
|
||||
// useEffect(() => {
|
||||
// if (!currentConversation.id && conversationsList.length > 0) {
|
||||
// switchConversation(conversationsList[0]);
|
||||
// }
|
||||
// return () => {};
|
||||
// }, [conversationsList]);
|
||||
|
||||
const poseConversationItemClose = async (item) => {
|
||||
const res = await postJSON(`${API_HOST}/closeconversation`, { opisn: userId, conversationid: item.sn });
|
||||
}
|
||||
|
||||
const getConversationsList = async () => {
|
||||
const { result: data } = await fetchJSON(`${API_HOST}/getconversations`, { opisn: userId });
|
||||
// const _data = [];
|
||||
const _data = testConversations;
|
||||
const list = [..._data, ...data.map(ele => ({...ele, customer_name: ele.whatsapp_name.trim()}))];
|
||||
const dataMapped = list.reduce((r, v) => ({ ...r, [`${v.sn}`]: [] }), {});
|
||||
setConversationsList(list);
|
||||
setActiveConversations({...dataMapped, ...activeConversations});
|
||||
console.log(list, dataMapped);
|
||||
if (list && list.length) {
|
||||
switchConversation(list[0]);
|
||||
}
|
||||
};
|
||||
|
||||
const [templatesList, setTemplatesList] = useState([]);
|
||||
const getTemplates = async () => {
|
||||
const data = await fetchJSON(`${API_HOST}/listtemplates`);
|
||||
const canUseTemplates = (data?.result?.items || []).filter((_t) => _t.status !== 'REJECTED').map((ele) => ({ ...ele, components: groupBy(ele.components, (_c) => _c.type.toLowerCase()) }));
|
||||
setTemplatesList(canUseTemplates);
|
||||
};
|
||||
|
||||
const [customerOrderProfile, setCustomerProfile] = useState({});
|
||||
const getCustomerProfile = async (colisn) => {
|
||||
const { result } = await fetchJSON(`${API_HOST}/getorderinfo`, { colisn });
|
||||
const data = result?.[0] || {};
|
||||
setCustomerProfile(data);
|
||||
|
||||
if (!isEmpty(data.conversation)) {
|
||||
setConversationsList((pre) => [...data.conversations, ...pre]);
|
||||
setCurrentConversation(data.conversation[0]);
|
||||
const thisCMapped = data.conversation.reduce((r, v) => ({ ...r, [`${v.sn}`]: [] }), {});
|
||||
setActiveConversations((pre) => ({ ...pre, ...thisCMapped }));
|
||||
setMessages([]); // todo: 获取当前会话的历史消息
|
||||
} else {
|
||||
// reset chat window
|
||||
setMessages([]);
|
||||
if (isEmpty(data.contact?.[0]?.whatsapp_phone_number)) {
|
||||
setCurrentConversation({ sn: '', customer_name: '', coli_sn: '' });
|
||||
return false;
|
||||
}
|
||||
// 加入新会话
|
||||
const newChat = {
|
||||
'sn': uuid(),
|
||||
// 'opi_sn': 354,
|
||||
'coli_sn': colisn,
|
||||
'whatsapp_phone_number': data.contact[0].whatsapp_phone_number,
|
||||
"last_received_time": '',
|
||||
"last_send_time": '',
|
||||
'unread_msg_count': 0,
|
||||
'whatsapp_name': data.contact[0].name,
|
||||
'customer_name': data.contact[0].name,
|
||||
};
|
||||
setConversationsList((pre) => [...pre, newChat]);
|
||||
setActiveConversations((pre) => ({ ...pre, [`${newChat.sn}`]: [] }));
|
||||
setCurrentConversation(pick(newChat, ['sn', 'coli_sn', 'whatsapp_phone_number', 'whatsapp_name', 'customer_name']));
|
||||
}
|
||||
};
|
||||
|
||||
const switchConversation = (cc) => {
|
||||
setCurrentID(`${cc.sn}`);
|
||||
setCurrentConversation({...cc, id: cc.sn, customer_name: cc.whatsapp_name.trim()});
|
||||
|
||||
if (isEmpty(cc.coli_sn) || cc.coli_sn === '0') {
|
||||
setCustomerProfile({});
|
||||
}
|
||||
};
|
||||
|
||||
// Get customer profile when switching conversation
|
||||
useEffect(() => {
|
||||
console.log('currentConversation', currentConversation);
|
||||
setCurrentID(currentConversation.sn);
|
||||
setMessages([...(activeConversations[currentConversation.sn] || [])]);
|
||||
return () => {};
|
||||
}, [currentConversation]);
|
||||
|
||||
/**
|
||||
* *****************************************************************************************************
|
||||
* websocket --------------------------------------------------------------------------------------------
|
||||
* *****************************************************************************************************
|
||||
*/
|
||||
const addError = (reason) => {
|
||||
setErrors((prevErrors) => [...prevErrors, { reason }]);
|
||||
};
|
||||
|
||||
const addMessageToConversations = (targetId, message) => {
|
||||
setActiveConversations((prevList) => ({
|
||||
...prevList,
|
||||
[targetId]: [...(prevList[targetId] || []), message],
|
||||
}));
|
||||
// console.log('activeConversations', activeConversations);
|
||||
if (targetId !== currentID) {
|
||||
setConversationsList((prevList) => {
|
||||
return prevList.map((ele) => {
|
||||
if (ele.sn === targetId) {
|
||||
return { ...ele, new_msgs: ele.new_msgs + 1, last_received_time: message.date };
|
||||
}
|
||||
return ele;
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
console.log(messages, 'messages');
|
||||
|
||||
return () => {
|
||||
|
||||
}
|
||||
}, [messages])
|
||||
|
||||
|
||||
const addMessage = (message) => {
|
||||
addMessageToConversations(message.conversationid, message);
|
||||
if (message.conversationid === currentID) {
|
||||
setMessages((prevMessages) => [...prevMessages, message]);
|
||||
}
|
||||
};
|
||||
|
||||
const updateMessage = (message) => {
|
||||
let targetMsgs;
|
||||
setMessages((prevMessages) => {
|
||||
targetMsgs = prevMessages.map(ele => {
|
||||
if (ele.id === ele.actionId && ele.actionId === message.actionId) {
|
||||
return {...ele, id: message.id, status: message.status, dateString: message.dateString};
|
||||
}
|
||||
else if (ele.id === message.id) {
|
||||
return {...ele, id: message.id, status: message.status, dateString: message.dateString};
|
||||
}
|
||||
return ele;
|
||||
});
|
||||
return targetMsgs;
|
||||
});
|
||||
// 更新会话中的消息
|
||||
const targetId = message.conversationid; // currentConversationRef.current.sn;
|
||||
setActiveConversations((prevList) => ({
|
||||
...prevList,
|
||||
[targetId]: targetMsgs,
|
||||
}));
|
||||
// 更新列表的时间
|
||||
setConversationsList((prevList) => {
|
||||
return prevList.map((ele) => {
|
||||
if (ele.sn === targetId) {
|
||||
return { ...ele, new_msgs: ele.new_msgs + 1, last_received_time: message.date };
|
||||
}
|
||||
return ele;
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
const handleMessage = (data) => {
|
||||
console.log('handleMessage------------------', );
|
||||
/**
|
||||
* ! event handlers in JavaScript capture the environment (including variables) at the time they are defined, not when they are executed.
|
||||
*/
|
||||
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)) {
|
||||
updateMessage(msgUpdate);
|
||||
// return false;
|
||||
}
|
||||
if ( ! isEmpty(msgRender)) {
|
||||
addMessage(msgRender);
|
||||
}
|
||||
console.log('handleMessage*******************', );
|
||||
};
|
||||
|
||||
const sendMessage = (msgObj) => {
|
||||
const contentToSend = sentMsgTypeMapped[msgObj.type].contentToSend(msgObj);
|
||||
realtimeAPI.sendMessage({ ...contentToSend, opi_sn: userId });
|
||||
const contentToRender = sentMsgTypeMapped[msgObj.type].contentToRender(msgObj);
|
||||
console.log(contentToRender, 'contentToRender sendMessage------------------');
|
||||
addMessage(contentToRender);
|
||||
};
|
||||
|
||||
return {
|
||||
errors,
|
||||
messages,
|
||||
conversationsList,
|
||||
currentConversation,
|
||||
sendMessage,
|
||||
getConversationsList,
|
||||
switchConversation,
|
||||
templates: templatesList, // setTemplates, getTemplates,
|
||||
customerOrderProfile, getCustomerProfile,
|
||||
poseConversationItemClose
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// test:
|
||||
const testConversations = [
|
||||
{
|
||||
'sn': 3001,
|
||||
'opi_sn': 354,
|
||||
'coli_sn': 0,
|
||||
'whatsapp_phone_number': '+8618777396951',
|
||||
"last_received_time": new Date().toDateString(),
|
||||
"last_send_time": new Date().toDateString(),
|
||||
'unread_msg_count': Math.floor(Math.random() * (100 - 2 + 1) + 2),
|
||||
'whatsapp_name': 'LiaoYijun',
|
||||
'customer_name': 'LiaoYijun',
|
||||
},
|
||||
{
|
||||
'sn': 3002,
|
||||
'opi_sn': 354,
|
||||
'coli_sn': 0,
|
||||
'whatsapp_phone_number': '+8613317835586',
|
||||
"last_received_time": new Date().toDateString(),
|
||||
"last_send_time": new Date().toDateString(),
|
||||
'unread_msg_count': Math.floor(Math.random() * (100 - 2 + 1) + 2),
|
||||
'whatsapp_name': 'QinQianSheng',
|
||||
'customer_name': 'QinQianSheng',
|
||||
},
|
||||
// {
|
||||
// 'sn': 3003,
|
||||
// 'opi_sn': 354,
|
||||
// 'coli_sn': 240129003,
|
||||
// 'whatsapp_phone_number': '+8618777396951',
|
||||
// "last_received_time": new Date().toDateString(),
|
||||
// "last_send_time": new Date().toDateString(),
|
||||
// 'unread_msg_count': Math.floor(Math.random() * (100 - 2 + 1) + 2),
|
||||
// 'whatsapp_name': 'LeiYuanTing',
|
||||
// },
|
||||
];
|
Loading…
Reference in New Issue