// ============== misc pages: role detail, password reset, accept invite ============== function RoleDetailPage({ publicId, go }) { const [role, setRole] = React.useState(null); const [err, setErr] = React.useState(""); React.useEffect(() => { window.W3J_API.apiFetch(`/roles/by-public-id/${publicId}`, { auth: false }) .then((r) => setRole(window.W3J.normalizeRole(r))) .catch((ex) => setErr(ex.status === 404 ? "Role not found or no longer open." : ex.message)); }, [publicId]); if (err) { return (
404 · Role unavailable

Not found.

{err}

go("jobs")}>Browse open roles
); } if (!role) { return

Loading…

; } return (
{role.id} · {role.cat}{role.chain ? ` · ${role.chain}` : ""}

{role.title}

{role.company} · {role.remote}
{role.chain && {role.chain}} {role.stack.map((s) => {s})} {role.level}
{role.description && (<>

About the role

{role.description}

)} {role.requirements?.length > 0 && ( <>

What we're looking for

    {role.requirements.map((s, i) =>
  • {s}
  • )}
)} {role.offer?.length > 0 && ( <>

What's on offer

    {role.offer.map((s, i) =>
  • {s}
  • )}
)}
); } function ResetPasswordPage({ token, go }) { const [password, setPassword] = React.useState(""); const [busy, setBusy] = React.useState(false); const [err, setErr] = React.useState(""); const submit = async (e) => { e.preventDefault(); setBusy(true); setErr(""); try { const tokens = await window.W3J_API.apiFetch("/auth/reset-password", { method: "POST", body: { token, new_password: password }, auth: false, }); window.W3J_API.tokens.set(tokens); go("dashboard"); } catch (ex) { setErr(ex.message); } finally { setBusy(false); } }; if (!token) { return (
Reset password

Missing reset token.

Use the link from your reset email, or request a new one.

go("forgot")}>Request a new link
); } return (
Reset password

Choose a new password.

{err &&
{err}
}
); } function ForgotPasswordPage({ go }) { const [email, setEmail] = React.useState(""); const [busy, setBusy] = React.useState(false); const [sent, setSent] = React.useState(false); const submit = async (e) => { e.preventDefault(); setBusy(true); try { await window.W3J_API.apiFetch("/auth/forgot-password", { method: "POST", body: { email }, auth: false }); setSent(true); } catch { setSent(true); // never reveal account existence } finally { setBusy(false); } }; return (
Forgot password

{sent ? <>Check your inbox. : <>Recover your account.}

{sent ? "If an account exists for that email, we just sent a reset link. The link expires in 30 minutes." : "Enter the email tied to your account. We'll send a one-time reset link."}

{!sent && (
)}
); } function AcceptInvitePage({ token, go }) { const [info, setInfo] = React.useState(null); const [err, setErr] = React.useState(""); const [busy, setBusy] = React.useState(false); const [form, setForm] = React.useState({ full_name: "", password: "" }); React.useEffect(() => { if (!token) { setErr("Missing invite token."); return; } window.W3J_API.apiFetch(`/auth/invite/${token}`, { auth: false }) .then(setInfo).catch((ex) => setErr(ex.message)); }, [token]); const submit = async (e) => { e.preventDefault(); setBusy(true); setErr(""); try { const tokens = await window.W3J_API.apiFetch("/auth/accept-invite", { method: "POST", body: { token, full_name: form.full_name, password: form.password }, auth: false, }); window.W3J_API.tokens.set(tokens); go("admin"); } catch (ex) { setErr(ex.message); } finally { setBusy(false); } }; if (err) { return (
Invite

Invite unavailable.

{err}

); } if (!info) return

Loading invite…

; return (
Recruiter invite

Welcome to Web3JOE.

Joining as {info.email}. Set a password and you're in.

); } window.RoleDetailPage = RoleDetailPage; window.ResetPasswordPage = ResetPasswordPage; window.ForgotPasswordPage = ForgotPasswordPage; window.AcceptInvitePage = AcceptInvitePage;