// Campaign Page Management Module class CampaignPage { constructor() { this.campaign = null; this.representatives = []; this.userInfo = {}; this.currentStep = 1; this.init(); } init() { // Get campaign slug from URL const pathParts = window.location.pathname.split('/'); this.campaignSlug = pathParts[pathParts.length - 1]; // Set up form handlers document.getElementById('user-info-form').addEventListener('submit', (e) => { this.handleUserInfoSubmit(e); }); // Postal code formatting document.getElementById('user-postal-code').addEventListener('input', (e) => { this.formatPostalCode(e); }); // Load campaign data this.loadCampaign(); } async loadCampaign() { this.showLoading('Loading campaign...'); try { const response = await fetch(`/api/campaigns/${this.campaignSlug}`); const data = await response.json(); if (!data.success) { throw new Error(data.error || 'Failed to load campaign'); } this.campaign = data.campaign; this.renderCampaign(); } catch (error) { this.showError('Failed to load campaign: ' + error.message); } finally { this.hideLoading(); } } renderCampaign() { // Update page title and header document.title = `${this.campaign.title} - BNKops Influence Tool`; document.getElementById('page-title').textContent = `${this.campaign.title} - BNKops Influence Tool`; document.getElementById('campaign-title').textContent = this.campaign.title; document.getElementById('campaign-description').textContent = this.campaign.description; // Show email count if enabled if (this.campaign.show_email_count && this.campaign.emailCount !== null) { document.getElementById('email-count').textContent = this.campaign.emailCount; document.getElementById('campaign-stats').style.display = 'block'; } // Show call to action if (this.campaign.call_to_action) { document.getElementById('call-to-action').innerHTML = `
${this.campaign.call_to_action}
`; document.getElementById('call-to-action').style.display = 'block'; } // Set up email preview this.setupEmailPreview(); // Set up email method options this.setupEmailMethodOptions(); // Show optional fields if user info collection is enabled if (this.campaign.collect_user_info) { const optionalFields = document.getElementById('optional-fields'); if (optionalFields) { optionalFields.style.display = 'block'; console.log('Showing optional user info fields'); } } // Set initial step this.setStep(1); } setupEmailMethodOptions() { const emailMethodSection = document.getElementById('email-method-selection'); const allowSMTP = this.campaign.allow_smtp_email; const allowMailto = this.campaign.allow_mailto_link; if (!emailMethodSection) { console.warn('Email method selection element not found'); return; } // Configure existing radio buttons instead of replacing HTML const smtpRadio = document.getElementById('method-smtp'); const mailtoRadio = document.getElementById('method-mailto'); if (allowSMTP && allowMailto) { // Both methods allowed - keep default setup smtpRadio.disabled = false; mailtoRadio.disabled = false; smtpRadio.checked = true; } else if (allowSMTP && !allowMailto) { // Only SMTP allowed smtpRadio.disabled = false; mailtoRadio.disabled = true; smtpRadio.checked = true; } else if (!allowSMTP && allowMailto) { // Only mailto allowed smtpRadio.disabled = true; mailtoRadio.disabled = false; mailtoRadio.checked = true; } else { // Neither allowed - hide the section emailMethodSection.style.display = 'none'; } } setupEmailPreview() { const emailPreview = document.getElementById('email-preview'); const previewDescription = document.getElementById('preview-description'); // Store original email content this.originalEmailSubject = this.campaign.email_subject; this.originalEmailBody = this.campaign.email_body; this.currentEmailSubject = this.campaign.email_subject; this.currentEmailBody = this.campaign.email_body; // Set up preview content document.getElementById('preview-subject').textContent = this.currentEmailSubject; document.getElementById('preview-body').textContent = this.currentEmailBody; // Set up editable fields document.getElementById('edit-subject').value = this.currentEmailSubject; document.getElementById('edit-body').value = this.currentEmailBody; if (this.campaign.allow_email_editing) { // Enable editing mode emailPreview.classList.remove('preview-mode'); emailPreview.classList.add('edit-mode'); previewDescription.textContent = 'You can edit this message before sending to your representatives:'; // Set up event listeners for editing this.setupEmailEditingListeners(); } else { // Read-only preview mode emailPreview.classList.remove('edit-mode'); emailPreview.classList.add('preview-mode'); previewDescription.textContent = 'This is the message that will be sent to your representatives:'; } emailPreview.style.display = 'block'; } setupEmailEditingListeners() { const editSubject = document.getElementById('edit-subject'); const editBody = document.getElementById('edit-body'); const previewBtn = document.getElementById('preview-email-btn'); const saveBtn = document.getElementById('save-email-btn'); // Auto-update current content as user types editSubject.addEventListener('input', (e) => { this.currentEmailSubject = e.target.value; }); editBody.addEventListener('input', (e) => { this.currentEmailBody = e.target.value; }); // Preview button - toggle between edit and preview mode previewBtn.addEventListener('click', () => { this.toggleEmailPreview(); }); // Save button - save changes saveBtn.addEventListener('click', () => { this.saveEmailChanges(); }); } toggleEmailPreview() { const emailPreview = document.getElementById('email-preview'); const previewBtn = document.getElementById('preview-email-btn'); if (emailPreview.classList.contains('edit-mode')) { // Switch to preview mode document.getElementById('preview-subject').textContent = this.currentEmailSubject; document.getElementById('preview-body').textContent = this.currentEmailBody; emailPreview.classList.remove('edit-mode'); emailPreview.classList.add('preview-mode'); previewBtn.textContent = '✏️ Edit'; } else { // Switch to edit mode emailPreview.classList.remove('preview-mode'); emailPreview.classList.add('edit-mode'); previewBtn.textContent = '👁️ Preview'; } } saveEmailChanges() { // Update the current values and show confirmation document.getElementById('preview-subject').textContent = this.currentEmailSubject; document.getElementById('preview-body').textContent = this.currentEmailBody; // Show success message this.showMessage('Email content updated successfully!', 'success'); // Switch to preview mode const emailPreview = document.getElementById('email-preview'); const previewBtn = document.getElementById('preview-email-btn'); emailPreview.classList.remove('edit-mode'); emailPreview.classList.add('preview-mode'); previewBtn.textContent = '✏️ Edit'; } showMessage(message, type = 'info') { // Use existing message display system if available if (window.messageDisplay) { window.messageDisplay.show(message, type); } else { // Fallback to alert alert(message); } } formatPostalCode(e) { let value = e.target.value.replace(/\s/g, '').toUpperCase(); if (value.length > 3) { value = value.substring(0, 3) + ' ' + value.substring(3, 6); } e.target.value = value; } async handleUserInfoSubmit(e) { e.preventDefault(); const formData = new FormData(e.target); this.userInfo = { postalCode: formData.get('postalCode').replace(/\s/g, '').toUpperCase(), userName: formData.get('userName') || '', userEmail: formData.get('userEmail') || '' }; // Track user info when they click "Find My Representatives" await this.trackUserInfo(); await this.loadRepresentatives(); } async trackUserInfo() { try { const response = await fetch(`/api/campaigns/${this.campaignSlug}/track-user`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userEmail: this.userInfo.userEmail, userName: this.userInfo.userName, postalCode: this.userInfo.postalCode }) }); const data = await response.json(); if (!data.success) { console.warn('Failed to track user info:', data.error); // Don't throw error - this is just tracking, shouldn't block the user } } catch (error) { console.warn('Failed to track user info:', error.message); // Don't throw error - this is just tracking, shouldn't block the user } } async loadRepresentatives() { this.showLoading('Finding your representatives...'); try { const response = await fetch(`/api/campaigns/${this.campaignSlug}/representatives/${this.userInfo.postalCode}`); const data = await response.json(); if (!data.success) { throw new Error(data.error || 'Failed to load representatives'); } this.representatives = data.representatives; this.renderRepresentatives(); this.setStep(2); // Scroll to representatives section document.getElementById('representatives-section').scrollIntoView({ behavior: 'smooth' }); } catch (error) { this.showError('Failed to load representatives: ' + error.message); } finally { this.hideLoading(); } } renderRepresentatives() { const list = document.getElementById('representatives-list'); if (this.representatives.length === 0) { list.innerHTML = 'No representatives found for your area. Please check your postal code.
'; return; } list.innerHTML = this.representatives.map(rep => `${rep.elected_office || 'Representative'}
${rep.party_name || ''}
${rep.email ? `📧 ${rep.email}
` : ''} ${this.getPhoneNumber(rep) ? `📞 ${this.getPhoneNumber(rep)}
` : ''}No contact information available
' : ''}