feat: add plain html email template editor
This commit is contained in:
parent
4afd544c41
commit
b467e7002d
1079
dashboard/package-lock.json
generated
1079
dashboard/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -29,6 +29,10 @@ import {
|
||||||
Tbody,
|
Tbody,
|
||||||
Td,
|
Td,
|
||||||
Code,
|
Code,
|
||||||
|
Radio,
|
||||||
|
RadioGroup,
|
||||||
|
Stack,
|
||||||
|
Textarea,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { FaPlus, FaAngleDown, FaAngleUp } from 'react-icons/fa';
|
import { FaPlus, FaAngleDown, FaAngleUp } from 'react-icons/fa';
|
||||||
import { useClient } from 'urql';
|
import { useClient } from 'urql';
|
||||||
|
@ -38,6 +42,7 @@ import {
|
||||||
EmailTemplateInputDataFields,
|
EmailTemplateInputDataFields,
|
||||||
emailTemplateEventNames,
|
emailTemplateEventNames,
|
||||||
emailTemplateVariables,
|
emailTemplateVariables,
|
||||||
|
EmailTemplateEditors,
|
||||||
} from '../constants';
|
} from '../constants';
|
||||||
import { capitalizeFirstLetter } from '../utils';
|
import { capitalizeFirstLetter } from '../utils';
|
||||||
import { AddEmailTemplate, EditEmailTemplate } from '../graphql/mutation';
|
import { AddEmailTemplate, EditEmailTemplate } from '../graphql/mutation';
|
||||||
|
@ -66,6 +71,8 @@ interface templateVariableDataTypes {
|
||||||
interface emailTemplateDataType {
|
interface emailTemplateDataType {
|
||||||
[EmailTemplateInputDataFields.EVENT_NAME]: string;
|
[EmailTemplateInputDataFields.EVENT_NAME]: string;
|
||||||
[EmailTemplateInputDataFields.SUBJECT]: string;
|
[EmailTemplateInputDataFields.SUBJECT]: string;
|
||||||
|
[EmailTemplateInputDataFields.TEMPLATE]: string;
|
||||||
|
[EmailTemplateInputDataFields.DESIGN]: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface validatorDataType {
|
interface validatorDataType {
|
||||||
|
@ -75,6 +82,8 @@ interface validatorDataType {
|
||||||
const initTemplateData: emailTemplateDataType = {
|
const initTemplateData: emailTemplateDataType = {
|
||||||
[EmailTemplateInputDataFields.EVENT_NAME]: emailTemplateEventNames.Signup,
|
[EmailTemplateInputDataFields.EVENT_NAME]: emailTemplateEventNames.Signup,
|
||||||
[EmailTemplateInputDataFields.SUBJECT]: '',
|
[EmailTemplateInputDataFields.SUBJECT]: '',
|
||||||
|
[EmailTemplateInputDataFields.TEMPLATE]: '',
|
||||||
|
[EmailTemplateInputDataFields.DESIGN]: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
const initTemplateValidatorData: validatorDataType = {
|
const initTemplateValidatorData: validatorDataType = {
|
||||||
|
@ -91,6 +100,9 @@ const UpdateEmailTemplate = ({
|
||||||
const emailEditorRef = useRef(null);
|
const emailEditorRef = useRef(null);
|
||||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
const [loading, setLoading] = useState<boolean>(false);
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
|
const [editor, setEditor] = useState<string>(
|
||||||
|
EmailTemplateEditors.PLAIN_HTML_EDITOR,
|
||||||
|
);
|
||||||
const [templateVariables, setTemplateVariables] = useState<
|
const [templateVariables, setTemplateVariables] = useState<
|
||||||
templateVariableDataTypes[]
|
templateVariableDataTypes[]
|
||||||
>([]);
|
>([]);
|
||||||
|
@ -107,9 +119,11 @@ const UpdateEmailTemplate = ({
|
||||||
if (selectedTemplate) {
|
if (selectedTemplate) {
|
||||||
const { design } = selectedTemplate;
|
const { design } = selectedTemplate;
|
||||||
try {
|
try {
|
||||||
|
if (design) {
|
||||||
const designData = JSON.parse(design);
|
const designData = JSON.parse(design);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
emailEditorRef.current.editor.loadDesign(designData);
|
emailEditorRef.current.editor.loadDesign(designData);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
onClose();
|
onClose();
|
||||||
|
@ -136,24 +150,7 @@ const UpdateEmailTemplate = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveData = async () => {
|
const updateTemplate = async (params: emailTemplateDataType) => {
|
||||||
if (!validateData()) return;
|
|
||||||
setLoading(true);
|
|
||||||
// @ts-ignore
|
|
||||||
return await emailEditorRef.current.editor.exportHtml(async (data) => {
|
|
||||||
const { design, html } = data;
|
|
||||||
if (!html || !design) {
|
|
||||||
setLoading(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const params = {
|
|
||||||
[EmailTemplateInputDataFields.EVENT_NAME]:
|
|
||||||
templateData[EmailTemplateInputDataFields.EVENT_NAME],
|
|
||||||
[EmailTemplateInputDataFields.SUBJECT]:
|
|
||||||
templateData[EmailTemplateInputDataFields.SUBJECT],
|
|
||||||
[EmailTemplateInputDataFields.TEMPLATE]: html.trim(),
|
|
||||||
[EmailTemplateInputDataFields.DESIGN]: JSON.stringify(design),
|
|
||||||
};
|
|
||||||
let res: any = {};
|
let res: any = {};
|
||||||
if (
|
if (
|
||||||
view === UpdateModalViews.Edit &&
|
view === UpdateModalViews.Edit &&
|
||||||
|
@ -197,9 +194,41 @@ const UpdateEmailTemplate = ({
|
||||||
setValidator({ ...initTemplateValidatorData });
|
setValidator({ ...initTemplateValidatorData });
|
||||||
fetchEmailTemplatesData();
|
fetchEmailTemplatesData();
|
||||||
}
|
}
|
||||||
view === UpdateModalViews.ADD && onClose();
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const saveData = async () => {
|
||||||
|
if (!validateData()) return;
|
||||||
|
setLoading(true);
|
||||||
|
let params: emailTemplateDataType = {
|
||||||
|
[EmailTemplateInputDataFields.EVENT_NAME]:
|
||||||
|
templateData[EmailTemplateInputDataFields.EVENT_NAME],
|
||||||
|
[EmailTemplateInputDataFields.SUBJECT]:
|
||||||
|
templateData[EmailTemplateInputDataFields.SUBJECT],
|
||||||
|
[EmailTemplateInputDataFields.TEMPLATE]:
|
||||||
|
templateData[EmailTemplateInputDataFields.TEMPLATE],
|
||||||
|
[EmailTemplateInputDataFields.DESIGN]: '',
|
||||||
|
};
|
||||||
|
if (editor === EmailTemplateEditors.UNLAYER_EDITOR) {
|
||||||
|
// @ts-ignore
|
||||||
|
await emailEditorRef.current.editor.exportHtml(async (data) => {
|
||||||
|
const { design, html } = data;
|
||||||
|
if (!html || !design) {
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
params = {
|
||||||
|
...params,
|
||||||
|
[EmailTemplateInputDataFields.TEMPLATE]: html.trim(),
|
||||||
|
[EmailTemplateInputDataFields.DESIGN]: JSON.stringify(design),
|
||||||
|
};
|
||||||
|
await updateTemplate(params);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await updateTemplate(params);
|
||||||
|
}
|
||||||
|
view === UpdateModalViews.ADD && onClose();
|
||||||
|
};
|
||||||
|
|
||||||
const resetData = () => {
|
const resetData = () => {
|
||||||
if (selectedTemplate) {
|
if (selectedTemplate) {
|
||||||
setTemplateData(selectedTemplate);
|
setTemplateData(selectedTemplate);
|
||||||
|
@ -207,6 +236,8 @@ const UpdateEmailTemplate = ({
|
||||||
setTemplateData({ ...initTemplateData });
|
setTemplateData({ ...initTemplateData });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// set template data if edit modal is open
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
isOpen &&
|
isOpen &&
|
||||||
|
@ -214,10 +245,12 @@ const UpdateEmailTemplate = ({
|
||||||
selectedTemplate &&
|
selectedTemplate &&
|
||||||
Object.keys(selectedTemplate || {}).length
|
Object.keys(selectedTemplate || {}).length
|
||||||
) {
|
) {
|
||||||
const { id, created_at, template, design, ...rest } = selectedTemplate;
|
const { id, created_at, ...rest } = selectedTemplate;
|
||||||
setTemplateData(rest);
|
setTemplateData(rest);
|
||||||
}
|
}
|
||||||
}, [isOpen]);
|
}, [isOpen]);
|
||||||
|
|
||||||
|
// set template variables
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const updatedTemplateVariables = Object.entries(
|
const updatedTemplateVariables = Object.entries(
|
||||||
emailTemplateVariables,
|
emailTemplateVariables,
|
||||||
|
@ -244,6 +277,51 @@ const UpdateEmailTemplate = ({
|
||||||
setTemplateVariables(updatedTemplateVariables);
|
setTemplateVariables(updatedTemplateVariables);
|
||||||
}, [templateData[EmailTemplateInputDataFields.EVENT_NAME]]);
|
}, [templateData[EmailTemplateInputDataFields.EVENT_NAME]]);
|
||||||
|
|
||||||
|
// change editor
|
||||||
|
useEffect(() => {
|
||||||
|
if (isOpen && selectedTemplate) {
|
||||||
|
const { design } = selectedTemplate;
|
||||||
|
if (design) {
|
||||||
|
setEditor(EmailTemplateEditors.UNLAYER_EDITOR);
|
||||||
|
} else {
|
||||||
|
setEditor(EmailTemplateEditors.PLAIN_HTML_EDITOR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [isOpen, selectedTemplate]);
|
||||||
|
|
||||||
|
// reset fields when editor is changed
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedTemplate?.design) {
|
||||||
|
if (editor === EmailTemplateEditors.UNLAYER_EDITOR) {
|
||||||
|
setTemplateData({
|
||||||
|
...templateData,
|
||||||
|
[EmailTemplateInputDataFields.TEMPLATE]: selectedTemplate.template,
|
||||||
|
[EmailTemplateInputDataFields.DESIGN]: selectedTemplate.design,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setTemplateData({
|
||||||
|
...templateData,
|
||||||
|
[EmailTemplateInputDataFields.TEMPLATE]: '',
|
||||||
|
[EmailTemplateInputDataFields.DESIGN]: '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (selectedTemplate?.template) {
|
||||||
|
if (editor === EmailTemplateEditors.UNLAYER_EDITOR) {
|
||||||
|
setTemplateData({
|
||||||
|
...templateData,
|
||||||
|
[EmailTemplateInputDataFields.TEMPLATE]: '',
|
||||||
|
[EmailTemplateInputDataFields.DESIGN]: '',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setTemplateData({
|
||||||
|
...templateData,
|
||||||
|
[EmailTemplateInputDataFields.TEMPLATE]: selectedTemplate?.template,
|
||||||
|
[EmailTemplateInputDataFields.DESIGN]: '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [editor]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{view === UpdateModalViews.ADD ? (
|
{view === UpdateModalViews.ADD ? (
|
||||||
|
@ -414,7 +492,22 @@ const UpdateEmailTemplate = ({
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
marginBottom="2%"
|
marginBottom="2%"
|
||||||
>
|
>
|
||||||
Template Body
|
<Flex flex="1">Template Body</Flex>
|
||||||
|
<Flex flex="3">
|
||||||
|
<RadioGroup
|
||||||
|
onChange={(value) => setEditor(value)}
|
||||||
|
value={editor}
|
||||||
|
>
|
||||||
|
<Stack direction="row" spacing="50px">
|
||||||
|
<Radio value={EmailTemplateEditors.PLAIN_HTML_EDITOR}>
|
||||||
|
Plain HTML
|
||||||
|
</Radio>
|
||||||
|
<Radio value={EmailTemplateEditors.UNLAYER_EDITOR}>
|
||||||
|
Unlayer Editor
|
||||||
|
</Radio>
|
||||||
|
</Stack>
|
||||||
|
</RadioGroup>
|
||||||
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex
|
<Flex
|
||||||
width="100%"
|
width="100%"
|
||||||
|
@ -423,7 +516,22 @@ const UpdateEmailTemplate = ({
|
||||||
border="1px solid"
|
border="1px solid"
|
||||||
borderColor="gray.200"
|
borderColor="gray.200"
|
||||||
>
|
>
|
||||||
|
{editor === EmailTemplateEditors.UNLAYER_EDITOR ? (
|
||||||
<EmailEditor ref={emailEditorRef} onReady={onReady} />
|
<EmailEditor ref={emailEditorRef} onReady={onReady} />
|
||||||
|
) : (
|
||||||
|
<Textarea
|
||||||
|
value={templateData.template}
|
||||||
|
onChange={(e) => {
|
||||||
|
setTemplateData({
|
||||||
|
...templateData,
|
||||||
|
[EmailTemplateInputDataFields.TEMPLATE]: e.target.value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
placeholder="Template HTML"
|
||||||
|
border="0"
|
||||||
|
height="500px"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
|
|
|
@ -337,3 +337,8 @@ export const webhookPayloadExample: string = `{
|
||||||
},
|
},
|
||||||
"auth_recipe":"google"
|
"auth_recipe":"google"
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
|
export enum EmailTemplateEditors {
|
||||||
|
UNLAYER_EDITOR = 'unlayer_editor',
|
||||||
|
PLAIN_HTML_EDITOR = 'plain_html_editor',
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user