extractSources(jobs); renderJobs(jobs); updateSourceFilter(); const hasMore = jobs.length === jobsPageSize; pageInfo.textContent = `Showing ${jobsPage * jobsPageSize + 1}–${jobsPage * jobsPageSize + jobs.length} of ${jobs.length + (hasMore ? '+' : '')}`; prevBtn.disabled = jobsPage === 0; nextBtn.disabled = !hasMore; pagination.classList.remove('hidden'); table.classList.remove('hidden'); loading.classList.add('hidden'); } catch (e) { console.error('Failed to load jobs:', e); showToast('Failed to load jobs', 'error'); loading.classList.add('hidden'); empty.classList.remove('hidden'); } } function extractSources(jobs) { jobs.forEach(item => allSources.add(item.job.source)); } function updateSourceFilter() { const select = document.getElementById('jobSourceFilter'); const current = select.value; select.innerHTML = '' + Array.from(allSources).sort().map(s => ``).join(''); select.value = current; } function renderJobs(jobs) { const tbody = document.getElementById('jobsTableBody'); if (jobs.length === 0) { document.getElementById('jobsTable').classList.add('hidden'); document.getElementById('jobsEmpty').classList.remove('hidden'); return; } document.getElementById('jobsTable').classList.remove('hidden'); document.getElementById('jobsEmpty').classList.add('hidden'); tbody.innerHTML = jobs.map(item => { const job = item.job; const app = item.application; const score = job.match_score; let scoreClass = 'score-low'; if (score >= 75) scoreClass = 'score-high'; else if (score >= 50) scoreClass = 'score-medium'; let statusHtml = 'No Application'; if (app) { statusHtml = `${app.status}`; } return `
Company
${escapeHtml(job.company)}
Location
${escapeHtml(job.location)}
Remote
${escapeHtml(job.remote)}
Source
${escapeHtml(job.source)}
Match Score
${job.match_score}%
Status
${app.status}
ATS Score
${app.ats_score}%
Applied
${app.applied_date || '—'}
Follow-up
${app.follow_up_date || '—'}
Notes
${escapeHtml(app.notes)}
Rejection Reason
${escapeHtml(app.rejection_reason)}
Interview
${app.interview_date} (${app.interview_round || 'Round 1'})
Offer
${escapeHtml(app.offer_details)}
${r.filename.replace('.md', '').replace(/_/g, ' ')}
Click to view
${r.date}
${r.filename}
No data yet
'; return; } container.innerHTML = top.map(([company, count]) => `No recent activity
'; return; } container.innerHTML = recent.map(item => { const job = item.job; const app = item.application; return `${escapeHtml(job.title)}
${escapeHtml(job.company)} • ${formatDate(job.found_date)}