/* dashboard.jsx — document manager / home screen */ function timeAgo(ts) { if (!ts) return ""; const d = Date.now() - new Date(ts).getTime(); if (d < 60000) return "Just now"; if (d < 3600000) return Math.floor(d / 60000) + "m ago"; if (d < 86400000) return Math.floor(d / 3600000) + "h ago"; if (d < 604800000) return Math.floor(d / 86400000) + "d ago"; return new Date(ts).toLocaleDateString("en-US", { month: "short", day: "numeric" }); } function loadAllDocs() { try { return JSON.parse(localStorage.getItem("bdr_docs") || "[]"); } catch { return []; } } function saveAllDocs(docs) { localStorage.setItem("bdr_docs", JSON.stringify(docs)); } function loadDocData(id) { try { return JSON.parse(localStorage.getItem("bdr_doc_" + id)); } catch { return null; } } function saveDocData(id, payload) { localStorage.setItem("bdr_doc_" + id, JSON.stringify(payload)); } window.timeAgo = timeAgo; window.loadAllDocs = loadAllDocs; window.saveAllDocs = saveAllDocs; window.loadDocData = loadDocData; window.saveDocData = saveDocData; function DashDocCard({ doc, onOpen, onDelete, onDuplicate }) { const docPayload = React.useMemo(() => loadDocData(doc.id) || {}, [doc.id]); const data = docPayload.data || window.SAMPLE_RESUME; const design = docPayload.design || { font: "auto", accent: "#1C9BE6" }; const accent = design.accent || "#1C9BE6"; const [menuOpen, setMenuOpen] = React.useState(false); return (
Open →
{doc.name || "Untitled Résumé"}
{(window.TEMPLATES && window.TEMPLATES[doc.template] ? window.TEMPLATES[doc.template].name : "Modern")} · {timeAgo(doc.updatedAt)}
{menuOpen && (
)}
); } function Dashboard({ onOpen, onNew }) { const [docs, setDocs] = React.useState(loadAllDocs); const [confirmDel, setConfirmDel] = React.useState(null); const fileRef = React.useRef(null); const handleDelete = function(id) { const next = docs.filter(function(d) { return d.id !== id; }); saveAllDocs(next); try { localStorage.removeItem("bdr_doc_" + id); } catch(e) {} setDocs(next); setConfirmDel(null); }; const handleDuplicate = function(id) { const src = docs.find(function(d) { return d.id === id; }); if (!src) return; const newId = Math.random().toString(36).slice(2, 9); const srcData = loadDocData(id); const newDoc = Object.assign({}, src, { id: newId, name: (src.name || "Résumé") + " (copy)", updatedAt: new Date().toISOString() }); const next = [newDoc].concat(docs); saveAllDocs(next); if (srcData) saveDocData(newId, Object.assign({}, srcData, { docName: newDoc.name })); setDocs(next); }; const handleImport = function(e) { const f = e.target.files && e.target.files[0]; if (!f) return; const reader = new FileReader(); reader.onload = function(ev) { try { const payload = JSON.parse(ev.target.result); const id = Math.random().toString(36).slice(2, 9); const newDoc = { id: id, name: payload.docName || f.name.replace(/\.json$/, "") || "Imported Résumé", template: payload.template || "modern", updatedAt: new Date().toISOString(), }; const next = [newDoc].concat(docs); saveAllDocs(next); saveDocData(id, payload); setDocs(next); onOpen(id); } catch(err) { alert("Could not read the file. Make sure it is an exported BDRecruit résumé (.json)."); } }; reader.readAsText(f); e.target.value = ""; }; const delDoc = docs.find(function(d) { return d.id === confirmDel; }); const tplKeys = window.TEMPLATES ? Object.keys(window.TEMPLATES) : []; return (
BDRecruit BDRecruit Resume Studio

My Résumés

{docs.length} document{docs.length !== 1 ? "s" : ""} saved locally

{docs.length === 0 ? (

No résumés yet

Create your first résumé and land that next role.

) : (
New Résumé
{docs.map(function(doc) { return ( ); })}
)}

Start from a template

All templates are ATS-verified — switch any time without losing your content.

{tplKeys.map(function(key) { const tpl = window.TEMPLATES[key]; return ( ); })}

Cover Letter

Write a tailored cover letter that references your résumé data automatically.

Job Match

Paste any job description and instantly see which keywords your résumé is missing.

ATS Score

Real-time scoring across 7 weighted categories so recruiters and bots both love your résumé.

Smart Export

Download a pixel-perfect PDF or a clean ATS-safe plain-text PDF — your choice.

{confirmDel && (

Delete "{delDoc ? delDoc.name : "this résumé"}"?

This can't be undone. All data for this résumé will be permanently removed.

)}
); } window.Dashboard = Dashboard;