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

2.0/email-builder
Jimmy Liow 11 months ago
commit e4d1508047

@ -46,10 +46,10 @@ const DnDModal = ({ children, open, setOpen, onCancel, onMove, onResize, initial
maskClosable={false} maskClosable={false}
// theme='dark' // theme='dark'
// className={'!border !border-solid !border-indigo-500 rounded !p-2' } // className={'!border !border-solid !border-indigo-500 rounded !p-2' }
className='!rounded-t !rounded-b-none !border !border-solid !border-indigo-300 !shadow-heavy '
titleBarClassName='!bg-neutral-100 !rounded !rounded-b-none !border-none !p-3 !font-bold !text-slate-600' titleBarClassName='!bg-neutral-100 !rounded !rounded-b-none !border-none !p-3 !font-bold !text-slate-600'
contentClassName='!p-2' contentClassName='!p-2'
footerClassName='!p-2' footerClassName='!p-2'
className={`!rounded-t !rounded-b-none !border !border-solid !shadow-heavy ${props.rootClassName}`}
zIndex={2} zIndex={2}
initialWidth={(mobile ? window.innerWidth : (initial.width || 680))} // window.innerWidth < 680 initialWidth={(mobile ? window.innerWidth : (initial.width || 680))} // window.innerWidth < 680
initialHeight={(mobile ? window.innerHeight : (initial.height || 600))} // window.innerHeight < 700 initialHeight={(mobile ? window.innerHeight : (initial.height || 600))} // window.innerHeight < 700

@ -79,7 +79,7 @@ function LexicalDefaultValuePlugin({ value = "" }= {}) {
if (clear) { if (clear) {
root.clear(); root.clear();
} }
console.log(nodes); // console.log(nodes);
const p = $createParagraphNode(); const p = $createParagraphNode();
const _p = nodes.filter(n => n).forEach((n) => { const _p = nodes.filter(n => n).forEach((n) => {

@ -46,7 +46,7 @@
text-align: center; text-align: center;
} */ } */
h1 { .email-editor-wrapper h1 {
font-size: 24px; font-size: 24px;
color: #333; color: #333;
} }
@ -357,7 +357,7 @@ pre::-webkit-scrollbar-thumb {
text-decoration: underline; text-decoration: underline;
} }
.emoji { .email-editor-wrapper .emoji {
color: transparent; color: transparent;
background-size: 16px 16px; background-size: 16px 16px;
background-position: center; background-position: center;

@ -18,7 +18,7 @@ const ChatboxEmail = ({ onOpenEditor, onOpenEmail, ...message }) => {
); );
}); });
const handlePreview = (message) => { const handlePreview = (message) => {
console.log('handlePreview'); // console.log('handlePreview');
if (typeof onOpenEmail === 'function') { if (typeof onOpenEmail === 'function') {
onOpenEmail(message); onOpenEmail(message);
} }

@ -4,11 +4,13 @@ import { ReplyIcon, ShareForwardIcon } from '@/components/Icons';
import { stringToColour } from '@/utils/commons'; import { stringToColour } from '@/utils/commons';
import EmailEditorPopup from '../Input/EmailEditorPopup'; import EmailEditorPopup from '../Input/EmailEditorPopup';
import DnDModal from '@/components/DndModal'; import DnDModal from '@/components/DndModal';
import useStyleStore from '@/stores/StyleStore';
const TagColorStyle = (tag) => { const TagColorStyle = (tag) => {
const color = stringToColour(tag); const color = stringToColour(tag);
return { color: `${color}`, borderColor: `${color}66`, backgroundColor: `${color}0D` }; return { color: `${color}`, borderColor: `${color}66`, backgroundColor: `${color}0D` };
}; };
const EmailDetail = ({ open, setOpen, emailDetail, ...props }) => { const EmailDetail = ({ open, setOpen, emailDetail, ...props }) => {
let { emailOrigin } = emailDetail; let { emailOrigin } = emailDetail;
emailOrigin = emailOrigin || {}; emailOrigin = emailOrigin || {};
@ -39,9 +41,38 @@ const EmailDetail = ({ open, setOpen, emailDetail, ...props }) => {
setOpen(false); setOpen(false);
}; };
const [mobile] = useStyleStore((state) => [state.mobile]);
return ( return (
<> <>
<DnDModal open={open} setOpen={setOpen} title={emailOrigin.subject} initial={{ top: 74 }} onMove={onHandleMove} onResize={onHandleResize}> <DnDModal
open={open}
setOpen={setOpen}
title={emailOrigin.subject}
initial={{ top: 74 }}
onMove={onHandleMove}
onResize={onHandleResize}
footer={
mobile ? (
<>
<div className='flex items-center w-full '>
<Button
onClick={() => onOpenEditor(emailOrigin, 'reply')}
size='small'
type='text'
icon={<ReplyIcon className='text-indigo-500' />}>
回复
</Button>
<Button
onClick={() => onOpenEditor(emailOrigin, 'forward')}
size='small'
type='text'
icon={<ShareForwardIcon className='text-primary' />}>
转发
</Button>
</div>
</>
) : null
}>
{/* email toolbar */} {/* email toolbar */}
<div className='email-container flex flex-col gap-2 *:p-2 *:rounded-sm *:border-b *:border-gray-200 *:shadow-1md'> <div className='email-container flex flex-col gap-2 *:p-2 *:rounded-sm *:border-b *:border-gray-200 *:shadow-1md'>
{/* <div className='flex items-center justify-start '> {/* <div className='flex items-center justify-start '>
@ -52,22 +83,40 @@ const EmailDetail = ({ open, setOpen, emailDetail, ...props }) => {
<div className=' font-bold'>{emailOrigin.subject}</div> <div className=' font-bold'>{emailOrigin.subject}</div>
<div> <div>
<div className={['flex justify-between', window.innerWidth < 600 ? 'flex-row' : 'flex-row'].join(' ')}> <div
className={[
'flex justify-between',
window.innerWidth < 600 ? 'flex-row' : 'flex-row',
].join(' ')}>
<div className='flex gap-2 mb-2 items-center'> <div className='flex gap-2 mb-2 items-center'>
<Avatar className='' style={TagColorStyle(emailOrigin.fromEmail)}> <Avatar
className=''
style={TagColorStyle(emailOrigin.fromEmail)}>
{(emailOrigin.fromName || '').substring(0, 1)} {(emailOrigin.fromName || '').substring(0, 1)}
</Avatar> </Avatar>
<div className=' flex flex-col'> <div className=' flex flex-col'>
<span className=' font-bold text-base'>{emailOrigin.fromName}</span> <span className=' font-bold text-base'>
<span className='text-neutral-500'>{emailOrigin.fromEmail}</span> {emailOrigin.fromName}
</span>
<span className='text-neutral-500'>
{emailOrigin.fromEmail}
</span>
</div> </div>
</div> </div>
<div className='flex flex-col justify-start gap-1 items-end'> <div className='flex flex-col justify-start gap-1 items-end'>
<div className='flex items-center '> <div className='flex items-center '>
<Button onClick={() => onOpenEditor(emailOrigin, 'reply')} size='small' type='text' icon={<ReplyIcon className='text-indigo-500' />}> <Button
onClick={() => onOpenEditor(emailOrigin, 'reply')}
size='small'
type='text'
icon={<ReplyIcon className='text-indigo-500' />}>
回复 回复
</Button> </Button>
<Button onClick={() => onOpenEditor(emailOrigin, 'forward')} size='small' type='text' icon={<ShareForwardIcon className='text-primary' />}> <Button
onClick={() => onOpenEditor(emailOrigin, 'forward')}
size='small'
type='text'
icon={<ShareForwardIcon className='text-primary' />}>
转发 转发
</Button> </Button>
</div> </div>
@ -78,7 +127,9 @@ const EmailDetail = ({ open, setOpen, emailDetail, ...props }) => {
<div className='text-sm'> <div className='text-sm'>
<span className='text-neutral-500 pr-2'>收件人:</span> <span className='text-neutral-500 pr-2'>收件人:</span>
{emailOrigin.toName} {emailOrigin.toName}
<span className='text-neutral-600'>&nbsp;&nbsp;&lt;{emailOrigin.toEmail}&gt;</span> <span className='text-neutral-600'>
&nbsp;&nbsp;&lt;{emailOrigin.toEmail}&gt;
</span>
</div> </div>
{emailOrigin.cc && ( {emailOrigin.cc && (
<div className='text-sm'> <div className='text-sm'>
@ -98,7 +149,9 @@ const EmailDetail = ({ open, setOpen, emailDetail, ...props }) => {
</div> */} </div> */}
<Divider className='my-2' /> <Divider className='my-2' />
{/* <div className='mt-2'>{emailOrigin.body}</div> */} {/* <div className='mt-2'>{emailOrigin.body}</div> */}
<div className='mt-2' dangerouslySetInnerHTML={{ __html: emailOrigin.content }}></div> <div
className='mt-2'
dangerouslySetInnerHTML={{ __html: emailOrigin.content }}></div>
{/* <div className='mt-2'>{emailOrigin.attachments.map(attachment => <div key={attachment.name}>{attachment.name}</div>)}</div> */} {/* <div className='mt-2'>{emailOrigin.attachments.map(attachment => <div key={attachment.name}>{attachment.name}</div>)}</div> */}
</div> </div>
</div> </div>
@ -113,6 +166,6 @@ const EmailDetail = ({ open, setOpen, emailDetail, ...props }) => {
key={`email-editor-inner-${action}-popup_${ReferEmailMsg.id}`} key={`email-editor-inner-${action}-popup_${ReferEmailMsg.id}`}
/> />
</> </>
); )
}; };
export default EmailDetail; export default EmailDetail;

@ -1,6 +1,7 @@
.email-editor-wrapper .ant-upload-list.ant-upload-list-text{ .email-editor-wrapper .ant-upload-list.ant-upload-list-text{
display: flex; display: flex;
gap: 8px; /* gap: 8px; */
flex-wrap: wrap;
} }
.email-editor-wrapper .ant-upload-list-item-container{ .email-editor-wrapper .ant-upload-list-item-container{
flex-basis: 200px; flex-basis: 200px;

@ -1,6 +1,6 @@
import { createContext, useEffect, useState } from 'react'; import { createContext, useEffect, useState } from 'react';
import { ConfigProvider, Button, Form, Input, Flex, Checkbox, Switch, Mentions, Popover, Popconfirm, Select, Space, Upload } from 'antd'; import { ConfigProvider, Button, Form, Input, Flex, Checkbox, Switch, Mentions, Popover, Popconfirm, Select, Space, Upload, Divider } from 'antd';
import { UploadOutlined } from '@ant-design/icons'; import { DashOutlined, EllipsisOutlined, MenuOutlined, MoreOutlined, UploadOutlined } from '@ant-design/icons';
import Modal from '@dckj/react-better-modal'; import Modal from '@dckj/react-better-modal';
import '@dckj/react-better-modal/dist/index.css'; import '@dckj/react-better-modal/dist/index.css';
import DnDModal from '@/components/DndModal'; import DnDModal from '@/components/DndModal';
@ -197,6 +197,7 @@ const EmailEditorPopup = ({ open, setOpen, fromEmail, reference, quote = {}, ini
<> <>
<ConfigProvider theme={{ token: { colorPrimary: '#6366f1' } }}> <ConfigProvider theme={{ token: { colorPrimary: '#6366f1' } }}>
<DnDModal <DnDModal
rootClassName='email-editor-wrapper !border-indigo-300 '
open={open} open={open}
setOpen={setOpen} setOpen={setOpen}
initial={{ top: isEmpty(reference) ? 20 : 74 }} initial={{ top: isEmpty(reference) ? 20 : 74 }}
@ -244,10 +245,11 @@ const EmailEditorPopup = ({ open, setOpen, fromEmail, reference, quote = {}, ini
<Mentions // todo: <Mentions // todo:
split='; ' split='; '
options={[ options={[
{ value: 'afc163', label: 'afc163' }, { value: 'lyt@hainatravel.com', label: 'OT' },
{ value: 'zombieJ', label: 'zombieJ' }, { value: 'zombieJ', label: 'zombieJ' },
{ value: 'yesmeck', label: 'yesmeck' }, { value: 'yesmeck', label: 'yesmeck' },
]} ]}
placeholder='@'
/> />
<Flex gap={4}> <Flex gap={4}>
{!showCc && ( {!showCc && (
@ -296,9 +298,26 @@ const EmailEditorPopup = ({ open, setOpen, fromEmail, reference, quote = {}, ini
valuePropName='fileList' valuePropName='fileList'
getValueFromEvent={normFile} getValueFromEvent={normFile}
> >
<Upload {...uploadProps} name='file' > <Flex justify='space-between'>
<Button icon={<UploadOutlined />}>附件</Button> <Upload {...uploadProps} name='file' className='w-full' >
</Upload> <Button icon={<UploadOutlined />}>附件</Button>
</Upload>
<Flex align={'center'} className='absolute right-0'>
{/* todo: 添加图文集、支付链接 */}
<Divider type='vertical' />
<Button type={'link'}>图文集</Button>
<Button type={'link'}>支付链接</Button>
{/* 更多工具 */}
{/* <Popover
content={
<div className='flex flex-col gap-2'>
<Button type={'link'}>??</Button>
</div>
}
trigger='click'
><MoreOutlined /></Popover> */}
</Flex>
</Flex>
</Form.Item> </Form.Item>
<Form.Item name='content' hidden> <Form.Item name='content' hidden>
<Input /> <Input />

@ -280,7 +280,7 @@ const InputComposer = ({ isWABA, channel }) => {
placeholder={ placeholder={
!talkabled !talkabled
? '请先选择会话' ? '请先选择会话'
: !textabled0 && isWABA : !textabled0 && channel==='waba'
? '会话已超24h不活跃. 请发送打招呼消息激活对话💬.' ? '会话已超24h不活跃. 请发送打招呼消息激活对话💬.'
: mobile === false : mobile === false
? 'Enter 发送, Shift+Enter 换行\n支持复制粘贴 [截图/文件] 以备发送' ? 'Enter 发送, Shift+Enter 换行\n支持复制粘贴 [截图/文件] 以备发送'
@ -301,7 +301,7 @@ const InputComposer = ({ isWABA, channel }) => {
/> />
<Flex justify={'space-between'} className=' bg-gray-200 p-1 rounded-b-0'> <Flex justify={'space-between'} className=' bg-gray-200 p-1 rounded-b-0'>
<Flex gap={4} className='*:text-primary *:rounded-none items-center'> <Flex gap={4} className='*:text-primary *:rounded-none items-center'>
{isWABA && <InputTemplate key='templates' disabled={!talkabled} invokeSendMessage={invokeSendMessage} />} {channel==='waba' && <InputTemplate key='templates' disabled={!talkabled} invokeSendMessage={invokeSendMessage} />}
<InputEmoji key='emoji' disabled={!textabled} inputEmoji={addEmoji} /> <InputEmoji key='emoji' disabled={!textabled} inputEmoji={addEmoji} />
<InputMediaUpload key={'addNewMedia'} disabled={!textabled} {...{ invokeUploadFileMessage, invokeSendUploadMessage }} /> <InputMediaUpload key={'addNewMedia'} disabled={!textabled} {...{ invokeUploadFileMessage, invokeSendUploadMessage }} />
{/* <Button type='text' className='' icon={<YoutubeOutlined />} size={'middle'} /> {/* <Button type='text' className='' icon={<YoutubeOutlined />} size={'middle'} />

@ -57,10 +57,11 @@ const ReplyWrapper = () => {
}, [activeMessages]); }, [activeMessages]);
const replyTypes = [ const replyTypes = [
{ key: 'waba', label: mobile ? '' : (<WABASwitcher />), icon: <WABIcon />, children: <InputComposer isWABA channel={'waba'} /> }, // { key: 'waba', label: mobile ? '' : (<WABASwitcher />), icon: <WABIcon />, children: <InputComposer channel={'waba'} /> },
// { key: 'waba', label: 'WABA-Global Highlights', icon: <WABIcon />, children: <InputComposer isWABA channel={'waba'} /> }, { key: 'waba', label: mobile ? '' : 'WABA-Global Highlights', icon: <WABIcon />, children: <InputComposer channel={'waba'} /> }, // todo:
{ key: 'email', label: mobile ? '' : 'Email', icon: <MailOutlined className='text-indigo-500' />, children: <EmailComposer /> }, { key: 'email', label: mobile ? '' : 'Email', icon: <MailOutlined className='text-indigo-500' />, children: <EmailComposer /> },
// { key: 'whatsapp', label: mobile ? '' : 'WhatsApp', icon: <WhatsAppOutlined className='text-whatsapp' />, children: <InputComposer channel={'whatsapp'} /> }, // { key: 'whatsapp', label: mobile ? '' : 'WhatsApp', icon: <WhatsAppOutlined className='text-whatsapp' />, children: <InputComposer channel={'whatsapp'} /> },
{ key: 'whatsapp', label: mobile ? '' : 'WhatsApp', icon: <WhatsAppOutlined className='text-whatsapp' />, children: <div className='p-2 py-4 text-center text-whatsapp bg-gray-200 rounded rounded-b-none border-gray-300 border-solid border border-b-0 border-x-0'>敬请期待</div> },
]; ];
return ( return (

@ -13,7 +13,7 @@ function Chat() {
return ( return (
<> <>
<Layout className='h-full chatwindow-wrapper mobilechat-wrapper' style={{ maxHeight: 'calc(100vh - 20px)', height: 'calc(100vh - 20px)', minWidth: '360px' }}> <Layout className='h-full chatwindow-wrapper mobilechat-wrapper' style={{ maxHeight: 'calc(100vh - 20px)', height: 'calc(100vh - 20px)', minWidth: '360px' }}>
<Header className=' px-2 ant-layout-sider-light ant-card h-auto flex justify-between gap-1 items-center'> <Header className=' px-2 ant-layout-sider-light bg-white ant-card h-auto flex justify-between gap-1 items-center'>
<Button type='text' icon={<MenuFoldOutlined />} onClick={() => navigate('/m/conversation')} className=' rounded-none rounded-l' /> <Button type='text' icon={<MenuFoldOutlined />} onClick={() => navigate('/m/conversation')} className=' rounded-none rounded-l' />
<MessagesHeader /> <MessagesHeader />
<Button type='text' icon={<MenuUnfoldOutlined />} onClick={() => navigate('/m/order')} className=' rounded-none rounded-r' /> <Button type='text' icon={<MenuUnfoldOutlined />} onClick={() => navigate('/m/order')} className=' rounded-none rounded-r' />

Loading…
Cancel
Save