You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Global-sales/src/views/Conversations/Online/Input/EmailEditorPopup.jsx

336 lines
12 KiB
React

import { createContext, useEffect, useState } from 'react';
import { ConfigProvider, Button, Form, Input, Flex, Checkbox, Switch, Mentions, Popover, Popconfirm, Select, Space, Upload, Divider } from 'antd';
import { DashOutlined, EllipsisOutlined, MenuOutlined, MoreOutlined, UploadOutlined } from '@ant-design/icons';
import Modal from '@dckj/react-better-modal';
import '@dckj/react-better-modal/dist/index.css';
import DnDModal from '@/components/DndModal';
import useStyleStore from '@/stores/StyleStore';
import LexicalEditor from '@/components/LexicalEditor';
import { isEmpty } from '@/utils/commons';
import './EmailEditor.css';
const getAbstract = (longtext) => {
const lines = longtext.split('\n');
const firstLine = lines[0];
const abstract = firstLine.substring(0, 20);
return abstract;
};
const EmailEditorPopup = ({ open, setOpen, fromEmail, reference, quote = {}, initial = {}, action = 'reply', ...props }) => {
const [mobile] = useStyleStore((state) => [state.mobile]);
const [form] = Form.useForm();
const [isRichText, setIsRichText] = useState(mobile === false);
// const [isRichText, setIsRichText] = useState(false); // 默认纯文本
const [htmlContent, setHtmlContent] = useState('');
const [textContent, setTextContent] = useState('');
const [showCc, setShowCc] = useState(false);
const [showBcc, setShowBcc] = useState(false);
const handleShowCc = () => {
setShowCc(true);
};
const handleShowBcc = () => {
setShowBcc(true);
};
const handleEditorChange = ({ editorState, html, textContent }) => {
// console.log('textContent', textContent);
// console.log('html', html);
setHtmlContent(html);
setTextContent(textContent);
form.setFieldValue('content', html);
form.setFieldValue('abstract', getAbstract(textContent));
};
const onHandleSend = () => {
console.log('onSend callback', '\nisRichText', isRichText);
// console.log(form.getFieldsValue());
const body = structuredClone(form.getFieldsValue());
body.content = isRichText ? htmlContent : textContent;
body.fromEmail = newFromEmail || fromEmail;
console.log('body', body);
form.validateFields().then((values) => {
form.resetFields();
});
// .catch((err) => {})
// setOpen(false);
};
const [newFromEmail, setNewFromEmail] = useState('');
const [initialForm, setInitialForm] = useState({});
const [initialContent, setInitialContent] = useState('');
useEffect(() => {
if (isEmpty(quote)) {
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 preQuoteBody = `<br><br>
<hr>
<p>
<b>
<strong >From: </strong>
</b>
<span >${quote.fromName} &lt;${quote.fromEmail}&gt;</span>
</p>
<p>
<b>
<strong >Sent: </strong>
</b>
<span >${quote.sent}</span>
</p>
<p>
<b>
<strong >To: </strong>
</b>
<span >${quote.toName} &lt;${quote.toEmail}&gt;</span>
</p>
<p>
<b>
<strong >Subject: </strong>
</b>
<span >${subject}</span>
</p>
<p>
${content}
</p>
`;
// <blockquote class="editor-quote">
// </blockquote>
setInitialContent(preQuoteBody);
const _formValues = {
to: replyToEmail || fromEmail,
cc: quote.cc,
subject: `Re: ${subject}`,
};
const forwardValues = { subject: `Fw: ${subject}` };
if (action === 'reply') {
form.setFieldsValue(_formValues);
setInitialForm(_formValues);
} else if (action === 'forward') {
form.setFieldsValue(forwardValues);
setInitialForm(forwardValues);
}
return () => {};
}, [quote, open]);
const [openPlainTextConfirm, setOpenPlainTextConfirm] = useState(false);
const handlePlainTextOpenChange = ({ target }) => {
const { checked: newChecked } = target;
if (!newChecked) {
setIsRichText(true);
setOpenPlainTextConfirm(false);
return;
}
setOpenPlainTextConfirm(true);
};
const confirmPlainText = () => {
setIsRichText(false);
setOpenPlainTextConfirm(false);
};
// todo: 附件:
// 1. 直接上传返回地址
// 2. 发送文件信息
const [fileList, setFileList] = useState([]);
const handleChange = (info) => {
let newFileList = [...info.fileList];
// 2. Read from response and show file link
newFileList = newFileList.map((file) => {
if (file.response) {
// Component will show file.url as link
file.url = file.response.url;
}
return file;
});
setFileList(newFileList);
};
const normFile = (e) => {
console.log('Upload event:', e);
if (Array.isArray(e)) {
return e;
}
return e?.fileList;
};
const uploadProps = {
action: 'https://660d2bd96ddfa2943b33731c.mockapi.io/api/upload',
// onChange: handleChange,
// multiple: true,
};
return (
<>
<ConfigProvider theme={{ token: { colorPrimary: '#6366f1' } }}>
<DnDModal
rootClassName='email-editor-wrapper !border-indigo-300 '
open={open}
setOpen={setOpen}
initial={{ top: isEmpty(reference) ? 20 : 74 }}
onCancel={() => {
form.resetFields();
}}
title={initialForm.subject || `${reference ? '回复: ' : '写邮件: '} ${fromEmail || ''}`}
footer={
<div className='w-full flex gap-6 justify-start items-center text-indigo-600'>
11 months ago
<Button type='primary' onClick={onHandleSend}>
发送
</Button>
11 months ago
<Popconfirm description='切换内容为纯文本格式将丢失信件核签名的格式, 确定使用纯文本?' onConfirm={confirmPlainText} open={openPlainTextConfirm} onCancel={() => setOpenPlainTextConfirm(false)}>
<Checkbox checked={!isRichText} onChange={handlePlainTextOpenChange}>
纯文本
</Checkbox>
</Popconfirm>
<Select
options={[
{ key: 'lyt@hainatravel.com', value: 'lyt@hainatravel.com', label: 'LYT <lyt@hainatravel.com>' },
{ key: 'XXX@chinahighlights.com', value: 'XXX@chinahighlights.com', label: 'XXX <XXX@chinahighlights.com>' },
]}
value={newFromEmail || fromEmail}
onChange={(val) => setNewFromEmail(val)}
variant={'borderless'}
/>
</div>
}>
<Form
form={form}
preserve={false}
name='conversation_filter_form'
size='small'
layout={'inline'}
variant={'borderless'}
initialValues={{}}
// onFinish={() => {}}
className='email-editor-wrapper *:mb-2 *:border-b *:border-t-0 *:border-x-0 *:border-indigo-100 *:border-solid '
requiredMark={false}
// labelCol={{ span: 3 }}
>
<Form.Item label='收件人' name={'to'} rules={[{ required: true }]} className='w-full'>
{/* <Space.Compact className='w-full'> */}
<Flex justify='space-between'>
<Mentions // todo:
split='; '
options={[
{ value: 'lyt@hainatravel.com', label: 'OT' },
{ value: 'zombieJ', label: 'zombieJ' },
{ value: 'yesmeck', label: 'yesmeck' },
]}
placeholder='@'
/>
<Flex gap={4}>
{!showCc && (
<Button type='text' onClick={handleShowCc}>
Cc
</Button>
)}
{!showBcc && (
<Button type='text' hidden={showBcc} onClick={handleShowBcc}>
Bcc
</Button>
)}
</Flex>
</Flex>
{/* </Space.Compact> */}
{/* <Input
addonAfter={
<Flex gap={4}>
{!showCc && (
<Button type='text' onClick={handleShowCc}>
Cc
</Button>
)}
{!showBcc && (
<Button type='text' hidden={showBcc} onClick={handleShowBcc}>
Bcc
</Button>
)}
</Flex>
}
/> */}
</Form.Item>
<Form.Item label='抄送' name={'cc'} hidden={!showCc} className='w-full pt-1'>
<Input />
</Form.Item>
<Form.Item label='密送' name={'bcc'} hidden={!showBcc} className='w-full pt-1'>
<Input />
</Form.Item>
<Form.Item label='主题' name={'subject'} rules={[{ required: true }]} className='w-full pt-1'>
<Input />
</Form.Item>
<Form.Item
name='upload'
label=''
className='w-full py-1 border-b-0'
valuePropName='fileList'
getValueFromEvent={normFile}
>
<Flex justify='space-between'>
<Upload {...uploadProps} name='file' className='w-full' >
<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 name='content' hidden>
<Input />
</Form.Item>
<Form.Item name='abstract' hidden>
<Input />
</Form.Item>
</Form>
<LexicalEditor {...{ isRichText }} onChange={handleEditorChange} initialValue={initialContent} />
</DnDModal>
</ConfigProvider>
</>
);
};
export default EmailEditorPopup;