Merge branch 'main' of github.com:hainatravel/global-sales

2.0/email-builder
Jimmy Liow 10 months ago
commit 86ba6da2b7

@ -1,4 +1,4 @@
import { cloneDeep, isEmpty, olog, fixTo2Decimals } from "@/utils/commons";
import { cloneDeep, isEmpty, olog, fixTo2Decimals, pick } from "@/utils/commons";
import dayjs from "dayjs";
import { v4 as uuid } from "uuid";
@ -282,7 +282,8 @@ const emailMsgMapped = {
'email.inbound.received': {
getMsg: (result) => {
console.log('email.inbound.received', result);
return isEmpty(result?.emailMessage) ? null : { ...result.emailMessage, conversationid: result.conversationid, };
const data1 = pick(result, ['conversationid', 'opi_sn', 'coli_sn', 'coli_id']);
return isEmpty(result?.emailMessage) ? null : { ...result.emailMessage, ...data1, };
},
contentToRender: (contentObj) => {
// console.log('email.inbound.received to render', contentObj);
@ -295,7 +296,8 @@ const emailMsgMapped = {
getMsg: (result) => {
console.log('email.updated', result);
const { emailMessage } = result;
return isEmpty(result?.emailMessage) ? null : { ...emailMessage, conversationid: result.conversationid, };
const data1 = pick(result, ['conversationid', 'opi_sn', 'coli_sn', 'coli_id']);
return isEmpty(result?.emailMessage) ? null : { ...emailMessage, ...data1, };
},
contentToRender: (contentObj) => null,
contentToUpdate: (msgcontent) => ({
@ -398,24 +400,24 @@ export const whatsappMsgTypeMapped = {
},
text: {
type: 'text',
data: (msg) => ({ id: msg.wamid, text: autoLinkText(msg?.text?.body), originText: msg?.text?.body, title: msg?.customerProfile?.name || '' }),
data: (msg) => ({ id: msg.wamid, text: autoLinkText(msg?.text?.body), originText: msg?.text?.body, title: msg?.customerProfile?.name || msg?.from || '' }),
renderForReply: (msg) => ({ id: msg.wamid, message: msg?.text?.body }),
},
image: {
type: 'photo',
data: (msg) => ({
id: msg.wamid,
text: msg.image.caption,
text: msg.image?.caption,
onPhotoError: ({ currentTarget }) => {
currentTarget.onerror = null;
currentTarget.src="https://hiana-crm.oss-accelerate.aliyuncs.com/WAMedia/afe412d4-3acf-4e79-a623-048aeb4d696a.png";
},
data: {
id: msg.wamid,
uri: msg.image.link,
uri: msg.image?.link,
width: 'auto',
height: 200,
alt: msg.image.caption || '',
alt: msg.image?.caption || '',
status: {
click: true,
loading: 0,
@ -426,7 +428,7 @@ export const whatsappMsgTypeMapped = {
}),
renderForReply: (msg) => ({
id: msg.wamid,
photoURL: msg.image.link,
photoURL: msg.image?.link,
width: 'auto',
height: 200,
alt: msg.image?.caption || '',
@ -439,7 +441,7 @@ export const whatsappMsgTypeMapped = {
id: msg.wamid,
data: {
id: msg.wamid,
uri: msg.sticker.link,
uri: msg.sticker?.link,
width: '100%',
height: 120,
alt: '',
@ -602,8 +604,7 @@ export const parseRenderMessageItem = (msg) => {
dateString: dayjs(msg?.sendTime || msg.createTime).format('MM-DD HH:mm'),
from: msg.from,
sender: msg.from,
senderName: msg?.customerProfile?.name || msg?.fromName || msg?.from || 'me', // msg.from,
// title: msg.customerProfile.name,
senderName: msg?.customerProfile?.name || msg?.fromName || msg?.from || 'me',
customer_name: msg?.customerProfile?.name || '',
whatsapp_name: msg?.customerProfile?.name || '',
whatsapp_phone_number: isEmpty(msg?.customerProfile) ? msg.to : msg.from,
@ -665,23 +666,20 @@ export const parseRenderMessageList = (messages) => {
}
return {
...msg,
msgOrigin: {...msgContent, ...msgContent.email},
msgOrigin: { ...msgContent, ...msgContent.email },
...(whatsappMsgTypeMapped?.[msgType]?.data(msgContent) || {}),
type: msgContent.type,
...(typeof whatsappMsgTypeMapped[msgType].type === 'function' ? whatsappMsgTypeMapped[msgType].type(msg) : { type: whatsappMsgTypeMapped[msgType].type || 'text' }),
date: msgContent?.sendTime || msg.msgtime || '',
dateText: dayjs(msgContent?.sendTime || msg.msgtime).format('MM-DD HH:mm'),
dateString: dayjs(msgContent?.sendTime || msg.msgtime).format('MM-DD HH:mm'),
date: msg.msgtime, // msgContent?.sendTime || msg.msgtime || '',
dateText: dayjs(msg.msgtime).format('MM-DD HH:mm'),
dateString: dayjs(msg.msgtime).format('MM-DD HH:mm'),
localDate: (msg.msgtime || '').replace('T', ' '),
from: msgContent.from,
sender: msgContent.from,
senderName: msgContent?.customerProfile?.name || 'me', // msgContent.from,
senderName: msgContent?.customerProfile?.name || msgContent.from || 'me',
replyButton: ['text', 'document', 'image', 'email'].includes(msgContent.type) && (msgContent?.status || '') !== 'failed',
// 用forwarded表示Resend, 与Reply互斥
forwarded: msg.msg_direction === 'outbound'
&& msg.msg_source === 'email'
&& ['email'].includes(msgContent.type)
&& (msgContent?.status || 'failed') === 'failed',
forwarded: msg.msg_direction === 'outbound' && msg.msg_source === 'email' && ['email'].includes(msgContent.type) && (msgContent?.status || 'failed') === 'failed',
...(msg.msg_direction === 'outbound'
? {
sender: 'me',
@ -704,7 +702,7 @@ export const parseRenderMessageList = (messages) => {
? whatsappMsgTypeMapped[messageorigin?.type || 'unsupported'].renderForReply(messageorigin)
: {}),
// titleColor: messageorigin?.customerProfile?.name ? '#a791ff' : '#128c7e',
titleColor: msg.messageorigin_direction === 'inbound' ? '#a791ff' : "#128c7e",
titleColor: msg.messageorigin_direction === 'inbound' ? '#a791ff' : '#128c7e',
id: msgContent.context?.id || msgContent.context?.message_id || msgContent.reaction?.message_id || messageorigin?.wamid,
},
origin: messageorigin,

@ -51,10 +51,10 @@ const DnDModal = ({ children, open, setOpen, onCancel, onMove, onResize, initial
footerClassName='!p-2'
className={`!rounded-t !rounded-b-none !border !border-solid !shadow-heavy ${props.rootClassName}`}
zIndex={2}
initialWidth={(mobile ? window.innerWidth : (initial.width || 680))} // window.innerWidth < 680
initialHeight={(mobile ? window.innerHeight : (initial.height || 600))} // window.innerHeight < 700
initialTop={mobile ? 0 : (initial.top || 74)}
initialLeft={mobile ? 0 : (initial.left || (window.innerWidth - 700))}
initialWidth={(mobile ? window.innerWidth : (initial.width ?? 680))} // window.innerWidth < 680
initialHeight={(mobile ? window.innerHeight : (initial.height ?? 600))} // window.innerHeight < 700
initialTop={mobile ? 0 : (initial.top ?? 74)}
initialLeft={mobile ? 0 : (initial.left ?? (window.innerWidth - 700))}
title={title}
minimizeButton={<></>}
onMove={onHandleMove}
@ -63,6 +63,7 @@ const DnDModal = ({ children, open, setOpen, onCancel, onMove, onResize, initial
// onOk={onHandleOk}
onStageChange={onStageChange}
footer={footer}
{...props}
{...(mobile ? { maximizeButton: <></> } : {})}>
<>{children}</>
</Modal>

@ -4,7 +4,7 @@ import { Input, Button, Empty, Tooltip, List } from 'antd';
import { PlusOutlined, LoadingOutlined, HistoryOutlined, FireOutlined,AudioTwoTone } from '@ant-design/icons';
import { fetchConversationsList, fetchOrderConversationsList, CONVERSATION_PAGE_SIZE } from '@/actions/ConversationActions';
import ConversationsNewItem from './ConversationsNewItem';
import { debounce, isEmpty, isNotEmpty, pick } from '@/utils/commons';
import { debounce, flush, isEmpty, isNotEmpty, pick } from '@/utils/commons';
import useConversationStore from '@/stores/ConversationStore';
import useAuthStore from '@/stores/AuthStore';
import { useVisibilityState } from '@/hooks/useVisibilityState';
@ -76,8 +76,10 @@ const Conversations = () => {
} else {
addToConversationList(_list, 'next');
}
const pageTimeArr = flush(_list.map(item => item.lasttime));
const _lasttime = pageTimeArr.pop()
setFilter({
lastpagetime: _list.length > 0 ? _list[_list.length - 1].lasttime : '',
lastpagetime: _lasttime || '',
loadNextPage: !(_list.length === 0 || _list.length < CONVERSATION_PAGE_SIZE),
// ...((_list.length === 0 || _list.length < CONVERSATION_PAGE_SIZE) ? {
// lastactivetime: dayjs(filterState.lastactivetime).subtract(6, 'months').format(DATETIME_FORMAT),

@ -13,6 +13,8 @@ export const ConversationItemForm = ({ initialValues, onFormInstanceReady }) =>
const [formatPhone, setFormatPhone] = useState('');
const [formatVisible, setFormatVisible] = useState(false);
const [contactValidateStatus, setContactValidateStatus] = useState('success');
useEffect(() => {
onFormInstanceReady(form);
setFormatPhone(phoneNumberToWAID(initialValues.phone_number || ''));
@ -29,42 +31,45 @@ export const ConversationItemForm = ({ initialValues, onFormInstanceReady }) =>
setFormatPhone(_t);
setFormatVisible(_t !== changeValues.phone_number);
}
setContactValidateStatus((isEmpty(allValues.email) && isEmpty(allValues.phone_number) )? 'error' : 'success');
};
return (
<Form layout='horizontal' form={form} name='form_in_modal' initialValues={{ ...fromCurrent, ...initialValues, wa_id: formatPhone }} onValuesChange={onValuesChange} labelCol={{span: 4}} labelWrap={true} >
{/* {!initialValues.is_current_order && ( */}
<Form.Item name={'name'} label='名称' rules={[{ required: true, message: '请输入联系人名称' },]} >
<Input placeholder='请输入联系人名称' />
</Form.Item>
{/* )} */}
<Form.Item name={'remark'} label='备注' rules={[{type: 'string', max: 500, message: '备注最多500字' }]}>
<Form
layout='horizontal'
form={form}
name='form_in_modal'
initialValues={{ ...fromCurrent, ...initialValues, wa_id: formatPhone }}
onValuesChange={onValuesChange}
labelCol={{ span: 4 }}
labelWrap={true}>
<Form.Item name={'name'} label='名称' rules={[{ required: true, message: '请输入联系人名称' }]}>
<Input placeholder='请输入联系人名称' />
</Form.Item>
<Form.Item name={'remark'} label='备注' rules={[{ type: 'string', max: 500, message: '备注最多500字' }]}>
<Input />
</Form.Item>
<Form.Item
name={'phone_number'}
label='手机'
validateStatus={formatVisible ? 'warning' : undefined}
validateStatus={contactValidateStatus === 'success' ? (formatVisible ? 'warning' : undefined) : contactValidateStatus}
help={formatVisible ? `WhatsApp格式: ${formatPhone}` : undefined}
rules={[{ required: true, message: '请输入联系人手机号' }]}>
rules={[{ required: false, message: '请输入联系人手机号' }]}>
<Input placeholder='请输入联系人手机号' disabled={!initialValues.is_new && isNotEmpty(initialValues.phone_number)} />
</Form.Item>
<Form.Item label='WhatsApp' name={'wa_id'} dependencies={['phone_number']} >
<Form.Item label='WhatsApp' name={'wa_id'} dependencies={['phone_number']}>
<Input disabled={!initialValues.is_new && isNotEmpty(initialValues.wa_id)} />
</Form.Item>
{/* <Form.Item name={'phone'} label=''>
<Input />
</Form.Item> */}
<Form.Item name={'email'} label='邮箱' rules={[{ type: 'email', message: '请输入正确的邮箱地址' }]}>
<Form.Item
name={'email'}
label='邮箱'
validateStatus={contactValidateStatus}
help={contactValidateStatus === 'success' ? '' : '手机号或邮箱至少输入一个, 否则无法发送消息'}
rules={[{ type: 'email', message: '请输入正确的邮箱地址' }]}>
<Input disabled={!initialValues.is_new && isNotEmpty(initialValues.email)} />
</Form.Item>
{initialValues.is_current_order && (
<>
<Form.Item
name={'coli_id'}
label={'关联当前订单'}
rules={[{ required: true, message: '关联的订单' }]}
validateStatus='warning'
help='请务必确认关联的订单是否正确'>
<Form.Item name={'coli_id'} label={'关联当前订单'} rules={[{ required: true, message: '关联的订单' }]} validateStatus='warning' help='请务必确认关联的订单是否正确'>
<Input placeholder='请先关联订单' disabled={initialValues.is_current_order} />
</Form.Item>
<Form.Item name={'coli_sn'} label='订单SN' hidden={initialValues.is_current_order} rules={[{ required: true, message: '订单SN' }]}>
@ -74,7 +79,7 @@ export const ConversationItemForm = ({ initialValues, onFormInstanceReady }) =>
)}
{/* <div className=' text-neutral-500 italic'>如果会话已存在, 将直接切换</div> */}
</Form>
);
)
};
/**
* 新建会话弹窗

@ -143,7 +143,7 @@ const EmailEditorPopup = ({ open, setOpen, fromEmail, fromUser, toEmail, convers
const [htmlContent, setHtmlContent] = useState('');
const [textContent, setTextContent] = useState('');
const [showCc, setShowCc] = useState(false);
const [showCc, setShowCc] = useState(true);
const [showBcc, setShowBcc] = useState(false);
const handleShowCc = () => {
setShowCc(true);
@ -174,7 +174,8 @@ const EmailEditorPopup = ({ open, setOpen, fromEmail, fromUser, toEmail, convers
return () => {};
}
const { info, } = mailData
setShowCc(!isEmpty(mailData.info?.MAI_CS));
// setShowCc(!isEmpty(mailData.info?.MAI_CS));
setShowCc(true);
const preQuoteBody = generateQuoteContent(mailData);
@ -372,7 +373,10 @@ const EmailEditorPopup = ({ open, setOpen, fromEmail, fromUser, toEmail, convers
rootClassName='email-editor-wrapper !border-indigo-300 '
open={open}
setOpen={setOpen}
initial={{ top: isEmpty(quoteid) ? 20 : 74 }}
// initial={{ top: isEmpty(quoteid) ? 20 : 74 }}
initial={{ width: window.innerWidth-40, height: window.innerHeight-40, left: 20, top: 20 }}
maximizeButton={<></>}
initialStage={'FULLSCREEN'}
onCancel={() => {
form.resetFields();
}}

Loading…
Cancel
Save