/* ============================================================ interviews.js — Interviews list, upcoming, mini calendar ============================================================ */ window.Views = window.Views || {}; window.Interviews = {}; Views.interviews = function () { const filters = { q: '', status: '', type: '' }; let table; const upcoming = DB.interviews.filter(iv => iv.status === 'Scheduled').slice(0, 4); const stats = { scheduled: DB.interviews.filter(i => i.status === 'Scheduled').length, completed: DB.interviews.filter(i => i.status === 'Completed').length, today: 5, cancelled: DB.interviews.filter(i => ['Cancelled', 'No Show'].includes(i.status)).length }; function apply() { const rows = DB.interviews.filter(iv => { if (filters.status && iv.status !== filters.status) return false; if (filters.type && iv.type !== filters.type) return false; if (filters.q && !(iv.candidate + iv.jobTitle + iv.interviewers.join(' ')).toLowerCase().includes(filters.q.toLowerCase())) return false; return true; }); table.update(rows); } table = UI.dataTable({ pageSize: 8, rows: DB.interviews, columns: [ { key: 'candidate', label: 'Candidate', sortable: true, render: iv => `
${UI.avatar(iv.candidate, iv.candInitials, iv.color)}
${iv.candidate}
${iv.jobTitle}
` }, { key: 'type', label: 'Round', sortable: true, render: iv => UI.badge(iv.type, 'b-indigo') }, { key: 'when', label: 'Date & Time', sortable: true, sortValue: iv => iv.when.getTime(), render: iv => `
${DB.fmtShort(iv.when)}
${iv.when.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })} · ${iv.duration}m
` }, { key: 'meeting', label: 'Type', render: iv => `${UI.icon(iv.meeting === 'Video Call' ? 'video' : iv.meeting === 'Phone' ? 'phone' : 'map')} ${iv.meeting}` }, { key: 'interviewers', label: 'Interviewers', render: iv => UI.avatarStack(iv.interviewers) }, { key: 'status', label: 'Status', sortable: true, render: iv => UI.badge(iv.status) }, { key: 'feedback', label: 'Feedback', render: iv => iv.feedback ? UI.badge(iv.feedback) : '' }, { key: '_a', label: 'Actions', align: 'right', render: iv => `
` } ] }); const statusOpts = [''].concat(['Scheduled', 'Completed', 'Cancelled', 'No Show'].map(s => ``)).join(''); const typeOpts = [''].concat(DB.interviewTypes.map(t => ``)).join(''); const statCard = (label, val, icn, cls) => `
${label}${UI.icon(icn)}
${val}
`; const upcomingHtml = upcoming.map(iv => `
${UI.avatar(iv.candidate, iv.candInitials, iv.color)}
${iv.candidate}
${iv.type} · ${iv.meeting}
${DB.fmtShort(iv.when)}
${iv.when.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })}
`).join(''); const html = `

Interviews

Manage and track all interview activity

${statCard('Scheduled', stats.scheduled, 'calendar', 'i-blue')} ${statCard('Completed', stats.completed, 'check-circle', 'i-green')} ${statCard('Today', stats.today, 'clock', 'i-purple')} ${statCard('Cancelled / No-show', stats.cancelled, 'x-circle', 'i-red')}

All Interviews

${table.html}

Up Next

Scheduled sessions
${upcomingHtml}
`; return { html, onMount() { table.mount(); const s = document.getElementById('ivSearch'); s.oninput = () => { filters.q = s.value; apply(); }; document.getElementById('ivStatus').onchange = e => { filters.status = e.target.value; apply(); }; document.getElementById('ivType').onchange = e => { filters.type = e.target.value; apply(); }; } }; }; Interviews.feedback = function (id) { const iv = DB.interviews.find(i => i.id === id); // pick evaluation template by department const job = DB.jobs.find(j => j.title === iv.jobTitle); const dept = job ? job.department : 'All'; const tmpl = DB.evalTemplates.find(t => t.dept === dept) || DB.evalTemplates.find(t => t.dept === 'All'); const tmplOpts = DB.evalTemplates.map(t => ``).join(''); const ratingRow = (crit) => `

${crit}

${[1, 2, 3, 4, 5].map(n => `${UI.icon('star')}`).join('')}
`; const body = `
${UI.avatar(iv.candidate, iv.candInitials, iv.color, 'avatar-lg')}
${iv.candidate}
${iv.type} · ${iv.jobTitle}
${UI.badge(iv.status)}
Dynamic Form
Upload Sheet
Both
${tmpl.criteria.map(ratingRow).join('')}
${UI.icon('upload')}

Upload evaluation sheet

PDF, DOC, or DOCX · scanned scorecards supported

${['PDF', 'DOC', 'DOCX'].map(t => `${t}`).join('')}

Capture structured ratings and attach a signed sheet — both are stored on the scorecard.

${tmpl.criteria.slice(0, 3).map(ratingRow).join('')}
${UI.icon('file')}
Interviewer_Scorecard.pdf
Attached · 214 KB
${UI.badge('Uploaded', 'b-green')}
`; const footer = ` `; UI.modal({ title: 'Interview Evaluation', subtitle: iv.id + ' · ' + iv.type, body, footer, size: 'modal-lg' }); // wire tabs const panes = document.querySelectorAll('#evalPanes .tab-pane'); document.querySelectorAll('#evalTabs .tab').forEach(tab => tab.onclick = () => { document.querySelectorAll('#evalTabs .tab').forEach(t => t.classList.remove('active')); tab.classList.add('active'); panes.forEach(p => p.classList.remove('active')); panes[+tab.dataset.etab].classList.add('active'); }); // wire star ratings Interviews._bindStars(); // template switch rebuilds criteria const tmplSel = document.getElementById('evalTmpl'); if (tmplSel) tmplSel.onchange = () => { const t = DB.evalTemplates.find(x => x.name === tmplSel.value); document.getElementById('critList').innerHTML = t.criteria.map(ratingRow).join(''); Interviews._bindStars(); }; // recommendation seg document.querySelectorAll('[data-rec]').forEach(b => b.onclick = () => { b.parentElement.querySelectorAll('button').forEach(x => x.classList.remove('active')); b.classList.add('active'); }); }; Interviews._bindStars = function () { document.querySelectorAll('.rating-stars').forEach(group => { group.querySelectorAll('.rs').forEach(star => star.onclick = () => { const val = +star.dataset.val; group.querySelectorAll('.rs').forEach(s => s.classList.toggle('on', +s.dataset.val <= val)); }); }); }; Interviews.schedule = function () { const opt = arr => arr.map(o => ``).join(''); const body = `
`; const footer = ` `; UI.modal({ title: 'Schedule Interview', subtitle: 'Set up a new interview session', body, footer }); };