// DOM Elements document.addEventListener('DOMContentLoaded', function() { // Navigation const menuItems = document.querySelectorAll('.menu li'); const pages = document.querySelectorAll('.page'); // Generate Content Page const generateBtn = document.getElementById('generate-btn'); const promptInput = document.getElementById('prompt'); const contentTypeSelect = document.getElementById('content-type'); const lengthSelect = document.getElementById('length'); const includeCTACheckbox = document.getElementById('include-cta'); const referenceSimilarCheckbox = document.getElementById('reference-similar'); const resultContainer = document.getElementById('result-container'); const resultContent = document.getElementById('result-content'); const loadingIndicator = document.getElementById('loading-indicator'); const alignmentScore = document.getElementById('alignment-score'); const suggestionsList = document.getElementById('suggestions-list'); const copyBtn = document.getElementById('copy-btn'); const improveBtn = document.getElementById('improve-btn'); const saveBtn = document.getElementById('save-btn'); const improvementPanel = document.getElementById('improvement-panel'); const improvementFeedback = document.getElementById('improvement-feedback'); const submitImprovement = document.getElementById('submit-improvement'); // History Page const historyFilterType = document.getElementById('history-filter-type'); const historySearch = document.getElementById('history-search'); const historyList = document.querySelector('.history-list'); // Brand Style Page const toneSelector = document.getElementById('tone-selector'); const voiceSelector = document.getElementById('voice-selector'); const tabooWords = document.getElementById('taboo-words'); const tabooInput = document.getElementById('taboo-input'); const addTabooBtn = document.getElementById('add-taboo-btn'); const avoidTerm = document.getElementById('avoid-term'); const useTerm = document.getElementById('use-term'); const addTermBtn = document.getElementById('add-term-btn'); const saveBrandStyleBtn = document.getElementById('save-brand-style'); const resetBrandStyleBtn = document.getElementById('reset-brand-style'); // Training Page const trainingTabs = document.querySelectorAll('.training-tabs .tab'); const tabContents = document.querySelectorAll('.tab-content'); const addTrainingBtn = document.getElementById('add-training-btn'); const trainingContentType = document.getElementById('training-content-type'); const campaignName = document.getElementById('campaign-name'); const trainingContent = document.getElementById('training-content'); const openRate = document.getElementById('open-rate'); const clickRate = document.getElementById('click-rate'); const conversionRate = document.getElementById('conversion-rate'); const trainingFilterType = document.getElementById('training-filter-type'); const trainingSearch = document.getElementById('training-search'); const trainingList = document.querySelector('.training-list'); // API Base URL const API_URL = 'http://localhost:8000'; // Menu Navigation menuItems.forEach(item => { item.addEventListener('click', function() { const pageName = this.getAttribute('data-page'); // Update active menu item menuItems.forEach(menuItem => menuItem.classList.remove('active')); this.classList.add('active'); // Show selected page pages.forEach(page => { if (page.id === `${pageName}-page`) { page.classList.add('active'); // Load data for specific pages when they're opened if (pageName === 'history') { loadUserQueries(); } else if (pageName === 'training') { // Check if the view training tab is active if (document.querySelector('.tab[data-tab="view-training"]').classList.contains('active')) { loadTrainingData(); } } } else { page.classList.remove('active'); } }); }); }); // Generate Content if (generateBtn) { generateBtn.addEventListener('click', function() { if (!promptInput.value.trim()) { alert('Please enter a prompt for content generation.'); return; } // Show loading indicator loadingIndicator.classList.remove('hidden'); resultContainer.classList.add('hidden'); // Prepare request data const requestData = { prompt: promptInput.value, content_type: contentTypeSelect.value || null, length: lengthSelect.value || null, include_cta: includeCTACheckbox.checked, reference_similar_content: referenceSimilarCheckbox.checked }; // Call the API fetch(`${API_URL}/generate-copy`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(requestData) }) .then(response => { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return response.json(); }) .then(data => { // Hide loading indicator loadingIndicator.classList.add('hidden'); // Display result with preserved formatting resultContent.innerHTML = data.content .split('\n') .map(line => { // Convert bullet points to list items if (line.trim().startsWith('•')) { return `
  • ${line.trim().substring(1).trim()}
  • `; } // Wrap non-empty lines in paragraphs return line.trim() ? `

    ${line}

    ` : ''; }) .join('\n'); // Set alignment score const score = data.metadata.alignment_score || 0; alignmentScore.style.width = `${score}%`; alignmentScore.textContent = `${Math.round(score)}%`; if (score < 60) { alignmentScore.style.backgroundColor = 'var(--danger-color)'; } else if (score < 80) { alignmentScore.style.backgroundColor = 'var(--warning-color)'; } else { alignmentScore.style.backgroundColor = 'var(--success-color)'; } // Display suggestions if (data.suggestions && data.suggestions.length > 0) { suggestionsList.innerHTML = ''; data.suggestions.forEach(suggestion => { const li = document.createElement('li'); li.textContent = suggestion; li.addEventListener('click', function() { promptInput.value = suggestion; }); suggestionsList.appendChild(li); }); } // Show result container resultContainer.classList.remove('hidden'); }) .catch(error => { console.error('Error:', error); loadingIndicator.classList.add('hidden'); alert('An error occurred while generating content. Please try again.'); }); }); } // Copy to Clipboard if (copyBtn) { copyBtn.addEventListener('click', function() { navigator.clipboard.writeText(resultContent.textContent) .then(() => { const originalTitle = copyBtn.getAttribute('title'); copyBtn.setAttribute('title', 'Copied!'); setTimeout(() => { copyBtn.setAttribute('title', originalTitle); }, 2000); }) .catch(err => { console.error('Could not copy text: ', err); }); }); } // Toggle Improvement Panel if (improveBtn) { improveBtn.addEventListener('click', function() { improvementPanel.classList.toggle('hidden'); }); } // Submit Improvement Feedback if (submitImprovement) { submitImprovement.addEventListener('click', function() { const feedback = improvementFeedback.value.trim(); if (!feedback) { alert('Please provide improvement feedback.'); return; } loadingIndicator.classList.remove('hidden'); fetch(`${API_URL}/improve-content`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ content: resultContent.textContent, feedback: feedback }) }) .then(response => response.json()) .then(data => { loadingIndicator.classList.add('hidden'); // Update result content with preserved formatting resultContent.innerHTML = data.improved_content .split('\n') .map(line => { if (line.trim().startsWith('•')) { return `
  • ${line.trim().substring(1).trim()}
  • `; } return line.trim() ? `

    ${line}

    ` : ''; }) .join('\n'); improvementPanel.classList.add('hidden'); improvementFeedback.value = ''; }) .catch(error => { console.error('Error:', error); loadingIndicator.classList.add('hidden'); alert('An error occurred while improving content. Please try again.'); }); }); } // Save Content to History if (saveBtn) { saveBtn.addEventListener('click', function() { alert('Content saved to history!'); // Note: The backend automatically saves the query as part of the generate-copy endpoint // so we don't need to make another API call here }); } // Load User Queries (History) function loadUserQueries(page = 1, contentType = '') { if (!historyList) return; // Show loading state historyList.innerHTML = '
    Loading history...
    '; // Build the query parameters let queryParams = `?page=${page}&limit=10`; // Call the API fetch(`${API_URL}/user-queries${queryParams}`) .then(response => { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return response.json(); }) .then(data => { historyList.innerHTML = ''; if (data.items.length === 0) { historyList.innerHTML = '
    No history found.
    '; return; } // Filter by content type if provided let filteredItems = data.items; if (contentType) { filteredItems = data.items.filter(item => item.parameters && item.parameters.content_type === contentType ); } // Create history items filteredItems.forEach(item => { const contentType = item.parameters?.content_type || 'general'; const timestamp = item.timestamp ? new Date(item.timestamp).toLocaleDateString() : 'Unknown date'; const promptPreview = item.prompt.length > 80 ? item.prompt.substring(0, 80) + '...' : item.prompt; const historyItem = document.createElement('div'); historyItem.className = 'history-item'; historyItem.innerHTML = `
    ${getContentTypeLabel(contentType)}

    ${getPromptTitle(item.prompt)}

    ${promptPreview}

    ${timestamp}
    `; historyList.appendChild(historyItem); }); // Add event listeners for view and delete buttons document.querySelectorAll('.view-query').forEach(btn => { btn.addEventListener('click', function() { const timestamp = this.getAttribute('data-timestamp'); viewUserQuery(timestamp); }); }); document.querySelectorAll('.delete-query').forEach(btn => { btn.addEventListener('click', function() { const timestamp = this.getAttribute('data-timestamp'); if (confirm('Are you sure you want to delete this query?')) { deleteUserQuery(timestamp); } }); }); // Add pagination if needed if (data.pagination && data.pagination.pages > 1) { // Remove existing pagination if any const existingPagination = document.querySelector('.pagination'); if (existingPagination) { existingPagination.remove(); } const paginationElement = document.createElement('div'); paginationElement.className = 'pagination'; let paginationHTML = ''; for (let i = 1; i <= data.pagination.pages; i++) { paginationHTML += ``; } paginationElement.innerHTML = paginationHTML; historyList.after(paginationElement); // Add event listeners for pagination buttons document.querySelectorAll('.page-btn').forEach(btn => { btn.addEventListener('click', function() { const pageNum = parseInt(this.getAttribute('data-page')); loadUserQueries(pageNum, contentType); }); }); } }) .catch(error => { console.error('Error loading user queries:', error); historyList.innerHTML = '
    Error loading history. Please try again.
    '; }); } // Helper function to extract timestamp from ISO date function getTimestampFromISODate(isoDate) { if (!isoDate) return ''; const date = new Date(isoDate); return date.toISOString().replace(/[-:T.]/g, '').slice(0, 14); } // Helper function to generate a title from prompt function getPromptTitle(prompt) { if (!prompt) return 'Untitled Query'; const words = prompt.split(' '); if (words.length <= 5) return prompt; return words.slice(0, 5).join(' ') + '...'; } // Helper function to get display label for content type function getContentTypeLabel(contentType) { if (!contentType) return 'General'; const labels = { 'email': 'Email', 'social_media': 'Social', 'blog_post': 'Blog', 'website_copy': 'Website', 'sales_copy': 'Sales', 'ad_copy': 'Ad', 'video_script': 'Video', 'case_study': 'Case Study', 'product_description': 'Product', 'landing_page': 'Landing', 'press_release': 'Press', 'newsletter': 'Newsletter', 'general': 'General' }; return labels[contentType] || contentType.charAt(0).toUpperCase() + contentType.slice(1); } // View User Query function viewUserQuery(timestamp) { fetch(`${API_URL}/user-queries/${timestamp}`) .then(response => { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return response.json(); }) .then(data => { // Create a modal to display the query details const modal = document.createElement('div'); modal.className = 'modal'; const modalContent = document.createElement('div'); modalContent.className = 'modal-content'; const parameters = data.parameters || {}; const contentType = parameters.content_type || 'Not specified'; const length = parameters.length || 'Not specified'; const includeCTA = parameters.include_cta ? 'Yes' : 'No'; modalContent.innerHTML = ` `; modal.appendChild(modalContent); document.body.appendChild(modal); // Close button functionality modal.querySelector('.modal-close').addEventListener('click', function() { document.body.removeChild(modal); }); // Close when clicking outside the modal window.addEventListener('click', function(event) { if (event.target === modal) { document.body.removeChild(modal); } }); }) .catch(error => { console.error('Error viewing user query:', error); alert('Error viewing query details. Please try again.'); }); } // Delete User Query function deleteUserQuery(timestamp) { fetch(`${API_URL}/user-queries/${timestamp}`, { method: 'DELETE' }) .then(response => { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return response.json(); }) .then(data => { alert('Query successfully deleted.'); // Reload the user queries loadUserQueries(); }) .catch(error => { console.error('Error deleting user query:', error); alert('Error deleting query. Please try again.'); }); } // History Filter Handlers if (historyFilterType) { historyFilterType.addEventListener('change', function() { loadUserQueries(1, this.value); }); } if (historySearch) { historySearch.addEventListener('input', function() { // Client-side filtering - this would ideally be server-side, // but we'll implement a simple client-side filter for now const searchTerm = this.value.toLowerCase(); document.querySelectorAll('.history-item').forEach(item => { const content = item.querySelector('.history-item-content').textContent.toLowerCase(); if (content.includes(searchTerm)) { item.style.display = 'flex'; } else { item.style.display = 'none'; } }); }); } // Brand Style Tag Selection - Disabled as brand style is fixed to Adriana James' style // Read-only display of brand style tags // Taboo Words - Read-only as brand style is fixed to Adriana James' style // Disabled taboo word editing functionality if (tabooInput) { tabooInput.disabled = true; tabooInput.placeholder = "Taboo words are fixed to maintain brand consistency"; } if (addTabooBtn) { addTabooBtn.disabled = true; } // Terminology - Read-only as brand style is fixed to Adriana James' style // Disabled terminology editing functionality if (avoidTerm) { avoidTerm.disabled = true; avoidTerm.placeholder = "Terminology is fixed"; } if (useTerm) { useTerm.disabled = true; useTerm.placeholder = "Terminology is fixed"; } if (addTermBtn) { addTermBtn.disabled = true; } // Disable remove buttons for terminology rows document.querySelectorAll('.terminology-row:not(.add-row):not(.terminology-header) .btn-icon').forEach(btn => { btn.disabled = true; btn.style.opacity = '0.5'; btn.style.cursor = 'not-allowed'; }); // Brand Style is fixed - removed save functionality // Brand Style is fixed - removed reset functionality // Training Tabs if (trainingTabs.length > 0) { trainingTabs.forEach(tab => { tab.addEventListener('click', function() { const tabName = this.getAttribute('data-tab'); // Update active tab trainingTabs.forEach(t => t.classList.remove('active')); this.classList.add('active'); // Show selected tab content tabContents.forEach(content => { if (content.id === `${tabName}-tab`) { content.classList.add('active'); // Load training data when the View tab is selected if (tabName === 'view-training') { loadTrainingData(); } } else { content.classList.remove('active'); } }); }); }); } // Add Training Data if (addTrainingBtn) { addTrainingBtn.addEventListener('click', function() { if (!trainingContentType.value) { alert('Please select a content type.'); return; } if (!trainingContent.value.trim()) { alert('Please enter content for training.'); return; } // Prepare request data const requestData = { content_type: trainingContentType.value, content: trainingContent.value, metadata: { campaign_name: campaignName.value, performance_metrics: {} } }; // Add performance metrics if provided if (openRate.value) { requestData.metadata.performance_metrics.open_rate = parseFloat(openRate.value) / 100; } if (clickRate.value) { requestData.metadata.performance_metrics.click_rate = parseFloat(clickRate.value) / 100; } if (conversionRate.value) { requestData.metadata.performance_metrics.conversion_rate = parseFloat(conversionRate.value) / 100; } // Call the API fetch(`${API_URL}/training-data`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(requestData) }) .then(response => { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return response.json(); }) .then(data => { alert('Training data added successfully!'); // Clear form trainingContentType.value = ''; campaignName.value = ''; trainingContent.value = ''; openRate.value = ''; clickRate.value = ''; conversionRate.value = ''; // Switch to view tab document.querySelector('.tab[data-tab="view-training"]').click(); }) .catch(error => { console.error('Error:', error); alert('An error occurred while adding training data. Please try again.'); }); }); } // Load Training Data function loadTrainingData(page = 1, contentType = '') { if (!trainingList) return; // Show loading state trainingList.innerHTML = '
    Loading training data...
    '; // Build the query parameters let queryParams = `?page=${page}&limit=10`; if (contentType) { queryParams += `&content_type=${contentType}`; } // Call the API fetch(`${API_URL}/training-data${queryParams}`) .then(response => { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return response.json(); }) .then(data => { trainingList.innerHTML = ''; if (data.items.length === 0) { trainingList.innerHTML = '
    No training data found.
    '; return; } // Create training items data.items.forEach(item => { const trainingItem = document.createElement('div'); trainingItem.className = 'training-item'; // Generate metrics HTML let metricsHTML = ''; if (item.metadata && item.metadata.performance_metrics) { const metrics = item.metadata.performance_metrics; if (metrics.open_rate) { metricsHTML += `Open Rate: ${(metrics.open_rate * 100).toFixed(1)}%`; } if (metrics.click_rate) { metricsHTML += `Click Rate: ${(metrics.click_rate * 100).toFixed(1)}%`; } if (metrics.conversion_rate) { metricsHTML += `Conversion: ${(metrics.conversion_rate * 100).toFixed(1)}%`; } } if (!metricsHTML) { metricsHTML = 'No metrics available'; } const campaignName = item.metadata?.campaign_name || 'Untitled'; trainingItem.innerHTML = `
    ${getContentTypeLabel(item.content_type)}

    ${campaignName}

    Added on: ${new Date(item.added_at).toLocaleDateString()}

    ${metricsHTML}
    `; trainingList.appendChild(trainingItem); }); // Add event listeners for view and delete buttons document.querySelectorAll('.view-training').forEach(btn => { btn.addEventListener('click', function() { const id = this.getAttribute('data-id'); viewTrainingData(id); }); }); document.querySelectorAll('.delete-training').forEach(btn => { btn.addEventListener('click', function() { const id = this.getAttribute('data-id'); if (confirm('Are you sure you want to delete this training data?')) { deleteTrainingData(id); } }); }); // Add pagination for training data if (data.pagination && data.pagination.pages > 1) { // Remove existing pagination if any const existingPagination = document.querySelector('.pagination'); if (existingPagination) { existingPagination.remove(); } const paginationElement = document.createElement('div'); paginationElement.className = 'pagination'; let paginationHTML = ''; for (let i = 1; i <= data.pagination.pages; i++) { paginationHTML += ``; } paginationElement.innerHTML = paginationHTML; trainingList.after(paginationElement); // Add event listeners for pagination buttons document.querySelectorAll('.page-btn').forEach(btn => { btn.addEventListener('click', function() { const pageNum = parseInt(this.getAttribute('data-page')); loadTrainingData(pageNum, contentType); }); }); } }) .catch(error => { console.error('Error loading training data:', error); trainingList.innerHTML = '
    Error loading training data. Please try again.
    '; }); } // View Training Data function viewTrainingData(id) { fetch(`${API_URL}/training-data/${id}`) .then(response => { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return response.json(); }) .then(data => { // Create a modal to display the training data details const modal = document.createElement('div'); modal.className = 'modal'; const modalContent = document.createElement('div'); modalContent.className = 'modal-content'; const campaignName = data.metadata?.campaign_name || 'Untitled'; let metricsHTML = ''; if (data.metadata && data.metadata.performance_metrics) { const metrics = data.metadata.performance_metrics; if (metrics.open_rate !== undefined) { metricsHTML += `
    Open Rate: ${(metrics.open_rate * 100).toFixed(1)}%
    `; } if (metrics.click_rate !== undefined) { metricsHTML += `
    Click Rate: ${(metrics.click_rate * 100).toFixed(1)}%
    `; } if (metrics.conversion_rate !== undefined) { metricsHTML += `
    Conversion Rate: ${(metrics.conversion_rate * 100).toFixed(1)}%
    `; } } modalContent.innerHTML = ` `; modal.appendChild(modalContent); document.body.appendChild(modal); // Close button functionality modal.querySelector('.modal-close').addEventListener('click', function() { document.body.removeChild(modal); }); // Close when clicking outside the modal window.addEventListener('click', function(event) { if (event.target === modal) { document.body.removeChild(modal); } }); }) .catch(error => { console.error('Error viewing training data:', error); alert('Error viewing training data details. Please try again.'); }); } // Delete Training Data function deleteTrainingData(id) { fetch(`${API_URL}/training-data/${id}`, { method: 'DELETE' }) .then(response => { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return response.json(); }) .then(data => { alert('Training data successfully deleted.'); // Reload the training data loadTrainingData(); }) .catch(error => { console.error('Error deleting training data:', error); alert('Error deleting training data. Please try again.'); }); } // Training Filter Handlers if (trainingFilterType) { trainingFilterType.addEventListener('change', function() { loadTrainingData(1, this.value); }); } if (trainingSearch) { trainingSearch.addEventListener('input', function() { // Client-side filtering const searchTerm = this.value.toLowerCase(); document.querySelectorAll('.training-item').forEach(item => { const content = item.querySelector('.training-item-content').textContent.toLowerCase(); if (content.includes(searchTerm)) { item.style.display = 'flex'; } else { item.style.display = 'none'; } }); }); } // Load Brand Style on Page Load fetch(`${API_URL}/brand-style`) .then(response => { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return response.json(); }) .then(data => { console.log('Loaded brand style:', data); // In a real implementation, you would update the UI based on the loaded data }) .catch(error => { console.error('Error loading brand style:', error); }); // For demonstration purposes, let's create a mocked pre-filled content // In a real implementation, this would be loaded from the backend document.getElementById('prompt').value = 'Generate an email campaign for a product launch'; // Add CSS for modal const modalStyle = document.createElement('style'); modalStyle.textContent = ` .modal { display: block; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); overflow: auto; } .modal-content { background-color: white; margin: 5% auto; padding: 0; border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); width: 80%; max-width: 800px; animation: modalOpen 0.3s ease-out; } @keyframes modalOpen { from {opacity: 0; transform: translateY(-20px);} to {opacity: 1; transform: translateY(0);} } .modal-header { padding: 20px 25px; border-bottom: 1px solid var(--grey-200); display: flex; justify-content: space-between; align-items: center; } .modal-header h3 { margin: 0; } .modal-close { background: transparent; border: none; font-size: 24px; cursor: pointer; color: var(--grey-600); } .modal-close:hover { color: var(--grey-800); } .modal-body { padding: 25px; } .detail-item { margin-bottom: 15px; } .detail-label { font-weight: 600; color: var(--grey-700); display: block; margin-bottom: 5px; } .detail-value { color: var(--grey-800); } .content-preview { margin-top: 25px; } .content-box { background-color: var(--grey-100); border: 1px solid var(--grey-200); border-radius: var(--radius-md); padding: 15px; margin-top: 10px; white-space: pre-wrap; max-height: 300px; overflow-y: auto; } .loading-state, .empty-state, .error-state { text-align: center; padding: 30px; color: var(--grey-500); } .pagination { display: flex; justify-content: center; gap: 5px; margin-top: 20px; } .page-btn { padding: 8px 12px; border: 1px solid var(--grey-300); background-color: white; border-radius: var(--radius-md); cursor: pointer; } .page-btn.active { background-color: var(--primary-color); color: white; border-color: var(--primary-color); } `; document.head.appendChild(modalStyle); });