Email Improvements.
This commit is contained in:
@@ -10669,6 +10669,74 @@
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>fields</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>cc</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>subject</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>to</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>labels</name>
|
||||
<children>
|
||||
|
||||
@@ -1,68 +1,82 @@
|
||||
import { UploadOutlined } from "@ant-design/icons";
|
||||
import { Button, Card, Divider, Input, Select, Upload } from "antd";
|
||||
import { Card, Divider, Form, Input, Select, Upload } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function EmailOverlayComponent({
|
||||
messageOptions,
|
||||
handleConfigChange,
|
||||
handleToChange,
|
||||
handleHtmlChange,
|
||||
handleUpload,
|
||||
handleFileRemove,
|
||||
}) {
|
||||
export default function EmailOverlayComponent({ form }) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div>
|
||||
To:
|
||||
<Select
|
||||
<Form.Item
|
||||
label={t("emails.fields.to")}
|
||||
name="to"
|
||||
mode="tags"
|
||||
value={messageOptions.to}
|
||||
//style={{ width: "100%" }}
|
||||
onChange={handleToChange}
|
||||
tokenSeparators={[",", ";"]}
|
||||
/>
|
||||
CC:
|
||||
<Select
|
||||
value={messageOptions.cc}
|
||||
mode="tags"
|
||||
onChange={(value) => handleConfigChange("cc", value)}
|
||||
name="cc"
|
||||
tokenSeparators={[",", ";"]}
|
||||
/>
|
||||
Subject:
|
||||
<Input
|
||||
value={messageOptions.subject}
|
||||
onChange={(e) => handleConfigChange("subject", e.target.value)}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Select mode="tags" tokenSeparators={[",", ";"]} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("emails.fields.cc")} name="cc">
|
||||
<Select mode="tags" tokenSeparators={[",", ";"]} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("emails.fields.subject")}
|
||||
name="subject"
|
||||
/>
|
||||
<Divider>{t("emails.labels.preview")}</Divider>
|
||||
<div
|
||||
style={{
|
||||
padding: "1rem",
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
backgroundColor: "lightgray",
|
||||
borderLeft: "6px solid #2196F3",
|
||||
<Divider>{t("emails.labels.preview")}</Divider>
|
||||
<Form.Item shouldUpdate>
|
||||
{() => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
padding: "1rem",
|
||||
|
||||
backgroundColor: "lightgray",
|
||||
borderLeft: "6px solid #2196F3",
|
||||
}}
|
||||
dangerouslySetInnerHTML={{ __html: form.getFieldValue("html") }}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
dangerouslySetInnerHTML={{ __html: messageOptions.html }}
|
||||
/>
|
||||
<Divider>
|
||||
<Divider>{t("emails.labels.preview")}</Divider>
|
||||
</Divider>
|
||||
</Form.Item>
|
||||
|
||||
<Card title={t("emails.labels.attachments")}>
|
||||
<Upload
|
||||
fileList={messageOptions.fileList}
|
||||
beforeUpload={handleUpload}
|
||||
onRemove={handleFileRemove}
|
||||
multiple
|
||||
listType="picture-card"
|
||||
style={{ width: "100%" }}
|
||||
<Form.Item
|
||||
name="fileList"
|
||||
valuePropName="fileList"
|
||||
getValueFromEvent={(e) => {
|
||||
console.log("Upload event:", e);
|
||||
|
||||
if (Array.isArray(e)) {
|
||||
return e;
|
||||
}
|
||||
|
||||
return e && e.fileList;
|
||||
}}
|
||||
>
|
||||
<Button>
|
||||
<UploadOutlined /> Upload
|
||||
</Button>
|
||||
</Upload>
|
||||
<Upload.Dragger multiple listType="picture-card">
|
||||
<>
|
||||
<p className="ant-upload-drag-icon">
|
||||
<UploadOutlined />
|
||||
</p>
|
||||
<p className="ant-upload-text">
|
||||
Click or drag files to this area to upload.
|
||||
</p>
|
||||
</>
|
||||
</Upload.Dragger>
|
||||
</Form.Item>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Modal, notification } from "antd";
|
||||
import { Form, Modal, notification } from "antd";
|
||||
import axios from "axios";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -10,7 +10,10 @@ import {
|
||||
selectEmailConfig,
|
||||
selectEmailVisible,
|
||||
} from "../../redux/email/email.selectors.js";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import {
|
||||
selectBodyshop,
|
||||
selectCurrentUser,
|
||||
} from "../../redux/user/user.selectors";
|
||||
import RenderTemplate from "../../utils/RenderTemplate";
|
||||
import { EmailSettings } from "../../utils/TemplateConstants";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||
@@ -20,6 +23,7 @@ const mapStateToProps = createStructuredSelector({
|
||||
modalVisible: selectEmailVisible,
|
||||
emailConfig: selectEmailConfig,
|
||||
bodyshop: selectBodyshop,
|
||||
currentUser: selectCurrentUser,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
@@ -31,31 +35,27 @@ export function EmailOverlayContainer({
|
||||
modalVisible,
|
||||
toggleEmailOverlayVisible,
|
||||
bodyshop,
|
||||
currentUser,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [sending, setSending] = useState(false);
|
||||
const [rawHtml, setRawHtml] = useState("");
|
||||
const defaultEmailFrom = {
|
||||
from: {
|
||||
name: bodyshop.shopname || EmailSettings.fromNameDefault,
|
||||
name: `${currentUser.displayName} @ ${bodyshop.shopname}`,
|
||||
address: EmailSettings.fromAddress,
|
||||
},
|
||||
replyTo: bodyshop.email,
|
||||
ReplyTo: { Email: currentUser.email, Name: currentUser.displayName },
|
||||
};
|
||||
const [messageOptions, setMessageOptions] = useState({
|
||||
...defaultEmailFrom,
|
||||
html: "",
|
||||
fileList: [],
|
||||
});
|
||||
|
||||
const handleOk = async () => {
|
||||
const handleFinish = async (values) => {
|
||||
logImEXEvent("email_send_from_modal");
|
||||
|
||||
console.log(`values`, values);
|
||||
const attachments = [];
|
||||
|
||||
await asyncForEach(messageOptions.fileList, async (f) => {
|
||||
await asyncForEach(values.fileList, async (f) => {
|
||||
const t = {
|
||||
ContentType: f.type,
|
||||
Filename: f.name,
|
||||
@@ -67,7 +67,8 @@ export function EmailOverlayContainer({
|
||||
setSending(true);
|
||||
try {
|
||||
await axios.post("/sendemail", {
|
||||
...messageOptions,
|
||||
...defaultEmailFrom,
|
||||
...values,
|
||||
html: rawHtml,
|
||||
attachments,
|
||||
});
|
||||
@@ -82,34 +83,6 @@ export function EmailOverlayContainer({
|
||||
setSending(false);
|
||||
};
|
||||
|
||||
const handleConfigChange = (name, value) => {
|
||||
setMessageOptions({ ...messageOptions, [name]: value });
|
||||
};
|
||||
const handleHtmlChange = (text) => {
|
||||
setMessageOptions({ ...messageOptions, html: text });
|
||||
};
|
||||
const handleToChange = (recipients) => {
|
||||
setMessageOptions({ ...messageOptions, to: recipients });
|
||||
};
|
||||
|
||||
const handleUpload = (file) => {
|
||||
setMessageOptions({
|
||||
...messageOptions,
|
||||
fileList: [...messageOptions.fileList, file],
|
||||
});
|
||||
return false;
|
||||
};
|
||||
|
||||
const handleFileRemove = (file) => {
|
||||
setMessageOptions((state) => {
|
||||
const index = state.fileList.indexOf(file);
|
||||
const newfileList = state.fileList.slice();
|
||||
newfileList.splice(index, 1);
|
||||
return {
|
||||
fileList: newfileList,
|
||||
};
|
||||
});
|
||||
};
|
||||
const render = async () => {
|
||||
logImEXEvent("email_render_template", { template: emailConfig.template });
|
||||
setLoading(true);
|
||||
@@ -120,11 +93,9 @@ export function EmailOverlayContainer({
|
||||
url: `${window.location.protocol}://${window.location.host}/`,
|
||||
});
|
||||
setRawHtml(response.data);
|
||||
|
||||
console.log("response", response);
|
||||
setMessageOptions({
|
||||
form.setFieldsValue({
|
||||
...emailConfig.messageOptions,
|
||||
...defaultEmailFrom,
|
||||
|
||||
html: response.data,
|
||||
fileList: [],
|
||||
});
|
||||
@@ -140,29 +111,16 @@ export function EmailOverlayContainer({
|
||||
destroyOnClose={true}
|
||||
visible={modalVisible}
|
||||
width={"80%"}
|
||||
onOk={handleOk}
|
||||
onOk={() => form.submit()}
|
||||
onCancel={() => {
|
||||
toggleEmailOverlayVisible();
|
||||
}}
|
||||
okButtonProps={{ loading: sending }}
|
||||
>
|
||||
<LoadingSpinner loading={loading}>
|
||||
<EmailOverlayComponent
|
||||
handleConfigChange={handleConfigChange}
|
||||
messageOptions={messageOptions}
|
||||
handleHtmlChange={handleHtmlChange}
|
||||
handleUpload={handleUpload}
|
||||
handleFileRemove={handleFileRemove}
|
||||
handleToChange={handleToChange}
|
||||
/>
|
||||
<button
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(messageOptions.html);
|
||||
}}
|
||||
>
|
||||
Copy HTML
|
||||
</button>
|
||||
</LoadingSpinner>
|
||||
<Form layout="vertical" form={form} onFinish={handleFinish}>
|
||||
{loading && <LoadingSpinner />}
|
||||
<EmailOverlayComponent form={form} />
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -686,6 +686,11 @@
|
||||
"errors": {
|
||||
"notsent": "Email not sent. Error encountered while sending {{message}}"
|
||||
},
|
||||
"fields": {
|
||||
"cc": "CC",
|
||||
"subject": "Subject",
|
||||
"to": "To"
|
||||
},
|
||||
"labels": {
|
||||
"attachments": "Attachments",
|
||||
"preview": "Email Preview"
|
||||
|
||||
@@ -686,6 +686,11 @@
|
||||
"errors": {
|
||||
"notsent": "Correo electrónico no enviado Se encontró un error al enviar {{message}}"
|
||||
},
|
||||
"fields": {
|
||||
"cc": "",
|
||||
"subject": "",
|
||||
"to": ""
|
||||
},
|
||||
"labels": {
|
||||
"attachments": "",
|
||||
"preview": ""
|
||||
|
||||
@@ -686,6 +686,11 @@
|
||||
"errors": {
|
||||
"notsent": "Courriel non envoyé. Erreur rencontrée lors de l'envoi de {{message}}"
|
||||
},
|
||||
"fields": {
|
||||
"cc": "",
|
||||
"subject": "",
|
||||
"to": ""
|
||||
},
|
||||
"labels": {
|
||||
"attachments": "",
|
||||
"preview": ""
|
||||
|
||||
@@ -136,7 +136,12 @@ export const GenerateDocument = async (template, messageOptions, sendType) => {
|
||||
if (sendType === "e") {
|
||||
store.dispatch(
|
||||
setEmailOptions({
|
||||
messageOptions,
|
||||
messageOptions: {
|
||||
...messageOptions,
|
||||
to: Array.isArray(messageOptions.to)
|
||||
? messageOptions.to
|
||||
: [messageOptions.to],
|
||||
},
|
||||
template,
|
||||
})
|
||||
);
|
||||
|
||||
@@ -42,8 +42,8 @@ exports.sendEmail = async (req, res) => {
|
||||
return { Email: i };
|
||||
}),
|
||||
ReplyTo: {
|
||||
Email: req.body.from.address,
|
||||
Name: req.body.from.name,
|
||||
Email: req.body.ReplyTo.Email,
|
||||
Name: req.body.ReplyTo.Name,
|
||||
},
|
||||
Subject: req.body.subject,
|
||||
// TextPart:
|
||||
|
||||
Reference in New Issue
Block a user