/** * Email Templates Management Page * * Handles: * - Listing all platform email templates * - Editing template content (all languages) * - Preview and test email sending */ const emailTemplatesLog = window.LogConfig?.createLogger?.('emailTemplates') || { info: () => {}, debug: () => {}, warn: () => {}, error: () => {} }; function emailTemplatesPage() { return { // Inherit base layout functionality from init-alpine.js ...data(), // Set current page for navigation currentPage: 'email-templates', // Data loading: false, templates: [], categories: [], selectedCategory: null, // Edit Modal showEditModal: false, editingTemplate: null, editLanguage: 'en', loadingTemplate: false, editForm: { subject: '', body_html: '', body_text: '', variables: [], required_variables: [] }, saving: false, // Preview Modal showPreviewModal: false, previewData: null, // Test Email Modal showTestEmailModal: false, testEmailAddress: '', sendingTest: false, // Computed get filteredTemplates() { if (!this.selectedCategory) { return this.templates; } return this.templates.filter(t => t.category === this.selectedCategory); }, // Lifecycle async init() { // Guard against duplicate initialization if (window._adminEmailTemplatesInitialized) return; window._adminEmailTemplatesInitialized = true; // Load i18n translations await I18n.loadModule('messaging'); await this.loadData(); }, // Data Loading async loadData() { this.loading = true; try { const [templatesData, categoriesData] = await Promise.all([ apiClient.get('/admin/email-templates'), apiClient.get('/admin/email-templates/categories') ]); this.templates = templatesData.templates || []; this.categories = categoriesData.categories || []; } catch (error) { emailTemplatesLog.error('Failed to load email templates:', error); Utils.showToast(I18n.t('messaging.messages.failed_to_load_templates'), 'error'); } finally { this.loading = false; } }, // Category styling getCategoryClass(category) { const classes = { 'auth': 'bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200', 'orders': 'bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200', 'billing': 'bg-orange-100 dark:bg-orange-900 text-orange-800 dark:text-orange-200', 'system': 'bg-purple-100 dark:bg-purple-900 text-purple-800 dark:text-purple-200', 'marketing': 'bg-pink-100 dark:bg-pink-900 text-pink-800 dark:text-pink-200' }; return classes[category] || 'bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200'; }, // Edit Template async editTemplate(template) { this.editingTemplate = template; this.editLanguage = 'en'; this.showEditModal = true; await this.loadTemplateLanguage(); }, async loadTemplateLanguage() { if (!this.editingTemplate) return; this.loadingTemplate = true; try { const data = await apiClient.get( `/admin/email-templates/${this.editingTemplate.code}/${this.editLanguage}` ); this.editForm = { subject: data.subject || '', body_html: data.body_html || '', body_text: data.body_text || '', variables: data.variables || [], required_variables: data.required_variables || [] }; } catch (error) { if (error.status === 404) { // Template doesn't exist for this language yet this.editForm = { subject: '', body_html: '', body_text: '', variables: [], required_variables: [] }; Utils.showToast(I18n.t('messaging.messages.no_template_for_language', { language: this.editLanguage.toUpperCase() }), 'info'); } else { emailTemplatesLog.error('Failed to load template:', error); Utils.showToast(I18n.t('messaging.messages.failed_to_load_template'), 'error'); } } finally { this.loadingTemplate = false; } }, closeEditModal() { this.showEditModal = false; this.editingTemplate = null; this.editForm = { subject: '', body_html: '', body_text: '', variables: [], required_variables: [] }; }, async saveTemplate() { if (!this.editingTemplate) return; this.saving = true; try { await apiClient.put( `/admin/email-templates/${this.editingTemplate.code}/${this.editLanguage}`, { subject: this.editForm.subject, body_html: this.editForm.body_html, body_text: this.editForm.body_text } ); Utils.showToast(I18n.t('messaging.messages.template_saved_successfully'), 'success'); // Refresh templates list await this.loadData(); } catch (error) { emailTemplatesLog.error('Failed to save template:', error); Utils.showToast(error.detail || I18n.t('messaging.messages.failed_to_save_template'), 'error'); } finally { this.saving = false; } }, // Preview async previewTemplate(template) { try { // Use sample variables for preview const sampleVariables = this.getSampleVariables(template.code); const data = await apiClient.post( `/admin/email-templates/${template.code}/preview`, { template_code: template.code, language: 'en', variables: sampleVariables } ); this.previewData = data; this.showPreviewModal = true; } catch (error) { emailTemplatesLog.error('Failed to preview template:', error); Utils.showToast(I18n.t('messaging.messages.failed_to_load_preview'), 'error'); } }, getSampleVariables(templateCode) { // Sample variables for common templates const samples = { 'signup_welcome': { first_name: 'John', merchant_name: 'Acme Corp', email: 'john@example.com', store_code: 'acme', login_url: 'https://example.com/login', trial_days: '14', tier_name: 'Business' }, 'order_confirmation': { customer_name: 'Jane Doe', order_number: 'ORD-12345', order_total: '99.99', order_items_count: '3', order_date: '2024-01-15', shipping_address: '123 Main St, Luxembourg City, L-1234' }, 'password_reset': { customer_name: 'John Doe', reset_link: 'https://example.com/reset?token=abc123', expiry_hours: '1' }, 'team_invite': { invitee_name: 'Jane', inviter_name: 'John', store_name: 'Acme Corp', role: 'Admin', accept_url: 'https://example.com/accept', expires_in_days: '7' } }; return samples[templateCode] || { platform_name: 'Orion' }; }, // Test Email sendTestEmail() { this.showTestEmailModal = true; }, async confirmSendTestEmail() { if (!this.testEmailAddress || !this.editingTemplate) return; this.sendingTest = true; try { const result = await apiClient.post( `/admin/email-templates/${this.editingTemplate.code}/test`, { template_code: this.editingTemplate.code, language: this.editLanguage, to_email: this.testEmailAddress, variables: this.getSampleVariables(this.editingTemplate.code) } ); if (result.success) { Utils.showToast(I18n.t('messaging.messages.test_email_sent', { email: this.testEmailAddress }), 'success'); this.showTestEmailModal = false; this.testEmailAddress = ''; } else { Utils.showToast(result.message || I18n.t('messaging.messages.failed_to_send_test_email'), 'error'); } } catch (error) { emailTemplatesLog.error('Failed to send test email:', error); Utils.showToast(I18n.t('messaging.messages.failed_to_send_test_email'), 'error'); } finally { this.sendingTest = false; } } }; }