import { createClient } from 'https://cdn.jsdelivr.net/npm/@supabase/supabase-js/+esm'; // --- SUPABASE SETUP --- const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY); document.addEventListener('DOMContentLoaded', () => { // --- RENDER FUNCTIONS --- const renderContractList = () => { /* ... */ }; const renderDetails = () => { /* ... */ }; const renderActiveTimers = () => { /* ... */ }; // --- EVENT HANDLERS --- contractListEl.addEventListener('click', (e) => { const link = e.target.closest('.contract-item'); const completeBtn = e.target.closest('.quick-complete-btn'); if (completeBtn) { e.stopPropagation(); const contractId = parseInt(completeBtn.dataset.id); const contract = contracts.find(c => c.id === contractId); if (contract) { updateContractStatus(contract.id, 'Completed'); } } else if (link) { e.preventDefault(); selectedContractId = parseInt(link.dataset.id); renderContractList(); renderDetails(); } }); detailsPanelEl.addEventListener('change', (e) => { const el = e.target; const action = el.dataset.action; if (action === 'change-status') { const contract = contracts.find(c => c.id === selectedContractId); if (contract) { updateContractStatus(contract.id, el.value); } } }); detailsPanelEl.addEventListener('input', (e) => { const el = e.target; const action = el.dataset.action; if (action === 'update-signature') { const contract = contracts.find(c => c.id === selectedContractId); if (contract) { contract.signatures[el.dataset.type] = el.value; updateContract(contract.id, { signatures: contract.signatures }); } } }); detailsPanelEl.addEventListener('click', (e) => { const button = e.target.closest('.action-btn'); if (!button) return; const action = button.dataset.action; const contract = contracts.find(c => c.id === selectedContractId); if (!contract) return; switch (action) { case 'delete': document.getElementById('delete-modal-text').innerHTML = `Are you sure you want to delete contract ${contract.contract_id} for client ${contract.client}? This action cannot be undone.`; deleteModalEl.classList.remove('hidden'); break; case 'edit': openAddModal(contract); break; case 'get-book-content': const pages = generateBookPages(contract); const container = document.getElementById('command-pages-container'); container.innerHTML = ''; // Clear previous content pages.forEach((pageContent, index) => { const pageId = `page-content-${index}`; const pageHtml = `
`; container.insertAdjacentHTML('beforeend', pageHtml); }); commandModalEl.classList.remove('hidden'); break; } }); // --- MODAL & FORM HANDLING --- const getNextContractId = async () => { const prefix = "RM-"; let { data, error } = await supabase.from('settings').select('value').eq('key', 'totalContractsCreated').maybeSingle(); if (error) { console.error("Error fetching contract counter from settings:", error); // Fallback if settings table is empty or has an issue let { data: maxIdData, error: maxIdError } = await supabase.from('contracts').select('contract_id').order('contract_id', { ascending: false }).limit(1).maybeSingle(); if (maxIdError) { console.error("Error fetching max contract ID:", maxIdError); return `${prefix}001`; // Ultimate fallback } const nextIdNumber = (maxIdData ? parseInt(maxIdData.contract_id.substring(3)) : 0) + 1; return `${prefix}${nextIdNumber.toString().padStart(3, '0')}`; } const nextIdNumber = (data ? parseInt(data.value) : 0) + 1; return `${prefix}${nextIdNumber.toString().padStart(3, '0')}`; }; addContractForm.addEventListener('submit', async (e) => { e.preventDefault(); const formData = new FormData(e.target); const contractId = formData.get('contract_id'); const timeframe = formData.get('deliveryTimeframe'); const contractData = { contract_id: contractId, client: formData.get('client'), service: { name: formData.get('serviceName'), details: formData.get('serviceDetails'), itemQuantity: parseInt(formData.get('itemQuantity')) || 0 }, payment: { amount: formData.get('paymentAmount'), due: formData.get('paymentDue') }, delivery: { timeframe: timeframe, method: formData.get('deliveryMethod') }, terms: formData.get('terms').split('\n').filter(t => t.trim() !== ''), due_date: parseTimeframeToDate(timeframe), }; if (editMode) { const contractToUpdate = contracts.find(c => c.contract_id === contractId); if (contractToUpdate) { await updateContract(contractToUpdate.id, contractData); } } else { contractData.date = new Date().toISOString(); contractData.signatures = { client: "", provider: "" }; contractData.status = isAdminLoggedIn ? 'Active' : 'Pending'; await addContract(contractData); } addModalEl.classList.add('hidden'); }); document.getElementById('confirm-delete-button').addEventListener('click', () => { const contract = contracts.find(c => c.id === selectedContractId); if (contract) deleteContract(contract.id); selectedContractId = null; deleteModalEl.classList.add('hidden'); }); // --- BOOK CONTENT GENERATION --- const generateBookPages = (contract) => { const pages = []; pages.push(`&3&lService Contract&r\n${contract.contract_id}\n\n&8Client:&r\n&e${contract.client}&r\n&8Provider:&r\n&e${contract.signatures.provider || 'N/A'}&r\n\n&7Date: ${new Date(contract.date).toLocaleDateString()}`); pages.push(`&3&lService&r\n&8---------------\n&l${contract.service.name}&r\n&7${contract.service.details}`); pages.push(`&3&lPayment&r\nAmount: &e${contract.payment.amount}&r\nDue: ${contract.payment.due}\n\n&3&lDelivery&r\nTimeframe: ${contract.delivery.timeframe}\nMethod: ${contract.delivery.method}`); let termsContent = "&3&lTerms&r\n&8---------------\n"; (contract.terms || []).forEach(term => { termsContent += `&7• ${term}&r\n`; }); pages.push(termsContent.trim()); pages.push(`&3&lSignatures&r\n&8---------------\nClient Signature:\n\n&e&l${contract.signatures.client || ' '}&r\n\n\nProvider Signature:\n\n&e&l${contract.signatures.provider || ' '}&r`); return pages; }; // --- SUPABASE FUNCTIONS --- async function addContract(contractData) { const { error } = await supabase.from('contracts').insert([contractData]); if (error) { showCustomAlert(`Error adding contract: ${error.message}`, 'Error'); console.error('Error adding contract:', error); } else { const newIdNumber = parseInt(contractData.contract_id.substring(3)); await supabase.from('settings').upsert({ key: 'totalContractsCreated', value: newIdNumber }, { onConflict: 'key' }); } } async function updateContract(id, updates) { const { error } = await supabase.from('contracts').update(updates).eq('id', id); if (error) console.error('Error updating contract:', error); } async function updateContractStatus(id, status) { await updateContract(id, { status }); } async function deleteContract(id) { const { error } = await supabase.from('contracts').delete().eq('id', id); if (error) console.error('Error deleting contract:', error); } // --- INITIALIZATION --- const init = async () => { // ... (Initial setup logic) ... const [contractsRes, settingsRes, stockRes] = await Promise.all([ supabase.from('contracts').select('*'), ]); if (contractsRes.error) { showCustomAlert('Could not fetch contracts. Check database permissions (RLS) and network connection.', 'Fatal Error'); console.error('Error fetching contracts:', contractsRes.error); } else { contracts = contractsRes.data; } // real-time subscriptions supabase.channel('public:contracts').on('postgres_changes', { event: '*', schema: 'public', table: 'contracts' }, async () => { await fetchInitialData(); updateAndRender(); }).subscribe(); }; init(); });