Files
orion/app/modules/messaging/static/admin/js/email-templates.js
Samir Boulahtit e9253fbd84 refactor: rename Wizamart to Orion across entire codebase
Replace all ~1,086 occurrences of Wizamart/wizamart/WIZAMART/WizaMart
with Orion/orion/ORION across 184 files. This includes database
identifiers, email addresses, domain references, R2 bucket names,
DNS prefixes, encryption salt, Celery app name, config defaults,
Docker configs, CI configs, documentation, seed data, and templates.

Renames homepage-wizamart.html template to homepage-orion.html.
Fixes duplicate file_pattern key in api.yaml architecture rule.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 16:46:56 +01:00

278 lines
9.9 KiB
JavaScript

/**
* 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;
}
}
};
}