WhatsApp模板参数填充; 增加显示消息类型: 文件; 发送消息的同步回调处理; 自动重连(10次);

dev/chat
Lei OT 1 year ago
parent 9cd3e1d38e
commit 23fd7dc22f

@ -35,7 +35,7 @@ export const sentMsgTypeMapped = {
const templateDataMapped = msg.template?.components ? msg.template.components.reduce((r, v) => ({...r, [v.type]: v}), {}) : null; const templateDataMapped = msg.template?.components ? msg.template.components.reduce((r, v) => ({...r, [v.type]: v}), {}) : null;
const templateParam = (templateDataMapped?.body?.parameters || []).map(e => e.text); const templateParam = (templateDataMapped?.body?.parameters || []).map(e => e.text);
const fillTemplate = templateParam.length ? replaceTemplateString(msg.template_origin.components.body?.[0]?.text || '', templateParam) : (msg.template_origin.components.body?.[0]?.text || ''); const fillTemplate = templateParam.length ? replaceTemplateString(msg.template_origin.components.body?.[0]?.text || '', templateParam) : (msg.template_origin.components.body?.[0]?.text || '');
const footer = msg.template_origin.components?.footer?.[0]?.text || ''; // const footer = msg.template_origin.components?.footer?.[0]?.text || '';
return { return {
...msg, ...msg,
type: 'text', type: 'text',
@ -56,6 +56,7 @@ const whatsappMsgMapped = {
const contentObj = result?.whatsappInboundMessage || result; // debug: const contentObj = result?.whatsappInboundMessage || result; // debug:
return parseRenderMessageItem(contentObj); return parseRenderMessageItem(contentObj);
}, },
contentToUpdate: () => null,
}, },
'whatsapp.message.updated': { 'whatsapp.message.updated': {
getMsg: (result) => { getMsg: (result) => {
@ -83,18 +84,26 @@ const whatsappMsgMapped = {
}, },
contentToUpdate: (msgcontent) => ({ ...msgcontent, id: msgcontent.id, status: msgcontent.status }), contentToUpdate: (msgcontent) => ({ ...msgcontent, id: msgcontent.id, status: msgcontent.status }),
}, },
};
export const receivedMsgTypeMapped = {
...cloneDeep(whatsappMsgMapped),
'message': { 'message': {
getMsg: (result) => { // 发送消息的同步记录 status: 'accepted'
return result; getMsg: (result) => ({ ...result, conversationId: result.actionId.split('.')[0] }),
}, contentToRender: () => null,
contentToRender: (msgcontent) => { contentToUpdate: (msgcontent) => ({
return null; // todo: 仅更新消息状态, 没有输出 ...msgcontent,
}, id: msgcontent.actionId,
contentToUpdate: (msgcontent) => ({ ...msgcontent, id: msgcontent.actionId, status: msgcontent?.status || ('failed'), dateString: '发送失败 ❌' }), status: ['delivered', 'accepted', 'sent'].includes(msgcontent?.status || '' ? 'sent' : 'failed'),
conversationId: msgcontent.conversation.id,
}),
},
'error': {
getMsg: (result) => result,
contentToRender: () => null,
contentToUpdate: (msgcontent) => ({ ...msgcontent, id: msgcontent.actionId, status: msgcontent?.status || 'failed', dateString: '发送失败 ❌' }),
}, },
}; };
// whatsappMsgMapped.message = cloneDeep(whatsappMsgMapped['whatsapp.message.updated']);
export const receivedMsgTypeMapped = whatsappMsgMapped;
export const whatsappMsgTypeMapped = { export const whatsappMsgTypeMapped = {
error: { error: {
type: (_m) => ({ type: 'system' }), type: (_m) => ({ type: 'system' }),
@ -147,15 +156,10 @@ export const whatsappMsgTypeMapped = {
type: 'text', type: 'text',
data: (msg) => ({ id: msg.wamid, text: msg.reaction?.emoji || msg.reaction?.text?.body || 'Reaction', reply: { message: '{content}', title: 'React from' } }), data: (msg) => ({ id: msg.wamid, text: msg.reaction?.emoji || msg.reaction?.text?.body || 'Reaction', reply: { message: '{content}', title: 'React from' } }),
}, },
template: { document: {
type: (msg) => 'text', type: 'file',
data: (msg) => ({ data: (msg) => ({ id: msg.wamid, text: msg.document.filename, data: { uri: msg.document.link, extension: 'PDF', status: { click: false, loading: 0, } } }),
id: msg.wamid,
// todo: update status: sent
status: msg.status,
}),
}, },
// file: 'file',
// location: 'location', // location: 'location',
// contact: 'contact', // contact: 'contact',
// 'contact-card': 'contact-card', // 'contact-card': 'contact-card',
@ -190,3 +194,11 @@ export const parseRenderMessageList = (messages) => {
}; };
}); });
}; };
/**
* WhatsApp Templates params
*/
export const whatsappTemplatesParamMapped = {
'say_hello': [['customer_name']],
'asia_highlights_has_receive_your_inquiry': [['agent_name']],
};

