freealberta/influence/app/public/js/email-composer.js

237 lines
7.9 KiB
JavaScript

// Email Composer Module
class EmailComposer {
constructor() {
this.modal = document.getElementById('email-modal');
this.form = document.getElementById('email-form');
this.closeBtn = document.getElementById('close-modal');
this.cancelBtn = document.getElementById('cancel-email');
this.messageTextarea = document.getElementById('email-message');
this.charCounter = document.querySelector('.char-counter');
this.currentRecipient = null;
this.init();
}
init() {
// Modal controls
this.closeBtn.addEventListener('click', () => this.closeModal());
this.cancelBtn.addEventListener('click', () => this.closeModal());
this.modal.addEventListener('click', (e) => {
if (e.target === this.modal) this.closeModal();
});
// Form handling
this.form.addEventListener('submit', (e) => this.handleSubmit(e));
// Character counter
this.messageTextarea.addEventListener('input', () => this.updateCharCounter());
// Escape key to close modal
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && this.modal.style.display === 'block') {
this.closeModal();
}
});
}
openModal(recipient) {
this.currentRecipient = recipient;
// Populate recipient info
document.getElementById('recipient-email').value = recipient.email;
document.getElementById('recipient-info').innerHTML = `
<strong>${recipient.name}</strong><br>
${recipient.office}<br>
${recipient.district}<br>
<em>${recipient.email}</em>
`;
// Set postal code from current lookup
const postalCode = window.postalLookup ? window.postalLookup.currentPostalCode : '';
document.getElementById('sender-postal-code').value = postalCode;
// Clear form fields
document.getElementById('sender-name').value = '';
document.getElementById('sender-email').value = '';
document.getElementById('email-subject').value = '';
document.getElementById('email-message').value = '';
// Set default subject
document.getElementById('email-subject').value = `Message from your constituent in ${postalCode}`;
this.updateCharCounter();
this.modal.style.display = 'block';
// Focus on first input
document.getElementById('sender-name').focus();
}
closeModal() {
this.modal.style.display = 'none';
this.currentRecipient = null;
}
updateCharCounter() {
const maxLength = 5000;
const currentLength = this.messageTextarea.value.length;
const remaining = maxLength - currentLength;
this.charCounter.textContent = `${remaining} characters remaining`;
if (remaining < 100) {
this.charCounter.style.color = '#dc3545'; // Red
} else if (remaining < 500) {
this.charCounter.style.color = '#ffc107'; // Yellow
} else {
this.charCounter.style.color = '#666'; // Default
}
}
validateForm() {
const errors = [];
const senderName = document.getElementById('sender-name').value.trim();
const senderEmail = document.getElementById('sender-email').value.trim();
const subject = document.getElementById('email-subject').value.trim();
const message = document.getElementById('email-message').value.trim();
if (!senderName) {
errors.push('Your name is required');
}
if (!senderEmail) {
errors.push('Your email is required');
} else if (!this.validateEmail(senderEmail)) {
errors.push('Please enter a valid email address');
}
if (!subject) {
errors.push('Subject is required');
}
if (!message) {
errors.push('Message is required');
} else if (message.length < 10) {
errors.push('Message must be at least 10 characters long');
}
// Check for suspicious content
if (this.containsSuspiciousContent(message) || this.containsSuspiciousContent(subject)) {
errors.push('Your message contains content that may not be appropriate');
}
return errors;
}
validateEmail(email) {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email);
}
containsSuspiciousContent(text) {
const suspiciousPatterns = [
/<script/i,
/javascript:/i,
/on\w+\s*=/i,
/<iframe/i,
/<object/i,
/<embed/i
];
return suspiciousPatterns.some(pattern => pattern.test(text));
}
async handleSubmit(e) {
e.preventDefault();
const errors = this.validateForm();
if (errors.length > 0) {
window.messageDisplay.show(errors.join('<br>'), 'error');
return;
}
const submitButton = this.form.querySelector('button[type="submit"]');
const originalText = submitButton.textContent;
try {
submitButton.disabled = true;
submitButton.textContent = 'Sending...';
const emailData = {
recipientEmail: document.getElementById('recipient-email').value,
senderName: document.getElementById('sender-name').value.trim(),
senderEmail: document.getElementById('sender-email').value.trim(),
subject: document.getElementById('email-subject').value.trim(),
message: document.getElementById('email-message').value.trim(),
postalCode: document.getElementById('sender-postal-code').value
};
const result = await window.apiClient.sendEmail(emailData);
if (result.success) {
window.messageDisplay.show('Email sent successfully! Your representative will receive your message.', 'success');
this.closeModal();
} else {
throw new Error(result.message || 'Failed to send email');
}
} catch (error) {
console.error('Email send failed:', error);
window.messageDisplay.show(`Failed to send email: ${error.message}`, 'error');
} finally {
submitButton.disabled = false;
submitButton.textContent = originalText;
}
}
// Helper method to get template messages
getTemplateMessage(type) {
const templates = {
general: `Dear {{name}},
I am writing as your constituent from {{postalCode}} to express my views on an important matter.
[Please write your message here]
I would appreciate your response on this issue and would like to know your position.
Thank you for your time and service to our community.
Sincerely,
{{senderName}}`,
concern: `Dear {{name}},
I am writing to express my concern about [specific issue] as your constituent from {{postalCode}}.
[Describe your concern and its impact]
I urge you to [specific action you want them to take].
Thank you for considering my views on this important matter.
Best regards,
{{senderName}}`,
support: `Dear {{name}},
I am writing to express my support for [specific issue/bill/policy] as your constituent from {{postalCode}}.
[Explain why you support this and its importance]
I encourage you to continue supporting this initiative.
Thank you for your leadership on this matter.
Respectfully,
{{senderName}}`
};
return templates[type] || templates.general;
}
}
// Initialize when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
window.emailComposer = new EmailComposer();
});