feat: 解析Email气泡; 获取详情; 回复

2.0/email-builder
Lei OT 11 months ago
parent fbbe573768
commit 7a4a8df4a0

@ -512,6 +512,9 @@ export const whatsappMsgTypeMapped = {
return { id: msg.wamid, message: templateDataMapped?.body?.text || templateDataMapped?.body?.parameters?.[0]?.text || '', title: `${msg.template.name}` };
},
},
email: {
data: (msg) => ({ id: msg.id, subject: msg.email.subject, originText: msg.text.body, title: msg?.customerProfile?.name || '' }),
},
};
/**
* render received msg
@ -534,7 +537,7 @@ export const parseRenderMessageItem = (msg) => {
customer_name: msg?.customerProfile?.name || '',
whatsapp_name: msg?.customerProfile?.name || '',
whatsapp_phone_number: isEmpty(msg?.customerProfile) ? msg.to : msg.from,
whatsapp_msg_type: msg.type,
whatsapp_msg_type: msg.msg_source==='WABA' ? msg.type : '',
statusCN: msgStatusRenderMappedCN[msg?.status || 'failed'],
statusTitle: msgStatusRenderMappedCN[msg?.status || 'failed'],
replyButton: ['text', 'document', 'image'].includes(msg.type) && (msg?.status || '') !== 'failed',
@ -562,17 +565,19 @@ export const parseRenderMessageItem = (msg) => {
export const parseRenderMessageList = (messages) => {
return messages.map((msg, i) => {
let msgContentString = '';
if (typeof msg.msgtext_AsJOSN === 'string') {
const msgtext = msg?.msgtext || msg?.msgtext_AsJOSN || {};
const messageorigin = msg?.messageorigin || msg?.messageorigin_AsJOSN || {};
if (typeof msgtext === 'string') {
// debug: json 缺少一部分
msgContentString = msg.msgtext_AsJOSN.charAt(msg.msgtext_AsJOSN.length - 1) !== '}' ? msg.msgtext_AsJOSN + '}}' : msg.msgtext_AsJOSN;
// if (msg.msgtext_AsJOSN.charAt(msg.msgtext_AsJOSN.length - 1) === '"') {
// msgContentString = msg.msgtext_AsJOSN + '}}';
msgContentString = msgtext.charAt(msgtext.length - 1) !== '}' ? msgtext + '}}' : msgtext;
// if (msg.msgtext.charAt(msg.msgtext.length - 1) === '"') {
// msgContentString = msg.msgtext + '}}';
// } else {
// msgContentString = msg.msgtext_AsJOSN + '"}';
// msgContentString = msg.msgtext + '"}';
// }
}
const msgContent = typeof msg.msgtext_AsJOSN === 'string' ? JSON.parse(msgContentString) : (msg.msgtext_AsJOSN || {});
msgContent.template = msg.msgtype === 'template' ? { ...msgContent.template, ...msg.template_AsJOSN } : {};
const msgContent = typeof msgtext === 'string' ? JSON.parse(msgContentString) : (msgtext || {});
msgContent.template = msg.msgtype === 'template' ? { ...msgContent.template, ...msg.template } : {};
const msgType = Object.keys(whatsappMsgTypeMapped).includes(msgContent.type) ? msgContent.type : 'unsupported';
// const parseMethod = msgContent.bizType === 'whatsapp' ? cloneDeep(whatsappMsgTypeMapped) : {};
let waCode, waError = '';
@ -610,26 +615,26 @@ export const parseRenderMessageList = (messages) => {
statusTitle: msgStatusRenderMappedCN[msgContent?.status || 'failed'],
}
: {}),
...((isEmpty(msg.messageorigin_AsJOSN) && (isEmpty(msgContent.context) || msgContent.context?.forwarded === true))
// ...((isEmpty(msg.context) && isEmpty(msg.reaction)) || msg.context?.forwarded === true || isEmpty(msg.messageorigin)
// ...((isEmpty(msg.messageorigin_AsJOSN) || isEmpty(msgContent.context))
...((isEmpty(messageorigin) && (isEmpty(msgContent.context) || msgContent.context?.forwarded === true))
// ...((isEmpty(msg.context) && isEmpty(msg.reaction)) || msg.context?.forwarded === true || isEmpty(messageorigin)
// ...((isEmpty(messageorigin) || isEmpty(msgContent.context))
? {}
: {
reply: {
message: msg.messageorigin_AsJOSN?.text?.body || msg.messageorigin_AsJOSN?.text,
title: msg.messageorigin_AsJOSN?.customerProfile?.name || msg.messageorigin_AsJOSN?.senderName || 'me',
...(typeof whatsappMsgTypeMapped[(msg.messageorigin_AsJOSN?.type || 'unsupported')]?.renderForReply === 'function'
? whatsappMsgTypeMapped[(msg.messageorigin_AsJOSN?.type || 'unsupported')].renderForReply(msg.messageorigin_AsJOSN)
message: messageorigin?.text?.body || messageorigin?.text,
title: messageorigin?.customerProfile?.name || messageorigin?.senderName || 'me',
...(typeof whatsappMsgTypeMapped[(messageorigin?.type || 'unsupported')]?.renderForReply === 'function'
? whatsappMsgTypeMapped[(messageorigin?.type || 'unsupported')].renderForReply(messageorigin)
: {}),
titleColor: msg.messageorigin_AsJOSN?.customerProfile?.name ? '#a791ff' : "#128c7e",
titleColor: messageorigin?.customerProfile?.name ? '#a791ff' : "#128c7e",
// titleColor: msg.messageorigin_direction === 'inbound' ? '#a791ff' : "#128c7e",
id: msgContent.context?.id || msgContent.context?.message_id || msgContent.reaction?.message_id,
},
origin: msg.messageorigin_AsJOSN,
origin: messageorigin,
}),
// conversationid: conversationid,
// title: msg.customerProfile.name,
whatsapp_msg_type: msgContent.type,
whatsapp_msg_type: msg.msg_source==='WABA' ? msgContent.type : '',
};
});
};

@ -250,7 +250,7 @@ const MessagesList = ({ ...props }) => {
onTitleClick={() => handlePreview(message)}
notch={false}
title={message.whatsapp_msg_type === 'text' ? '' : message.title}
text={<RenderText str={message?.text || ''} className={message.status === 'failed' ? 'line-through text-neutral-400' : ''} template={message.template_AsJOSN} />}
text={<RenderText str={message?.text || ''} className={message.status === 'failed' ? 'line-through text-neutral-400' : ''} template={message.template} />}
copiableDate={true}
dateString={message.dateString || message.localDate}
className={[

@ -9,11 +9,11 @@ const ChatboxEmail = ({ onOpenEditor, onOpenEmail, ...message }) => {
const RenderText = memo(function renderText({ className, email, sender }) {
return (
<div onClick={() => handlePreview(message)} className={`text-sm leading-5 emoji-text whitespace-pre-wrap cursor-pointer ${className}`} key={'msg-text'}>
{sender === 'me' && <div><b>From: </b>{email.fromName}&nbsp;&lt;{email.fromEmail}&gt;</div>}
<div><b>To: </b>{email.toName}&nbsp;&lt;{email.toEmail}&gt;</div>
<div ><b>Subject: </b>{email.subject}</div>
{sender === 'me' && <div><b>From: </b>{email.from}</div>}
<div><b>To: </b>{email.to}</div>
<div ><b>Subject: </b>{email.email.subject}</div>
<hr className='border-0 border-solid border-b border-neutral-400'/>
<div className='line-clamp-2 text-neutral-600'>{email.abstract}</div>
<div className='line-clamp-2 text-neutral-600'>{email.email.abstract}</div>
</div>
);
});
@ -26,7 +26,7 @@ const ChatboxEmail = ({ onOpenEditor, onOpenEmail, ...message }) => {
return (
<MessageBox
{...message}
key={`${message.sn}.${message.id}`}
key={`${message.sn}.${message.msgtext.id}`}
type='text'
title={ message.sender !== 'me' &&
<>
@ -34,7 +34,8 @@ const ChatboxEmail = ({ onOpenEditor, onOpenEmail, ...message }) => {
<span className={`pl-2 ${message.sender === 'me' ? '' : 'text-indigo-600'}`}>
<b>From: </b>
<span>
{message?.emailOrigin?.fromName}&nbsp;&lt;{message?.emailOrigin.fromEmail}&gt;
{/* {message?.emailOrigin?.fromName}&nbsp;&lt;{message?.emailOrigin.fromEmail}&gt; */}
{message.msgtext?.from}
</span>
</span>
</>
@ -42,11 +43,11 @@ const ChatboxEmail = ({ onOpenEditor, onOpenEmail, ...message }) => {
// titleColor={message.sender !== 'me' ? '#4f46e5' : ''} // 600
notch={false}
position={message.sender === 'me' ? 'right' : 'left'}
onReplyClick={() => onOpenEditor(message.emailOrigin)}
onReplyClick={() => onOpenEditor(message.msgtext)}
// onReplyMessageClick={() => scrollToMessage(message.reply.id)}
onOpen={() => handlePreview(message)}
onTitleClick={() => handlePreview(message)}
text={<RenderText str={message?.text || ''} className={message.status === 'failed' ? 'line-through text-neutral-400' : ''} email={message.emailOrigin} sender={message.sender} />}
text={<RenderText str={message?.msgtext || ''} className={message.status === 'failed' ? 'line-through text-neutral-400' : ''} email={message.msgtext} sender={message.sender} />}
// forwarded={true}
// replyButton={message.sender !== 'me'}
// replyButton={['text', 'document', 'image'].includes(message.whatsapp_msg_type)}

@ -38,11 +38,11 @@ const EmailDetail = ({ open, setOpen, emailMsg, ...props }) => {
const [openEmailEditor, setOpenEmailEditor] = useState(false)
const [fromEmail, setFromEmail] = useState('')
const [ReferEmailMsg, setReferEmailMsg] = useState('')
const onOpenEditor = (emailOrigin, action) => {
const { replyToEmail: email_addr, content } = emailOrigin
const onOpenEditor = (magtext, action) => {
const { from } = magtext
setOpenEmailEditor(true)
setFromEmail(email_addr)
setReferEmailMsg(emailOrigin)
setFromEmail(from)
setReferEmailMsg(magtext)
setAction(action)
setOpen(false)
}
@ -66,14 +66,14 @@ const EmailDetail = ({ open, setOpen, emailMsg, ...props }) => {
const ActionBtns = (props) => (
<div className={`flex items-center w-full ${props.className || ''}`}>
<Button
onClick={() => onOpenEditor(emailMsg, 'reply')}
onClick={() => onOpenEditor(emailMsg.msgtext, 'reply')}
size='small'
type='text'
icon={<ReplyIcon className='text-indigo-500' />}>
回复
</Button>
<Button
onClick={() => onOpenEditor(emailMsg, 'forward')}
onClick={() => onOpenEditor(emailMsg.msgtext, 'forward')}
size='small'
type='text'
icon={<ShareForwardIcon className='text-primary' />}>
@ -87,14 +87,14 @@ const EmailDetail = ({ open, setOpen, emailMsg, ...props }) => {
<DnDModal
open={open}
setOpen={setOpen}
title={mailData.info?.subject}
title={mailData.info?.subject || emailMsg?.msgtext?.email?.subject}
initial={{ top: 74 }}
onMove={onHandleMove}
onResize={onHandleResize}
footer={mobile ? <ActionBtns className='w-full' /> : null}>
<div className='email-container flex flex-col gap-2 *:p-2 *:rounded-sm *:border-b *:border-gray-200 *:shadow-1md'>
<div className=' font-bold'>{mailData.info?.subject}</div>
<div className=' font-bold'>{mailData.info?.subject || emailMsg?.msgtext?.email?.subject}</div>
<div>
<div

@ -348,12 +348,12 @@ const MessageListFilter = ({ ...props }) => {
dataSource={data}
loadMore={loadMore}
loading={loading}
renderItem={({ emailOrigin, ...item }) => (
renderItem={({ msgtext, ...item }) => (
<List.Item
// actions={[item.localDate]}
className='cursor-pointer'
onClick={() => {
onOpenEmail({ emailOrigin, ...item });
onOpenEmail({ msgtext, ...item });
setOpenPopup(false);
}}>
<List.Item.Meta
@ -363,20 +363,20 @@ const MessageListFilter = ({ ...props }) => {
// {item.senderName.substring(0, 3)}
// </Avatar>
}
title={emailOrigin.subject}
// description={`To: ${emailOrigin.toEmail}`}
title={msgtext?.email?.subject}
// description={`To: ${msgtext.to}`}
description={
<Flex justify={'space-between'} className='max-w-full overflow-hidden'>
<div className='flex-auto line-clamp-1 break-all pr-2'>{`To: ${emailOrigin.toEmail}`}</div>
<div className='flex-auto line-clamp-1 break-all pr-2'>{`To: ${msgtext.to}`}</div>
<div className=' basis-32 flex-grow-0 flex-shrink-0'>{item.localDate}</div>
</Flex>
}
/>
{emailOrigin.abstract}
{msgtext?.email?.abstract}
</List.Item>
)}
/>
<EmailDetail open={openEmailDetail} setOpen={setOpenEmailDetail} emailDetail={emailDetail} key={`email-detail-1-${emailDetail.id}`} />
<EmailDetail open={openEmailDetail} setOpen={setOpenEmailDetail} emailMsg={emailDetail} key={`email-detail-1-${emailDetail.id}`} />
</>
);
};

@ -58,54 +58,26 @@ const EmailEditorPopup = ({ open, setOpen, fromEmail, reference, quote = {}, ini
return () => {};
}
setShowCc(!isEmpty(quote.cc));
const { fromEmail, replyToEmail, subject, content } = quote;
// const preQuoteBody = `<p class="editor-paragraph" dir="ltr"><br></p><p class="editor-paragraph" dir="ltr"><br>
// <hr>
// <p class="editor-paragraph" dir="ltr">
// <b>
// <strong class="editor-text-bold" style="white-space: pre-wrap;">From: </strong>
// </b>
// <span style="white-space: pre-wrap;">${quote.fromName} &lt;${quote.fromEmail}&gt;</span>
// </p>
// <p class="editor-paragraph" dir="ltr">
// <b>
// <strong class="editor-text-bold" style="white-space: pre-wrap;">Sent: </strong>
// </b>
// <span style="white-space: pre-wrap;">${quote.sent}</span>
// </p>
// <p class="editor-paragraph" dir="ltr">
// <b>
// <strong class="editor-text-bold" style="white-space: pre-wrap;">To: </strong>
// </b>
// <span style="white-space: pre-wrap;">${quote.toName} &lt;${quote.toEmail}&gt;</span>
// </p>
// <p class="editor-paragraph" dir="ltr">
// <b>
// <strong class="editor-text-bold" style="white-space: pre-wrap;">Subject: </strong>
// </b>
// <span style="white-space: pre-wrap;">${subject}</span>
// </p>
// <p class="editor-paragraph" dir="ltr">${content}</p>
// `;
const { from, email: { subject, content, mai_sn } } = quote;
const preQuoteBody = `<br><br>
<hr>
<p>
<b>
<strong >From: </strong>
</b>
<span >${quote.fromName} &lt;${quote.fromEmail}&gt;</span>
<span >${quote.from} </span>
</p>
<p>
<b>
<strong >Sent: </strong>
</b>
<span >${quote.sent}</span>
<span >${quote.sendTime}</span>
</p>
<p>
<b>
<strong >To: </strong>
</b>
<span >${quote.toName} &lt;${quote.toEmail}&gt;</span>
<span >${quote.to}</span>
</p>
<p>
<b>
@ -117,12 +89,10 @@ const EmailEditorPopup = ({ open, setOpen, fromEmail, reference, quote = {}, ini
${content}
</p>
`;
// <blockquote class="editor-quote">
// </blockquote>
setInitialContent(preQuoteBody);
const _formValues = {
to: replyToEmail || fromEmail,
to: from || fromEmail,
cc: quote.cc || '',
bcc: quote.bcc || '',
subject: `Re: ${subject}`,
@ -252,7 +222,7 @@ const EmailEditorPopup = ({ open, setOpen, fromEmail, reference, quote = {}, ini
onCancel={() => {
form.resetFields();
}}
title={initialForm.subject || `${reference ? '回复: ' : '写邮件: '} ${fromEmail || ''}`}
title={initialForm.subject || `${isEmpty(quote) ? '回复: ' : '写邮件: '} ${fromEmail || ''}`}
footer={
<div className='w-full flex gap-6 justify-start items-center text-indigo-600'>
<Button type='primary' onClick={onHandleSend}>
@ -289,17 +259,7 @@ const EmailEditorPopup = ({ open, setOpen, fromEmail, reference, quote = {}, ini
>
<Form.Item label='收件人' className='w-full'>
<Space.Compact className='w-full'>
{/* <Flex justify='space-between' className='w-full'> */}
{/* <Mentions // todo: 用客人列表
split='; '
options={[
{ value: 'lyt@hainatravel.com', label: 'OT' },
{ value: 'zombieJ', label: 'zombieJ' },
{ value: 'yesmeck', label: 'yesmeck' },
]}
placeholder='@'
/> */}
<Form.Item name={'to'} rules={[{ required: true }]} className='flex-1'>
<Form.Item name={'to'} rules={[{ required: true }]} className='!flex-1'>
<Input className='w-full' />
</Form.Item>
<Flex gap={4}>
@ -314,7 +274,6 @@ const EmailEditorPopup = ({ open, setOpen, fromEmail, reference, quote = {}, ini
</Button>
)}
</Flex>
{/* </Flex> */}
</Space.Compact>
{/* <Input
addonAfter={

@ -67,7 +67,7 @@ const MessagesWrapper = ({ updateRead = true, forceGetMessages }) => {
// test:
data.push(emailItem);
data.push(emailReItem);
// data.push(emailReItem);
setMsgLoading(false);
receivedMessageList(item.sn, data);
@ -140,18 +140,20 @@ const MessagesWrapper = ({ updateRead = true, forceGetMessages }) => {
const [openEmailEditor, setOpenEmailEditor] = useState(false);
const [fromEmail, setFromEmail] = useState('');
const [ReferEmailMsg, setReferEmailMsg] = useState('');
const onOpenEditor = (emailOrigin) => {
const { replyToEmail: email_addr, content } = emailOrigin;
const onOpenEditor = (emailMsgContent) => {
const { from } = emailMsgContent; // msgtext
console.log('emailMsgContent', emailMsgContent);
setOpenEmailEditor(true);
setFromEmail(email_addr);
setReferEmailMsg(emailOrigin);
setFromEmail(from);
setReferEmailMsg(emailMsgContent);
};
const [openEmailDetail, setOpenEmailDetail] = useState(false);
const [emailDetail, setEmailDetail] = useState({});
const onOpenEmail = (email_detail) => {
const onOpenEmail = (emailMsg) => {
setOpenEmailDetail(true);
setEmailDetail(email_detail);
setEmailDetail(emailMsg);
}
return (

Loading…
Cancel
Save