AO
PASSWORD
Go
Incorrect Password
Connecting...
ALAN ยท
OS
Tasks
Goals
Schedule
Finance
Business Dev
Editing Pipeline
Projects
Social
Sunshine
Tasks
๐ Docs
๐
Tonight
Focus Tasks
0
+ Add Task
+ Add Goal
Schedule
Coming soon...
INVOICES
+ Add Invoice
CONTRACTS
+ Add Contract
+ Add Lead
+ Add Item
+ Add Project
โ๏ธ SUNSHINE COFFEE
7838 Atlantic Way ยท Miami Beach
Add Task
Task
Priority
๐ด NOW - Critical
๐ก SOON
โช LATER
Bucket
Personal
Family
What's Good Miami
TMD
Sunshine Coffee
Lucky
Cancel
Add
Add Goal
Goal Title
Description
Target Date
Cancel
Add
Task Notes
Notes
Cancel
Save
Add Invoice
Client
Description
Amount ($)
Entity
Date
Due Date
Status
Draft
Sent
Paid
Overdue
Cancel
Add
Add Contract
Client
Title
Value ($)
Entity
Sent Date
Status
Draft
Sent
Signed
Notes
Cancel
Add
Add Lead
Name
Company
Stage
New
Contacted
Proposal
Closing
Won
Lost
Value ($)
Next Action
Cancel
Add
Add Project
Name
Bucket
TMD
What's Good Miami
Sunshine Coffee
Personal
Notes
Canva Link
Claude Link
Cancel
Add
Add Pipeline Item
Title
Client
Status
Brief
Scripting
Filming
Editing
Review
Done
Cancel
Add
function updateConnectionStatus(status, message) { const statusEl = document.getElementById('connectionStatus'); statusEl.className = `connection-status ${status}`; statusEl.textContent = message; if (status === 'connected') { setTimeout(() => statusEl.style.opacity = '0.7', 3000); } } // โโ GLOBAL STATE โโ let tasks = []; let invoices = []; let leads = []; let goals = []; let contracts = []; let pipeline = []; let projects = []; let socPlats = []; let nextIds = {}; let tonightTasks = JSON.parse(localStorage.getItem('alan-tonight') || '[]'); let currentEditingTaskId = null; let currentEditingGoalId = null; let currentNotesTaskId = null; let currentEditingInvoiceId = null; let currentEditingContractId = null; let currentEditingLeadId = null; // โโ INIT CHECK โโ if (localStorage.getItem(PW_KEY)) { document.getElementById('pwGate').style.display = 'none'; } else { setTimeout(() => document.getElementById('pwInput').focus(), 500); } // โโ NAV โโ const PTITLES = { todo:'Tasks', goals:'Goals', schedule:'Schedule', money:'Finance', bd:'Business Dev', pipeline:'Editing Pipeline', projects:'Projects', social:'Social', sunshine:'Sunshine' }; function toggleNav() { document.getElementById('sidenav').classList.toggle('open'); document.getElementById('navOverlay').classList.toggle('open'); } function closeNav() { document.getElementById('sidenav').classList.remove('open'); document.getElementById('navOverlay').classList.remove('open'); } function showPage(id,btn) { document.querySelectorAll('.page').forEach(p=>p.classList.remove('active')); document.querySelectorAll('.nav-link').forEach(n=>n.classList.remove('active')); document.getElementById('page-'+id).classList.add('active'); btn?.classList.add('active'); document.getElementById('pageTitle').textContent=PTITLES[id]||id; closeNav(); var gdBtn=document.getElementById('gdocsBtn'); if(gdBtn) { gdBtn.style.display=['todo','money','bd'].includes(id)?'block':'none'; } var tonightBanner = document.getElementById('tonightBanner'); if (tonightBanner) { tonightBanner.style.display = id === 'todo' ? 'block' : 'none'; } if(id==='todo') renderTasks(); if(id==='goals') renderGoals(); } // โโ DATA FUNCTIONS โโ async function loadData() { console.log('๐ Loading data...'); const result = await findWorkingTable(); if (result && result.config) { console.log(`โ Using table: ${result.config.table}`); WORKING_CONFIG = result.config; // Load existing data if any if (result.data && result.data.length > 0) { try { const row = result.data[0]; const rawTasks = JSON.parse(row.tasks || '[]'); tasks = rawTasks.map(t => ({ ...t, id: t.id || t.row_id || Date.now(), row_id: t.row_id || t.id, text: t.text || t.txt || '', priority: t.priority || t.pri || 'soon', bucket: t.bucket || 'personal', done: t.done || false, notes: t.notes || '' })); invoices = JSON.parse(row.invoices || '[]'); leads = JSON.parse(row.leads || '[]'); goals = JSON.parse(row.goals || '[]'); contracts = JSON.parse(row.contracts || '[]'); pipeline = JSON.parse(row.pipeline || '[]'); projects = JSON.parse(row.projects || '[]'); socPlats = JSON.parse(row.soc_plats || '[]'); nextIds = JSON.parse(row.next_ids || '{}'); populateClientSelects(); console.log(`๐ Loaded: ${tasks.length}T ${goals.length}G`); updateConnectionStatus('connected', `${tasks.length}T ${goals.length}G loaded`); return; } catch (error) { console.error('Data parsing error:', error); } } else { console.log('Database connected but empty'); updateConnectionStatus('connected', 'Database ready'); } } else { console.log('Using localStorage fallback'); } // Load from localStorage tasks = JSON.parse(localStorage.getItem('alan-tasks') || '[]'); goals = JSON.parse(localStorage.getItem('alan-goals') || '[]'); invoices = JSON.parse(localStorage.getItem('alan-invoices') || '[]'); leads = JSON.parse(localStorage.getItem('alan-leads') || '[]'); console.log(`๐ฑ Local: ${tasks.length}T ${goals.length}G`); updateConnectionStatus(WORKING_CONFIG ? 'connected' : 'error', `Local: ${tasks.length}T ${goals.length}G`); } async function saveAll() { // Always save to localStorage localStorage.setItem('alan-tasks', JSON.stringify(tasks)); localStorage.setItem('alan-goals', JSON.stringify(goals)); localStorage.setItem('alan-invoices', JSON.stringify(invoices)); localStorage.setItem('alan-leads', JSON.stringify(leads)); localStorage.setItem('alan-tonight', JSON.stringify(tonightTasks)); if (!WORKING_CONFIG) return; try { const payload = { id: 'alan', tasks: JSON.stringify(tasks), invoices: JSON.stringify(invoices), leads: JSON.stringify(leads), goals: JSON.stringify(goals), contracts: JSON.stringify(contracts), pipeline: JSON.stringify(pipeline), projects: JSON.stringify(projects), soc_plats: JSON.stringify(socPlats), next_ids: JSON.stringify(nextIds), updated_at: new Date().toISOString() }; const response = await fetch(`${WORKING_CONFIG.url}/rest/v1/${WORKING_CONFIG.table}`, { method: 'POST', headers: { 'apikey': WORKING_CONFIG.key, 'Authorization': `Bearer ${WORKING_CONFIG.key}`, 'Content-Type': 'application/json', 'Prefer': 'resolution=merge-duplicates' }, body: JSON.stringify(payload) }); if (response.ok) { console.log('โ Saved to database'); } else { console.error('โ Save failed:', response.status); } } catch (error) { console.error('โ Save error:', error); } } // โโ TASKS โโ function renderTasks() { const todoStats = document.getElementById('todoStats'); const todoContent = document.getElementById('todoContent'); const total = tasks.length; const done = tasks.filter(t => t.done).length; const open = total - done; todoStats.innerHTML = `
${open}
Open
${done}
Done
${total}
Total
`; const BUCKETS = [ {id: 'personal', name: 'Personal'}, {id: 'family', name: 'Family'}, {id: 'wgm', name: "What's Good Miami"}, {id: 'tmd', name: 'TMD'}, {id: 'sunshine', name: 'Sunshine Coffee'}, {id: 'lucky', name: 'Lucky'} ]; let html = ''; BUCKETS.forEach(bucket => { const bucketTasks = tasks.filter(t => t.bucket === bucket.id); if (bucketTasks.length === 0) return; html += `
${bucket.name.toUpperCase()}
`; ['now', 'soon', 'later'].forEach(pri => { const priTasks = bucketTasks.filter(t => t.priority === pri); if (priTasks.length === 0) return; priTasks.forEach(task => { const taskId = task.row_id || task.id || Date.now(); const isTonight = tonightTasks.includes(taskId); html += `
${task.done ? 'โ' : ''}
${task.text}
๐ Notes
๐ ${isTonight ? 'Remove' : 'Tonight'}
โ๏ธ Edit
๐ Del
${task.notes ? `
${task.notes}
` : ''}
`; }); }); }); if (!html) { html = '
No tasks yet. Add your first task!
'; } todoContent.innerHTML = html; renderTonightBanner(); } function renderTonightBanner() { const tonightList = document.getElementById('tonightList'); const tonightCount = document.getElementById('tonightCount'); const tonightTasksData = tasks.filter(t => { const taskId = t.row_id || t.id; return tonightTasks.includes(taskId); }); tonightCount.textContent = tonightTasksData.length; const banner = document.getElementById('tonightBanner'); if (document.getElementById('page-todo').classList.contains('active')) { banner.style.display = tonightTasksData.length > 0 ? 'block' : 'none'; } let html = ''; tonightTasksData.forEach(task => { const taskId = task.row_id || task.id; html += `
${task.done ? 'โ' : ''}
${task.text}
ร
`; }); tonightList.innerHTML = html; } function toggleTask(taskId) { const task = tasks.find(t => (t.row_id || t.id) == taskId); if (task) { task.done = !task.done; saveAll(); renderTasks(); } } function toggleTonight(taskId) { const index = tonightTasks.indexOf(taskId); if (index > -1) { tonightTasks.splice(index, 1); } else { tonightTasks.push(taskId); } localStorage.setItem('alan-tonight', JSON.stringify(tonightTasks)); renderTasks(); } function openTaskNotes(taskId) { const task = tasks.find(t => (t.row_id || t.id) == taskId); if (task) { currentNotesTaskId = taskId; document.getElementById('nm-notes').value = task.notes || ''; openModal('notesModal'); } } function saveTaskNotes() { if (currentNotesTaskId) { const task = tasks.find(t => (t.row_id || t.id) == currentNotesTaskId); if (task) { task.notes = document.getElementById('nm-notes').value.trim(); saveAll(); closeModals(); renderTasks(); } } } function editTask(taskId) { const task = tasks.find(t => (t.row_id || t.id) == taskId); if (task) { currentEditingTaskId = taskId; document.getElementById('taskModalTitle').textContent = 'Edit Task'; document.getElementById('taskSaveBtn').textContent = 'Save'; document.getElementById('tm-txt').value = task.text; document.getElementById('tm-pri').value = task.priority; document.getElementById('tm-bucket').value = task.bucket; openModal('taskModal'); } } function saveTask() { const text = document.getElementById('tm-txt').value.trim(); const priority = document.getElementById('tm-pri').value; const bucket = document.getElementById('tm-bucket').value; if (!text) return; if (currentEditingTaskId) { const task = tasks.find(t => (t.row_id || t.id) == currentEditingTaskId); if (task) { task.text = text; task.priority = priority; task.bucket = bucket; } currentEditingTaskId = null; } else { const newTask = { row_id: Date.now(), id: Date.now(), text: text, priority: priority, bucket: bucket, done: false, created: new Date().toISOString(), notes: '' }; tasks.push(newTask); } saveAll(); closeModals(); renderTasks(); document.getElementById('taskModalTitle').textContent = 'Add Task'; document.getElementById('taskSaveBtn').textContent = 'Add'; document.getElementById('tm-txt').value = ''; document.getElementById('tm-pri').value = 'soon'; document.getElementById('tm-bucket').value = 'personal'; } function deleteTask(taskId) { if (confirm('Delete this task?')) { tasks = tasks.filter(t => (t.row_id || t.id) != taskId); tonightTasks = tonightTasks.filter(tid => tid != taskId); localStorage.setItem('alan-tonight', JSON.stringify(tonightTasks)); saveAll(); renderTasks(); } } // โโ GOALS โโ function renderGoals() { const goalsStats = document.getElementById('goalsStats'); const goalsContent = document.getElementById('goalsContent'); const total = goals.length; const completed = goals.filter(g => g.completed).length; const overdue = goals.filter(g => !g.completed && new Date(g.targetDate) < new Date()).length; goalsStats.innerHTML = `
${total}
Total
${completed}
Done
${overdue}
Overdue
`; let html = ''; goals.forEach((goal, index) => { const targetDate = new Date(goal.targetDate); const today = new Date(); const daysUntil = Math.ceil((targetDate - today) / (1000 * 60 * 60 * 24)); let statusClass = 'ontrack'; let statusText = 'On Track'; if (goal.completed) { statusClass = 'complete'; statusText = 'Complete'; } else if (daysUntil < 0) { statusClass = 'overdue'; statusText = `${Math.abs(daysUntil)} days overdue`; } else if (daysUntil <= 7) { statusClass = 'urgent'; statusText = `${daysUntil} days left`; } else { statusText = `${daysUntil} days left`; } html += `
${statusText}
${goal.title}
${goal.description ? `
${goal.description}
` : ''}
Target: ${targetDate.toLocaleDateString()}
โ๏ธ Edit
${goal.completed ? 'โฉ๏ธ Reopen' : 'โ Complete'}
๐ Del
`; }); if (!html) { html = '
No goals yet. Add your first goal!
'; } goalsContent.innerHTML = html; } function editGoal(index) { const goal = goals[index]; if (goal) { currentEditingGoalId = index; document.getElementById('goalModalTitle').textContent = 'Edit Goal'; document.getElementById('goalSaveBtn').textContent = 'Save'; document.getElementById('gm-title').value = goal.title; document.getElementById('gm-desc').value = goal.description || ''; document.getElementById('gm-date').value = goal.targetDate; openModal('goalModal'); } } function saveGoal() { const title = document.getElementById('gm-title').value.trim(); const description = document.getElementById('gm-desc').value.trim(); const targetDate = document.getElementById('gm-date').value; if (!title || !targetDate) return; if (currentEditingGoalId !== null) { goals[currentEditingGoalId].title = title; goals[currentEditingGoalId].description = description; goals[currentEditingGoalId].targetDate = targetDate; currentEditingGoalId = null; } else { goals.push({ gid: Date.now(), title: title, description: description, targetDate: targetDate, completed: false, created: new Date().toISOString() }); } saveAll(); closeModals(); renderGoals(); document.getElementById('goalModalTitle').textContent = 'Add Goal'; document.getElementById('goalSaveBtn').textContent = 'Add'; document.getElementById('gm-title').value = ''; document.getElementById('gm-desc').value = ''; document.getElementById('gm-date').value = ''; } function toggleGoal(index) { goals[index].completed = !goals[index].completed; if (goals[index].completed) { goals[index].completedDate = new Date().toISOString(); } else { delete goals[index].completedDate; } saveAll(); renderGoals(); } function deleteGoal(index) { if (confirm('Delete this goal?')) { goals.splice(index, 1); saveAll(); renderGoals(); } } // โโ FINANCE โโ function renderMoney() { const inv = invoices; const con = contracts; const paid = inv.filter(i=>i.sts==='paid').reduce((s,i)=>s+i.amt,0); const sent = inv.filter(i=>i.sts==='sent').reduce((s,i)=>s+i.amt,0); const draft = inv.filter(i=>i.sts==='draft').reduce((s,i)=>s+i.amt,0); document.getElementById('moneyStats').innerHTML = `
$${(paid/1000).toFixed(0)}k
Collected
$${(sent/1000).toFixed(0)}k
Sent
$${(draft/1000).toFixed(0)}k
Draft
`; const STS_INV = {paid:'#1db954',sent:'#f5a623',draft:'#888',overdue:'#e63329'}; document.getElementById('invoicesContent').innerHTML = inv.length ? inv.map((i,idx)=>`
${i.cli}
${i.dsc||''} ยท ${i.dt||''}
$${i.amt?.toLocaleString()}
${i.sts}
โ๏ธ
๐
`).join('') : '
No invoices yet
'; const STS_CON = {signed:'#1db954',sent:'#f5a623',draft:'#888'}; document.getElementById('contractsContent').innerHTML = con.length ? con.map((c,idx)=>`
${c.cli} โ ${c.ttl}
${c.nts||''}
$${c.val?.toLocaleString()}
${c.sts}
๐
`).join('') : '
No contracts yet
'; } function editInvoice(idx) { const i = invoices[idx]; currentEditingInvoiceId = idx; populateClientSelects(); document.getElementById('invoiceModalTitle').textContent = 'Edit Invoice'; document.getElementById('invoiceSaveBtn').textContent = 'Save'; document.getElementById('im-cli').value = i.cli; document.getElementById('im-dsc').value = i.dsc||''; document.getElementById('im-amt').value = i.amt||''; document.getElementById('im-ent').value = i.ent||'Breakthrough Brands LLC'; document.getElementById('im-dt').value = i.dt||''; document.getElementById('im-due').value = i.due||''; document.getElementById('im-sts').value = i.sts||'draft'; openModal('invoiceModal'); } function saveInvoice() { const obj = { id: currentEditingInvoiceId !== null ? invoices[currentEditingInvoiceId].id : (nextIds.nextIId++), cli: document.getElementById('im-cli').value, dsc: document.getElementById('im-dsc').value, amt: parseFloat(document.getElementById('im-amt').value)||0, ent: document.getElementById('im-ent').value, dt: document.getElementById('im-dt').value, due: document.getElementById('im-due').value, sts: document.getElementById('im-sts').value }; if (currentEditingInvoiceId !== null) { invoices[currentEditingInvoiceId] = obj; currentEditingInvoiceId = null; } else invoices.push(obj); saveAll(); closeModals(); renderMoney(); document.getElementById('invoiceModalTitle').textContent = 'Add Invoice'; document.getElementById('invoiceSaveBtn').textContent = 'Add'; } function deleteInvoice(idx) { if(confirm('Delete invoice?')) { invoices.splice(idx,1); saveAll(); renderMoney(); } } function saveContract() { const obj = { id: currentEditingContractId !== null ? contracts[currentEditingContractId].id : (nextIds.nextCId++), cli: document.getElementById('cm-cli').value, ttl: document.getElementById('cm-ttl').value, val: parseFloat(document.getElementById('cm-val').value)||0, ent: document.getElementById('cm-ent').value, sent: document.getElementById('cm-sent').value, sts: document.getElementById('cm-sts').value, nts: document.getElementById('cm-nts').value, sgn: '' }; if (currentEditingContractId !== null) { contracts[currentEditingContractId] = obj; currentEditingContractId = null; } else contracts.push(obj); saveAll(); closeModals(); renderMoney(); } function deleteContract(idx) { if(confirm('Delete contract?')) { contracts.splice(idx,1); saveAll(); renderMoney(); } } // โโ BUSINESS DEV โโ const STAGE_ORDER = ['new','contacted','proposal','closing','won','lost']; const STAGE_COLOR = {new:'#888',contacted:'#3a00f4',proposal:'#f5a623',closing:'#1db954',won:'#1db954',lost:'#e63329'}; function renderBD() { const total = leads.length; const pipeline = leads.filter(l=>!['won','lost'].includes(l.stg)).reduce((s,l)=>s+(l.val||0),0); const won = leads.filter(l=>l.stg==='won').reduce((s,l)=>s+(l.val||0),0); document.getElementById('bdStats').innerHTML = `
${total}
Leads
$${(pipeline/1000).toFixed(0)}k
Pipeline
$${(won/1000).toFixed(0)}k
Won
`; document.getElementById('leadsContent').innerHTML = leads.length ? leads.map((l,idx)=>`
${l.nm}
${l.co||''}
$${(l.val||0).toLocaleString()}
${l.stg}
${l.act ? `
โ ${l.act}
` : ''}
โ๏ธ Edit
๐ Del
`).join('') : '
No leads yet
'; } function editLead(idx) { const l = leads[idx]; currentEditingLeadId = idx; document.getElementById('leadModalTitle').textContent = 'Edit Lead'; document.getElementById('leadSaveBtn').textContent = 'Save'; document.getElementById('lm-nm').value = l.nm||''; document.getElementById('lm-co').value = l.co||''; document.getElementById('lm-stg').value = l.stg||'new'; document.getElementById('lm-val').value = l.val||''; document.getElementById('lm-act').value = l.act||''; openModal('leadModal'); } function saveLead() { const obj = { id: currentEditingLeadId !== null ? leads[currentEditingLeadId].id : (nextIds.nextLId++), nm: document.getElementById('lm-nm').value, co: document.getElementById('lm-co').value, stg: document.getElementById('lm-stg').value, val: parseFloat(document.getElementById('lm-val').value)||0, act: document.getElementById('lm-act').value, tags: [] }; if (currentEditingLeadId !== null) { leads[currentEditingLeadId] = obj; currentEditingLeadId = null; } else leads.push(obj); saveAll(); closeModals(); renderBD(); document.getElementById('leadModalTitle').textContent = 'Add Lead'; document.getElementById('leadSaveBtn').textContent = 'Add'; } function deleteLead(idx) { if(confirm('Delete lead?')) { leads.splice(idx,1); saveAll(); renderBD(); } } // โโ PIPELINE โโ const PL_STATUS = {brief:'#888',scripting:'#3a00f4',filming:'#f5a623',editing:'#f5a623',review:'#cfc0ff',done:'#1db954'}; function renderPipeline() { const total = pipeline.length; const inprog = pipeline.filter(p=>!['done'].includes(p.sts)).length; const done = pipeline.filter(p=>p.sts==='done').length; document.getElementById('pipelineStats').innerHTML = `
${total}
Total
${inprog}
In Progress
${done}
Done
`; document.getElementById('pipelineContent').innerHTML = pipeline.length ? pipeline.map((p,idx)=>`
${p.ttl||p.title||''}
${p.cli||''}
${p.sts}
๐
`).join('') : '
No pipeline items yet
'; } function savePipelineItem() { pipeline.push({ id: nextIds.nextPId++, ttl: document.getElementById('plm-ttl').value, cli: document.getElementById('plm-cli').value, sts: document.getElementById('plm-sts').value }); saveAll(); closeModals(); renderPipeline(); } function deletePipelineItem(idx) { if(confirm('Delete?')) { pipeline.splice(idx,1); saveAll(); renderPipeline(); } } // โโ PROJECTS โโ const BKT_LABEL = {tmd:'TMD',wgm:"What's Good Miami",sunshine:'Sunshine Coffee',personal:'Personal',lucky:'Lucky'}; const BKT_COLOR = {tmd:'pu',wgm:'gr',sunshine:'or',personal:'bl',lucky:'ye'}; function renderProjects() { document.getElementById('projectsContent').innerHTML = projects.length ? projects.map((p,idx)=>`
${p.nm}
${BKT_LABEL[p.bkt]||p.bkt}
๐
${p.notes ? `
${p.notes}
` : ''}
${p.canva && p.canva !== 'https://canva.com' ? `
๐ Canva
` : ''} ${p.claude && p.claude !== 'https://claude.ai' ? `
๐ค Claude
` : ''}
`).join('') : '
No projects yet
'; } function saveProject() { projects.push({ id: nextIds.nextProjId++, nm: document.getElementById('pm-nm').value, bkt: document.getElementById('pm-bkt').value, notes: document.getElementById('pm-notes').value, canva: document.getElementById('pm-canva').value, claude: document.getElementById('pm-claude').value }); saveAll(); closeModals(); renderProjects(); } function deleteProject(idx) { if(confirm('Delete project?')) { projects.splice(idx,1); saveAll(); renderProjects(); } } // โโ SOCIAL โโ const POST_STS = {live:'#1db954',scheduled:'#3a00f4',draft:'#888'}; function renderSocial() { document.getElementById('socialContent').innerHTML = socPlats.map(plat=>`
${plat.nm} ยท ${plat.hdl}
${(plat.posts||[]).map(p=>`
${p.txt}
${p.dt||''}
${p.sts}
`).join('')} ${!(plat.posts||[]).length ? '
No posts yet
' : ''}
`).join(''); } // โโ SUNSHINE โโ function renderSunshine() { const sunTasks = tasks.filter(t=>t.bucket==='sunshine'); const sunLeads = leads.filter(l=>(l.tags||[]).includes('Sunshine') || (l.co||'').toLowerCase().includes('sunshine')); document.getElementById('sunshineContent').innerHTML = `
TASKS (${sunTasks.length})
${sunTasks.length ? sunTasks.map(t=>`
${t.done?'โ':''}
${t.text}
`).join('') : '
No Sunshine tasks
'}
SOCIAL POSTS
${socPlats.filter(p=>p.hdl.includes('sunshine')).map(plat=>`
${plat.nm} ยท ${plat.hdl}
${(plat.posts||[]).map(p=>`
${p.txt}
${p.sts}
`).join('')}
`).join('')} `; } // โโ POPULATE CLIENT SELECTS โโ function populateClientSelects() { const clients = nextIds.clients || []; ['im-cli','cm-cli','plm-cli'].forEach(id => { const el = document.getElementById(id); if (el) el.innerHTML = clients.map(c=>`
${c}
`).join(''); }); } // โโ SHOW PAGE OVERRIDE โโ const _origShowPage = showPage; function showPage(id, btn) { _origShowPage(id, btn); if (id==='money') renderMoney(); if (id==='bd') renderBD(); if (id==='pipeline') renderPipeline(); if (id==='projects') renderProjects(); if (id==='social') renderSocial(); if (id==='sunshine') renderSunshine(); } function exportToGoogleDocs() { alert('Google Docs export coming soon!'); } // โโ MODALS โโ function openModal(id) { document.getElementById(id).classList.add('open'); setTimeout(() => { const firstInput = document.querySelector(`#${id} input, #${id} textarea`); if (firstInput) firstInput.focus(); }, 100); } function closeModals() { document.querySelectorAll('.mo').forEach(m => m.classList.remove('open')); currentEditingTaskId = null; currentEditingGoalId = null; currentNotesTaskId = null; } document.addEventListener('click', (e) => { if (e.target.classList.contains('mo')) closeModals(); }); document.addEventListener('keydown', (e) => { if (e.key === 'Escape') closeModals(); }); // โโ BOOT โโ async function boot() { console.log('๐ Alan OS starting...'); document.getElementById('topDate').textContent = new Date().toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric' }); await loadData(); renderTasks(); console.log('โ Alan OS loaded'); } if (localStorage.getItem(PW_KEY)) { boot(); }