/* ============================================================ dashboard.js โ€” Main dashboard view ============================================================ */ window.Views = window.Views || {}; Views.dashboard = function () { const k = DB.kpis; const kpiCards = [ { label: 'Open Jobs', value: k.openJobs, icon: 'briefcase', cls: 'i-indigo', trend: '+8%', dir: 'up', foot: 'vs last month' }, { label: 'Total Candidates', value: k.totalCandidates, icon: 'users', cls: 'i-blue', trend: '+12%', dir: 'up', foot: 'active in pipeline' }, { label: 'Interviews Today', value: k.interviewsToday, icon: 'calendar', cls: 'i-purple', trend: '3 upcoming', dir: 'flat', foot: 'next at 2:00 PM' }, { label: 'Offers Accepted', value: k.offersAccepted, icon: 'check-circle', cls: 'i-green', trend: '+5%', dir: 'up', foot: `of ${k.offersSent} sent` } ]; const kpiCards2 = [ { label: 'Time to Hire', value: k.timeToHire + ' days', icon: 'clock', cls: 'i-teal', trend: '-3 days', dir: 'up', foot: 'faster than target' }, { label: 'Time to Fill', value: k.timeToFill + ' days', icon: 'target', cls: 'i-amber', trend: '-2 days', dir: 'up', foot: '41 day average' }, { label: 'Cost per Hire', value: DB.money(k.costPerHire), icon: 'dollar', cls: 'i-red', trend: '+4%', dir: 'down', foot: 'above budget' }, { label: 'Closed Jobs', value: k.closedJobs + k.hires, icon: 'award', cls: 'i-purple', trend: '+15%', dir: 'up', foot: 'this quarter' } ]; function trendHtml(dir, txt) { if (dir === 'flat') return `${txt}`; const cls = dir === 'up' ? 'trend-up' : 'trend-down'; const ic = dir === 'up' ? 'trending-up' : 'trending-down'; return `${UI.icon(ic)}${txt}`; } const kpiHtml = arr => arr.map(c => `
${c.label} ${UI.icon(c.icon)}
${c.value}
${trendHtml(c.dir, c.trend)}${c.foot}
`).join(''); // upcoming interviews const upcoming = DB.interviews.filter(iv => iv.status === 'Scheduled').slice(0, 5); const upcomingHtml = upcoming.length ? upcoming.map(iv => `
${UI.avatar(iv.candidate, iv.candInitials, iv.color)}
${iv.candidate}
${iv.type} ยท ${iv.jobTitle}
${DB.fmtShort(iv.when)}
${iv.when.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })}
`).join('') : '
No upcoming interviews
'; // recent applications const recentApps = [...DB.candidates].sort((a, b) => b.applied - a.applied).slice(0, 5); const recentHtml = recentApps.map(c => `
${UI.avatar(c.name, c.initials, c.color)}
${c.name}
${c.jobTitle}
${UI.scoreChip(c.aiScore)}
`).join(''); // activity feed const activityHtml = DB.activity.slice(0, 8).map(a => `
${UI.icon(a.icon)}
${a.html}
${DB.relTime(a.time)}
`).join(''); // recruiter performance const topRecs = [...DB.recruiters].sort((a, b) => b.hires - a.hires).slice(0, 5); const recPerf = topRecs.map(r => `
${UI.avatar(r.name, r.initials, r.color)}
${r.name}
${r.openReqs} open reqs ยท ${r.avgTimeToHire}d avg
${r.hires}
hires
`).join(''); const html = `

Good morning, Asfand ๐Ÿ‘‹

Here's what's happening with your hiring today โ€” Thursday, July 9, 2026

${kpiHtml(kpiCards)}
${kpiHtml(kpiCards2)}

Hiring Trend

Hires vs applications over the last 7 months
7M1Y
${Charts.legend([{ label: 'Applications', color: Charts.PALETTE[4] }, { label: 'Hires', color: Charts.PALETTE[0] }])}

Candidate Pipeline

Active by stage

Upcoming Interviews

Next scheduled sessions
${upcomingHtml}

Source Analytics

Where candidates come from

Recent Applications

${recentHtml}

Recruiter Performance

${recPerf}

Recent Activity

${activityHtml}
`; return { html, onMount() { const a = DB.analytics; Charts.line(document.getElementById('chartTrend'), { labels: a.hiringTrend.labels, area: true, datasets: [ { label: 'Applications', data: a.hiringTrend.applications, color: Charts.PALETTE[4] }, { label: 'Hires', data: a.hiringTrend.hires, color: Charts.PALETTE[0] } ] }); Charts.horizontalBar(document.getElementById('chartPipeline'), { labels: a.pipeline.map(p => p.stage), data: a.pipeline.map(p => p.count), colors: Charts.PALETTE }); Charts.bar(document.getElementById('chartSource'), { labels: a.sources.map(s => s.source), data: a.sources.map(s => s.count) }); } }; };