document.addEventListener('DOMContentLoaded', () => { const spreadsheetDiv = document.getElementById('spreadsheet'); const commandInput = document.getElementById('commandInput'); const sendBtn = document.getElementById('sendBtn'); const saveBtn = document.getElementById('saveBtn'); const exportBtn = document.getElementById('exportBtn'); const loadingOverlay = document.getElementById('loadingOverlay'); const statsDisplay = document.getElementById('statsDisplay'); const micBtn = document.getElementById('micBtn'); let spreadsheet = null; // --- ISO Codes & Data --- const statusOptions = ['To-do', 'Booked', 'In Progress', 'Done']; // Full ISO 3166-1 alpha-2 Country Codes const countryOptions = [ { id: 'US', name: 'United States' }, { id: 'GB', name: 'United Kingdom' }, { id: 'CA', name: 'Canada' }, { id: 'AU', name: 'Australia' }, { id: 'DE', name: 'Germany' }, { id: 'FR', name: 'France' }, { id: 'IT', name: 'Italy' }, { id: 'ES', name: 'Spain' }, { id: 'JP', name: 'Japan' }, { id: 'CN', name: 'China' }, { id: 'IN', name: 'India' }, { id: 'BR', name: 'Brazil' }, { id: 'MX', name: 'Mexico' }, { id: 'RU', name: 'Russia' }, { id: 'ZA', name: 'South Africa' }, { id: 'NL', name: 'Netherlands' }, { id: 'SE', name: 'Sweden' }, { id: 'NO', name: 'Norway' }, { id: 'DK', name: 'Denmark' }, { id: 'FI', name: 'Finland' }, { id: 'KR', name: 'South Korea' }, { id: 'SG', name: 'Singapore' }, { id: 'NZ', name: 'New Zealand' }, { id: 'IE', name: 'Ireland' }, { id: 'CH', name: 'Switzerland' }, { id: 'AT', name: 'Austria' }, { id: 'BE', name: 'Belgium' }, { id: 'PL', name: 'Poland' }, { id: 'PT', name: 'Portugal' }, { id: 'GR', name: 'Greece' }, { id: 'TR', name: 'Turkey' }, { id: 'AE', name: 'United Arab Emirates' }, { id: 'SA', name: 'Saudi Arabia' }, { id: 'IL', name: 'Israel' }, { id: 'AR', name: 'Argentina' }, { id: 'CL', name: 'Chile' }, { id: 'CO', name: 'Colombia' }, { id: 'PE', name: 'Peru' }, { id: 'TH', name: 'Thailand' }, { id: 'VN', name: 'Vietnam' }, { id: 'ID', name: 'Indonesia' }, { id: 'MY', name: 'Malaysia' }, { id: 'PH', name: 'Philippines' } // Add more as needed or fetch from an API ]; // Full ISO 639-1 Language Codes const languageOptions = [ { id: 'EN', name: 'English' }, { id: 'FR', name: 'French' }, { id: 'DE', name: 'German' }, { id: 'IT', name: 'Italian' }, { id: 'ES', name: 'Spanish' }, { id: 'PT', name: 'Portuguese' }, { id: 'RU', name: 'Russian' }, { id: 'ZH', name: 'Chinese' }, { id: 'JA', name: 'Japanese' }, { id: 'KO', name: 'Korean' }, { id: 'AR', name: 'Arabic' }, { id: 'HI', name: 'Hindi' }, { id: 'BN', name: 'Bengali' }, { id: 'NL', name: 'Dutch' }, { id: 'SV', name: 'Swedish' }, { id: 'NO', name: 'Norwegian' }, { id: 'DA', name: 'Danish' }, { id: 'FI', name: 'Finnish' }, { id: 'TR', name: 'Turkish' }, { id: 'PL', name: 'Polish' }, { id: 'EL', name: 'Greek' }, { id: 'HE', name: 'Hebrew' }, { id: 'TH', name: 'Thai' }, { id: 'ID', name: 'Indonesian' }, { id: 'MS', name: 'Malay' }, { id: 'VI', name: 'Vietnamese' } ]; const categoryOptions = ['Digital', 'DOOH', 'Online - Banner - Celtra', 'OOH', 'Print', 'Video']; const mediaOptions = ['POS', 'OOH', 'Social', 'Community management', 'Online advertising', 'Banner', 'Rich media', 'Landing page', 'Static Image', 'Video', 'Push notifications', '.com', 'Print', 'Digital', 'Direct mail', 'Packaging', 'TV', 'Cinema', 'Radio', 'VOD']; // --- Initial Load --- loadData(); // --- API Interactions --- async function loadData() { showLoading(true); try { // Cache buster const response = await fetch(`api.php?action=load&t=${Date.now()}`); const rawData = await response.json(); if (!rawData) { initSpreadsheet([]); return; } // Transform JSON object array to Array of Arrays for Jspreadsheet if needed, // BUT Jspreadsheet supports JSON directly if we define columns matching keys. // Let's use JSON support for simplicity. initSpreadsheet(rawData); updateStats(rawData.length); } catch (error) { console.error('Error loading data:', error); alert('Failed to load data.'); } finally { showLoading(false); } } function initSpreadsheet(data) { if (spreadsheet) { spreadsheet.destroy(); } spreadsheet = jspreadsheet(spreadsheetDiv, { data: data, columns: [ { type: 'hidden', title: 'Number', width: 100, readOnly: true, name: 'Number' }, // Hidden but present for logic { type: 'text', title: 'Title', width: 300, name: 'Title' }, { type: 'dropdown', title: 'Status', width: 100, name: 'Status', source: statusOptions }, { type: 'dropdown', title: 'Category', width: 120, name: 'Category', source: categoryOptions }, { type: 'dropdown', title: 'Media', width: 120, name: 'Media', source: mediaOptions }, { type: 'text', title: 'Sub-media', width: 150, name: 'Sub-media' }, { type: 'calendar', title: 'Supply date', width: 100, name: 'Supply date', options: { format: 'YYYY-MM-DD' } }, { type: 'calendar', title: 'Live date', width: 100, name: 'Live date', options: { format: 'YYYY-MM-DD' } }, { type: 'dropdown', title: 'Language', width: 100, name: 'Language', source: languageOptions }, { type: 'dropdown', title: 'Country', width: 100, name: 'Country', source: countryOptions }, { type: 'hidden', title: 'Quantity', width: 50, name: 'Quantity' } ], defaultColWidth: 100, tableOverflow: true, tableWidth: '100%', tableHeight: '70vh', // Fixed height for scrolling // Context Menu contextMenu: function (obj, x, y, e) { var items = []; if (y == null) { // Header context menu if (obj.options.allowInsertColumn == true) { items.push({ title: obj.options.text.insertNewColumnBefore, onclick: function () { obj.insertColumn(1, parseInt(x), 1); } }); items.push({ title: obj.options.text.insertNewColumnAfter, onclick: function () { obj.insertColumn(1, parseInt(x), 0); } }); } } else { // Row context menu items.push({ title: 'Delete Selected Rows', onclick: function () { // Use the same logic as the button document.getElementById('deleteSelectedBtn').click(); } }); items.push({ title: 'Insert New Row', onclick: function () { obj.insertRow(1, parseInt(y)); } }); } return items; }, // Events onchange: function (instance, cell, x, y, value) { // Auto-save on change? Or wait? // User asked for "real time", but constant saving might be heavy. // Let's save on every change for now to be safe. saveData(); }, oninsertrow: function () { saveData(); }, ondeleterow: function () { saveData(); } }); } async function saveData(dataOverride = null) { // showLoading(true); // Don't block UI for auto-save try { const data = dataOverride || spreadsheet.getJson(); const response = await fetch('api.php?action=save', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ data: data }) }); const result = await response.json(); if (result.success) { console.log('Saved.'); updateStats(data.length); } else { console.error('Save failed:', result.message); } } catch (error) { console.error('Error saving data:', error); } finally { // showLoading(false); } } let lastCommandText = ''; async function sendCommand(overrideCommand = null, forceYolo = false) { const command = overrideCommand || commandInput.value.trim(); if (!command) return; lastCommandText = command; const yoloMode = forceYolo || document.getElementById('yoloToggle').checked; const aiOutput = document.getElementById('aiOutput'); aiOutput.textContent = `> Sending command: "${command}" (YOLO: ${yoloMode})...\n`; showLoading(true); try { const response = await fetch('api.php?action=command', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ command: command, yolo_mode: yoloMode }) }); const result = await response.json(); if (result.success) { if (result.question) { // AI has a question aiOutput.innerHTML += `