UNPKG

strapi-plugin-email-designer-v5

Version:
949 lines (948 loc) 39.1 kB
import { jsxs, Fragment, jsx } from "react/jsx-runtime"; import { useNotification, getFetchClient, Page as Page$1 } from "@strapi/strapi/admin"; import { useNavigate, useParams, Routes, Route } from "react-router-dom"; import { Page, useNotification as useNotification$1, Layouts } from "@strapi/admin/strapi-admin"; import { Button, Dialog, IconButton, Box, Field, Tabs, Textarea, Table, Thead, Tr, Th, Typography, VisuallyHidden, Tbody, Td, Flex, Loader, EmptyStateLayout, TFooter, Tooltip, Divider } from "@strapi/design-system"; import { CloudUpload, ArrowLeft, Pencil, Download, Plus, Trash, Duplicate } from "@strapi/icons"; import { isEmpty } from "lodash"; import { useRef, useState, memo, useCallback, useEffect, StrictMode } from "react"; import { EmailEditor } from "react-email-editor"; import striptags from "striptags"; import styled from "styled-components"; import destr, { destr as destr$1 } from "destr"; import { useIntl } from "react-intl"; import { P as PLUGIN_ID, p as pluginName } from "./index-B7YsXhSw.mjs"; import dayjs from "dayjs"; import { EmptyPictures } from "@strapi/icons/symbols"; import { BsFiletypeHtml, BsFiletypeJson } from "react-icons/bs"; import { FaHashtag } from "react-icons/fa6"; import { LuCopyCheck } from "react-icons/lu"; const getTranslation = (id) => `${PLUGIN_ID}.${id}`; const useTr = () => { const { formatMessage } = useIntl(); return (key) => formatMessage({ id: getTranslation(key) }); }; const ImportSingleDesign = ({ emailEditorRef }) => { const translate = useTr(); const { toggleNotification } = useNotification(); const hiddenInput = useRef(null); const [showModal, setShowModal] = useState(false); const [template, setTemplate] = useState(); const handleFileChange = (event) => { if (!event) return; const files = event.target.files; if (!files || files.length === 0) return; const file = files[0]; if (!file) return; const fr = new FileReader(); fr.onload = async () => { setTemplate(destr(fr.result)); setShowModal(true); if (hiddenInput.current) hiddenInput.current.value = ""; }; fr.readAsText(file); }; const handleLoadSingleDesign = () => { if (emailEditorRef?.current) { try { emailEditorRef.current?.editor?.loadDesign(template); toggleNotification({ type: "success", title: translate("success"), message: translate("success.single.message") }); } catch (error) { toggleNotification({ type: "danger", title: translate("error"), message: error.message }); } } }; return /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx( "input", { type: "file", multiple: false, onChange: handleFileChange, accept: ".json", hidden: true, ref: hiddenInput } ), /* @__PURE__ */ jsx( Button, { startIcon: /* @__PURE__ */ jsx(CloudUpload, {}), onClick: () => hiddenInput.current?.click(), style: { marginTop: "19px", height: "38px", width: "100%" }, variant: "tertiary", children: translate("import") } ), /* @__PURE__ */ jsx( Dialog.Root, { open: showModal, onOpenChange: () => { setShowModal((s) => !s); }, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [ /* @__PURE__ */ jsx(Dialog.Header, { children: translate("confirm.title") }), /* @__PURE__ */ jsx(Dialog.Body, { children: translate("confirm.singleImport") }), /* @__PURE__ */ jsxs(Dialog.Footer, { children: [ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { fullWidth: true, variant: "tertiary", children: translate("cancel") }) }), /* @__PURE__ */ jsx(Dialog.Action, { children: /* @__PURE__ */ jsx(Button, { onClick: () => handleLoadSingleDesign(), fullWidth: true, variant: "success-light", children: translate("confirm") }) }) ] }) ] }) } ) ] }); }; const getUrl = (to) => to ? `/plugins/${PLUGIN_ID}/${to}` : `/plugins/${PLUGIN_ID}`; const standardEmailRegistrationTemplate = { counters: { u_row: 2, u_content_text: 1, u_content_image: 1, u_column: 2 }, body: { values: { backgroundColor: "#ffffff", linkStyle: { body: true, linkHoverColor: "#0000ee", linkHoverUnderline: true, linkColor: "#0000ee", linkUnderline: true }, contentWidth: "500px", backgroundImage: { repeat: false, center: true, fullWidth: true, url: "", cover: false }, contentAlign: "center", textColor: "#000000", _meta: { htmlID: "u_body", htmlClassNames: "u_body" }, fontFamily: { label: "Arial", value: "arial,helvetica,sans-serif" }, preheaderText: "" }, rows: [ { cells: [1], values: { backgroundImage: { cover: false, url: "", repeat: false, fullWidth: true, center: true }, hideDesktop: false, selectable: true, columnsBackgroundColor: "", hideable: true, backgroundColor: "", padding: "0px", columns: false, _meta: { htmlID: "u_row_2", htmlClassNames: "u_row" }, deletable: true, displayCondition: null, duplicatable: true, draggable: true }, columns: [ { contents: [ { values: { hideDesktop: false, duplicatable: true, deletable: true, linkStyle: { linkHoverUnderline: true, linkColor: "#0000ee", inherit: true, linkUnderline: true, linkHoverColor: "#0000ee" }, hideable: true, lineHeight: "140%", draggable: true, containerPadding: "10px", text: '<p style="font-size: 14px; line-height: 140%; text-align: center;"><span style="font-size: 14px; line-height: 19.6px;">__PLACEHOLDER__</span></p>', _meta: { htmlID: "u_content_text_1", htmlClassNames: "u_content_text" }, textAlign: "left", selectable: true }, type: "text" } ], values: { border: {}, _meta: { htmlClassNames: "u_column", htmlID: "u_column_2" }, backgroundColor: "", padding: "0px" } } ] } ] }, schemaVersion: 6 }; const { post, get, del } = getFetchClient(); const DATE_FORMAT = "MMM DD, YYYY [at] h:mmA"; const getTemplatesData = async () => { const { data } = await get(`/${pluginName}/templates`); data.forEach((template) => { template.createdAt = dayjs(template.createdAt).format(DATE_FORMAT); template.updatedAt = dayjs(template.updatedAt).format(DATE_FORMAT); }); return data; }; const getFullEditorConfig = async () => { const { data } = await get(`/${pluginName}/config`); return data; }; const getTemplateById = async (id) => { const { data } = await get(`/${pluginName}/templates/${id}`); return data; }; const getCoreTemplate = async (coreEmailType) => { const { data } = await get(`/${pluginName}/core/${coreEmailType}`); return data; }; const createTemplate = async (templateId, data) => { const { data: response } = await post(`/${pluginName}/templates/${templateId}`, data); return response; }; const updateCoreTemplate = async (coreEmailType, data) => { const { data: response } = await post(`/${pluginName}/core/${coreEmailType}`, data); return response; }; const duplicateTemplate = async (id) => { const { data } = await post(`/${pluginName}/templates/duplicate/${id}`); return data; }; const deleteTemplate = async (id) => { await del(`/${pluginName}/templates/${id}`); }; const downloadTemplate = async (id, type) => { const { data } = await get(`/${pluginName}/download/${id}`, { params: { type }, headers: { Accept: "application/octet-stream" } }); const blob = new Blob([data], { type: type === "json" ? "application/json" : "text/html" }); const downloadUrl = window.URL.createObjectURL(blob); const link = document.createElement("a"); link.href = downloadUrl; const fileName = `template-${id}.${type}`; link.setAttribute("download", fileName); document.body.appendChild(link); link.click(); link.remove(); window.URL.revokeObjectURL(downloadUrl); }; const __DEV__ = process.env.NODE_ENV === "development"; function shallowIsEqual(object1, object2) { const keys1 = Object.keys(object1); const keys2 = Object.keys(object2); if (keys1.length !== keys2.length) { if (__DEV__) console.log("shallowIsEqual: keys1.length !== keys2.length"); return false; } for (const key of keys1) { if (object1[key] !== object2[key]) { if (__DEV__) console.log(`shallowIsEqual: ${key}`, object1[key], " !== ", object2[key]); return false; } } return true; } const DesignerContainer = styled.div` padding: 18px 30px; min-height: 100vh; display: flex; flex-direction: column; gap: 10px; `; const Header = styled.div` display: flex; flex-shrink: 0; width: 100%; height: 60px; align-items: center; gap: 10px; `; const Designer = ({ isCore = false }) => { const emailEditorRef = useRef(null); const navigate = useNavigate(); const translate = useTr(); const { templateId, coreEmailType } = useParams(); const [templateData, setTemplateData] = useState(); const [errorRefId, setErrorRefId] = useState(""); const [bodyText, setBodyText] = useState(""); const [mode, setMode] = useState("html"); const [serverConfigLoaded, setServerConfigLoaded] = useState(false); const [editorOptions, setEditorOptions] = useState(); const { toggleNotification } = useNotification(); const saveDesign = async () => { if (!coreEmailType && !templateData?.templateReferenceId) { toggleNotification({ type: "danger", title: translate("error.noReferenceId.title"), message: translate("error.noReferenceId.message") }); setErrorRefId("Required"); return; } setErrorRefId(""); let design, html, response; try { await new Promise((resolve) => { emailEditorRef.current?.editor?.exportHtml((data) => { ({ design, html } = data); resolve(); }); }); } catch (error) { console.log(error); return; } try { if (templateId) { response = await createTemplate(templateId, { name: templateData?.name || translate("noName"), templateReferenceId: templateData?.templateReferenceId, subject: templateData?.subject || "", design, bodyText, bodyHtml: html }); } else if (coreEmailType) { response = await updateCoreTemplate(coreEmailType, { subject: templateData?.subject || "", design, message: html, bodyText }); } toggleNotification({ type: "success", title: translate("success"), message: translate("success.message") }); if (templateId === "new") navigate(`/plugins/${PLUGIN_ID}/design/${response?.id}`); } catch (err) { console.error(err); const errorMessage = err?.response?.data?.error?.message; if (errorMessage) { toggleNotification({ type: "danger", title: translate("error"), message: errorMessage }); } else { toggleNotification({ type: "danger", title: translate("error"), message: errorMessage }); } } }; const onLoadHandler = useCallback(() => { setTimeout(() => { if (templateData) emailEditorRef.current?.editor?.loadDesign(templateData.design); }, 500); }, []); const init = async () => { if (!templateId && !coreEmailType || coreEmailType && !["user-address-confirmation", "reset-password"].includes(coreEmailType) || templateId === "new") return; let _templateData = {}; if (templateId) { _templateData = await getTemplateById(templateId); } else if (coreEmailType) { _templateData = await getCoreTemplate(coreEmailType); } if (coreEmailType && isEmpty(_templateData.design)) { let _message = _templateData.message || ""; if (_templateData.message && _templateData.message.match(/\<body/)) { const parser = new DOMParser(); const parsedDocument = parser.parseFromString(_message, "text/html"); _message = parsedDocument.body.innerText; } _message = striptags(_message, ["a", "img", "strong", "b", "i", "%", "%="]).replace(/"/g, "'").replace(/<%|&#x3C;%/g, "{{").replace(/%>|%&#x3E;/g, "}}").replace(/\n/g, "<br />"); _templateData.design = JSON.parse( JSON.stringify(standardEmailRegistrationTemplate).replace("__PLACEHOLDER__", _message) ); } setTemplateData(_templateData); setBodyText(_templateData.bodyText || ""); }; useEffect(() => { getFullEditorConfig().then((config) => { setEditorOptions(config); setServerConfigLoaded(true); }); return () => { emailEditorRef.current?.editor?.destroy(); }; }, []); useEffect(() => { init(); }, [templateId, coreEmailType]); useEffect(() => { setTimeout(() => { if (emailEditorRef.current?.editor && templateData?.design) { emailEditorRef.current.editor.loadDesign(templateData.design); } }, 600); }, [templateData]); return /* @__PURE__ */ jsxs(Page.Main, { children: [ /* @__PURE__ */ jsx(Page.Title, { children: translate("page.design.title") }), /* @__PURE__ */ jsxs(DesignerContainer, { children: [ /* @__PURE__ */ jsxs(Header, { children: [ /* @__PURE__ */ jsx( IconButton, { style: { marginTop: "19px", padding: "10px" }, label: translate("goBack"), onClick: () => navigate({ pathname: getUrl() }), children: /* @__PURE__ */ jsx(ArrowLeft, {}) } ), !isCore && /* @__PURE__ */ jsx(Box, { style: { width: "100%", maxWidth: "150px" }, children: /* @__PURE__ */ jsxs(Field.Root, { required: true, error: errorRefId, children: [ /* @__PURE__ */ jsx(Field.Label, { children: translate("input.label.templateReferenceId") }), /* @__PURE__ */ jsx( Field.Input, { onChange: (e) => setTemplateData((state) => ({ ...state || {}, templateReferenceId: e.target.value === "" ? "" : isFinite(parseInt(e.target.value)) ? parseInt(e.target.value) : state?.templateReferenceId ?? "" })), value: templateData?.templateReferenceId ?? "", type: "number", placeholder: translate("input.placeholder.templateReferenceId") } ), /* @__PURE__ */ jsx(Field.Error, {}) ] }) }), /* @__PURE__ */ jsx(Box, { style: { width: "100%" }, children: /* @__PURE__ */ jsxs(Field.Root, { disabled: isCore, required: true, children: [ /* @__PURE__ */ jsx(Field.Label, { children: translate("input.label.templateName") }), /* @__PURE__ */ jsx( Field.Input, { disabled: isCore, value: isCore && coreEmailType ? translate(coreEmailType) : templateData?.name || "", onChange: (e) => { setTemplateData((state) => ({ ...state, name: e.target.value })); }, placeholder: translate("input.placeholder.templateName") } ), /* @__PURE__ */ jsx(Field.Error, {}) ] }) }), /* @__PURE__ */ jsx(Box, { style: { width: "100%" }, children: /* @__PURE__ */ jsxs(Field.Root, { required: true, children: [ /* @__PURE__ */ jsx(Field.Label, { children: translate("input.label.subject") }), /* @__PURE__ */ jsx( Field.Input, { onChange: (value) => { setTemplateData((state) => ({ ...state, subject: value.target.value })); }, value: templateData?.subject || "", placeholder: translate("input.placeholder.subject") } ), /* @__PURE__ */ jsx(Field.Error, {}) ] }) }), /* @__PURE__ */ jsx(Box, { style: { width: "100%", maxWidth: "100px" }, children: /* @__PURE__ */ jsx(ImportSingleDesign, { emailEditorRef }) }), /* @__PURE__ */ jsx(Box, { style: { width: "100%", maxWidth: "100px" }, children: /* @__PURE__ */ jsx(Button, { onClick: () => saveDesign(), style: { marginTop: "19px", height: "38px", width: "100%" }, children: translate("save") }) }) ] }), /* @__PURE__ */ jsx(Box, { style: { flex: 1, display: "flex", height: "calc(100dvh - 80px)" }, children: /* @__PURE__ */ jsxs( Tabs.Root, { value: mode, onValueChange: (selected) => { setMode(selected); if (selected === "html") { init(); } }, children: [ /* @__PURE__ */ jsxs(Tabs.List, { "aria-label": "Switch between the html and text design", children: [ /* @__PURE__ */ jsx(Tabs.Trigger, { value: "html", children: translate("designer.tab.html") }), /* @__PURE__ */ jsx(Tabs.Trigger, { value: "text", children: translate("designer.tab.text") }) ] }), /* @__PURE__ */ jsx(Tabs.Content, { style: { height: "calc(100vh - 160px)" }, value: "html", children: /* @__PURE__ */ jsx( Box, { style: { minHeight: "540px", height: "100%" }, children: serverConfigLoaded && /* @__PURE__ */ jsx(StrictMode, { children: /* @__PURE__ */ jsx( EmailEditor, { options: editorOptions, minHeight: "100%", ref: emailEditorRef, onLoad: onLoadHandler } ) }) } ) }), /* @__PURE__ */ jsx(Tabs.Content, { style: { height: "calc(100vh - 160px)", padding: "20px" }, value: "text", children: /* @__PURE__ */ jsx( Textarea, { onChange: (e) => setBodyText(e.target.value), value: bodyText, style: { resize: "vertical" } } ) }) ] } ) }) ] }) ] }); }; const Designer$1 = memo(Designer, shallowIsEqual); const CoreEmailTable = () => { const { formatMessage } = useIntl(); const navigate = useNavigate(); const headers = [ { name: formatMessage({ id: getTranslation("table.header.coreEmailType") }), value: "name" } ]; const coreEmailTypes = [ { coreEmailType: "user-address-confirmation", name: formatMessage({ id: getTranslation("emailTypes.user-address-confirmation") }) }, { coreEmailType: "reset-password", name: formatMessage({ id: getTranslation("emailTypes.reset-password") }) } ]; return /* @__PURE__ */ jsx(Box, { padding: 3, children: /* @__PURE__ */ jsxs(Table, { colCount: headers.length + 1, rowCount: coreEmailTypes.length, children: [ /* @__PURE__ */ jsx(Thead, { children: /* @__PURE__ */ jsxs(Tr, { children: [ headers.map((header) => /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { style: { fontWeight: "bold" }, variant: "sigma", children: header.name }) }, header.value)), /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(VisuallyHidden, { children: "Actions" }) }) ] }) }), /* @__PURE__ */ jsx(Tbody, { children: coreEmailTypes.map((coreEmailType, idx) => /* @__PURE__ */ jsxs(Tr, { children: [ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { style: { fontWeight: "bold" }, textColor: "neutral800", children: coreEmailType.name }) }), /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Flex, { justifyContent: "end", gap: "8px", children: /* @__PURE__ */ jsx( IconButton, { onClick: () => navigate({ pathname: getUrl(`core/${coreEmailType.coreEmailType}`) }), label: formatMessage({ id: getTranslation("table.action.edit") }), children: /* @__PURE__ */ jsx(Pencil, {}) } ) }) }) ] }, idx)) }) ] }) }); }; const GlobalLoader = ({ loading }) => { const { formatMessage } = useIntl(); return /* @__PURE__ */ jsx(Fragment, { children: loading && /* @__PURE__ */ jsxs( "div", { style: { position: "fixed", top: 0, left: 0, width: "100%", height: "100%", zIndex: 999, backgroundColor: "rgba(0, 0, 0, 0.4)", display: "flex", justifyContent: "center", alignItems: "center", flexDirection: "column", backdropFilter: "blur(5px)" }, children: [ /* @__PURE__ */ jsx(Loader, {}), /* @__PURE__ */ jsx(Typography, { variant: "beta", style: { marginTop: "20px" }, children: formatMessage({ id: getTranslation("pleaseWait") }) }) ] } ) }); }; const ImportExportActions = ({ data = [], reload, handleTemplatesExport }) => { const { formatMessage } = useIntl(); const { toggleNotification } = useNotification(); const emailTemplatesFileSelect = useRef(null); const [importConfirmationModal, setImportConfirmationModal] = useState(false); const [importedTemplates, setImportedTemplates] = useState([]); const [importLoading, setImportLoading] = useState(false); const handleFileChange = (event) => { if (!event) return; const files = event.target.files; if (!files || files.length === 0) return; const file = files[0]; if (!file) return; const fr = new FileReader(); fr.onload = async () => { const content = destr$1(fr.result); setImportedTemplates(content); setImportConfirmationModal(true); }; fr.readAsText(file); }; const handleTemplatesImport = async () => { try { setImportLoading(true); let _importedTemplates = []; for (const template of importedTemplates) { const response = await createTemplate(template.id, { ...template, createdAt: dayjs().toDate(), updatedAt: dayjs().toDate(), import: true }); if (!isEmpty(response)) _importedTemplates.push(response); } await reload(); toggleNotification({ type: "success", title: formatMessage({ id: getTranslation("success") }), message: formatMessage({ id: getTranslation("success.importingTemplates") }) }); } catch (error) { console.error("💬 :: handleTemplatesImport :: Error", error); toggleNotification({ type: "danger", title: formatMessage({ id: getTranslation("error") }), message: formatMessage({ id: getTranslation("error.importingTemplates") }) }); } finally { setImportConfirmationModal(false); setImportLoading(false); setImportedTemplates([]); } }; return /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx(GlobalLoader, { loading: importLoading }), /* @__PURE__ */ jsx( Dialog.Root, { open: importConfirmationModal, onOpenChange: () => { setImportConfirmationModal((s) => !s); if (emailTemplatesFileSelect.current) { emailTemplatesFileSelect.current.value = ""; } }, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [ /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({ id: getTranslation("confirm.title") }) }), /* @__PURE__ */ jsx(Dialog.Body, { icon: /* @__PURE__ */ jsx(CloudUpload, { width: 50, height: 50 }), children: formatMessage({ id: getTranslation("confirm.import.message") }) }), /* @__PURE__ */ jsxs(Dialog.Footer, { children: [ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { disabled: importLoading, fullWidth: true, variant: "tertiary", children: "Cancel" }) }), /* @__PURE__ */ jsx( Button, { loading: importLoading, disabled: importLoading, onClick: () => handleTemplatesImport(), fullWidth: true, variant: "success-light", children: "Yes, import" } ) ] }) ] }) } ), /* @__PURE__ */ jsxs(Flex, { style: { padding: "30px 0px 10px" }, gap: "14px", justifyContent: "end", children: [ data?.length > 0 && /* @__PURE__ */ jsx(Button, { onClick: () => handleTemplatesExport(), color: "success", startIcon: /* @__PURE__ */ jsx(Download, {}), children: formatMessage({ id: getTranslation("designer.exportTemplates") }) }), /* @__PURE__ */ jsx( Button, { onClick: () => { emailTemplatesFileSelect?.current?.click(); }, startIcon: /* @__PURE__ */ jsx(CloudUpload, {}), children: formatMessage({ id: getTranslation("designer.importTemplates") }) } ) ] }), /* @__PURE__ */ jsx("input", { accept: ".json", hidden: true, type: "file", ref: emailTemplatesFileSelect, onChange: handleFileChange }) ] }); }; const CustomEmailTable = ({ data = [], reload }) => { const { formatMessage } = useIntl(); const navigate = useNavigate(); const { toggleNotification } = useNotification(); const [duplicateConfirmationModal, setDuplicateConfirmationModal] = useState(false); const [duplicateId, setDuplicateId] = useState(); const [deleteId, setDeleteId] = useState(); const [showDeleteModal, setShowDeleteModal] = useState(false); const handleTemplateDuplication = useCallback(async () => { if (!duplicateId) return; try { const response = await duplicateTemplate(duplicateId); toggleNotification({ type: "success", title: formatMessage({ id: getTranslation("success") }), message: formatMessage({ id: getTranslation("success.duplicate") }) }); navigate({ pathname: getUrl(`design/${response.id}`) }); } catch (error) { toggleNotification({ type: "danger", title: formatMessage({ id: getTranslation("error") }), message: formatMessage({ id: getTranslation("error.duplicate") }) }); } }, [duplicateConfirmationModal]); const handleDelete = useCallback(async () => { if (!deleteId) return; try { await deleteTemplate(deleteId); await reload(); toggleNotification({ type: "success", title: formatMessage({ id: getTranslation("success") }), message: formatMessage({ id: getTranslation("success.delete") }) }); } catch (error) { toggleNotification({ type: "danger", title: formatMessage({ id: getTranslation("error") }), message: formatMessage({ id: getTranslation("error.delete") }) }); } }, [deleteId]); const handleTemplatesExport = async () => { const templates = await getTemplatesData(); const dataStr = `data:text/json;charset=utf-8,${encodeURIComponent(JSON.stringify(templates))}`; let a = document.createElement("a"); a.href = dataStr; a.download = `email_templates_${dayjs().unix()}.json`; a.click(); }; const emailTemplatesHeaders = [ { name: formatMessage({ id: getTranslation("table.header.name") }), value: "name" }, { name: formatMessage({ id: getTranslation("table.header.templateReferenceId") }), value: "templateReferenceId" }, { name: formatMessage({ id: getTranslation("table.header.createdAt") }), value: "createdAt" } ]; if (data.length === 0) { return /* @__PURE__ */ jsxs(Box, { padding: 8, children: [ /* @__PURE__ */ jsx( EmptyStateLayout, { shadow: "none", icon: /* @__PURE__ */ jsx(EmptyPictures, { width: "210px" }), content: formatMessage({ id: getTranslation("customTable.noDesigns") }), action: /* @__PURE__ */ jsx( Button, { variant: "secondary", startIcon: /* @__PURE__ */ jsx(Plus, {}), onClick: () => navigate({ pathname: getUrl(`design/new`) }), children: formatMessage({ id: getTranslation("customTable.addDesign") }) } ) } ), /* @__PURE__ */ jsx(ImportExportActions, { data, reload, handleTemplatesExport }) ] }); } return /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx( Dialog.Root, { open: duplicateConfirmationModal, onOpenChange: () => setDuplicateConfirmationModal((s) => !s), children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [ /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({ id: getTranslation("confirm.title") }) }), /* @__PURE__ */ jsx(Dialog.Body, { icon: /* @__PURE__ */ jsx(LuCopyCheck, { size: "30px" }), children: formatMessage({ id: getTranslation("confirm.duplicate.message") }) }), /* @__PURE__ */ jsxs(Dialog.Footer, { children: [ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { onClick: () => setDuplicateId(void 0), fullWidth: true, variant: "tertiary", children: "Cancel" }) }), /* @__PURE__ */ jsx(Dialog.Action, { children: /* @__PURE__ */ jsx(Button, { onClick: () => handleTemplateDuplication(), fullWidth: true, variant: "success-light", children: "Yes, duplicate" }) }) ] }) ] }) } ), /* @__PURE__ */ jsx(Dialog.Root, { open: showDeleteModal, onOpenChange: () => setShowDeleteModal((s) => !s), children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [ /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({ id: getTranslation("confirm.title") }) }), /* @__PURE__ */ jsx(Dialog.Body, { icon: /* @__PURE__ */ jsx(Trash, { width: "30px" }), children: formatMessage({ id: getTranslation("confirm.delete.message") }) }), /* @__PURE__ */ jsxs(Dialog.Footer, { children: [ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { onClick: () => setDeleteId(void 0), fullWidth: true, variant: "tertiary", children: "Cancel" }) }), /* @__PURE__ */ jsx(Dialog.Action, { children: /* @__PURE__ */ jsx(Button, { onClick: () => handleDelete(), fullWidth: true, variant: "danger-light", children: "Yes, delete" }) }) ] }) ] }) }), /* @__PURE__ */ jsxs(Box, { padding: 3, children: [ /* @__PURE__ */ jsxs( Table, { colCount: emailTemplatesHeaders.length + 1, rowCount: data.length, footer: /* @__PURE__ */ jsx( TFooter, { style: { cursor: "pointer" }, icon: /* @__PURE__ */ jsx(Plus, {}), onClick: () => navigate({ pathname: getUrl(`design/new`) }), children: formatMessage({ id: getTranslation("customTable.addDesign") }) } ), children: [ /* @__PURE__ */ jsx(Thead, { children: /* @__PURE__ */ jsxs(Tr, { children: [ emailTemplatesHeaders.map((header) => /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { style: { fontWeight: "bold" }, variant: "sigma", children: header.name }) }, header.name)), /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(VisuallyHidden, { children: "Actions" }) }) ] }) }), /* @__PURE__ */ jsx(Tbody, { children: data.map((entry, idx) => /* @__PURE__ */ jsxs(Tr, { children: [ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { style: { fontWeight: "bold" }, textColor: "neutral800", children: entry.name }) }), /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral800", children: entry.templateReferenceId }) }), /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral800", children: entry.createdAt }) }), /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsxs(Flex, { gap: "10px", justifyContent: "end", children: [ /* @__PURE__ */ jsx( IconButton, { label: formatMessage({ id: getTranslation("tooltip.edit") }), onClick: () => navigate({ pathname: getUrl(`design/${entry.id}`) }), children: /* @__PURE__ */ jsx(Pencil, {}) } ), /* @__PURE__ */ jsx( IconButton, { label: formatMessage({ id: getTranslation("tooltip.downloadHtml") }), onClick: () => downloadTemplate(entry.id, "html"), children: /* @__PURE__ */ jsx(BsFiletypeHtml, { size: 16 }) } ), /* @__PURE__ */ jsx( IconButton, { label: formatMessage({ id: getTranslation("tooltip.downloadDesign") }), onClick: () => downloadTemplate(entry.id, "json"), children: /* @__PURE__ */ jsx(BsFiletypeJson, { size: 16 }) } ), /* @__PURE__ */ jsx( IconButton, { label: formatMessage({ id: getTranslation("tooltip.duplicate") }), onClick: () => { setDuplicateId(entry.id); setDuplicateConfirmationModal(true); }, children: /* @__PURE__ */ jsx(Duplicate, {}) } ), /* @__PURE__ */ jsx( IconButton, { label: formatMessage({ id: getTranslation("tooltip.copyTemplateId") }), onClick: () => { navigator.clipboard.writeText(`${entry.templateReferenceId}`).then( () => { toggleNotification({ type: "success", title: formatMessage({ id: getTranslation("success") }), message: formatMessage({ id: getTranslation("success.copyTemplateId") }) }); }, (err) => { console.error("Could not copy text: ", err); } ); }, children: /* @__PURE__ */ jsx(FaHashtag, { size: 16 }) } ), /* @__PURE__ */ jsx(Box, { paddingLeft: 1, children: /* @__PURE__ */ jsx( IconButton, { label: formatMessage({ id: getTranslation("tooltip.delete") }), onClick: () => { setDeleteId(entry.id); setShowDeleteModal(true); }, children: /* @__PURE__ */ jsx(Trash, {}) } ) }) ] }) }) ] }, idx)) }) ] } ), /* @__PURE__ */ jsx(ImportExportActions, { data, reload, handleTemplatesExport }) ] }) ] }); }; const HomePage = () => { const navigate = useNavigate(); const translate = useTr(); const [emailTemplates, setEmailTemplates] = useState([]); const [activeTab, setActiveTab] = useState("customEmailTemplates"); const { toggleNotification } = useNotification$1(); const init = useCallback(async () => { const data = await getTemplatesData(); setEmailTemplates(data); }, []); useEffect(() => { init().catch(() => { toggleNotification({ type: "danger", title: translate("error"), message: translate("error.loadingTemplates") }); }); }, []); return /* @__PURE__ */ jsxs(Page.Main, { children: [ /* @__PURE__ */ jsx(Page.Title, { children: translate("page.title") }), /* @__PURE__ */ jsx( Layouts.Header, { id: "title", title: translate("page.title"), subtitle: translate("page.subTitle"), primaryAction: /* @__PURE__ */ jsx(Tooltip, { label: translate("page.home.cta.tooltip"), children: /* @__PURE__ */ jsx(Button, { onClick: () => navigate({ pathname: getUrl(`design/new`) }), children: translate("page.home.cta") }) }) } ), /* @__PURE__ */ jsxs(Layouts.Content, { children: [ /* @__PURE__ */ jsx(Divider, { style: { marginBottom: "50px" } }), /* @__PURE__ */ jsxs( Tabs.Root, { value: activeTab, onValueChange: (selected) => { setActiveTab(selected); }, children: [ /* @__PURE__ */ jsxs(Tabs.List, { "aria-label": "Switch between custom email designs & core email designs", children: [ /* @__PURE__ */ jsx(Tabs.Trigger, { value: "customEmailTemplates", children: translate("emailTypes.custom.tab.label") }), /* @__PURE__ */ jsx(Tabs.Trigger, { value: "coreEmailTemplates", children: translate("emailTypes.core.tab.label") }) ] }), /* @__PURE__ */ jsx( Tabs.Content, { style: { borderBottomRightRadius: "6px", borderBottomLeftRadius: "6px" }, value: "customEmailTemplates", children: /* @__PURE__ */ jsx(CustomEmailTable, { reload: init, data: emailTemplates }) } ), /* @__PURE__ */ jsx( Tabs.Content, { style: { borderBottomRightRadius: "6px", borderBottomLeftRadius: "6px" }, value: "coreEmailTemplates", children: /* @__PURE__ */ jsx(CoreEmailTable, {}) } ) ] } ), /* @__PURE__ */ jsx("div", { style: { paddingBottom: "20px" } }) ] }) ] }); }; const App = () => { return /* @__PURE__ */ jsxs(Routes, { children: [ /* @__PURE__ */ jsx(Route, { index: true, element: /* @__PURE__ */ jsx(HomePage, {}) }), /* @__PURE__ */ jsx(Route, { path: "design/:templateId", element: /* @__PURE__ */ jsx(Designer$1, {}) }), /* @__PURE__ */ jsx(Route, { path: "core/:coreEmailType", element: /* @__PURE__ */ jsx(Designer$1, { isCore: true }) }), /* @__PURE__ */ jsx(Route, { path: "*", element: /* @__PURE__ */ jsx(Page$1.Error, {}) }) ] }); }; export { App };