const STORAGE_KEY = 'jobprep-resume-v1'; const SUGGESTED_SKILLS = [ 'Reliable & On Time', 'Customer Service', 'Teamwork', 'Communication', 'Time Management', 'Cash Handling', 'Problem Solving', 'Fast Learner', 'Works Well Under Pressure', 'Attention to Detail', 'Following Instructions', 'Physical Stamina', 'Basic Computer Skills', 'Multitasking', ]; let state = { name: '', phone: '', email: '', location: '', summary: '', jobs: [{ title: '', employer: '', start: '', end: '', current: false, bullets: '' }], edu: [{ school: '', credential: '', year: '' }], skills: [], }; function loadState() { try { const saved = localStorage.getItem(STORAGE_KEY); if (saved) state = JSON.parse(saved); } catch { // ignore corrupt storage } } function saveState() { localStorage.setItem(STORAGE_KEY, JSON.stringify(state)); } function jobBlockHtml(job, i) { return `
${state.jobs.length > 1 ? `` : ''}
`; } function eduBlockHtml(edu, i) { return `
${state.edu.length > 1 ? `` : ''}
`; } function esc(str) { return (str || '').toString() .replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); } function monthLabel(value) { if (!value) return ''; const [y, m] = value.split('-'); const names = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; const idx = parseInt(m, 10) - 1; return names[idx] ? `${names[idx]} ${y}` : y; } function renderForm() { document.getElementById('f-name').value = state.name; document.getElementById('f-phone').value = state.phone; document.getElementById('f-email').value = state.email; document.getElementById('f-location').value = state.location; document.getElementById('f-summary').value = state.summary; document.getElementById('jobs-container').innerHTML = state.jobs.map(jobBlockHtml).join(''); document.getElementById('edu-container').innerHTML = state.edu.map(eduBlockHtml).join(''); const chipsWrap = document.getElementById('skill-chips'); const allSkills = [...new Set([...SUGGESTED_SKILLS, ...state.skills])]; chipsWrap.innerHTML = allSkills.map((s) => { const selected = state.skills.includes(s); return `${esc(s)}`; }).join(''); } function renderPreview() { const preview = document.getElementById('preview'); const hasAnything = state.name || state.jobs.some((j) => j.title || j.employer); if (!hasAnything) { preview.innerHTML = '

Your resume preview will appear here as you fill out the form.

'; return; } const contactParts = [state.phone, state.email, state.location].filter(Boolean).join(' • '); const jobsHtml = state.jobs .filter((j) => j.title || j.employer) .map((j) => { const dateRange = [monthLabel(j.start), j.current ? 'Present' : monthLabel(j.end)] .filter(Boolean).join(' – '); const bullets = (j.bullets || '').split('\n').map((b) => b.trim()).filter(Boolean); return `
${esc(j.title) || 'Job Title'}${j.employer ? ` — ${esc(j.employer)}` : ''}
${dateRange ? `
${esc(dateRange)}
` : ''} ${bullets.length ? `` : ''}
`; }).join(''); const eduHtml = state.edu .filter((e) => e.school) .map((e) => `
${esc(e.school)}
${[esc(e.credential), esc(e.year)].filter(Boolean).join(' • ')}
`).join(''); preview.innerHTML = `

${esc(state.name) || 'Your Name'}

${contactParts}
${state.summary ? `

Summary

${esc(state.summary)}

` : ''} ${jobsHtml ? `

Experience

${jobsHtml}` : ''} ${eduHtml ? `

Education

${eduHtml}` : ''} ${state.skills.length ? `

Skills

${state.skills.map(esc).join(' • ')}

` : ''} `; } function renderAll() { renderForm(); renderPreview(); } document.addEventListener('input', (e) => { const t = e.target; if (t.id === 'f-name') state.name = t.value; else if (t.id === 'f-phone') state.phone = t.value; else if (t.id === 'f-email') state.email = t.value; else if (t.id === 'f-location') state.location = t.value; else if (t.id === 'f-summary') state.summary = t.value; else if (t.dataset.jobField) { const i = parseInt(t.dataset.i, 10); if (t.dataset.jobField === 'current') { state.jobs[i].current = t.checked; renderForm(); } else { state.jobs[i][t.dataset.jobField] = t.value; } } else if (t.dataset.eduField) { const i = parseInt(t.dataset.i, 10); state.edu[i][t.dataset.eduField] = t.value; } else { return; } saveState(); renderPreview(); }); document.addEventListener('click', (e) => { const t = e.target; if (t.id === 'add-job') { state.jobs.push({ title: '', employer: '', start: '', end: '', current: false, bullets: '' }); renderAll(); saveState(); } else if (t.id === 'add-edu') { state.edu.push({ school: '', credential: '', year: '' }); renderAll(); saveState(); } else if (t.dataset.removeJob !== undefined) { state.jobs.splice(parseInt(t.dataset.removeJob, 10), 1); renderAll(); saveState(); } else if (t.dataset.removeEdu !== undefined) { state.edu.splice(parseInt(t.dataset.removeEdu, 10), 1); renderAll(); saveState(); } else if (t.dataset.skill) { const skill = t.dataset.skill; if (state.skills.includes(skill)) { state.skills = state.skills.filter((s) => s !== skill); } else { state.skills.push(skill); } renderAll(); saveState(); } else if (t.id === 'clear-form') { if (confirm('Clear everything you\'ve entered? This can\'t be undone.')) { localStorage.removeItem(STORAGE_KEY); location.reload(); } } else if (t.id === 'download-pdf') { downloadPdf(); } }); document.getElementById('f-custom-skill').addEventListener('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); const val = e.target.value.trim(); if (val && !state.skills.includes(val)) { state.skills.push(val); e.target.value = ''; renderAll(); saveState(); } } }); function downloadPdf() { const hasAnything = state.name || state.jobs.some((j) => j.title || j.employer); if (!hasAnything) { alert('Fill in at least your name or a job before downloading your resume.'); return; } // Uses the browser's built-in Print > Save as PDF instead of a third-party // screenshot library — those libraries (html2canvas et al.) render blank // on current Chrome versions and are unmaintained. A print stylesheet // (see @media print in styles.css) hides everything except #preview. const originalTitle = document.title; document.title = `${(state.name || 'Resume').trim().replace(/\s+/g, '_')}_Resume`; window.print(); document.title = originalTitle; } loadState(); renderAll();