CV. Roti Semua Generasi

WELCOME TO
TAOBUN MANAGEMENT SUITE

๐Ÿ‘‹
Mulai Input Data Bulan Ini
Belum ada data yang tersimpan. Yuk, mulai dengan mengisi Branch Comparison untuk bulan ini!
TAOBUN Management Suite

Actual Monthly Revenue

Rp 0
Potential Leads
Target Rate
%
Active Customers
โ†ณ Actual Conv.
0%
โ†ณ New / Retained
0/
Basket Size
Rp
Avg Tx / Month
x
Growth Ambition
%
Projected Revenue
Rp 0

Customer Funnel Analysis

Revenue Target Comparison

LEAD Conversion Analysis
Reach / Impressions
Profile Visits
External Link Clicks
ESB Order Clicks
Success Payments

Lengkapi data di atas.

BRANCH Comparison
Februari 2026
Taobun Raya
Taobun Kemboja
Taobun Perdos
Total Revenue
Rp 0
Gabungan 3 cabang
Revenue Leader
โ€”
โ€”
Gross Margin Leader
โ€”
โ€”
Total Customers
0
Gabungan 3 cabang
Metrik ๐ŸŸฃ Raya ๐ŸŸก Kemboja ๐ŸŸข Perdos Unggul
Isi data di atas untuk melihat perbandingan
Revenue & Gross Profit โ€” Raya vs Kemboja vs Perdos
๐ŸŽฏ Target Revenue per Cabang
๐ŸŸฃ Raya
๐ŸŸก Kemboja
๐ŸŸข Perdos
๐Ÿ“ˆ Tren Historis per Cabang
Dashboard
TaoBun Loyalty Program
Total Produk Terdaftar
64
4 Tier Level Aktif
64
Total Produk
4
Tier Level
Rp2.000
Belanja โ†’ 1 Poin
Rp20
Nilai Tukar 1 Poin
๐Ÿฅ‰
Bronze Bun
Entry Level
1ร—
Poin Multiplier
Naik ke Silverโ‰ฅ Rp250rb/thn
StayOtomatis
๐Ÿฅˆ
Silver Bun
Active
1.2ร—
Poin Multiplier
Naik ke Goldโ‰ฅ Rp600rb/thn
Stay SilverRp300rb/thn
๐Ÿฅ‡
Gold Bun
Loyal
1.5ร—
Poin Multiplier
Naik ke Platinumโ‰ฅ Rp1,5jt/thn
Stay GoldRp750rb/thn
๐Ÿ’Ž
Platinum Bun
VIP
2ร—
Poin Multiplier
Stay PlatinumRp1,8jt/thn
Turun jika< Rp1,8jt
Kalkulator Poin
Masukkan jumlah belanja
Alur Naik & Turun Tier โ€” Evaluasi Akhir Tahun
๐Ÿฅ‰ Bronze
Entry
โ‰ฅ Rp250rb โ†—
โ†’
โ€” tetap
๐Ÿฅˆ Silver
Stay โ‰ฅ 300rb
โ‰ฅ Rp600rb โ†—
โ†’
โ†™ <300rb
๐Ÿฅ‡ Gold
Stay โ‰ฅ 750rb
โ‰ฅ Rp1,5jt โ†—
โ†’
โ†™ <750rb
๐Ÿ’Ž Platinum
Stay โ‰ฅ 1,8jt
Master Produk
64 produk โ€” HPP, harga jual, margin, status redeem
๐Ÿ”
#Nama ProdukHPPHarga JualGross MarginGM %ParetoMin. PoinRedeem
Skema Tiering
Parameter sistem poin dan simulasi cost of loyalty
Parameter Sistem
Cost of Loyalty per Tier
TierPoin DidapatNilai PoinCost of Loyalty
๐Ÿฅ‰
Bronze Bun
1ร— Multiplier
๐Ÿฅˆ
Silver Bun
1.2ร— Multiplier
๐Ÿฅ‡
Gold Bun
1.5ร— Multiplier
๐Ÿ’Ž
Platinum Bun
2ร— Multiplier
Simulasi Profitabilitas
Gross margin final per tier setelah dikurangi biaya poin
Parameter