@ -10,10 +10,11 @@ export class RealTimeAPI {
getObservable() { getObservable() {
return this.webSocket.pipe( return this.webSocket.pipe(
retry({ retry(10)
count: 10, // retry({
delay: () => timer(1000) // count: 10,
}) // delay: () => timer(3000)
// })
); );
} }

@ -28,10 +28,7 @@ export const useConversations = ({loginUser, realtimeAPI}) => {
const [activeConversations, setActiveConversations] = useState({}); // all active conversation const [activeConversations, setActiveConversations] = useState({}); // all active conversation
const [currentID, setCurrentID] = useState(); const [currentID, setCurrentID] = useState();
const [conversationsList, setConversationsList] = useState([]); // open conversations const [conversationsList, setConversationsList] = useState([]); // open conversations
const [currentConversation, setCurrentConversation] = useState({ const [currentConversation, setCurrentConversation] = useState({ id: '', customer_name: '', order_sn: '' });
id: '',
name: '',
});
const currentConversationRef = useRef(currentConversation); const currentConversationRef = useRef(currentConversation);
useEffect(() => { useEffect(() => {
currentConversationRef.current = currentConversation; currentConversationRef.current = currentConversation;
@ -61,12 +58,12 @@ export const useConversations = ({loginUser, realtimeAPI}) => {
return () => {}; return () => {};
}, []); }, []);
useEffect(() => { // useEffect(() => {
if (!currentConversation.id && conversationsList.length > 0) { // if (!currentConversation.id && conversationsList.length > 0) {
switchConversation(conversationsList[0]); // switchConversation(conversationsList[0]);
} // }
return () => {}; // return () => {};
}, [conversationsList]); // }, [conversationsList]);
const getConversationsList = async () => { const getConversationsList = async () => {
@ -75,12 +72,12 @@ export const useConversations = ({loginUser, realtimeAPI}) => {
setConversationsList(data); setConversationsList(data);
setActiveConversations({...dataMapped, ...activeConversations}); setActiveConversations({...dataMapped, ...activeConversations});
console.log(data, dataMapped); console.log(data, dataMapped);
// if (data && data.length) { if (data && data.length) {
// switchConversation(data[0]); switchConversation(data[0]);
// } }
}; };
const templates = AllTemplates.filter((_t) => _t.status !== 'REJECTED').map((ele) => ({ ...ele, components: groupBy(ele.components, (_c) => _c.type.toLowerCase()) })); // test: 0 // const templates = AllTemplates.filter((_t) => _t.status !== 'REJECTED').map((ele) => ({ ...ele, components: groupBy(ele.components, (_c) => _c.type.toLowerCase()) })); // test: 0
// const [templates, setTemplates] = useState([]); // const [templates, setTemplates] = useState([]);
const [templatesList, setTemplatesList] = useState([]); const [templatesList, setTemplatesList] = useState([]);
const getTemplates = async () => { const getTemplates = async () => {
@ -98,8 +95,8 @@ export const useConversations = ({loginUser, realtimeAPI}) => {
const switchConversation = (cc) => { const switchConversation = (cc) => {
setCurrentID(cc.id); setCurrentID(cc.id);
setCurrentConversation(cc); setCurrentConversation(cc);
const _all = []; // const _all = [];
// const _all = all.map((ele) => receivedMsgTypeMapped['whatsapp.inbound_message.received'].contentToRender(ele)); // debug: 0 const _all = all.map((ele) => receivedMsgTypeMapped['whatsapp.inbound_message.received'].contentToRender(ele)); // debug: 0
// todo: update msg status // todo: update msg status
// const _all = all2.map((ele) => receivedMsgTypeMapped['whatsapp.message.updated'].contentToRender(ele)); // debug: 0 // const _all = all2.map((ele) => receivedMsgTypeMapped['whatsapp.message.updated'].contentToRender(ele)); // debug: 0
setMessages([..._all, ...(activeConversations[cc.id] || [])]); setMessages([..._all, ...(activeConversations[cc.id] || [])]);
@ -109,10 +106,10 @@ export const useConversations = ({loginUser, realtimeAPI}) => {
// Get customer profile when switching conversation // Get customer profile when switching conversation
// useEffect(() => { // useEffect(() => {
// return () => { // const colisn = currentConversation.order_sn;
// getCustomerProfile(currentID); // getCustomerProfile(colisn);
// }; // return () => {};
// }, [currentID]); // }, [currentConversation]);
/** /**
* ***************************************************************************************************** * *****************************************************************************************************
@ -123,21 +120,22 @@ export const useConversations = ({loginUser, realtimeAPI}) => {
setErrors((prevErrors) => [...prevErrors, { reason }]); setErrors((prevErrors) => [...prevErrors, { reason }]);
}; };
const addMessageToConversations = (customerId, message) => { const addMessageToConversations = (targetId, message) => {
// setActiveConversations((prevList) => ({ setActiveConversations((prevList) => ({
// ...prevList, ...prevList,
// [customerId]: [...(prevList[customerId] || []), message], [targetId]: [...(prevList[targetId] || []), message],
// })); }));
// console.log('activeConversations', activeConversations); // console.log('activeConversations', activeConversations);
setActiveConversations((prevList) => { if (targetId !== currentID) {
const updatedList = {...prevList}; setConversationsList((prevList) => {
if(updatedList[customerId]) { return prevList.map((ele) => {
updatedList[customerId].push(message); if (ele.id === targetId) {
} else { return { ...ele, new_msgs: ele.new_msgs + 1 };
updatedList[customerId] = [message]; }
} return ele;
return updatedList; });
}); });
}
}; };
useEffect(() => { useEffect(() => {
@ -155,14 +153,23 @@ export const useConversations = ({loginUser, realtimeAPI}) => {
}; };
const updateMessage = (message) => { const updateMessage = (message) => {
let targetMsgs;
setMessages((prevMessages) => { setMessages((prevMessages) => {
return prevMessages.map(ele => { targetMsgs = prevMessages.map(ele => {
if (ele.id === message.id) { if (ele.id === message.id) {
return {...ele, id: message.id, status: message.status, dateString: message.dateString}; return {...ele, id: message.id, status: message.status, dateString: message.dateString};
} }
return ele; return ele;
}); });
return targetMsgs;
}); });
// 更新会话中的消息
const targetId = currentConversationRef.current.id;
setActiveConversations((prevList) => ({
...prevList,
[targetId]: targetMsgs,
}));
}; };
const handleMessage = (data) => { const handleMessage = (data) => {
@ -178,14 +185,14 @@ export const useConversations = ({loginUser, realtimeAPI}) => {
let resultType = result.type; let resultType = result.type;
if (errcode !== 0) { if (errcode !== 0) {
// addError('Error Connecting to Server'); // addError('Error Connecting to Server');
resultType = result.action; resultType = 'error';
} }
console.log(resultType, 'result.type'); console.log(resultType, 'result.type');
const msgObj = receivedMsgTypeMapped[resultType].getMsg(result); const msgObj = receivedMsgTypeMapped[resultType].getMsg(result);
const msgRender = receivedMsgTypeMapped[resultType].contentToRender(msgObj); const msgRender = receivedMsgTypeMapped[resultType].contentToRender(msgObj);
const msgUpdate = receivedMsgTypeMapped[resultType].contentToUpdate(msgObj); const msgUpdate = receivedMsgTypeMapped[resultType].contentToUpdate(msgObj);
console.log('msgRender msgUpdate', msgRender, msgUpdate); console.log('msgRender msgUpdate', msgRender, msgUpdate);
if ( ['whatsapp.message.updated', 'message'].includes(resultType)) { if ( ['whatsapp.message.updated', 'message', 'error'].includes(resultType)) {
updateMessage(msgUpdate); updateMessage(msgUpdate);
// return false; // return false;
} }
@ -222,123 +229,145 @@ export const useConversations = ({loginUser, realtimeAPI}) => {
// test: 0 "type": "whatsapp.inbound_message.received", // test: 0 "type": "whatsapp.inbound_message.received",
const all = [ const all = [
{ // {
'id': '65b06828619a1d82777eb4c6', // 'id': '65b06828619a1d82777eb4c6',
'wamid': 'wamid.HBgNODYxMzMxNzgzNTU4NhUCABIYFDNBQzNDNzBFNjFCREJBNDIyQjQ2AA==', // 'wamid': 'wamid.HBgNODYxMzMxNzgzNTU4NhUCABIYFDNBQzNDNzBFNjFCREJBNDIyQjQ2AA==',
'wabaId': '190290134156880', // 'wabaId': '190290134156880',
'from': '+8613317835586', // 'from': '+8613317835586',
'customerProfile': { // 'customerProfile': {
'name': 'qqs', // 'name': 'qqs',
}, // },
'to': '+8617607730395', // 'to': '+8617607730395',
'sendTime': '2024-01-24T01:30:14.000Z', // 'sendTime': '2024-01-24T01:30:14.000Z',
'type': 'image', // 'type': 'image',
'image': { // 'image': {
'link': // 'link':
'https://api.ycloud.com/v2/whatsapp/media/download/934379820978291?sig=t%3D1706059814%2Cs%3D91a79a0e4007ad2f6a044a28307affe663f7f81903b3537bd80e758d3c0d0563&payload=eyJpZCI6IjkzNDM3OTgyMDk3ODI5MSIsIndhYmFJZCI6IjE5MDI5MDEzNDE1Njg4MCIsImluYm91bmRNZXNzYWdlSWQiOiI2NWIwNjgyODYxOWExZDgyNzc3ZWI0YzYiLCJtaW1lVHlwZSI6ImltYWdlL2pwZWciLCJzaGEyNTYiOiJPVTJjdkN2eHplMUdMMmQ5NUxyTGVaNmpNb2ZscUZYM1RvcXdTTUNWZkxNPSJ9', // 'https://api.ycloud.com/v2/whatsapp/media/download/934379820978291?sig=t%3D1706059814%2Cs%3D91a79a0e4007ad2f6a044a28307affe663f7f81903b3537bd80e758d3c0d0563&payload=eyJpZCI6IjkzNDM3OTgyMDk3ODI5MSIsIndhYmFJZCI6IjE5MDI5MDEzNDE1Njg4MCIsImluYm91bmRNZXNzYWdlSWQiOiI2NWIwNjgyODYxOWExZDgyNzc3ZWI0YzYiLCJtaW1lVHlwZSI6ImltYWdlL2pwZWciLCJzaGEyNTYiOiJPVTJjdkN2eHplMUdMMmQ5NUxyTGVaNmpNb2ZscUZYM1RvcXdTTUNWZkxNPSJ9',
'id': '934379820978291', // 'id': '934379820978291',
'sha256': 'OU2cvCvxze1GL2d95LrLeZ6jMoflqFX3ToqwSMCVfLM=', // 'sha256': 'OU2cvCvxze1GL2d95LrLeZ6jMoflqFX3ToqwSMCVfLM=',
'mime_type': 'image/jpeg', // 'mime_type': 'image/jpeg',
}, // },
}, // },
{ // {
'id': '65b06ce6619a1d8277c97fc0', // 'id': '65b06ce6619a1d8277c97fc0',
'wamid': 'wamid.HBgNODYxMzMxNzgzNTU4NhUCABIYFDNBMUJBOUZCODY4NkNBMkM2NUEzAA==', // 'wamid': 'wamid.HBgNODYxMzMxNzgzNTU4NhUCABIYFDNBMUJBOUZCODY4NkNBMkM2NUEzAA==',
'wabaId': '190290134156880', // 'wabaId': '190290134156880',
'from': '+8613317835586', // 'from': '+8613317835586',
'customerProfile': { // 'customerProfile': {
'name': 'qqs', // 'name': 'qqs',
}, // },
'to': '+8617607730395', // 'to': '+8617607730395',
'sendTime': '2024-01-24T01:50:29.000Z', // 'sendTime': '2024-01-24T01:50:29.000Z',
'type': 'text', // 'type': 'text',
'text': { // 'text': {
'body': 'eeee', // 'body': 'eeee',
}, // },
}, // },
{ // {
'id': '65b06b2f619a1d8277b5ab06', // 'id': '65b06b2f619a1d8277b5ab06',
'wamid': 'wamid.HBgNODYxMzMxNzgzNTU4NhUCABIYFDNBRkU0RUZGRUI1OUQzQUFBMEExAA==', // 'wamid': 'wamid.HBgNODYxMzMxNzgzNTU4NhUCABIYFDNBRkU0RUZGRUI1OUQzQUFBMEExAA==',
'wabaId': '190290134156880', // 'wabaId': '190290134156880',
'from': '+8613317835586', // 'from': '+8613317835586',
'customerProfile': { // 'customerProfile': {
'name': 'qqs', // 'name': 'qqs',
}, // },
'to': '+8617607730395', // 'to': '+8617607730395',
'sendTime': '2024-01-24T01:43:09.000Z', // 'sendTime': '2024-01-24T01:43:09.000Z',
'type': 'audio', // 'type': 'audio',
'audio': { // 'audio': {
'link': // 'link':
'https://api.ycloud.com/v2/whatsapp/media/download/901696271448320?sig=t%3D1706060589%2Cs%3Dca75dbd57e4867783390c913491263f07c9738d69c141d4ae622c76df9fa033b&payload=eyJpZCI6IjkwMTY5NjI3MTQ0ODMyMCIsIndhYmFJZCI6IjE5MDI5MDEzNDE1Njg4MCIsImluYm91bmRNZXNzYWdlSWQiOiI2NWIwNmIyZjYxOWExZDgyNzdiNWFiMDYiLCJtaW1lVHlwZSI6ImF1ZGlvL29nZzsgY29kZWNzPW9wdXMiLCJzaGEyNTYiOiJoZUNSUDdEMjM3bG9ydkZ4eFhSdHZpU1ZsNDR3Rlk4TytaMFhic2k5cy9rPSJ9', // 'https://api.ycloud.com/v2/whatsapp/media/download/901696271448320?sig=t%3D1706060589%2Cs%3Dca75dbd57e4867783390c913491263f07c9738d69c141d4ae622c76df9fa033b&payload=eyJpZCI6IjkwMTY5NjI3MTQ0ODMyMCIsIndhYmFJZCI6IjE5MDI5MDEzNDE1Njg4MCIsImluYm91bmRNZXNzYWdlSWQiOiI2NWIwNmIyZjYxOWExZDgyNzdiNWFiMDYiLCJtaW1lVHlwZSI6ImF1ZGlvL29nZzsgY29kZWNzPW9wdXMiLCJzaGEyNTYiOiJoZUNSUDdEMjM3bG9ydkZ4eFhSdHZpU1ZsNDR3Rlk4TytaMFhic2k5cy9rPSJ9',
'id': '901696271448320', // 'id': '901696271448320',
'sha256': 'heCRP7D237lorvFxxXRtviSVl44wFY8O+Z0Xbsi9s/k=', // 'sha256': 'heCRP7D237lorvFxxXRtviSVl44wFY8O+Z0Xbsi9s/k=',
'mime_type': 'audio/ogg; codecs=opus', // 'mime_type': 'audio/ogg; codecs=opus',
}, // },
}, // },
{ // {
'id': '65b06b12619a1d8277b3c0c4', // 'id': '65b06b12619a1d8277b3c0c4',
'wamid': 'wamid.HBgNODYxMzMxNzgzNTU4NhUCABIYFDNBREZEMEM0MURDNjJGREVEQjY3AA==', // 'wamid': 'wamid.HBgNODYxMzMxNzgzNTU4NhUCABIYFDNBREZEMEM0MURDNjJGREVEQjY3AA==',
'wabaId': '190290134156880', // 'wabaId': '190290134156880',
'from': '+8613317835586', // 'from': '+8613317835586',
'customerProfile': { // 'customerProfile': {
'name': 'qqs', // 'name': 'qqs',
}, // },
'to': '+8617607730395', // 'to': '+8617607730395',
'sendTime': '2024-01-24T01:42:40.000Z', // 'sendTime': '2024-01-24T01:42:40.000Z',
'type': 'video', // 'type': 'video',
'video': { // 'video': {
'link': // 'link':
'https://api.ycloud.com/v2/whatsapp/media/download/742404324517058?sig=t%3D1706060560%2Cs%3D53eeb1508c2103e310fb14a72563a8e07c5a84c7e6192a25f3608ac9bea32334&payload=eyJpZCI6Ijc0MjQwNDMyNDUxNzA1OCIsIndhYmFJZCI6IjE5MDI5MDEzNDE1Njg4MCIsImluYm91bmRNZXNzYWdlSWQiOiI2NWIwNmIxMjYxOWExZDgyNzdiM2MwYzQiLCJtaW1lVHlwZSI6InZpZGVvL21wNCIsInNoYTI1NiI6IlNJcjRlZFlPb1BDTGtETEgrVTY2d3dkMDgra2JndFV5OHRDd2RjQU5FaFU9In0', // 'https://api.ycloud.com/v2/whatsapp/media/download/742404324517058?sig=t%3D1706060560%2Cs%3D53eeb1508c2103e310fb14a72563a8e07c5a84c7e6192a25f3608ac9bea32334&payload=eyJpZCI6Ijc0MjQwNDMyNDUxNzA1OCIsIndhYmFJZCI6IjE5MDI5MDEzNDE1Njg4MCIsImluYm91bmRNZXNzYWdlSWQiOiI2NWIwNmIxMjYxOWExZDgyNzdiM2MwYzQiLCJtaW1lVHlwZSI6InZpZGVvL21wNCIsInNoYTI1NiI6IlNJcjRlZFlPb1BDTGtETEgrVTY2d3dkMDgra2JndFV5OHRDd2RjQU5FaFU9In0',
'caption': 'and', // 'caption': 'and',
'id': '742404324517058', // 'id': '742404324517058',
'sha256': 'SIr4edYOoPCLkDLH+U66wwd08+kbgtUy8tCwdcANEhU=', // 'sha256': 'SIr4edYOoPCLkDLH+U66wwd08+kbgtUy8tCwdcANEhU=',
'mime_type': 'video/mp4', // 'mime_type': 'video/mp4',
}, // },
}, // },
{ // {
'id': '65b06aa7619a1d8277ac806e', // 'id': '65b06aa7619a1d8277ac806e',
'wamid': 'wamid.HBgNODYxMzMxNzgzNTU4NhUCABIYFDNBOTFBOTU5RDE2QjgxQTQ1MEE2AA==', // 'wamid': 'wamid.HBgNODYxMzMxNzgzNTU4NhUCABIYFDNBOTFBOTU5RDE2QjgxQTQ1MEE2AA==',
'wabaId': '190290134156880', // 'wabaId': '190290134156880',
'from': '+8613317835586', // 'from': '+8613317835586',
'customerProfile': { // 'customerProfile': {
'name': 'qqs', // 'name': 'qqs',
}, // },
'to': '+8617607730395', // 'to': '+8617607730395',
'sendTime': '2024-01-24T01:40:53.000Z', // 'sendTime': '2024-01-24T01:40:53.000Z',
'type': 'sticker', // 'type': 'sticker',
'sticker': { // 'sticker': {
'link': // 'link':
'https://api.ycloud.com/v2/whatsapp/media/download/1156118002042289?sig=t%3D1706060453%2Cs%3Dfbd5f881856614e35715b1e3e1097b3bbe56f8a36aaa67bfbef25a37d9143d51&payload=eyJpZCI6IjExNTYxMTgwMDIwNDIyODkiLCJ3YWJhSWQiOiIxOTAyOTAxMzQxNTY4ODAiLCJpbmJvdW5kTWVzc2FnZUlkIjoiNjViMDZhYTc2MTlhMWQ4Mjc3YWM4MDZlIiwibWltZVR5cGUiOiJpbWFnZS93ZWJwIiwic2hhMjU2IjoibUNaLzdhNnNaNlRNYTE0WW9rUkNTZnVsdGpZNmFRRVZFNVoxMVRwanNQOD0ifQ', // 'https://api.ycloud.com/v2/whatsapp/media/download/1156118002042289?sig=t%3D1706060453%2Cs%3Dfbd5f881856614e35715b1e3e1097b3bbe56f8a36aaa67bfbef25a37d9143d51&payload=eyJpZCI6IjExNTYxMTgwMDIwNDIyODkiLCJ3YWJhSWQiOiIxOTAyOTAxMzQxNTY4ODAiLCJpbmJvdW5kTWVzc2FnZUlkIjoiNjViMDZhYTc2MTlhMWQ4Mjc3YWM4MDZlIiwibWltZVR5cGUiOiJpbWFnZS93ZWJwIiwic2hhMjU2IjoibUNaLzdhNnNaNlRNYTE0WW9rUkNTZnVsdGpZNmFRRVZFNVoxMVRwanNQOD0ifQ',
'id': '1156118002042289', // 'id': '1156118002042289',
'sha256': 'mCZ/7a6sZ6TMa14YokRCSfultjY6aQEVE5Z11TpjsP8=', // 'sha256': 'mCZ/7a6sZ6TMa14YokRCSfultjY6aQEVE5Z11TpjsP8=',
'mime_type': 'image/webp', // 'mime_type': 'image/webp',
'animated': false, // 'animated': false,
}, // },
}, // },
{ // {
'id': '65b06a91619a1d8277aaf05e', // 'id': '65b06a91619a1d8277aaf05e',
'wamid': 'wamid.HBgNODYxMzMxNzgzNTU4NhUCABIYFDNBRjUxNzdCQ0FEOTlFQzc5MzQ1AA==', // 'wamid': 'wamid.HBgNODYxMzMxNzgzNTU4NhUCABIYFDNBRjUxNzdCQ0FEOTlFQzc5MzQ1AA==',
'wabaId': '190290134156880', // 'wabaId': '190290134156880',
'from': '+8613317835586', // 'from': '+8613317835586',
'customerProfile': { // 'customerProfile': {
'name': 'qqs', // 'name': 'qqs',
}, // },
'to': '+8617607730395', // 'to': '+8617607730395',
'sendTime': '2024-01-24T01:40:32.000Z', // 'sendTime': '2024-01-24T01:40:32.000Z',
'type': 'unsupported', // 'type': 'unsupported',
'errors': [ // 'errors': [
{ // {
'code': '131051', // 'code': '131051',
'title': 'Message type unknown', // 'title': 'Message type unknown',
'message': 'Message type unknown', // 'message': 'Message type unknown',
'error_data': { // 'error_data': {
'details': 'Message type is currently not supported.', // 'details': 'Message type is currently not supported.',
}, // },
}, // },
], // ],
}, // },
// {
// "id": "65b38323619a1d827778986d",
// "wamid": "wamid.HBgMOTE4NTg3OTAxMDg2FQIAEhgWM0VCMDMwMjc5OThGN0EyN0JERjY5QwA=",
// "wabaId": "190290134156880",
// "from": "+918587901086",
// "customerProfile": {
// "name": "Shailesh"
// },
// "to": "+8617607730395",
// "sendTime": "2024-01-26T10:02:09.000Z",
// "type": "document",
// "document": {
// "link": "https://api.ycloud.com/v2/whatsapp/media/download/773594381476592?sig=t%3D1706263329%2Cs%3D0e0221fc921b29f6e2f896a2f62a3b99a60d09b40e7332d509e7b0cd2a4a630e&payload=eyJpZCI6Ijc3MzU5NDM4MTQ3NjU5MiIsIndhYmFJZCI6IjE5MDI5MDEzNDE1Njg4MCIsIndhbWlkIjoid2FtaWQuSEJnTU9URTROVGczT1RBeE1EZzJGUUlBRWhnV00wVkNNRE13TWpjNU9UaEdOMEV5TjBKRVJqWTVRd0E9IiwibWltZVR5cGUiOiJhcHBsaWNhdGlvbi92bmQub3BlbnhtbGZvcm1hdHMtb2ZmaWNlZG9jdW1lbnQud29yZHByb2Nlc3NpbmdtbC5kb2N1bWVudCIsInNoYTI1NiI6ImFUK3hnSGRhaGNtekVFa0g3bmdZbHloVSt1R2ZuTnIvdlEwNGtKSTBaMFU9In0",
// "filename": "NEPAL INDIA TOUR - NOV 2024 - revised.docx",
// "id": "773594381476592",
// "sha256": "aT+xgHdahcmzEEkH7ngYlyhU+uGfnNr/vQ04kJI0Z0U=",
// "mime_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
// }
// }
]; ];
const all2 = [ const all2 = [
{ {

@ -26,9 +26,11 @@ const ChatWindow = (() => {
const { errors, sendMessage, currentConversation, customerOrderProfile: orderInfo, getCustomerProfile } = useConversationContext(); const { errors, sendMessage, currentConversation, customerOrderProfile: orderInfo, getCustomerProfile } = useConversationContext();
const { quotes, contact, last_contact, ...order } = orderInfo; const { quotes, contact, last_contact, ...order } = orderInfo;
console.log(order_sn, currentUser); // console.log(order_sn, currentUser);
useEffect(() => { useEffect(() => {
getCustomerProfile(order_sn); if (order_sn) {
getCustomerProfile(order_sn);
}
return () => {}; return () => {};
}, [order_sn]); }, [order_sn]);
@ -36,8 +38,8 @@ const ChatWindow = (() => {
return ( return (
<Spin spinning={false} tip={'正在连接...'} > <Spin spinning={false} tip={'正在连接...'} >
<Layout className='full-height h-full chatwindow-wrapper' style={{ maxHeight: 'calc(100% - 198px)', height: 'calc(100% - 198px)' }}> <Layout className='h-screen chatwindow-wrapper' style={{ maxHeight: 'calc(100% - 198px)', height: 'calc(100% - 198px)' }}>
<Sider width={240} theme={'light'} className='scrollable-column' style={{ maxHeight: 'calc(100vh - 198px)', height: 'calc(100vh - 198px)' }}> <Sider width={240} theme={'light'} className='h-full overflow-y-auto' style={{ maxHeight: 'calc(100vh - 198px)', height: 'calc(100vh - 198px)' }}>
<ConversationsList /> <ConversationsList />
</Sider> </Sider>
@ -45,10 +47,10 @@ const ChatWindow = (() => {
<Layout className='h-full'> <Layout className='h-full'>
<Header className='ant-layout-sider-light ant-card p-1 h-auto'> <Header className='ant-layout-sider-light ant-card p-1 h-auto'>
<Flex gap={16}> <Flex gap={16}>
<Avatar src={`https://api.dicebear.com/7.x/avataaars/svg?seed=${currentConversation.name}`}>{currentConversation.name}</Avatar> <Avatar src={`https://api.dicebear.com/7.x/avataaars/svg?seed=${currentConversation.customer_name}`}>{currentConversation.customer_name}</Avatar>
<Flex flex={'1'} justify='space-between'> <Flex flex={'1'} justify='space-between'>
<Flex vertical={true} justify='space-between'> <Flex vertical={true} justify='space-between'>
<Typography.Text strong>{currentConversation.name}</Typography.Text> <Typography.Text strong>{currentConversation.customer_name}</Typography.Text>
{/* <Typography.Text>{contact?.phone}</Typography.Text> */} {/* <Typography.Text>{contact?.phone}</Typography.Text> */}
</Flex> </Flex>
<Flex vertical={true} justify='space-between'> <Flex vertical={true} justify='space-between'>
@ -61,7 +63,7 @@ const ChatWindow = (() => {
</Flex> </Flex>
</Header> </Header>
<Content style={{ maxHeight: '74vh', height: '74vh' }}> <Content style={{ maxHeight: '74vh', height: '74vh' }}>
<div className='scrollable-column'> <div className='h-full overflow-y-auto'>
<Messages /> <Messages />
</div> </div>
</Content> </Content>
@ -72,7 +74,7 @@ const ChatWindow = (() => {
{/* <InputBox onSend={(v) => sendMessage(v)} /> */} {/* <InputBox onSend={(v) => sendMessage(v)} /> */}
</Content> </Content>
<Sider width={300} theme={'light'} className='scrollable-column' style={{ maxHeight: 'calc(100vh - 198px)', height: 'calc(100vh - 198px)' }}> <Sider width={300} theme={'light'} className='h-full overflow-y-auto' style={{ maxHeight: 'calc(100vh - 198px)', height: 'calc(100vh - 198px)' }}>
<CustomerProfile customer={{}} /> <CustomerProfile customer={{}} />
</Sider> </Sider>
</Layout> </Layout>

@ -14,9 +14,9 @@ const Conversations = (({ conversations }) => {
setChatlist( setChatlist(
(conversationsList || []).map((item) => ({ (conversationsList || []).map((item) => ({
...item, ...item,
avatar: `https://api.dicebear.com/7.x/avataaars/svg?seed=${item.name}`, avatar: `https://api.dicebear.com/7.x/avataaars/svg?seed=${item.customer_name}`,
alt: item.name, alt: item.customer_name,
title: item.name, title: item.customer_name,
subtitle: item.lastMessage, subtitle: item.lastMessage,
date: item.last_time, date: item.last_time,
unread: item.new_msgs, unread: item.new_msgs,

@ -3,35 +3,24 @@ import { Input, Button, Tabs, List, Space, Popover, Flex } from 'antd';
// import { Input } from 'react-chat-elements'; // import { Input } from 'react-chat-elements';
import { useConversationContext } from '@/stores/Conversations/ConversationContext'; import { useConversationContext } from '@/stores/Conversations/ConversationContext';
import { LikeOutlined, MessageOutlined, StarOutlined, SendOutlined, PlusOutlined, PlusCircleOutlined } from '@ant-design/icons'; import { LikeOutlined, MessageOutlined, StarOutlined, SendOutlined, PlusOutlined, PlusCircleOutlined } from '@ant-design/icons';
import { isEmpty } from '@/utils/utils'; import { cloneDeep, getNestedValue, isEmpty } from '@/utils/utils';
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
import { whatsappTemplatesParamMapped } from '@/lib/msgUtils';
const InputBox = (({ onSend }) => { const InputBox = (({ onSend }) => {
const { currentConversation, templates } = useConversationContext(); const { currentConversation, templates } = useConversationContext();
const [textContent, setTextContent] = useState(''); const [textContent, setTextContent] = useState('');
// console.log('ttt', uuid());
const handleSendText = () => { const handleSendText = () => {
// console.log(textContent);
if (typeof onSend === 'function' && textContent.trim() !== '') { if (typeof onSend === 'function' && textContent.trim() !== '') {
const msgObj = { const msgObj = {
type: 'text', type: 'text',
text: textContent, text: textContent,
sender: 'me', sender: 'me',
// from: '',
to: currentConversation.channel_id, to: currentConversation.channel_id,
id: uuid(), // Date.now().toString(16), id: `${currentConversation.id}.${uuid()}`, // Date.now().toString(16),
date: new Date(), date: new Date(),
status: 'waiting', status: 'waiting',
// renderAddCmp: () => (
// <Button size={'small'} type='link' key={'send'} icon={<SendOutlined />}>
// test
// </Button>
// ),
// statusTitle: 'Ready to send',
// removeButton: true,
// replyButtom: true,
// focus: true,
}; };
onSend(msgObj); onSend(msgObj);
setTextContent(''); setTextContent('');
@ -41,10 +30,11 @@ const InputBox = (({ onSend }) => {
const handleSendTemplate = (fromTemplate) => { const handleSendTemplate = (fromTemplate) => {
console.log(fromTemplate, 'fromTemplate'); console.log(fromTemplate, 'fromTemplate');
if (typeof onSend === 'function') { if (typeof onSend === 'function') {
const _conversation = {...cloneDeep(currentConversation), };
const msgObj = { const msgObj = {
type: 'whatsappTemplate', type: 'whatsappTemplate',
to: currentConversation.channel_id, to: currentConversation.channel_id,
id: uuid(), // Date.now().toString(16), id: `${currentConversation.id}.${uuid()}`,
date: new Date(), date: new Date(),
status: 'waiting', status: 'waiting',
statusTitle: 'Ready to send', statusTitle: 'Ready to send',
@ -59,11 +49,11 @@ const InputBox = (({ onSend }) => {
'parameters': [ 'parameters': [
{ {
'type': 'text', 'type': 'text',
'text': currentConversation.name, 'text': getNestedValue(_conversation, whatsappTemplatesParamMapped[fromTemplate.name][0]) ,
}, },
{ { // debug:
'type': 'text', 'type': 'text',
'text': currentConversation.name, 'text': getNestedValue(_conversation, whatsappTemplatesParamMapped[fromTemplate.name]?.[1] || whatsappTemplatesParamMapped[fromTemplate.name][0]) ,
}, },
], ],
}, },

@ -16,7 +16,7 @@ export const ConversationProvider = ({ children, loginUser, realtimeAPI }) => {
const AuthAndConversationProvider = ({ children }) => { const AuthAndConversationProvider = ({ children }) => {
const { loginUser } = useContext(AuthContext); const { loginUser } = useContext(AuthContext);
const {userId} = loginUser; const {userId} = loginUser;
const realtimeAPI = new RealTimeAPI({ url: `${WS_URL}?opisn=${userId || ''}&aa=m&_spam=${Date.now().toString()}`, protocol: 'WhatsApp' }); const realtimeAPI = new RealTimeAPI({ url: `${WS_URL}?opisn=${userId || ''}&_spam=${Date.now().toString()}`, protocol: 'WhatsApp' });
return ( return (
<ConversationProvider loginUser={loginUser} realtimeAPI={realtimeAPI} > <ConversationProvider loginUser={loginUser} realtimeAPI={realtimeAPI} >

Loading…
Cancel
Save