/* global React, Icon, KpiCard, StageChip, ChannelIcon, fmtAED, Avatar, EmptyState */
const { useState } = React;
/* ============================================================
DASHBOARD
Two layout variations (toggle via Tweaks):
1. "modular" — original brief: 12-col grid, KPI cards on top
2. "ops" — left-rail today/calendar focus, right side metrics
============================================================ */
function Dashboard({ layout = 'modular', goto }) {
return layout === 'ops' ? : ;
}
/* ----- Variation 1: Modular ----- */
function DashboardModular({ goto }) {
return (
Tuesday · 28 Apr 2026
Good morning, Sebastiano.
Pipeline weighted total · AED 187,400
{/* Top row: 4 KPI cards */}
{/* Row 2: Pipeline by stage + Today */}
{/* Row 3: Account health full-width */}
{/* Row 4: Funnels, Campaigns, Payments */}
);
}
/* ----- Variation 2: Ops ----- */
function DashboardOps({ goto }) {
return (
Tuesday · 28 Apr 2026
Today.
{/* 2-col split: Today (left, larger) + everything else stacked right */}
);
}
/* ============================================================
CARDS
============================================================ */
function PipelineCard({ goto }) {
const stages = window.STAGES_OUTBOUND;
const counts = {};
const values = {};
window.PIPELINE_OUTBOUND.forEach(d => {
counts[d.stage] = (counts[d.stage] || 0) + 1;
if (d.value) values[d.stage] = (values[d.stage] || 0) + d.value;
});
const maxCount = Math.max(...Object.values(counts), 1);
const totalAed = Object.values(values).reduce((a,b) => a+b, 0);
const weightedAed = 187400;
return (
This Week's Pipeline
AED {fmtAED(totalAed)} total
AED {fmtAED(weightedAed)} weighted
{stages.filter(s => counts[s.id]).map(s => (
{s.label}
{counts[s.id]}
{values[s.id] ? `AED ${fmtAED(values[s.id])}` : '—'}
))}
);
}
function TodayCard({ goto, expanded = false }) {
const events = window.CALENDAR_EVENTS.filter(e => e.day === 1);
const tasks = [
{ id: 1, text: 'Send proposal to Globex', done: false, due: '11:00' },
{ id: 2, text: 'Follow up · Initech pricing', done: false, due: '14:30' },
{ id: 3, text: 'Recap deck · Acme tweaks', done: false, due: 'EOD' },
{ id: 4, text: 'Review LinkedIn responses', done: true, due: 'morning' },
];
return (
Today
{events.length === 0 && (
No calls scheduled
)}
{events.map(e => (
goto('calendar')}>
{String(Math.floor(e.start)).padStart(2,'0')}:{String(Math.round((e.start%1)*60)).padStart(2,'0')}
{e.type === 'discovery' ? 'Discovery' : 'Strategy'}
))}
Tasks · {tasks.filter(t => !t.done).length} due
{tasks.map(t => (
{t.done && }
{t.text}
{t.due}
))}
4 unread messages
across LinkedIn, WhatsApp, IG
);
}
function AccountHealthCard({ goto }) {
const channels = window.CHANNELS.filter(c => c.kind !== 'email');
return (
Account Health · Messaging
Account
Channel
Sends today
Ramp
{channels.map(ch => {
const dotClass = ch.status === 'active' ? 'dot-green' : ch.status === 'paused' ? 'dot-yellow' : 'dot-red';
const pct = (ch.sendsToday / ch.cap) * 100;
return (
{ch.label}
{ch.errorMsg &&
{ch.errorMsg}
}
{ch.kind}
90 ? 'var(--orange)' : 'var(--accent)' }}>
{ch.sendsToday}/{ch.cap}
W{ch.rampWeek}
);
})}
);
}
function FunnelsCard({ goto }) {
const funnels = window.FUNNELS.filter(f => f.status === 'live').slice(0, 5);
return (
Funnels · This Week
{funnels.map(f => (
{f.submissions}
{f.conversion}%
))}
);
}
function CampaignsCard({ goto }) {
const active = window.CAMPAIGNS.filter(c => c.status === 'active');
return (
Campaigns · Active
{active.map(c => (
{c.name}
1 ? 'var(--orange)' : 'var(--text)' }}>{c.bounces}%
bounces
))}
);
}
function PaymentsCard({ goto }) {
const newPayments = window.PAYMENTS.filter(p => p.status === 'paid').slice(0, 3);
const expected = 26000;
const mrr = 53000;
return (
Payments · This Week
Expected
AED {fmtAED(expected)}
MRR proj.
AED {fmtAED(mrr)}
{newPayments.map(p => (
{p.deal}
{fmtAED(p.amount)}
))}
);
}
Object.assign(window, { Dashboard });