Avg Struk per Tier
Gross Margin per Tier
TierAvg StrukEst. HPPGM AwalBiaya PoinGM FinalGM %Status
Aturan Baku Margin
โœ… AMAN Gross Margin โ‰ฅ 45%
โš ๏ธ MENIPIS 38%โ€“44%
๐Ÿ”ด BONCOS <38%
Reward Berjenjang
Katalog reward per tier โ€” integrasi skema poin
TierNama ProgramItem RewardHarga JualHPPGM%PoinBelanja EfektifRasio vs STAYKeterangan
Simulasi Promo & Misi
Uji kelayakan promo sebelum dijalankan
Buat Simulasi Baru
โš ๏ธ Belum ada data produk. Import Excel dulu via tombol Import Excel di nav bar atas.
โ–พ
๐Ÿ“‹
Belum ada simulasi promo.
Buat dari panel kiri.
๐Ÿ“ฅ Import dari Excel
Upload file SKEMA_SOBAT_TAOBUN.xlsx untuk memperbarui data Master Produk, Reward, dan parameter sistem secara otomatis.
๐Ÿ“Š
Klik atau drag & drop file Excel di sini
.xlsx / .xls โ€” SKEMA_SOBAT_TAOBUN.xlsx
Membaca file...
Preview Data yang Akan Diupdate
Memproses data...

Branch Report

