// ============== app + router + tweaks ============== const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "density": "default", "typePair": "geist-instrument", "invert": false }/*EDITMODE-END*/; const TYPE_PAIRS = { "geist-instrument": { sans: "'Geist', system-ui, sans-serif", serif: "'Instrument Serif', serif", label: "Geist + Instrument" }, "geist-fraunces": { sans: "'Geist', system-ui, sans-serif", serif: "'Fraunces', serif", label: "Geist + Fraunces" }, "ibm-instrument": { sans: "'IBM Plex Sans', sans-serif", serif: "'Instrument Serif', serif", label: "IBM Plex + Instrument" }, }; const ROUTES = ["home", "jobs", "companies", "candidates", "about", "events", "blog", "contact", "login", "register", "dashboard", "admin", "forgot", "reset", "accept-invite", "roles"]; function parseHash() { // Supports: #home | #roles/W3J-0421 | #reset?token=... | #accept-invite?token=... const raw = window.location.hash.slice(1); if (!raw) return { route: "home", arg: null, query: {} }; const [pathPart, queryPart = ""] = raw.split("?"); const segments = pathPart.split("/"); const route = segments[0]; const arg = segments.slice(1).join("/") || null; const query = {}; if (queryPart) { for (const pair of queryPart.split("&")) { const [k, v] = pair.split("="); query[decodeURIComponent(k)] = decodeURIComponent(v || ""); } } return { route: ROUTES.includes(route) ? route : "home", arg, query }; } function Shell() { const [hashState, setHashState] = React.useState(() => parseHash()); const { route, arg: hashArg, query: hashQuery } = hashState; const [routeArg, setRouteArg] = React.useState(null); const [tweaks, setTweak] = window.useTweaks(TWEAK_DEFAULTS); const { user, loading: authLoading } = useAuth(); const go = (id, arg = null) => { if (id === "events") { window.open("https://lu.ma/web3joe", "_blank", "noopener"); return; } setRouteArg(arg); const hash = arg && arg.publicId ? `${id}/${arg.publicId}` : id; setHashState({ route: id, arg: arg?.publicId || null, query: {} }); window.location.hash = hash; window.scrollTo({ top: 0, behavior: "instant" }); }; React.useEffect(() => { const onHash = () => setHashState(parseHash()); window.addEventListener("hashchange", onHash); return () => window.removeEventListener("hashchange", onHash); }, []); React.useEffect(() => { const root = document.documentElement; root.style.removeProperty("--accent"); root.style.removeProperty("--accent-fg"); root.style.removeProperty("--accent-soft"); root.setAttribute("data-density", tweaks.density); root.setAttribute("data-theme", tweaks.invert ? "light" : "dark"); const tp = TYPE_PAIRS[tweaks.typePair] || TYPE_PAIRS["geist-instrument"]; root.style.setProperty("--sans", tp.sans); root.style.setProperty("--serif", tp.serif); }, [tweaks]); // Auth gates — redirect AFTER auth load completes React.useEffect(() => { if (authLoading) return; if ((route === "dashboard" || route === "admin") && !user) { go("login"); } else if (route === "dashboard" && user && user.role !== "candidate") { go("admin"); } else if (route === "admin" && user && user.role === "candidate") { go("dashboard"); } }, [route, user, authLoading]); let Page = null; if (route === "home") Page = ; else if (route === "jobs") Page = ; else if (route === "roles" && hashArg) Page = ; else if (route === "companies") Page = ; else if (route === "candidates") Page = ; else if (route === "about") Page = ; else if (route === "blog") Page = ; else if (route === "contact") Page = ; else if (route === "login") Page = ; else if (route === "register") Page = ; else if (route === "forgot") Page = ; else if (route === "reset") Page = ; else if (route === "accept-invite") Page = ; else if (route === "dashboard") Page = user ? : ; else if (route === "admin") Page = (user && user.role !== "candidate") ? : ; else Page = ; return (
); } function AuthPage({ mode, go }) { const { user } = useAuth(); React.useEffect(() => { if (user) go(user.role === "candidate" ? "dashboard" : "admin"); }, [user]); return (
{mode === "login" ? "Sign in" : "Create account"}

{mode === "login" ? <>Welcome back. : <>Join the network.}

{mode === "login" ? "Sign in to your candidate dashboard or recruiter control room." : "Build a private candidate file. We only share it with companies you'd actually want to work for."}

); } function AuthForm({ mode }) { const { login, register } = useAuth(); const [email, setEmail] = React.useState(""); const [password, setPassword] = React.useState(""); const [fullName, setFullName] = React.useState(""); const [err, setErr] = React.useState(""); const [busy, setBusy] = React.useState(false); const submit = async (e) => { e.preventDefault(); setErr(""); setBusy(true); try { if (mode === "login") await login(email, password); else await register(email, password, fullName); } catch (ex) { setErr(ex.message); } finally { setBusy(false); } }; return (
{mode === "register" && ( )} {err &&
{err}
}
); } function App() { return ; } const extraFonts = document.createElement("link"); extraFonts.rel = "stylesheet"; extraFonts.href = "https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,400;0,9..144,500;0,9..144,600;1,9..144,400&family=IBM+Plex+Sans:wght@400;500;600;700&display=swap"; document.head.appendChild(extraFonts); ReactDOM.createRoot(document.getElementById("root")).render();