Tonne of updates to influence, the configs, update the homepage, and generally just did more bug testing with Influence
This commit is contained in:
285
influence/app/public/email-test.html
Normal file
285
influence/app/public/email-test.html
Normal file
@@ -0,0 +1,285 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Email Testing Interface - Alberta Influence Campaign</title>
|
||||
<link rel="stylesheet" href="css/styles.css">
|
||||
<style>
|
||||
.test-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.test-section {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.test-controls {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.test-controls button {
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: #6c757d;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-warning {
|
||||
background-color: #ffc107;
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
.test-controls button:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.test-controls button:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.email-preview {
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
padding: 20px;
|
||||
margin-top: 20px;
|
||||
background: white;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.email-preview.empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #6c757d;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group textarea {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.form-group textarea {
|
||||
resize: vertical;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.logs-section {
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.log-entry {
|
||||
background: white;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.log-entry.test-mode {
|
||||
border-left: 4px solid #ffc107;
|
||||
}
|
||||
|
||||
.log-entry.failed {
|
||||
border-left: 4px solid #dc3545;
|
||||
}
|
||||
|
||||
.log-entry.sent {
|
||||
border-left: 4px solid #28a745;
|
||||
}
|
||||
|
||||
.log-meta {
|
||||
font-size: 12px;
|
||||
color: #6c757d;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.status-indicator {
|
||||
display: inline-block;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.status-sent {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.status-failed {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
.status-test {
|
||||
background-color: #fff3cd;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.success-message {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="test-container">
|
||||
<header style="text-align: center; margin-bottom: 30px;">
|
||||
<h1>Email Testing Interface</h1>
|
||||
<p>Test and preview emails before sending to elected officials</p>
|
||||
<div id="auth-status" style="margin-top: 10px;"></div>
|
||||
</header>
|
||||
|
||||
<!-- Quick Test Section -->
|
||||
<div class="test-section">
|
||||
<h2>Quick Test</h2>
|
||||
<p>Send a test email to yourself to verify email configuration</p>
|
||||
<div class="test-controls">
|
||||
<button id="quick-test-btn" class="btn-primary">Send Quick Test Email</button>
|
||||
<button id="smtp-test-btn" class="btn-secondary">Test SMTP Connection</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Email Composition & Preview Section -->
|
||||
<div class="test-section">
|
||||
<h2>Email Preview & Test</h2>
|
||||
<form id="email-test-form">
|
||||
<div class="form-group">
|
||||
<label for="test-recipient">Test Recipient Email:</label>
|
||||
<input type="email" id="test-recipient" name="recipientEmail"
|
||||
placeholder="Enter email address for testing">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="test-subject">Subject:</label>
|
||||
<input type="text" id="test-subject" name="subject"
|
||||
placeholder="Enter email subject" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="test-message">Message:</label>
|
||||
<textarea id="test-message" name="message"
|
||||
placeholder="Enter your message to elected officials..." required></textarea>
|
||||
</div>
|
||||
|
||||
<div class="test-controls">
|
||||
<button type="button" id="preview-btn" class="btn-secondary">Preview Email</button>
|
||||
<button type="button" id="send-test-btn" class="btn-primary">Send Test Email</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div id="email-preview" class="email-preview empty">
|
||||
Click "Preview Email" to see how your email will look
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Email Logs Section -->
|
||||
<div class="test-section">
|
||||
<h2>Email Logs</h2>
|
||||
<div class="test-controls">
|
||||
<button id="refresh-logs-btn" class="btn-secondary">Refresh Logs</button>
|
||||
<button id="filter-test-btn" class="btn-warning">Show Test Emails Only</button>
|
||||
<button id="filter-all-btn" class="btn-success">Show All Emails</button>
|
||||
</div>
|
||||
<div id="email-logs" class="logs-section">
|
||||
<div class="loading">Loading email logs...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Test Mode Status -->
|
||||
<div class="test-section">
|
||||
<h2>Current Configuration</h2>
|
||||
<div id="config-status">
|
||||
<div class="loading">Loading configuration...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Success/Error Messages -->
|
||||
<div id="message-container"></div>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="js/auth.js"></script>
|
||||
<script src="js/api-client.js"></script>
|
||||
<script src="js/email-testing.js"></script>
|
||||
|
||||
<script>
|
||||
// Initialize the email testing interface
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Check authentication
|
||||
const authManager = new AuthManager();
|
||||
authManager.checkAuthStatus().then(isAuthenticated => {
|
||||
if (!isAuthenticated) {
|
||||
window.location.href = '/login.html?redirect=/email-test.html';
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize email testing
|
||||
const emailTest = new EmailTesting();
|
||||
emailTest.init();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -116,7 +116,7 @@
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>© 2025 Alberta Influence Campaign Tool. Connect with democracy.</p>
|
||||
<p>© 2025 <a href="https://bnkops.com/" target="_blank">BNKops</a> Influence Campaign Tool. Connect with democracy.</p>
|
||||
<p><small>This tool uses the <a href="https://represent.opennorth.ca" target="_blank">Represent API</a> by Open North to find your representatives.</small></p>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
@@ -18,7 +18,11 @@ class APIClient {
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error || data.message || `HTTP ${response.status}`);
|
||||
// Create enhanced error with response data for better error handling
|
||||
const error = new Error(data.error || data.message || `HTTP ${response.status}`);
|
||||
error.status = response.status;
|
||||
error.data = data;
|
||||
throw error;
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
@@ -403,7 +403,14 @@ class CampaignPage {
|
||||
throw new Error(data.error || 'Failed to send email');
|
||||
}
|
||||
} catch (error) {
|
||||
this.showError('Failed to send email: ' + error.message);
|
||||
// Handle rate limit errors specifically
|
||||
if (error.message && error.message.includes('You can only send one email per representative every 5 minutes')) {
|
||||
this.showError('Rate limit reached: You can only send one email per representative every 5 minutes. Please wait before sending another email to this representative. You can still email other representatives.');
|
||||
} else if (error.message && error.message.includes('Too many emails')) {
|
||||
this.showError('Too many emails sent. Please wait before sending more emails.');
|
||||
} else {
|
||||
this.showError('Failed to send email: ' + error.message);
|
||||
}
|
||||
} finally {
|
||||
this.hideLoading();
|
||||
}
|
||||
|
||||
@@ -177,7 +177,23 @@ class EmailComposer {
|
||||
|
||||
} catch (error) {
|
||||
console.error('Email send failed:', error);
|
||||
window.messageDisplay.show(`Failed to send email: ${error.message}`, 'error');
|
||||
|
||||
// Handle rate limit errors specifically
|
||||
if (error.status === 429 && error.data && error.data.rateLimitType === 'per-recipient') {
|
||||
const retryMinutes = Math.ceil((error.data.retryAfter || 300) / 60);
|
||||
window.messageDisplay.show(
|
||||
`Rate limit reached: You can only send one email per representative every 5 minutes. Please wait ${retryMinutes} more minutes before sending another email to this representative. You can still send emails to other representatives.`,
|
||||
'warning'
|
||||
);
|
||||
} else if (error.status === 429) {
|
||||
// General rate limit
|
||||
window.messageDisplay.show(
|
||||
`Too many emails sent. Please wait before sending more emails.`,
|
||||
'warning'
|
||||
);
|
||||
} else {
|
||||
window.messageDisplay.show(`Failed to send email: ${error.message}`, 'error');
|
||||
}
|
||||
} finally {
|
||||
submitButton.disabled = false;
|
||||
submitButton.textContent = originalText;
|
||||
|
||||
365
influence/app/public/js/email-testing.js
Normal file
365
influence/app/public/js/email-testing.js
Normal file
@@ -0,0 +1,365 @@
|
||||
/**
|
||||
* Email Testing Interface
|
||||
* Handles email preview, testing, and logging functionality
|
||||
*/
|
||||
class EmailTesting {
|
||||
constructor() {
|
||||
this.apiClient = new APIClient();
|
||||
this.currentFilter = 'all'; // 'all', 'test', 'live'
|
||||
this.logLimit = 50;
|
||||
this.logOffset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the email testing interface
|
||||
*/
|
||||
async init() {
|
||||
this.bindEvents();
|
||||
await this.loadConfiguration();
|
||||
await this.loadEmailLogs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind event listeners to UI elements
|
||||
*/
|
||||
bindEvents() {
|
||||
// Quick test buttons
|
||||
document.getElementById('quick-test-btn').addEventListener('click', () => this.sendQuickTest());
|
||||
document.getElementById('smtp-test-btn').addEventListener('click', () => this.testSMTPConnection());
|
||||
|
||||
// Email form buttons
|
||||
document.getElementById('preview-btn').addEventListener('click', () => this.previewEmail());
|
||||
document.getElementById('send-test-btn').addEventListener('click', () => this.sendTestEmail());
|
||||
|
||||
// Log control buttons
|
||||
document.getElementById('refresh-logs-btn').addEventListener('click', () => this.loadEmailLogs());
|
||||
document.getElementById('filter-test-btn').addEventListener('click', () => this.filterLogs('test'));
|
||||
document.getElementById('filter-all-btn').addEventListener('click', () => this.filterLogs('all'));
|
||||
|
||||
// Form validation
|
||||
document.getElementById('email-test-form').addEventListener('input', () => this.validateForm());
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a quick test email with default content
|
||||
*/
|
||||
async sendQuickTest() {
|
||||
const button = document.getElementById('quick-test-btn');
|
||||
button.disabled = true;
|
||||
button.textContent = 'Sending...';
|
||||
|
||||
try {
|
||||
const response = await this.apiClient.post('/api/emails/test', {
|
||||
subject: 'Quick Test Email',
|
||||
message: 'This is a quick test email sent from the Alberta Influence Campaign Tool email testing interface.'
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
this.showMessage(`Test email sent successfully to ${response.sentTo}`, 'success');
|
||||
await this.loadEmailLogs(); // Refresh logs
|
||||
} else {
|
||||
this.showMessage(`Failed to send test email: ${response.message}`, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
this.showMessage(`Error sending test email: ${error.message}`, 'error');
|
||||
} finally {
|
||||
button.disabled = false;
|
||||
button.textContent = 'Send Quick Test Email';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test SMTP connection
|
||||
*/
|
||||
async testSMTPConnection() {
|
||||
const button = document.getElementById('smtp-test-btn');
|
||||
button.disabled = true;
|
||||
button.textContent = 'Testing...';
|
||||
|
||||
try {
|
||||
// Note: This endpoint would need to be added to the API
|
||||
const response = await this.apiClient.get('/api/test-smtp');
|
||||
|
||||
if (response.success) {
|
||||
this.showMessage('SMTP connection test successful', 'success');
|
||||
} else {
|
||||
this.showMessage(`SMTP connection failed: ${response.message}`, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
this.showMessage(`SMTP test error: ${error.message}`, 'error');
|
||||
} finally {
|
||||
button.disabled = false;
|
||||
button.textContent = 'Test SMTP Connection';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Preview email content
|
||||
*/
|
||||
async previewEmail() {
|
||||
const formData = this.getFormData();
|
||||
if (!formData) return;
|
||||
|
||||
const button = document.getElementById('preview-btn');
|
||||
button.disabled = true;
|
||||
|
||||
try {
|
||||
const recipientEmail = formData.recipientEmail || 'recipient@example.com';
|
||||
const response = await this.apiClient.post('/api/emails/preview', {
|
||||
recipientEmail: recipientEmail,
|
||||
subject: formData.subject,
|
||||
message: formData.message
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
this.displayEmailPreview(response.preview, response.html);
|
||||
} else {
|
||||
this.showMessage(`Preview failed: ${response.message}`, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
this.showMessage(`Preview error: ${error.message}`, 'error');
|
||||
} finally {
|
||||
button.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send test email
|
||||
*/
|
||||
async sendTestEmail() {
|
||||
const formData = this.getFormData();
|
||||
if (!formData) return;
|
||||
|
||||
const button = document.getElementById('send-test-btn');
|
||||
button.disabled = true;
|
||||
button.textContent = 'Sending...';
|
||||
|
||||
try {
|
||||
const response = await this.apiClient.post('/api/emails/test', {
|
||||
subject: formData.subject,
|
||||
message: formData.message
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
this.showMessage(`Test email sent successfully to ${response.sentTo}`, 'success');
|
||||
await this.loadEmailLogs(); // Refresh logs
|
||||
} else {
|
||||
this.showMessage(`Failed to send test email: ${response.message}`, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
this.showMessage(`Error sending test email: ${error.message}`, 'error');
|
||||
} finally {
|
||||
button.disabled = false;
|
||||
button.textContent = 'Send Test Email';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get form data and validate
|
||||
*/
|
||||
getFormData() {
|
||||
const subject = document.getElementById('test-subject').value.trim();
|
||||
const message = document.getElementById('test-message').value.trim();
|
||||
const recipientEmail = document.getElementById('test-recipient').value.trim();
|
||||
|
||||
if (!subject || !message) {
|
||||
this.showMessage('Please fill in subject and message', 'error');
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
subject,
|
||||
message,
|
||||
recipientEmail: recipientEmail || null
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate form and update button states
|
||||
*/
|
||||
validateForm() {
|
||||
const subject = document.getElementById('test-subject').value.trim();
|
||||
const message = document.getElementById('test-message').value.trim();
|
||||
|
||||
const isValid = subject && message;
|
||||
|
||||
document.getElementById('preview-btn').disabled = !isValid;
|
||||
document.getElementById('send-test-btn').disabled = !isValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display email preview
|
||||
*/
|
||||
displayEmailPreview(preview, html) {
|
||||
const previewDiv = document.getElementById('email-preview');
|
||||
previewDiv.classList.remove('empty');
|
||||
|
||||
const testModeWarning = preview.testMode ?
|
||||
`<div style="background: #fff3cd; color: #856404; padding: 10px; border-radius: 4px; margin-bottom: 15px;">
|
||||
<strong>TEST MODE:</strong> Email will be redirected to ${preview.redirectTo}
|
||||
</div>` : '';
|
||||
|
||||
previewDiv.innerHTML = `
|
||||
${testModeWarning}
|
||||
<div style="margin-bottom: 15px;">
|
||||
<strong>From:</strong> ${preview.from}<br>
|
||||
<strong>To:</strong> ${preview.to}<br>
|
||||
<strong>Subject:</strong> ${preview.subject}<br>
|
||||
<strong>Timestamp:</strong> ${new Date(preview.timestamp).toLocaleString()}
|
||||
</div>
|
||||
<div style="border-top: 1px solid #ccc; padding-top: 15px;">
|
||||
<strong>Message Content:</strong>
|
||||
<div style="margin-top: 10px; padding: 10px; background: #f8f9fa; border-radius: 4px;">
|
||||
${html}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and display email logs
|
||||
*/
|
||||
async loadEmailLogs() {
|
||||
const logsDiv = document.getElementById('email-logs');
|
||||
logsDiv.innerHTML = '<div class="loading">Loading email logs...</div>';
|
||||
|
||||
try {
|
||||
const params = new URLSearchParams();
|
||||
params.append('limit', this.logLimit);
|
||||
params.append('offset', this.logOffset);
|
||||
|
||||
if (this.currentFilter === 'test') {
|
||||
params.append('testMode', 'true');
|
||||
} else if (this.currentFilter === 'live') {
|
||||
params.append('testMode', 'false');
|
||||
}
|
||||
|
||||
const response = await this.apiClient.get(`/api/emails/logs?${params.toString()}`);
|
||||
|
||||
if (response.success) {
|
||||
this.displayEmailLogs(response.logs);
|
||||
} else {
|
||||
logsDiv.innerHTML = `<div class="error-message">Failed to load logs: ${response.message}</div>`;
|
||||
}
|
||||
} catch (error) {
|
||||
logsDiv.innerHTML = `<div class="error-message">Error loading logs: ${error.message}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display email logs
|
||||
*/
|
||||
displayEmailLogs(logs) {
|
||||
const logsDiv = document.getElementById('email-logs');
|
||||
|
||||
if (!logs || logs.length === 0) {
|
||||
logsDiv.innerHTML = '<div style="text-align: center; color: #6c757d; padding: 20px;">No email logs found</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
logsDiv.innerHTML = logs.map(log => {
|
||||
const statusClass = log.Status === 'sent' ? 'sent' : 'failed';
|
||||
const testModeClass = log['Test Mode'] ? 'test-mode' : '';
|
||||
const statusIndicator = log['Test Mode'] ? 'test' : statusClass;
|
||||
|
||||
return `
|
||||
<div class="log-entry ${statusClass} ${testModeClass}">
|
||||
<div style="display: flex; justify-content: between; align-items: flex-start;">
|
||||
<div style="flex: 1;">
|
||||
<strong>${log.Subject}</strong>
|
||||
<div>To: ${log.Recipient}</div>
|
||||
${log['Actual Recipient'] && log['Actual Recipient'] !== log.Recipient ?
|
||||
`<div style="color: #856404;">Actually sent to: ${log['Actual Recipient']}</div>` : ''}
|
||||
${log.Error ? `<div style="color: #dc3545;">Error: ${log.Error}</div>` : ''}
|
||||
</div>
|
||||
<div style="text-align: right;">
|
||||
<span class="status-indicator status-${statusIndicator}">${log.Status}</span>
|
||||
${log['Test Mode'] ? '<span class="status-indicator status-test" style="margin-left: 5px;">TEST</span>' : ''}
|
||||
</div>
|
||||
</div>
|
||||
<div class="log-meta">
|
||||
${log['Sent At'] ? new Date(log['Sent At']).toLocaleString() :
|
||||
(log.CreatedAt ? new Date(log.CreatedAt).toLocaleString() : 'Unknown time')}
|
||||
${log['Message ID'] ? ` • ID: ${log['Message ID']}` : ''}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter logs by type
|
||||
*/
|
||||
async filterLogs(filter) {
|
||||
this.currentFilter = filter;
|
||||
this.logOffset = 0; // Reset offset when filtering
|
||||
|
||||
// Update button states
|
||||
document.getElementById('filter-all-btn').classList.toggle('btn-success', filter === 'all');
|
||||
document.getElementById('filter-test-btn').classList.toggle('btn-warning', filter === 'test');
|
||||
|
||||
await this.loadEmailLogs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and display current configuration
|
||||
*/
|
||||
async loadConfiguration() {
|
||||
const configDiv = document.getElementById('config-status');
|
||||
|
||||
// Since we don't have a dedicated config endpoint, we'll show env-based info
|
||||
const isTestMode = true; // Assuming test mode based on .env
|
||||
const testRecipient = 'admin@example.com'; // From .env
|
||||
|
||||
configDiv.innerHTML = `
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
|
||||
<div>
|
||||
<h4>Email Test Mode</h4>
|
||||
<div style="color: ${isTestMode ? '#856404' : '#155724'};">
|
||||
${isTestMode ? 'ENABLED' : 'DISABLED'}
|
||||
</div>
|
||||
<small style="color: #6c757d;">
|
||||
${isTestMode ? 'All emails will be redirected to test recipient' : 'Emails will be sent to actual recipients'}
|
||||
</small>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Test Email Recipient</h4>
|
||||
<div>${testRecipient}</div>
|
||||
<small style="color: #6c757d;">Emails will be sent here in test mode</small>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show success or error message
|
||||
*/
|
||||
showMessage(message, type) {
|
||||
const messageContainer = document.getElementById('message-container');
|
||||
const messageClass = type === 'success' ? 'success-message' : 'error-message';
|
||||
|
||||
const messageDiv = document.createElement('div');
|
||||
messageDiv.className = messageClass;
|
||||
messageDiv.textContent = message;
|
||||
messageDiv.style.position = 'fixed';
|
||||
messageDiv.style.top = '20px';
|
||||
messageDiv.style.left = '50%';
|
||||
messageDiv.style.transform = 'translateX(-50%)';
|
||||
messageDiv.style.zIndex = '1000';
|
||||
messageDiv.style.maxWidth = '500px';
|
||||
|
||||
messageContainer.appendChild(messageDiv);
|
||||
|
||||
// Auto-remove after 5 seconds
|
||||
setTimeout(() => {
|
||||
if (messageDiv.parentNode) {
|
||||
messageDiv.parentNode.removeChild(messageDiv);
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
// Export for use in other modules
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = EmailTesting;
|
||||
}
|
||||
Reference in New Issue
Block a user