UNPKG

strapi-plugin-email-designer-v5

Version:
954 lines (953 loc) 43.4 kB
"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const jsxRuntime = require("react/jsx-runtime"); const admin = require("@strapi/strapi/admin"); const reactRouterDom = require("react-router-dom"); const strapiAdmin = require("@strapi/admin/strapi-admin"); const designSystem = require("@strapi/design-system"); const icons = require("@strapi/icons"); const lodash = require("lodash"); const react = require("react"); const reactEmailEditor = require("react-email-editor"); const striptags = require("striptags"); const styled = require("styled-components"); const destr = require("destr"); const reactIntl = require("react-intl"); const index = require("./index-DSvb0BFI.js"); const dayjs = require("dayjs"); const symbols = require("@strapi/icons/symbols"); const bs = require("react-icons/bs"); const fa6 = require("react-icons/fa6"); const lu = require("react-icons/lu"); const _interopDefault = (e) => e && e.__esModule ? e : { default: e }; const striptags__default = /* @__PURE__ */ _interopDefault(striptags); const styled__default = /* @__PURE__ */ _interopDefault(styled); const destr__default = /* @__PURE__ */ _interopDefault(destr); const dayjs__default = /* @__PURE__ */ _interopDefault(dayjs); const getTranslation = (id) => `${index.PLUGIN_ID}.${id}`; const useTr = () => { const { formatMessage } = reactIntl.useIntl(); return (key) => formatMessage({ id: getTranslation(key) }); }; const ImportSingleDesign = ({ emailEditorRef }) => { const translate = useTr(); const { toggleNotification } = admin.useNotification(); const hiddenInput = react.useRef(null); const [showModal, setShowModal] = react.useState(false); const [template, setTemplate] = react.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__default.default(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__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [ /* @__PURE__ */ jsxRuntime.jsx( "input", { type: "file", multiple: false, onChange: handleFileChange, accept: ".json", hidden: true, ref: hiddenInput } ), /* @__PURE__ */ jsxRuntime.jsx( designSystem.Button, { startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.CloudUpload, {}), onClick: () => hiddenInput.current?.click(), style: { marginTop: "19px", height: "38px", width: "100%" }, variant: "tertiary", children: translate("import") } ), /* @__PURE__ */ jsxRuntime.jsx( designSystem.Dialog.Root, { open: showModal, onOpenChange: () => { setShowModal((s) => !s); }, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: translate("confirm.title") }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: translate("confirm.singleImport") }), /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { fullWidth: true, variant: "tertiary", children: translate("cancel") }) }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Action, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: () => handleLoadSingleDesign(), fullWidth: true, variant: "success-light", children: translate("confirm") }) }) ] }) ] }) } ) ] }); }; const getUrl = (to) => to ? `/plugins/${index.PLUGIN_ID}/${to}` : `/plugins/${index.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 } = admin.getFetchClient(); const DATE_FORMAT = "MMM DD, YYYY [at] h:mmA"; const getTemplatesData = async () => { const { data } = await get(`/${index.pluginName}/templates`); data.forEach((template) => { template.createdAt = dayjs__default.default(template.createdAt).format(DATE_FORMAT); template.updatedAt = dayjs__default.default(template.updatedAt).format(DATE_FORMAT); }); return data; }; const getFullEditorConfig = async () => { const { data } = await get(`/${index.pluginName}/config`); return data; }; const getTemplateById = async (id) => { const { data } = await get(`/${index.pluginName}/templates/${id}`); return data; }; const getCoreTemplate = async (coreEmailType) => { const { data } = await get(`/${index.pluginName}/core/${coreEmailType}`); return data; }; const createTemplate = async (templateId, data) => { const { data: response } = await post(`/${index.pluginName}/templates/${templateId}`, data); return response; }; const updateCoreTemplate = async (coreEmailType, data) => { const { data: response } = await post(`/${index.pluginName}/core/${coreEmailType}`, data); return response; }; const duplicateTemplate = async (id) => { const { data } = await post(`/${index.pluginName}/templates/duplicate/${id}`); return data; }; const deleteTemplate = async (id) => { await del(`/${index.pluginName}/templates/${id}`); }; const downloadTemplate = async (id, type) => { const { data } = await get(`/${index.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__default.default.div` padding: 18px 30px; min-height: 100vh; display: flex; flex-direction: column; gap: 10px; `; const Header = styled__default.default.div` display: flex; flex-shrink: 0; width: 100%; height: 60px; align-items: center; gap: 10px; `; const Designer = ({ isCore = false }) => { const emailEditorRef = react.useRef(null); const navigate = reactRouterDom.useNavigate(); const translate = useTr(); const { templateId, coreEmailType } = reactRouterDom.useParams(); const [templateData, setTemplateData] = react.useState(); const [errorRefId, setErrorRefId] = react.useState(""); const [bodyText, setBodyText] = react.useState(""); const [mode, setMode] = react.useState("html"); const [serverConfigLoaded, setServerConfigLoaded] = react.useState(false); const [editorOptions, setEditorOptions] = react.useState(); const { toggleNotification } = admin.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/${index.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 = react.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 && lodash.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__default.default(_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 || ""); }; react.useEffect(() => { getFullEditorConfig().then((config) => { setEditorOptions(config); setServerConfigLoaded(true); }); return () => { emailEditorRef.current?.editor?.destroy(); }; }, []); react.useEffect(() => { init(); }, [templateId, coreEmailType]); react.useEffect(() => { setTimeout(() => { if (emailEditorRef.current?.editor && templateData?.design) { emailEditorRef.current.editor.loadDesign(templateData.design); } }, 600); }, [templateData]); return /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Page.Main, { children: [ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Page.Title, { children: translate("page.design.title") }), /* @__PURE__ */ jsxRuntime.jsxs(DesignerContainer, { children: [ /* @__PURE__ */ jsxRuntime.jsxs(Header, { children: [ /* @__PURE__ */ jsxRuntime.jsx( designSystem.IconButton, { style: { marginTop: "19px", padding: "10px" }, label: translate("goBack"), onClick: () => navigate({ pathname: getUrl() }), children: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowLeft, {}) } ), !isCore && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: "100%", maxWidth: "150px" }, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { required: true, error: errorRefId, children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: translate("input.label.templateReferenceId") }), /* @__PURE__ */ jsxRuntime.jsx( designSystem.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__ */ jsxRuntime.jsx(designSystem.Field.Error, {}) ] }) }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { disabled: isCore, required: true, children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: translate("input.label.templateName") }), /* @__PURE__ */ jsxRuntime.jsx( designSystem.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__ */ jsxRuntime.jsx(designSystem.Field.Error, {}) ] }) }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { required: true, children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: translate("input.label.subject") }), /* @__PURE__ */ jsxRuntime.jsx( designSystem.Field.Input, { onChange: (value) => { setTemplateData((state) => ({ ...state, subject: value.target.value })); }, value: templateData?.subject || "", placeholder: translate("input.placeholder.subject") } ), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Error, {}) ] }) }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: "100%", maxWidth: "100px" }, children: /* @__PURE__ */ jsxRuntime.jsx(ImportSingleDesign, { emailEditorRef }) }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: "100%", maxWidth: "100px" }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: () => saveDesign(), style: { marginTop: "19px", height: "38px", width: "100%" }, children: translate("save") }) }) ] }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1, display: "flex", height: "calc(100dvh - 80px)" }, children: /* @__PURE__ */ jsxRuntime.jsxs( designSystem.Tabs.Root, { value: mode, onValueChange: (selected) => { setMode(selected); if (selected === "html") { init(); } }, children: [ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tabs.List, { "aria-label": "Switch between the html and text design", children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tabs.Trigger, { value: "html", children: translate("designer.tab.html") }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tabs.Trigger, { value: "text", children: translate("designer.tab.text") }) ] }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tabs.Content, { style: { height: "calc(100vh - 160px)" }, value: "html", children: /* @__PURE__ */ jsxRuntime.jsx( designSystem.Box, { style: { minHeight: "540px", height: "100%" }, children: serverConfigLoaded && /* @__PURE__ */ jsxRuntime.jsx(react.StrictMode, { children: /* @__PURE__ */ jsxRuntime.jsx( reactEmailEditor.EmailEditor, { options: editorOptions, minHeight: "100%", ref: emailEditorRef, onLoad: onLoadHandler } ) }) } ) }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tabs.Content, { style: { height: "calc(100vh - 160px)", padding: "20px" }, value: "text", children: /* @__PURE__ */ jsxRuntime.jsx( designSystem.Textarea, { onChange: (e) => setBodyText(e.target.value), value: bodyText, style: { resize: "vertical" } } ) }) ] } ) }) ] }) ] }); }; const Designer$1 = react.memo(Designer, shallowIsEqual); const CoreEmailTable = () => { const { formatMessage } = reactIntl.useIntl(); const navigate = reactRouterDom.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__ */ jsxRuntime.jsx(designSystem.Box, { padding: 3, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Table, { colCount: headers.length + 1, rowCount: coreEmailTypes.length, children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Thead, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [ headers.map((header) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { style: { fontWeight: "bold" }, variant: "sigma", children: header.name }) }, header.value)), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { children: "Actions" }) }) ] }) }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: coreEmailTypes.map((coreEmailType, idx) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { style: { fontWeight: "bold" }, textColor: "neutral800", children: coreEmailType.name }) }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "end", gap: "8px", children: /* @__PURE__ */ jsxRuntime.jsx( designSystem.IconButton, { onClick: () => navigate({ pathname: getUrl(`core/${coreEmailType.coreEmailType}`) }), label: formatMessage({ id: getTranslation("table.action.edit") }), children: /* @__PURE__ */ jsxRuntime.jsx(icons.Pencil, {}) } ) }) }) ] }, idx)) }) ] }) }); }; const GlobalLoader = ({ loading }) => { const { formatMessage } = reactIntl.useIntl(); return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: loading && /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(designSystem.Loader, {}), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", style: { marginTop: "20px" }, children: formatMessage({ id: getTranslation("pleaseWait") }) }) ] } ) }); }; const ImportExportActions = ({ data = [], reload, handleTemplatesExport }) => { const { formatMessage } = reactIntl.useIntl(); const { toggleNotification } = admin.useNotification(); const emailTemplatesFileSelect = react.useRef(null); const [importConfirmationModal, setImportConfirmationModal] = react.useState(false); const [importedTemplates, setImportedTemplates] = react.useState([]); const [importLoading, setImportLoading] = react.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.destr(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__default.default().toDate(), updatedAt: dayjs__default.default().toDate(), import: true }); if (!lodash.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__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [ /* @__PURE__ */ jsxRuntime.jsx(GlobalLoader, { loading: importLoading }), /* @__PURE__ */ jsxRuntime.jsx( designSystem.Dialog.Root, { open: importConfirmationModal, onOpenChange: () => { setImportConfirmationModal((s) => !s); if (emailTemplatesFileSelect.current) { emailTemplatesFileSelect.current.value = ""; } }, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: formatMessage({ id: getTranslation("confirm.title") }) }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CloudUpload, { width: 50, height: 50 }), children: formatMessage({ id: getTranslation("confirm.import.message") }) }), /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { disabled: importLoading, fullWidth: true, variant: "tertiary", children: "Cancel" }) }), /* @__PURE__ */ jsxRuntime.jsx( designSystem.Button, { loading: importLoading, disabled: importLoading, onClick: () => handleTemplatesImport(), fullWidth: true, variant: "success-light", children: "Yes, import" } ) ] }) ] }) } ), /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { style: { padding: "30px 0px 10px" }, gap: "14px", justifyContent: "end", children: [ data?.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: () => handleTemplatesExport(), color: "success", startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Download, {}), children: formatMessage({ id: getTranslation("designer.exportTemplates") }) }), /* @__PURE__ */ jsxRuntime.jsx( designSystem.Button, { onClick: () => { emailTemplatesFileSelect?.current?.click(); }, startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.CloudUpload, {}), children: formatMessage({ id: getTranslation("designer.importTemplates") }) } ) ] }), /* @__PURE__ */ jsxRuntime.jsx("input", { accept: ".json", hidden: true, type: "file", ref: emailTemplatesFileSelect, onChange: handleFileChange }) ] }); }; const CustomEmailTable = ({ data = [], reload }) => { const { formatMessage } = reactIntl.useIntl(); const navigate = reactRouterDom.useNavigate(); const { toggleNotification } = admin.useNotification(); const [duplicateConfirmationModal, setDuplicateConfirmationModal] = react.useState(false); const [duplicateId, setDuplicateId] = react.useState(); const [deleteId, setDeleteId] = react.useState(); const [showDeleteModal, setShowDeleteModal] = react.useState(false); const handleTemplateDuplication = react.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 = react.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__default.default().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__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 8, children: [ /* @__PURE__ */ jsxRuntime.jsx( designSystem.EmptyStateLayout, { shadow: "none", icon: /* @__PURE__ */ jsxRuntime.jsx(symbols.EmptyPictures, { width: "210px" }), content: formatMessage({ id: getTranslation("customTable.noDesigns") }), action: /* @__PURE__ */ jsxRuntime.jsx( designSystem.Button, { variant: "secondary", startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}), onClick: () => navigate({ pathname: getUrl(`design/new`) }), children: formatMessage({ id: getTranslation("customTable.addDesign") }) } ) } ), /* @__PURE__ */ jsxRuntime.jsx(ImportExportActions, { data, reload, handleTemplatesExport }) ] }); } return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [ /* @__PURE__ */ jsxRuntime.jsx( designSystem.Dialog.Root, { open: duplicateConfirmationModal, onOpenChange: () => setDuplicateConfirmationModal((s) => !s), children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: formatMessage({ id: getTranslation("confirm.title") }) }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { icon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuCopyCheck, { size: "30px" }), children: formatMessage({ id: getTranslation("confirm.duplicate.message") }) }), /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: () => setDuplicateId(void 0), fullWidth: true, variant: "tertiary", children: "Cancel" }) }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Action, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: () => handleTemplateDuplication(), fullWidth: true, variant: "success-light", children: "Yes, duplicate" }) }) ] }) ] }) } ), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: showDeleteModal, onOpenChange: () => setShowDeleteModal((s) => !s), children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: formatMessage({ id: getTranslation("confirm.title") }) }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, { width: "30px" }), children: formatMessage({ id: getTranslation("confirm.delete.message") }) }), /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: () => setDeleteId(void 0), fullWidth: true, variant: "tertiary", children: "Cancel" }) }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Action, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: () => handleDelete(), fullWidth: true, variant: "danger-light", children: "Yes, delete" }) }) ] }) ] }) }), /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 3, children: [ /* @__PURE__ */ jsxRuntime.jsxs( designSystem.Table, { colCount: emailTemplatesHeaders.length + 1, rowCount: data.length, footer: /* @__PURE__ */ jsxRuntime.jsx( designSystem.TFooter, { style: { cursor: "pointer" }, icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}), onClick: () => navigate({ pathname: getUrl(`design/new`) }), children: formatMessage({ id: getTranslation("customTable.addDesign") }) } ), children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Thead, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [ emailTemplatesHeaders.map((header) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { style: { fontWeight: "bold" }, variant: "sigma", children: header.name }) }, header.name)), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { children: "Actions" }) }) ] }) }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: data.map((entry, idx) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { style: { fontWeight: "bold" }, textColor: "neutral800", children: entry.name }) }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral800", children: entry.templateReferenceId }) }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral800", children: entry.createdAt }) }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: "10px", justifyContent: "end", children: [ /* @__PURE__ */ jsxRuntime.jsx( designSystem.IconButton, { label: formatMessage({ id: getTranslation("tooltip.edit") }), onClick: () => navigate({ pathname: getUrl(`design/${entry.id}`) }), children: /* @__PURE__ */ jsxRuntime.jsx(icons.Pencil, {}) } ), /* @__PURE__ */ jsxRuntime.jsx( designSystem.IconButton, { label: formatMessage({ id: getTranslation("tooltip.downloadHtml") }), onClick: () => downloadTemplate(entry.id, "html"), children: /* @__PURE__ */ jsxRuntime.jsx(bs.BsFiletypeHtml, { size: 16 }) } ), /* @__PURE__ */ jsxRuntime.jsx( designSystem.IconButton, { label: formatMessage({ id: getTranslation("tooltip.downloadDesign") }), onClick: () => downloadTemplate(entry.id, "json"), children: /* @__PURE__ */ jsxRuntime.jsx(bs.BsFiletypeJson, { size: 16 }) } ), /* @__PURE__ */ jsxRuntime.jsx( designSystem.IconButton, { label: formatMessage({ id: getTranslation("tooltip.duplicate") }), onClick: () => { setDuplicateId(entry.id); setDuplicateConfirmationModal(true); }, children: /* @__PURE__ */ jsxRuntime.jsx(icons.Duplicate, {}) } ), /* @__PURE__ */ jsxRuntime.jsx( designSystem.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__ */ jsxRuntime.jsx(fa6.FaHashtag, { size: 16 }) } ), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingLeft: 1, children: /* @__PURE__ */ jsxRuntime.jsx( designSystem.IconButton, { label: formatMessage({ id: getTranslation("tooltip.delete") }), onClick: () => { setDeleteId(entry.id); setShowDeleteModal(true); }, children: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {}) } ) }) ] }) }) ] }, idx)) }) ] } ), /* @__PURE__ */ jsxRuntime.jsx(ImportExportActions, { data, reload, handleTemplatesExport }) ] }) ] }); }; const HomePage = () => { const navigate = reactRouterDom.useNavigate(); const translate = useTr(); const [emailTemplates, setEmailTemplates] = react.useState([]); const [activeTab, setActiveTab] = react.useState("customEmailTemplates"); const { toggleNotification } = strapiAdmin.useNotification(); const init = react.useCallback(async () => { const data = await getTemplatesData(); setEmailTemplates(data); }, []); react.useEffect(() => { init().catch(() => { toggleNotification({ type: "danger", title: translate("error"), message: translate("error.loadingTemplates") }); }); }, []); return /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Page.Main, { children: [ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Page.Title, { children: translate("page.title") }), /* @__PURE__ */ jsxRuntime.jsx( strapiAdmin.Layouts.Header, { id: "title", title: translate("page.title"), subtitle: translate("page.subTitle"), primaryAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { label: translate("page.home.cta.tooltip"), children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: () => navigate({ pathname: getUrl(`design/new`) }), children: translate("page.home.cta") }) }) } ), /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Layouts.Content, { children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Divider, { style: { marginBottom: "50px" } }), /* @__PURE__ */ jsxRuntime.jsxs( designSystem.Tabs.Root, { value: activeTab, onValueChange: (selected) => { setActiveTab(selected); }, children: [ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tabs.List, { "aria-label": "Switch between custom email designs & core email designs", children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tabs.Trigger, { value: "customEmailTemplates", children: translate("emailTypes.custom.tab.label") }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tabs.Trigger, { value: "coreEmailTemplates", children: translate("emailTypes.core.tab.label") }) ] }), /* @__PURE__ */ jsxRuntime.jsx( designSystem.Tabs.Content, { style: { borderBottomRightRadius: "6px", borderBottomLeftRadius: "6px" }, value: "customEmailTemplates", children: /* @__PURE__ */ jsxRuntime.jsx(CustomEmailTable, { reload: init, data: emailTemplates }) } ), /* @__PURE__ */ jsxRuntime.jsx( designSystem.Tabs.Content, { style: { borderBottomRightRadius: "6px", borderBottomLeftRadius: "6px" }, value: "coreEmailTemplates", children: /* @__PURE__ */ jsxRuntime.jsx(CoreEmailTable, {}) } ) ] } ), /* @__PURE__ */ jsxRuntime.jsx("div", { style: { paddingBottom: "20px" } }) ] }) ] }); }; const App = () => { return /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Routes, { children: [ /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { index: true, element: /* @__PURE__ */ jsxRuntime.jsx(HomePage, {}) }), /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "design/:templateId", element: /* @__PURE__ */ jsxRuntime.jsx(Designer$1, {}) }), /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "core/:coreEmailType", element: /* @__PURE__ */ jsxRuntime.jsx(Designer$1, { isCore: true }) }), /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "*", element: /* @__PURE__ */ jsxRuntime.jsx(admin.Page.Error, {}) }) ] }); }; exports.App = App;