// ============== candidate dashboard ============== const SENIORITY = ["Mid", "Senior", "Lead", "Staff", "Director"]; const OPEN_TO = [ { v: "actively_looking", l: "Actively looking" }, { v: "open", l: "Open to offers" }, { v: "passive", l: "Passive" }, { v: "closed", l: "Not looking" }, ]; const STATUS_LABEL = { submitted: "Submitted", reviewed: "Under review", shortlisted: "Shortlisted", interviewing: "Interviewing", offered: "Offer extended", placed: "Placed", rejected: "Closed", withdrawn: "Withdrawn", }; function Tabs({ tabs, value, onChange }) { return (
{tabs.map((t) => ( ))}
); } function CandidateDashboard({ go }) { const { user, logout } = useAuth(); const [tab, setTab] = React.useState("profile"); const [profile, setProfile] = React.useState(null); const [apps, setApps] = React.useState([]); const [roles, setRoles] = React.useState({}); const [loading, setLoading] = React.useState(true); React.useEffect(() => { if (!user) return; (async () => { try { const [p, a] = await Promise.all([ window.W3J_API.apiFetch("/candidates/me"), window.W3J_API.apiFetch("/applications/me"), ]); setProfile(p); setApps(a); const roleIds = [...new Set(a.map((x) => x.role_id))]; const fetched = await Promise.all(roleIds.map((id) => window.W3J_API.apiFetch(`/roles/${id}`).catch(() => null))); const map = {}; fetched.forEach((r) => { if (r) map[r.id] = r; }); setRoles(map); } finally { setLoading(false); } })(); }, [user]); if (loading) return

Loading…

; if (!profile) return null; return (
Candidate · Signed in as {user.email}

{profile.full_name || "Your"} file.

{tab === "profile" && } {tab === "resume" && } {tab === "applications" && }
); } function ProfileForm({ profile, onSaved }) { const [form, setForm] = React.useState({ ...profile, skills: profile.skills || [], chains: profile.chains || [] }); const [skillsText, setSkillsText] = React.useState((profile.skills || []).join(", ")); const [chainsText, setChainsText] = React.useState((profile.chains || []).join(", ")); const [saving, setSaving] = React.useState(false); const [msg, setMsg] = React.useState(""); const set = (k) => (e) => setForm((f) => ({ ...f, [k]: e.target.value === "" ? null : e.target.value })); const setNum = (k) => (e) => setForm((f) => ({ ...f, [k]: e.target.value === "" ? null : Number(e.target.value) })); const submit = async (e) => { e.preventDefault(); setSaving(true); setMsg(""); try { const body = { full_name: form.full_name, headline: form.headline, bio: form.bio, location: form.location, timezone: form.timezone, skills: skillsText.split(",").map((s) => s.trim()).filter(Boolean), chains: chainsText.split(",").map((s) => s.trim()).filter(Boolean), years_experience: form.years_experience, seniority: form.seniority, comp_min_k: form.comp_min_k, comp_max_k: form.comp_max_k, open_to_offers: form.open_to_offers, github_url: form.github_url, twitter_url: form.twitter_url, linkedin_url: form.linkedin_url, website_url: form.website_url, }; const saved = await window.W3J_API.apiFetch("/candidates/me", { method: "PUT", body }); onSaved(saved); setMsg("Saved."); } catch (ex) { setMsg(ex.message || "Save failed"); } finally { setSaving(false); } }; return (

Basics