37063-vm/dashboard.php
2025-12-28 08:49:29 +00:00

2 lines
5.8 KiB
PHP

<?php require_once 'check_auth.php'; ?>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>FinMox OS — Dashboard</title> <!-- Tailwind CDN (AppWizzy-safe) --> <script src="https://cdn.tailwindcss.com"></script> <!-- Font --> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet"> <style> :root{ --ink:#0b0b0c; --paper:#fbfaf7; --warm:#f2efe7; --warm2:#ebe6da; --line: rgba(11,11,12,.08); --shadow: 0 18px 48px rgba(11,11,12,.10); --shadow2: 0 10px 26px rgba(11,11,12,.10); --radius: 26px; } html, body { height:100%; } body { font-family:'Inter',sans-serif; background: var(--paper); color: var(--ink); } .panel { border: 1px solid var(--line); border-radius: var(--radius); background: rgba(255,255,255,.70); box-shadow: var(--shadow2); backdrop-filter: blur(10px); } .panel-strong { border: 1px solid var(--line); border-radius: var(--radius); background: rgba(255,255,255,.92); box-shadow: var(--shadow); } .chip { border: 1px solid var(--line); border-radius: 999px; background: rgba(255,255,255,.78); } .hoverlift { transition: transform .18s ease, box-shadow .18s ease; } .hoverlift:hover { transform: translateY(-2px); box-shadow: var(--shadow); } .bg-warm { background: radial-gradient(1200px 520px at 20% 15%, rgba(243,236,223,.95), rgba(251,250,247,0) 60%), radial-gradient(900px 520px at 85% 20%, rgba(236,232,219,.9), rgba(251,250,247,0) 55%), radial-gradient(900px 520px at 55% 90%, rgba(241,238,230,.9), rgba(251,250,247,0) 60%), var(--paper); } /* dashboard tabs */ .dtab.active { background:#0b0b0c; color:#fff; border-color: transparent; } .section.hidden { display:none; } /* table */ .tbl { width:100%; border-collapse: separate; border-spacing: 0; overflow:hidden; border-radius: 18px; } .tbl th, .tbl td { padding: 12px 12px; font-size: 13px; } .tbl thead th { background: rgba(11,11,12,.06); text-align:left; font-weight: 700; } .tbl tbody tr { border-top: 1p<script> const fmState = { plan: 'growth', // starter | growth | enterprise tab: 'overview' }; const planRank = { starter: 1, growth: 2, enterprise: 3 }; function fmOpenTab(tab) { fmState.tab = tab; // sections const sections = document.querySelectorAll('.section'); sections.forEach(s => s.classList.add('hidden')); const main = document.getElementById(`sec-${tab}`); if (main) main.classList.remove('hidden'); // special: billing section lives in sidebar if (tab === 'billing') { const bill = document.getElementById('sec-billing'); if (bill) bill.classList.remove('hidden'); } else { const bill = document.getElementById('sec-billing'); if (bill) bill.classList.add('hidden'); } // tab styles document.querySelectorAll('.dtab').forEach(b => b.classList.remove('active')); const btn = document.querySelector(`.dtab[data-tab="${tab}"]`); if (btn) btn.classList.add('active'); window.scrollTo({ top: 0, behavior: 'smooth' }); } function fmSetPlan(plan) { fmState.plan = plan; // update badges const badge = document.getElementById('planBadge'); const planName = document.getElementById('planName'); const planLevel = document.getElementById('planLevel'); if (badge) badge.textContent = plan.charAt(0).toUpperCase() + plan.slice(1); if (planName) planName.textContent = plan.charAt(0).toUpperCase() + plan.slice(1); if (planLevel) planLevel.textContent = plan; // gate UI document.querySelectorAll('[data-requires]').forEach(node => { const req = node.getAttribute('data-requires'); const ok = planRank[plan] >= planRank[req]; node.style.display = ok ? '' : 'none'; }); fmToast(`Plan set to ${plan.toUpperCase()} (demo).`); } function fmToast(msg) { const wrap = document.getElementById('toast'); if (!wrap) return; const inner = wrap.querySelector('div'); inner.textContent = msg; wrap.classList.remove('hidden'); setTimeout(() => wrap.classList.add('hidden'), 2200); } </script><script> const demo = { roles: [ { role: 'Account Executive', status: 'Open', criteria: 'Locked v2', candidates: 128, owner: 'People Ops' }, { role: 'Sales Engineer', status: 'Open', criteria: 'Locked v1', candidates: 64, owner: 'RevOps' }, { role: 'Gov Account Manager', status: 'Pilot', criteria: 'Draft', candidates: 22, owner: 'Hiring Lead' }, ], candidates: [ { name: 'Jordan M.', role: 'Account Executive', score: 92, stage: 'Final', status: 'On track' }, { name: 'Ariana K.', role: 'Sales Engineer', score: 88, stage: 'Panel', status: 'SLA risk' }, { name: 'Devin R.', role: 'Account Executive', score: 83, stage: 'Screen', status: 'On track' }, { name: 'Mina S.', role: 'Gov Account Manager', score: 79, stage: 'Intake', status: 'Waiting' }, ], events: [ { time: 'Today 9:42a', event: 'CRITERIA_LOCKED', entity: 'Account Executive', actor: 'People Ops', notes: 'Locked v2 (scope freeze).' }, { time: 'Today 10:05a', event: 'SCORE_SUBMITTED', entity: 'Jordan M.', actor: 'Interviewer', notes: 'Score 92 + notes captured.' }, { time: 'Today 11:12a', event: 'STAGE_CHANGED', entity: 'Jordan M.', actor: 'FinMox', notes: 'Moved to Final (automation).' }, { time: 'Today 12:01p', event: 'SLA_NUDGE_SENT', entity: 'Ariana K.', actor: 'FinMox', notes: 'Feedback overdue → nudge.' }, ], sla: [ { title: 'Feedback overdue', detail: 'Sales Engineer · Panel interview', risk: 'High' }, { title: 'Schedule pending', detail: 'Account Executive · Final', risk: 'Medium' }, { title: 'Criteria draft', detail: 'Gov Account Manager · Needs lock', risk: 'Medium' }, ] }; function renderDemo() { // KPIs const roles = demo.roles.length; const candidates = demo.candidates.length; const sla = demo.sla.filter(x => x.risk === 'High' || x.risk === 'Medium').length; const kpiRoles = document.getElementById('kpiRoles'); const kpiCandidates = document.getElementById('kpiCandidates'); const kpiSla = document.getElementById('kpiSla'); if (kpiRoles) kpiRoles.textContent = roles; if (kpiCandidates) kpiCandidates.tex</script>