// screen-dashboard.jsx — Admin dashboard
const { useState: useDashState } = React;
// smooth catmull-rom -> bezier path
function smoothPath(pts) {
if (pts.length < 2) return '';
let d = `M ${pts[0][0]} ${pts[0][1]}`;
for (let i = 0; i < pts.length - 1; i++) {
const p0 = pts[i - 1] || pts[i], p1 = pts[i], p2 = pts[i + 1], p3 = pts[i + 2] || p2;
const c1x = p1[0] + (p2[0] - p0[0]) / 6, c1y = p1[1] + (p2[1] - p0[1]) / 6;
const c2x = p2[0] - (p3[0] - p1[0]) / 6, c2y = p2[1] - (p3[1] - p1[1]) / 6;
d += ` C ${c1x} ${c1y}, ${c2x} ${c2y}, ${p2[0]} ${p2[1]}`;
}
return d;
}
function LineChart() {
const W = 600, H = 230, pad = 28;
const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
const cur = [3.2, 4.1, 3.6, 5.2, 6.1, 8.4, 10.2];
const prev = [4.0, 3.4, 4.6, 4.2, 6.6, 7.0, 8.6];
const max = 12;
const toPts = (arr) => arr.map((v, i) => [pad + (i * (W - pad * 2)) / (days.length - 1), H - pad - (v / max) * (H - pad * 2)]);
const cp = toPts(cur), pp = toPts(prev);
const area = smoothPath(cp) + ` L ${cp[cp.length - 1][0]} ${H - pad} L ${cp[0][0]} ${H - pad} Z`;
return (
);
}
function Donut({ segments, size = 160, thickness = 26, center }) {
const r = (size - thickness) / 2, c = size / 2, circ = 2 * Math.PI * r;
let off = 0;
return (
);
}
function DashboardScreen({ openIdea, openUser, votes = {}, onVote }) {
const Icon = window.Icon;
const [tab, setTab] = useDashState('Total Users');
const [pending, setPending] = useDashState(window.IDEAS.filter(i => i.status === 'pending' || i.status === 'review').slice(0, 4).map(i => ({ ...i, decided: null })));
const tabs = ['Total Users', 'Total Ideas', 'Active Users', 'Pending Ideas'];
const decide = (id, v) => setPending(p => p.map(x => x.id === id ? { ...x, decided: v } : x));
const adminStats = [
{ key: 'a', icon: 'bulb', label: 'Total ideas', value: '1,000', trend: 9, tint: '#0a66ff' },
{ key: 'b', icon: 'checkCircle', label: 'Published', value: '612', trend: 14, tint: '#15a564' },
{ key: 'c', icon: 'calendar', label: 'Pending review', value: '188', trend: -6, tint: '#e8930c' },
{ key: 'd', icon: 'users', label: 'Active users', value: '500', trend: 8, tint: '#6d5cf0' },
];
return (
Dashboard
Admin overview of idea activity and moderation queue.
{adminStats.map(s => )}
General statistics
Current week
Previous week
{tabs.map(t => )}
Ideas by status
{[['Published', '#15a564', 550], ['Pending', '#e8930c', 280], ['Rejected', '#e23b56', 170]].map(([l, c, v]) => (
{l}
{window.fmt(v)}
))}
Traffic by devices
{window.DEVICES.map(d => (
))}
Users by gender
Male
Female
Most interactive users
{window.TOP_USERS.map((u, i) => (
openUser && openUser(u)}>
{u.ideas}
))}
{/* pending approvals */}
Last pending ideas
| # | Username | Idea title | Category | Status | Action |
{pending.map(p => (
| #{p.rank} |
{p.author} |
openIdea(p)}>{p.title} |
|
{p.decided === 'approve' ? : p.decided === 'reject' ? : } |
{p.decided ? {p.decided === 'approve' ? 'Approved' : 'Rejected'} : (
)}
|
))}
| # | Username | Idea title | Category | Statistics |
{window.IDEAS.slice(0, 4).map(i => (
openIdea(i)}>
| #{i.rank} |
{i.author} |
{i.title} |
|
onVote(i.id, d)} /> |
))}
);
}
window.DashboardScreen = DashboardScreen;