From ac75a806d93374313d8b65d77d6250c87c07a096 Mon Sep 17 00:00:00 2001 From: c0mrade Date: Wed, 10 Jun 2026 22:53:08 +0300 Subject: [PATCH] fix(admin): rework email template editor (#667043) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Companion to the bot-side fix: defaults now arrive with {placeholders} instead of baked-in sample values (example.com links). - inline preview tab (iframe srcDoc) — works on mobile and in Telegram; the separate desktop-only preview page and its route are removed - preview/test render the CURRENT editor content with sample values - test email: recipient input + detailed backend error messages - variable chips insert at cursor instead of copying to clipboard - 'insert default template' button to migrate broken saved overrides - fa added to language tabs --- src/App.tsx | 12 - src/api/adminEmailTemplates.ts | 3 + src/locales/en.json | 10 +- src/locales/fa.json | 10 +- src/locales/ru.json | 10 +- src/locales/zh.json | 10 +- src/pages/AdminEmailTemplatePreview.tsx | 116 -------- src/pages/AdminEmailTemplates.tsx | 369 ++++++++++++++---------- 8 files changed, 251 insertions(+), 289 deletions(-) delete mode 100644 src/pages/AdminEmailTemplatePreview.tsx diff --git a/src/App.tsx b/src/App.tsx index e4fda6f..46b78bc 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -135,7 +135,6 @@ const AdminBroadcastDetail = lazyWithRetry(() => import('./pages/AdminBroadcastD const AdminPinnedMessages = lazyWithRetry(() => import('./pages/AdminPinnedMessages')); const AdminPinnedMessageCreate = lazyWithRetry(() => import('./pages/AdminPinnedMessageCreate')); const AdminChannelSubscriptions = lazyWithRetry(() => import('./pages/AdminChannelSubscriptions')); -const AdminEmailTemplatePreview = lazyWithRetry(() => import('./pages/AdminEmailTemplatePreview')); const AdminRoles = lazyWithRetry(() => import('./pages/AdminRoles')); const AdminRoleEdit = lazyWithRetry(() => import('./pages/AdminRoleEdit')); const AdminRoleAssign = lazyWithRetry(() => import('./pages/AdminRoleAssign')); @@ -1212,17 +1211,6 @@ function App() { } /> - - - - - - } - /> - {/* RBAC routes */} (); - const iframeRef = useRef(null); - - const [previewHtml, setPreviewHtml] = useState(''); - - // Get data from navigation state - const state = location.state as PreviewState | null; - - // Preview mutation - const { - mutate: loadPreview, - isPending: previewPending, - isError: previewError, - } = useMutation({ - mutationFn: () => { - if (!type || !lang || !state) { - throw new Error('Missing required data'); - } - return adminEmailTemplatesApi.previewTemplate(type, { - language: lang, - subject: state.subject, - body_html: state.body_html, - }); - }, - onSuccess: (data) => { - setPreviewHtml(data.body_html); - }, - }); - - // Load preview on mount - useEffect(() => { - if (!type || !lang || !state) { - navigate('/admin/email-templates'); - return; - } - loadPreview(); - }, [type, lang, state, navigate, loadPreview]); - - // Write preview HTML into iframe - useEffect(() => { - if (previewHtml && iframeRef.current) { - const doc = iframeRef.current.contentDocument; - if (doc) { - doc.open(); - doc.write(previewHtml); - doc.close(); - } - } - }, [previewHtml]); - - if (!type || !lang || !state) { - return null; - } - - return ( -
- {/* Header */} -
- -
-

{t('admin.emailTemplates.preview')}

-

- {type} / {lang.toUpperCase()} -

-
-
- - {/* Preview content */} -
- {previewPending ? ( -
-
-
- ) : previewError ? ( -
-

{t('common.error')}

- -
- ) : ( -