319 lines
8.7 KiB
JavaScript
319 lines
8.7 KiB
JavaScript
/**
|
|
* Café Bach Email Generator - Form Handling & Preview Logic
|
|
*/
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const form = document.getElementById('emailForm');
|
|
const previewBtn = document.getElementById('previewBtn');
|
|
const descCount = document.getElementById('desc-count');
|
|
const descriptionField = document.getElementById('description');
|
|
|
|
// Character counter for description field
|
|
if (descriptionField && descCount) {
|
|
descriptionField.addEventListener('input', function() {
|
|
const currentLength = this.value.length;
|
|
const maxLength = this.maxLength;
|
|
descCount.textContent = `${currentLength}/${maxLength}`;
|
|
|
|
if (currentLength > maxLength * 0.9) {
|
|
descCount.style.color = '#e74c3c';
|
|
} else {
|
|
descCount.style.color = '#95a5a6';
|
|
}
|
|
});
|
|
}
|
|
|
|
// Form submission handler
|
|
if (form) {
|
|
form.addEventListener('submit', async function(e) {
|
|
e.preventDefault();
|
|
|
|
if (validateForm()) {
|
|
const formData = getFormData();
|
|
await submitFormData(formData);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Preview button handler
|
|
if (previewBtn) {
|
|
previewBtn.addEventListener('click', function() {
|
|
if (validateForm()) {
|
|
const formData = getFormData();
|
|
showPreview(formData);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Clear form handler
|
|
const clearBtn = document.querySelector('button[type="reset"]');
|
|
if (clearBtn) {
|
|
clearBtn.addEventListener('click', function() {
|
|
resetForm();
|
|
});
|
|
}
|
|
|
|
// Real-time validation on blur
|
|
const inputs = form ? form.querySelectorAll('input, textarea') : [];
|
|
inputs.forEach(input => {
|
|
input.addEventListener('blur', function() {
|
|
validateField(this);
|
|
});
|
|
});
|
|
|
|
// Real-time validation on input
|
|
inputs.forEach(input => {
|
|
if (input.required) {
|
|
input.addEventListener('input', function() {
|
|
if (this.classList.contains('error')) {
|
|
validateField(this);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
/**
|
|
* Validate the entire form
|
|
*/
|
|
function validateForm() {
|
|
const form = document.getElementById('emailForm');
|
|
const inputs = form.querySelectorAll('input[required], textarea[required]');
|
|
let isValid = true;
|
|
|
|
inputs.forEach(input => {
|
|
if (!validateField(input)) {
|
|
isValid = false;
|
|
}
|
|
});
|
|
|
|
// Validate URLs if provided
|
|
const urlFields = ['image_url', 'button_url', 'next_event_url'];
|
|
urlFields.forEach(fieldName => {
|
|
const field = document.getElementById(fieldName);
|
|
if (field && field.value && !isValidUrl(field.value)) {
|
|
showError(fieldName, 'Please enter a valid URL');
|
|
isValid = false;
|
|
}
|
|
});
|
|
|
|
return isValid;
|
|
}
|
|
|
|
/**
|
|
* Validate a single field
|
|
*/
|
|
function validateField(field) {
|
|
const fieldName = field.id;
|
|
const value = field.value.trim();
|
|
|
|
// Clear previous error
|
|
clearError(fieldName);
|
|
|
|
// Required field check
|
|
if (field.required && !value) {
|
|
showError(fieldName, 'This field is required');
|
|
field.classList.add('error');
|
|
return false;
|
|
}
|
|
|
|
// Length validation
|
|
if (value && field.maxLength) {
|
|
if (value.length > field.maxLength) {
|
|
showError(fieldName, `Must be less than ${field.maxLength} characters`);
|
|
field.classList.add('error');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
field.classList.remove('error');
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Show error message for a field
|
|
*/
|
|
function showError(fieldName, message) {
|
|
const errorElement = document.getElementById(`${fieldName}-error`);
|
|
if (errorElement) {
|
|
errorElement.textContent = message;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear error message for a field
|
|
*/
|
|
function clearError(fieldName) {
|
|
const errorElement = document.getElementById(`${fieldName}-error`);
|
|
if (errorElement) {
|
|
errorElement.textContent = '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate URL format
|
|
*/
|
|
function isValidUrl(string) {
|
|
try {
|
|
new URL(string);
|
|
return true;
|
|
} catch (_) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get form data as object
|
|
*/
|
|
function getFormData() {
|
|
const form = document.getElementById('emailForm');
|
|
const formData = new FormData(form);
|
|
const data = {};
|
|
|
|
for (let [key, value] of formData.entries()) {
|
|
data[key] = value;
|
|
}
|
|
|
|
// Convert to JSON string for display
|
|
data.jsonString = JSON.stringify(data, null, 2);
|
|
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* Submit form data to backend
|
|
*/
|
|
async function submitFormData(data) {
|
|
try {
|
|
const response = await fetch('/generate', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(data)
|
|
});
|
|
|
|
if (response.ok) {
|
|
const result = await response.json();
|
|
console.log('Form submitted successfully:', result);
|
|
alert('Email generated successfully!');
|
|
} else {
|
|
console.error('Submission failed');
|
|
alert('Failed to generate email. Please try again.');
|
|
}
|
|
} catch (error) {
|
|
console.error('Submission error:', error);
|
|
alert('Network error. Please check your connection and try again.');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show preview of email
|
|
*/
|
|
function showPreview(data) {
|
|
const previewContainer = document.getElementById('emailPreview');
|
|
|
|
// Format date for display
|
|
let formattedDate = '';
|
|
if (data.date_time) {
|
|
const date = new Date(data.date_time);
|
|
formattedDate = date.toLocaleString('en-US', {
|
|
weekday: 'long',
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric',
|
|
hour: '2-digit',
|
|
minute: '2-digit'
|
|
});
|
|
}
|
|
|
|
// Build HTML preview
|
|
const previewHTML = `
|
|
<div class="email-template">
|
|
<h1>${escapeHtml(data.title)}</h1>
|
|
|
|
${data.image_url ? `<img src="${escapeHtml(data.image_url)}" alt="Event Image" class="event-image">` : ''}
|
|
|
|
<div class="event-details">
|
|
<strong>📅 Date & Time</strong>
|
|
<p>${formattedDate || escapeHtml(data.date_time)}</p>
|
|
|
|
<strong>📍 Location</strong>
|
|
<p>${escapeHtml(data.location)}</p>
|
|
|
|
<strong>📝 Description</strong>
|
|
<p>${escapeHtml(data.description)}</p>
|
|
</div>
|
|
|
|
<a href="${escapeHtml(data.button_url)}" class="cta-button">${escapeHtml(data.button_text)}</a>
|
|
|
|
${data.next_event_text ? `
|
|
<div class="next-event">
|
|
<p><strong>Next Event:</strong> ${escapeHtml(data.next_event_text)}</p>
|
|
${data.next_event_url ? `<a href="${escapeHtml(data.next_event_url)}">Learn More</a>` : ''}
|
|
</div>
|
|
` : ''}
|
|
</div>
|
|
`;
|
|
|
|
previewContainer.innerHTML = previewHTML;
|
|
|
|
// Scroll to preview
|
|
previewContainer.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
}
|
|
|
|
/**
|
|
* Reset form to initial state
|
|
*/
|
|
function resetForm() {
|
|
const form = document.getElementById('emailForm');
|
|
form.reset();
|
|
|
|
// Clear all error messages
|
|
const errorMessages = document.querySelectorAll('.error-message');
|
|
errorMessages.forEach(el => el.textContent = '');
|
|
|
|
// Remove error classes
|
|
const inputs = form.querySelectorAll('input, textarea');
|
|
inputs.forEach(input => input.classList.remove('error'));
|
|
|
|
// Reset character counter
|
|
const descCount = document.getElementById('desc-count');
|
|
if (descCount) {
|
|
descCount.textContent = '0/2000';
|
|
descCount.style.color = '#95a5a6';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Escape HTML to prevent XSS
|
|
*/
|
|
function escapeHtml(text) {
|
|
if (!text) return '';
|
|
const div = document.createElement('div');
|
|
div.textContent = text;
|
|
return div.innerHTML;
|
|
}
|
|
|
|
/**
|
|
* Copy to clipboard functionality
|
|
*/
|
|
function copyToClipboard() {
|
|
const previewContent = document.getElementById('emailPreview').innerHTML;
|
|
|
|
navigator.clipboard.writeText(previewContent).then(() => {
|
|
const btn = document.getElementById('copyBtn');
|
|
if (btn) {
|
|
btn.textContent = '✓ Copied to Clipboard!';
|
|
setTimeout(() => {
|
|
btn.textContent = 'Copy HTML to Clipboard';
|
|
}, 2000);
|
|
}
|
|
}).catch(err => {
|
|
console.error('Failed to copy:', err);
|
|
alert('Failed to copy to clipboard. Please select and copy manually.');
|
|
});
|
|
}
|
|
|
|
// Export functions for global access
|
|
window.copyToClipboard = copyToClipboard;
|
|
|