Periode: ${period}  โ€ข  Dicetak: ${new Date().toLocaleDateString('id-ID', {weekday:'long', year:'numeric', month:'long', day:'numeric'})}
Revenue Summary
CabangRevenueCOGSGross ProfitGM %CustomersTransaksi
๐ŸŸฃ Raya${bcRp(r.rev)}${bcRp(r.cogs)}${bcRp(r.rev-r.cogs)}${r.gm}%${r.cust.toLocaleString('id-ID')}${r.tx.toLocaleString('id-ID')}
๐ŸŸก Kemboja${bcRp(k.rev)}${bcRp(k.cogs)}${bcRp(k.rev-k.cogs)}${k.gm}%${k.cust.toLocaleString('id-ID')}${k.tx.toLocaleString('id-ID')}
๐ŸŸข Perdos${bcRp(p.rev)}${bcRp(p.cogs)}${bcRp(p.rev-p.cogs)}${p.gm}%${p.cust.toLocaleString('id-ID')}${p.tx.toLocaleString('id-ID')}
TOTAL${bcRp(totalRev)}${bcRp(r.cogs+k.cogs+p.cogs)}${bcRp(totalRev - r.cogs - k.cogs - p.cogs)}โ€”${(r.cust+k.cust+p.cust).toLocaleString('id-ID')}${(r.tx+k.tx+p.tx).toLocaleString('id-ID')}
${(tgtRaya||tgtKemb||tgtPerd) ? `
Target vs Aktual
CabangTargetAktualPencapaianStatus
๐ŸŸฃ Raya${tgtRaya?bcRp(tgtRaya):'โ€”'}${bcRp(r.rev)}${pctRow(r.rev,tgtRaya)}${tgtRaya?(r.rev>=tgtRaya?'โœ… Tercapai':r.rev/tgtRaya>=0.75?'โšก On Track':'๐Ÿ”ด Off Track'):'โ€”'}
๐ŸŸก Kemboja${tgtKemb?bcRp(tgtKemb):'โ€”'}${bcRp(k.rev)}${pctRow(k.rev,tgtKemb)}${tgtKemb?(k.rev>=tgtKemb?'โœ… Tercapai':k.rev/tgtKemb>=0.75?'โšก On Track':'๐Ÿ”ด Off Track'):'โ€”'}
๐ŸŸข Perdos${tgtPerd?bcRp(tgtPerd):'โ€”'}${bcRp(p.rev)}${pctRow(p.rev,tgtPerd)}${tgtPerd?(p.rev>=tgtPerd?'โœ… Tercapai':p.rev/tgtPerd>=0.75?'โšก On Track':'๐Ÿ”ด Off Track'):'โ€”'}
` : ''} `; const win = window.open('', '_blank'); win.document.write(html); win.document.close(); setTimeout(() => { win.focus(); win.print(); }, 400); richToast(`๐Ÿ“„ Membuka preview PDF untuk ${period}...`); } function bcSave(r, k, p) { const data = {}; const fields = ['rev','cust','tx','basket','new_c','cogs']; fields.forEach(f => { const sfx = f === 'new_c' ? 'new' : f; data[`raya_${f}`] = document.getElementById(`br-raya-${sfx}`)?.value || '0'; data[`kemb_${f}`] = document.getElementById(`br-kemb-${sfx}`)?.value || '0'; data[`perd_${f}`] = document.getElementById(`br-perd-${sfx}`)?.value || '0'; }); try { localStorage.setItem(LS_KEY_BRANCH, JSON.stringify(data)); } catch(e) {} } function bcLoad() { try { const raw = localStorage.getItem(LS_KEY_BRANCH); if (!raw) return; const d = JSON.parse(raw); const map = { rev: 'rev', cust: 'cust', tx: 'tx', basket: 'basket', new_c: 'new', cogs: 'cogs' }; Object.entries(map).forEach(([key, sfx]) => { const rEl = document.getElementById(`br-raya-${sfx}`); const kEl = document.getElementById(`br-kemb-${sfx}`); const pEl = document.getElementById(`br-perd-${sfx}`); if (rEl && d[`raya_${key}`]) rEl.value = d[`raya_${key}`]; if (kEl && d[`kemb_${key}`]) kEl.value = d[`kemb_${key}`]; if (pEl && d[`perd_${key}`]) pEl.value = d[`perd_${key}`]; }); bcCalculate(); bcLoadTargets(); bcRenderHistory(); updatePeriodBadge(); } catch(e) {} } function bcReset() { showConfirm({ icon: '๐Ÿ—‘๏ธ', title: 'Reset Branch Data?', msg: 'Semua data input cabang akan dikosongkan. Target dan histori tetap tersimpan.', okLabel: 'Reset' }, function() { ['rev','cust','tx','basket','new','cogs'].forEach(f => { ['raya','kemb','perd'].forEach(b => { const el = document.getElementById(`br-${b}-${f}`); if (el) el.value = '0'; }); }); try { localStorage.removeItem(LS_KEY_BRANCH); } catch(e) {} bcCalculate(); richToast('โœ… Data ketiga cabang berhasil direset.'); buildHomeAlerts(); checkOnboarding(); }); } // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• // Init sobun on load // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• // PASSWORD GATE โ€” Sobat Taobun // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• // Password disimpan sebagai hash SHA-256. // Untuk ganti password: jalankan fungsi pwHashPassword('passwordbaru') // di console browser, lalu simpan hash-nya ke PW_HASH_KEY di localStorage. // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• const PW_HASH_KEY = 'taobun_pw_hash_v1'; // Hash SHA-256 dari password default (taobun2026). // Ganti string ini jika ingin ubah password default. const PW_DEFAULT_HASH = 'e53ceb6dfdb5845b305c826e2da049f495d66037df60056d14ee8bcea7779900'; async function pwHashPassword(plain) { const enc = new TextEncoder().encode(plain); const buf = await crypto.subtle.digest('SHA-256', enc); return Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2,'0')).join(''); } async function pwGetHash() { try { return localStorage.getItem(PW_HASH_KEY) || PW_DEFAULT_HASH; } catch(e) { return PW_DEFAULT_HASH; } } function pwOpen() { const overlay = document.getElementById('pwOverlay'); overlay.classList.add('open'); const inp = document.getElementById('pwInput'); inp.value = ''; inp.type = 'password'; document.getElementById('pwToggleBtn').textContent = '๐Ÿ‘'; document.getElementById('pwErrMsg').textContent = ''; inp.classList.remove('pw-error'); setTimeout(() => inp.focus(), 150); } function pwClose() { document.getElementById('pwOverlay').classList.remove('open'); } function pwToggleShow() { const inp = document.getElementById('pwInput'); const btn = document.getElementById('pwToggleBtn'); if (inp.type === 'password') { inp.type = 'text'; btn.textContent = '๐Ÿ™ˆ'; } else { inp.type = 'password'; btn.textContent = '๐Ÿ‘'; } } async function pwSubmit() { const inp = document.getElementById('pwInput'); const val = inp.value; if (!val) { document.getElementById('pwErrMsg').textContent = 'Password tidak boleh kosong.'; inp.classList.add('pw-error'); return; } const inputHash = await pwHashPassword(val); const storedHash = await pwGetHash(); if (inputHash !== storedHash) { document.getElementById('pwErrMsg').textContent = 'โŒ Password salah. Coba lagi.'; inp.classList.add('pw-error'); inp.value = ''; setTimeout(() => inp.classList.remove('pw-error'), 700); return; } window._sobunUnlocked = true; sessionStorage.setItem('taobun_sobun_unlocked', '1'); pwClose(); showView('sobun-view'); } // โ”€โ”€ Import Excel password gate โ”€โ”€ function pwImportClose() { document.getElementById('pwImportOverlay').classList.remove('open'); xlParsed = null; xlToast('โ„น๏ธ Update data dibatalkan.'); } function pwImportToggleShow() { const inp = document.getElementById('pwImportInput'); const btn = document.getElementById('pwImportToggleBtn'); if (inp.type === 'password') { inp.type = 'text'; btn.textContent = '๐Ÿ™ˆ'; } else { inp.type = 'password'; btn.textContent = '๐Ÿ‘'; } } async function pwImportSubmit() { const inp = document.getElementById('pwImportInput'); const val = inp.value; if (!val) { document.getElementById('pwImportErrMsg').textContent = 'Password tidak boleh kosong.'; inp.classList.add('pw-error'); return; } const inputHash = await pwHashPassword(val); const storedHash = await pwGetHash(); if (inputHash !== storedHash) { document.getElementById('pwImportErrMsg').textContent = 'โŒ Password salah. Coba lagi.'; inp.classList.add('pw-error'); inp.value = ''; setTimeout(() => inp.classList.remove('pw-error'), 700); return; } // Password benar โ€” terapkan semua data Excel document.getElementById('pwImportOverlay').classList.remove('open'); const d = xlParsed; if (!d) { xlToast('โš ๏ธ Tidak ada data Excel yang menunggu.'); return; } const changes = []; const rp = v => 'Rp ' + Math.round(v).toLocaleString('id-ID'); // Sheet 1: Master Produk if (d.products && d.products.length > 0) { const oldCount = P.length; P.length = 0; d.products.forEach(p => P.push(p)); changes.push(`๐Ÿ“ฆ Master Produk: ${oldCount} โ†’ ${d.products.length} produk`); } // Sheet 2: Skema Tiering if (d.tiering) { const setRp = (id, v) => { const el = document.getElementById(id); if(el) el.value = 'Rp ' + v.toLocaleString('id-ID'); }; setRp('t-bp', d.tiering.bp); setRp('p-bp', d.tiering.bp); setRp('t-np', d.tiering.np); setRp('p-np', d.tiering.np); changes.push(`โš™๏ธ Tiering: ${rp(d.tiering.bp)}/poin, nilai ${rp(d.tiering.np)}`); } // Sheet 3: Simulasi Profitabilitas โ€” HPP % + avg struk per tier if (d.hppPct !== undefined) { const el = document.getElementById('p-hpp'); if(el) el.value = d.hppPct.toFixed(2); changes.push(`๐Ÿ“Š HPP Assumption: ${d.hppPct.toFixed(2)}%`); } if (d.avgStruk) { const setRp2 = (id, v) => { const el = document.getElementById(id); if(el && v > 0) el.value = 'Rp ' + v.toLocaleString('id-ID'); }; setRp2('p-abr', d.avgStruk.bronze); setRp2('p-asi', d.avgStruk.silver); setRp2('p-ago', d.avgStruk.gold); setRp2('p-apl', d.avgStruk.platinum); const filled = ['bronze','silver','gold','platinum'].filter(k=>d.avgStruk[k]>0); if(filled.length) changes.push(`๐Ÿ“Š Avg Struk: ${filled.length} tier diupdate`); } // Sheet 3: Tier thresholds (naik/stay) โ€” update TIER_TH state & display if (d.thresholds) { let tCount = 0; // Map dari Excel: silver naik=3jtโ†’250rb? // Excel pakai nilai TAHUNAN (3.000.000). Di UI pakai shorthand. // Tapi nilai di Excel row14-16 col2=NAIK col3=STAY // Silver: naik=3000000 di Excel = threshold naik dari bronze ke silver // Kita map: bronze.naik = silver threshold NAIK (belanja min utk naik dari bronze) const th = d.thresholds; if (th.silver) { TIER_TH.bronze.naik = th.silver.naik; TIER_TH.silver.stay = th.silver.stay; tCount += 2; } if (th.gold) { TIER_TH.silver.naik = th.gold.naik; TIER_TH.gold.stay = th.gold.stay; tCount += 2; } if (th.platinum) { TIER_TH.gold.naik = th.platinum.naik; TIER_TH.platinum.stay= th.platinum.stay; tCount += 2; } TIER_TH.platinum.naik = TIER_TH.platinum.stay; updateTierDisplay(); if (tCount) changes.push('๐ŸŽฏ Threshold Tier: diupdate dari Excel'); } // Sheet 4: Simulasi Misi & Promo if (d.promos && d.promos.length > 0) { promos = d.promos; renderPromo(); const aman = d.promos.filter(p=>p.gm>=0.45).length; const boncos = d.promos.filter(p=>p.gm<0.38).length; changes.push(`๐ŸŽฏ Promo: ${d.promos.length} program (${aman} aman${boncos?' ยท '+boncos+' boncos':''})`); } // Sheet 5: Simulasi Reward if (d.rewards && d.rewards.length > 0) { RW = d.rewards; renderRw(); const byTier = {bronze:0,silver:0,gold:0,platinum:0}; d.rewards.forEach(r=>{ if(byTier[r.t]!==undefined) byTier[r.t]++; }); const summary = Object.entries(byTier).filter(([,v])=>v>0).map(([k,v])=>v+' '+k).join(', '); changes.push(`๐Ÿ† Reward: ${d.rewards.length} reward (${summary})`); } initDash(); renderMaster(); calcT(); calcP(); renderRw(); cbRender(); sbSave(); // save AFTER apply, before any load // โ”€โ”€ SIMPAN SEBAGAI EXCEL BASELINE (data permanen) โ”€โ”€ // Data ini akan jadi default yang tidak bisa diubah sampai Excel baru diimport try { const baseline = { importedAt: new Date().toISOString(), products: d.products && d.products.length > 0 ? d.products.slice() : null, tiering: d.tiering || null, hppPct: d.hppPct !== undefined ? d.hppPct : null, avgStruk: d.avgStruk || null, thresholds: d.thresholds || null, promos: d.promos && d.promos.length > 0 ? d.promos.slice() : null, rewards: d.rewards && d.rewards.length > 0 ? d.rewards.slice() : null, // Snapshot nilai field saat ini untuk restore fields: { t_bp: document.getElementById('t-bp')?.value, t_np: document.getElementById('t-np')?.value, p_hpp: document.getElementById('p-hpp')?.value, p_bp: document.getElementById('p-bp')?.value, p_np: document.getElementById('p-np')?.value, p_abr: document.getElementById('p-abr')?.value, p_asi: document.getElementById('p-asi')?.value, p_ago: document.getElementById('p-ago')?.value, p_apl: document.getElementById('p-apl')?.value, }, tierThresholds: JSON.parse(JSON.stringify(TIER_TH)), }; localStorage.setItem(LS_KEY_EXCEL_BASELINE, JSON.stringify(baseline)); _xlBaselineLoaded = true; applyExcelBaslineLock(true); console.log('[Excel Baseline] Disimpan:', new Date(baseline.importedAt).toLocaleString('id-ID')); } catch(e) { console.warn('[Excel Baseline] Gagal simpan:', e); } xlParsed = null; const msg = changes.length ? 'โœ… Data diupdate!\n' + changes.join('\n') : 'โœ… Data diupdate & disimpan!'; xlToast(msg.split('\n')[0] + (changes.length > 1 ? ` (+${changes.length-1} lainnya)` : '') + ' ยท ๐Ÿ”’ Disimpan sebagai data default'); console.log('[Import Sobat Taobun] Perubahan:\n' + changes.join('\n')); } function initSobun(){ initDash();renderMaster();calcT();calcP();renderRw();cbRender();sbLoad(); renderPromo(); // Pastikan promo dari baseline ikut dirender } window.onload = () => { // Sync anti-flash theme from to immediately const savedTheme = document.documentElement.getAttribute('data-theme'); if (savedTheme) document.body.setAttribute('data-theme', savedTheme); else document.body.setAttribute('data-theme', 'light'); // Build month/year dropdowns const monthContainers = document.querySelectorAll('.month-options-list'); monthContainers.forEach(container => { months.forEach(m => { let d = document.createElement('div'); d.className = 'option-item'; d.textContent = m.l; d.onclick = () => selectOption('Month', m.v, m.l); container.appendChild(d); }); }); const yearContainers = document.querySelectorAll('.year-options-list'); yearContainers.forEach(container => { for(let i=2026; i<=2030; i++) { let d = document.createElement('div'); d.className = 'option-item'; d.textContent = i; d.onclick = () => selectOption('Year', i.toString(), i.toString()); container.appendChild(d); } }); // Init core dashboard first (fast), defer heavy Sobun init slightly initCharts(); loadData(); // Apply correct chart colors after theme is loaded from localStorage updateChartTheme(); // Keybind logic const inputs = Array.from(document.querySelectorAll('.nav-input, .lead-field')); inputs.forEach((input, index) => { input.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === 'ArrowDown') { e.preventDefault(); if (inputs[index+1]) inputs[index+1].focus(); } else if (e.key === 'ArrowUp') { e.preventDefault(); if (inputs[index-1]) inputs[index-1].focus(); } }); }); // Defer Sobun init to next frame so home view renders first requestAnimationFrame(() => { initSobun(); bcLoad(); updatePeriodBadge(); checkOnboarding(); buildHomeAlerts(); // โ”€โ”€ RESTORE VIEW AKTIF setelah refresh โ”€โ”€ try { const savedView = localStorage.getItem('taobun_active_view'); if (savedView && savedView !== 'home-view') { const targetEl = document.getElementById(savedView); if (targetEl) { if (savedView === 'sobun-view') { // Cek apakah sobun sudah pernah di-unlock di session ini // atau di session sebelumnya (simpan di sessionStorage) const wasUnlocked = sessionStorage.getItem('taobun_sobun_unlocked') === '1'; if (wasUnlocked) { window._sobunUnlocked = true; // Langsung tampilkan sobun tanpa password gate document.querySelectorAll('.view-container').forEach(v => v.classList.remove('view-active')); targetEl.classList.add('view-active'); } // Kalau belum unlock, biarkan di home } else { showView(savedView); } } } } catch(e) {} // โ”€โ”€ RESTORE TAB AKTIF SOBAT TAOBUN setelah refresh โ”€โ”€ try { const savedTab = localStorage.getItem('taobun_active_sobun_tab'); if (savedTab) { const tabEl = document.getElementById('sb-page-' + savedTab); const navBtn = Array.from(document.querySelectorAll('.sobun-wrapper .nav-tab')) .find(btn => btn.getAttribute('onclick') && btn.getAttribute('onclick').includes("'" + savedTab + "'")); if (tabEl && navBtn) { document.querySelectorAll('.sobun-wrapper .page').forEach(p => p.classList.remove('active')); document.querySelectorAll('.sobun-wrapper .nav-tab').forEach(t => t.classList.remove('active')); tabEl.classList.add('active'); navBtn.classList.add('active'); if (savedTab === 'master') renderMaster(); else if (savedTab === 'reward') renderRw(); else if (savedTab === 'dashboard') initDash(); else if (savedTab === 'tiering') calcT(); else if (savedTab === 'profit') calcP(); else if (savedTab === 'promo') cbRender(); } } } catch(e) {} }); // Close dropdowns on outside click document.addEventListener('click', (e) => { if (!e.target.closest('.custom-select-container')) { document.querySelectorAll('.custom-select-container').forEach(c => c.classList.remove('active')); } }); };