// Dashboard with three layout variants: timeline, checklist, grid.
const TaskIcon = ({ name, color }) => {
const C = I[name] || I.doc;
return (
);
};
// completion logic shared
const isDone = (taskId, progress) => COMPLETED_BY_PROGRESS[progress]?.has(taskId);
// ──────────────── Hero header (greeting + progress) ────────────────
function DashboardHero({ persona, progress, onJump }) {
const tasks = TASKS(persona);
const total = tasks.length;
const done = tasks.filter(t => isDone(t.id, progress)).length;
const pct = Math.round(done / total * 100);
const day = progress === "day1" ? "Day 1" : progress === "week1" ? "Week 1" : "All set";
return (
{day} · {PERSONAS[persona].startDate}
{progress === "done"
? <>Welcome aboard, {NEW_HIRE.first}. You're all set. >
: <>Welcome to Convoso, {NEW_HIRE.first} .>}
{progress === "done"
? "Onboarding complete — your team is ready when you are. Here's a quick look at what's coming this week."
: `You have ${total - done} ${total - done === 1 ? "task" : "tasks"} left in your onboarding plan. Most people finish in about ${progress === "day1" ? "two more hours" : "twenty minutes"}.`}
Your manager
{PERSONAS[persona].manager}
Role
{PERSONAS[persona].role}
Location
{PERSONAS[persona].location}
{pct}%
{done} of {total} done
);
}
// ──────────────── Quick stats row ────────────────
function QuickStats({ persona, progress, onNav }) {
const tasks = TASKS(persona);
const docCount = DOCS.filter(d => d.status === "pending").length;
const meetingCount = MEETINGS[0].items.length;
const trainCount = TRAININGS.filter(t => t.required && t.progress < 100).length;
const items = [
{ k: "meetings", icon: "calendar", label: "Meetings today", value: meetingCount, hint: "Next at 11:00 AM", color: "#2563eb" },
{ k: "documents", icon: "doc", label: "Documents to sign", value: docCount, hint: "2 due tomorrow", color: "#f97316" },
{ k: "training", icon: "book", label: "Trainings required", value: trainCount, hint: "12 hours total", color: "#a855f7" },
{ k: "insurance", icon: "shield", label: "Benefits enrollment", value: "30d", hint: "Window closes Jun 11", color: "#16a34a" },
];
return (
{items.map(it => {
const C = I[it.icon];
return (
onNav(it.k)}>
{it.value}
{it.label}
{it.hint}
);
})}
);
}
// ──────────────── TIMELINE layout ────────────────
function TimelineLayout({ persona, progress, onNav }) {
const tasks = TASKS(persona);
const phases = [
{ id: "day1", label: "Day 1", sub: "Mon · May 11", tone: "accent" },
{ id: "week1", label: "Week 1", sub: "May 11 – May 15", tone: "info" },
{ id: "month1", label: "Month 1", sub: "May 11 – Jun 11", tone: "muted" },
];
return (
{phases.map((ph, i) => {
const phaseTasks = tasks.filter(t => t.phase === ph.id);
const phaseDone = phaseTasks.filter(t => isDone(t.id, progress)).length;
const allDone = phaseDone === phaseTasks.length;
return (
0 ? "active" : "")}>
{allDone ? : {i + 1} }
{i < phases.length - 1 &&
}
{phaseDone}/{phaseTasks.length}
{phaseTasks.map(t => (
))}
);
})}
);
}
const KIND_TONE = {
meeting: { label: "Meeting", color: "#2563eb", icon: "calendar", nav: "meetings" },
doc: { label: "Document", color: "#f97316", icon: "doc", nav: "documents" },
training:{ label: "Training", color: "#a855f7", icon: "book", nav: "training" },
task: { label: "Task", color: "#0891b2", icon: "check", nav: null },
media: { label: "Watch", color: "#ec4899", icon: "play", nav: null },
};
function TaskRow({ t, done, onNav }) {
const tone = KIND_TONE[t.kind] || KIND_TONE.task;
const TIcon = I[t.icon] || I[tone.icon];
return (
{t.title}
{tone.label}
{t.time && {t.time} }
{t.duration && · {t.duration} }
{t.deadline && Due in {t.deadline} }
{t.required && Required }
{t.count && · {t.count} }
{tone.nav ? (
onNav(tone.nav)}>
{done ? "View" : "Open"}
) : (
{done ? "Replay" : "Start"}
)}
);
}
// ──────────────── CHECKLIST layout ────────────────
function ChecklistLayout({ persona, progress, onNav }) {
const tasks = TASKS(persona);
const groups = [
{ id: "required", label: "Required this week", tasks: tasks.filter(t => t.required && t.phase !== "month1") },
{ id: "month", label: "First 30 days", tasks: tasks.filter(t => t.phase === "month1") },
{ id: "optional", label: "Recommended", tasks: tasks.filter(t => !t.required && t.phase !== "month1") },
];
return (
{groups.map(g => (
{g.label}
{g.tasks.filter(t => isDone(t.id, progress)).length} / {g.tasks.length} complete
{g.tasks.map(t => )}
))}
);
}
// ──────────────── GRID layout ────────────────
function GridLayout({ persona, progress, onNav }) {
const tasks = TASKS(persona);
const cats = [
{ id: "meeting", label: "Meetings & 1:1s", icon: "calendar" },
{ id: "doc", label: "Paperwork & Forms", icon: "doc" },
{ id: "training", label: "Training", icon: "book" },
{ id: "task", label: "Setup tasks", icon: "laptop" },
{ id: "media", label: "Watch", icon: "play" },
];
return (
{cats.map(c => {
const cTasks = tasks.filter(t => t.kind === c.id);
if (!cTasks.length) return null;
const C = I[c.icon];
const tone = KIND_TONE[c.id];
const cDone = cTasks.filter(t => isDone(t.id, progress)).length;
return (
{c.label}
{cDone} / {cTasks.length} complete
{cTasks.slice(0, 4).map(t => (
{t.title}
{t.time || t.duration}
))}
{cTasks.length > 4 &&
+ {cTasks.length - 4} more
}
);
})}
);
}
// ──────────────── Side panel: today's events ────────────────
function TodayPanel({ onNav }) {
const today = MEETINGS[0];
return (
Today · {today.day} {today.date}
Your schedule
onNav("meetings")}>
Open calendar
{today.items.map((m, i) => (
{m.title}
{m.with}
·
{m.loc}
{m.loc === "Zoom" && Join }
))}
);
}
// ──────────────── Buddy / manager card ────────────────
function PeopleCard({ persona }) {
const p = PERSONAS[persona];
const buddy = persona === "eng" ? { name: "Sam Liu", role: "Senior Engineer · Voice Infra" }
: persona === "design" ? { name: "Devon Cole", role: "Senior Product Designer" }
: { name: "Maya Cruz", role: "AE · Mid-Market" };
return (
Your people
{p.manager}
{p.managerRole}
{buddy.name}
{buddy.role} · Buddy
Lila Park
People Operations
);
}
// ──────────────── Resources ────────────────
function ResourcesCard() {
const items = [
{ title: "Employee Handbook", meta: "PDF · 84 pages", icon: "book" },
{ title: "Convoso Brand & Voice", meta: "Notion", icon: "notion" },
{ title: "Engineering Wiki", meta: "Confluence", icon: "globe" },
{ title: "Office Map · DTLA HQ", meta: "PDF · 1 page", icon: "building" },
];
return (
Resources
{items.map((r, i) => {
const C = I[r.icon];
return (
);
})}
);
}
// ──────────────── Dashboard root ────────────────
function Dashboard({ persona, progress, layout, onNav }) {
return (
Your onboarding plan
{layout === "timeline" ? "By week" : layout === "checklist" ? "By priority" : "By category"}
{layout === "timeline" &&
}
{layout === "checklist" && }
{layout === "grid" && }
);
}
window.Dashboard = Dashboard;
window.TaskRow = TaskRow;