// Job detail screen — funnel, candidates list, job post settings
function JobFunnel({ jobId }) {
const stages = STAGES.filter(s => !["backburner","rejected","not_interested","declined"].includes(s.id));
const counts = stages.map(s => jobStageCount(jobId, s.id));
const max = Math.max(...counts, 1);
return (
{stages.map((s, i) => {
const count = counts[i];
const prev = i > 0 ? counts[i - 1] : count;
const conv = i > 0 && prev > 0 ? Math.round((count / prev) * 100) : null;
return (
{s.label}
{count}
{conv !== null ? `${conv}% from prev` : "Top of funnel"}
);
})}
);
}
const { useState: useStateJ } = React;
function JobDetail() {
const job = JOBS.find(j => j.id === "se-rt"); // Staff Engineer, Real-time Systems
const candidates = candidatesByJob(job.id);
const active = candidates.filter(c => !["rejected","not_interested","declined","hired"].includes(c.stage));
const [subtab, setSubtab] = useStateJ("Pipeline");
const [layout, setLayout] = useStateJ("compact"); // "kanban" | "compact"
const [filters, setFilters] = useStateJ({});
const [addModalOpen, setAddModalOpen] = useStateJ(false);
const [, showToast, ToastHost] = useAtsToast();
const toggleFilter = (id, label) => {
setFilters(p => {
const n = { ...p };
if (n[id]) { delete n[id]; showToast(`Cleared ${label}`); }
else { n[id] = label; showToast(`Filter applied: ${label}`); }
return n;
});
};
const SUBTABS = [
{ id: "Pipeline", label: "Pipeline", count: 39 },
{ id: "Job post", label: "Job post" },
{ id: "Scorecards", label: "Scorecards" },
{ id: "Sequences", label: "Sequences" },
{ id: "Sourcing", label: "Sourcing" },
{ id: "Activity", label: "Activity" },
{ id: "Settings", label: "Settings" },
];
return (
{
if (id === job.id) return;
const sel = JOBS.find(j => j.id === id);
if (sel) showToast(`Open ${sel.title} from the canvas to view its job page`);
else if (id === "__all__") showToast("All roles selected");
else if (id === null) showToast("Open roles selected");
else showToast("Saved view selected");
}} />
P0 · priority
{job.dept} · open since {job.opened}
{job.title}
{
try { navigator.clipboard && navigator.clipboard.writeText("https://nuancelabs.ai/careers/staff-rt"); } catch(e) {}
showToast("Link copied to clipboard", { tone: "success" });
}}>Share link
setAddModalOpen(true)}>+ Add candidate
Active candidates
{active.length}
+3 this week
Days open
27d
Target: 45d
Pass-through
62%
Sourced → Intro
Job-post views
1,284
38 applies
Sourcing
3
LinkedIn searches running
{SUBTABS.map(t => (
setSubtab(t.id)}
>
{t.label}
{t.count != null && {t.count} }
))}
{subtab === "Pipeline" && (
<>
toggleFilter("stage", "Stage")}>Stage ▾
toggleFilter("source", "Source")}>Source ▾
showToast("Pick a property to filter on — coming soon")}>+ Filter
setLayout("kanban")}
>Kanban
setLayout("compact")}
>Compact
{layout === "compact" && (
Candidate
Stage
Source
Days
Location
Comp ask
Owner
Last activity
{(() => {
// Spread across stages so the visible rows reflect the full pipeline,
// not just the first 22 sourced candidates returned by candidatesByJob.
const byStage = STAGES.map(s => candidates.filter(c => c.stage === s.id));
const interleaved = [];
let i = 0;
while (interleaved.length < 22) {
let added = 0;
for (const bucket of byStage) {
if (bucket[i]) { interleaved.push(bucket[i]); added++; if (interleaved.length >= 22) break; }
}
if (!added) break;
i++;
}
return interleaved;
})().map(c => {
const stage = STAGE_BY_ID[c.stage];
const isStale = c.days >= 12 && !["hired","rejected","declined","backburner"].includes(c.stage);
return (
{c.name}
{c.title} · {c.company}
{c.days}d
{c.location}
{c.salary}
{c.lastActivity}
);
})}
)}
{layout === "kanban" && (
)}
>
)}
{subtab !== "Pipeline" && (
)}
{ToastHost}
{addModalOpen && (
setAddModalOpen(false)} defaultJobId={job?.id} />
)}
);
}
Object.assign(window, { JobDetail, JobFunnel });
// === Mini-kanban for Job page ===
function JobMiniKanban({ candidates }) {
const stages = STAGES.filter(s => !["backburner","rejected","not_interested","declined"].includes(s.id));
const byStage = Object.fromEntries(stages.map(s => [s.id, candidates.filter(c => c.stage === s.id)]));
return (
{stages.map(s => (
{s.label}
{byStage[s.id].length}
{byStage[s.id].slice(0, 6).map(c => (
))}
{byStage[s.id].length > 6 && (
+{byStage[s.id].length - 6} more
)}
{byStage[s.id].length === 0 && (
—
)}
))}
);
}
// === Placeholder for non-Pipeline subtabs ===
function JobSubtabPlaceholder({ name, job }) {
const COPY = {
"Job post": {
title: "Job post",
desc: `The public-facing posting for ${job.title}. Edit copy, requirements, and where it's syndicated.`,
stats: [
{ k: "Views", v: "1,284" },
{ k: "Applies", v: "38" },
{ k: "Apply rate", v: "3.0%" },
],
},
Scorecards: {
title: "Interview scorecards",
desc: "The competency rubric every interviewer fills out for this role. Per-stage scorecards roll up into a single decision.",
stats: [
{ k: "Active scorecards", v: "5" },
{ k: "Avg completion", v: "94%" },
{ k: "Calibration sessions", v: "2" },
],
},
Sequences: {
title: "Outreach sequences",
desc: "Templated outreach used by sourcers and recruiters. AI-personalized opening + 2 follow-ups.",
stats: [
{ k: "Running", v: "3" },
{ k: "Reply rate", v: "31%" },
{ k: "Last sent", v: "12m ago" },
],
},
Sourcing: {
title: "Sourcing searches",
desc: "Saved LinkedIn / GitHub / arXiv searches. New matches drop into Auto-screen for AI review before reaching the pipeline.",
stats: [
{ k: "Saved searches", v: "3" },
{ k: "Matches today", v: "27" },
{ k: "Auto-passed", v: "12" },
],
},
Activity: {
title: "Activity feed",
desc: "Every change to this job — stage moves, comments, scorecard submissions, offer events.",
stats: [
{ k: "Events today", v: "18" },
{ k: "This week", v: "104" },
],
},
Settings: {
title: "Settings",
desc: "Who owns this role, who has access, default stages, hiring manager approval flow.",
stats: [
{ k: "Members", v: "6" },
{ k: "Visibility", v: "Hiring team" },
],
},
};
const c = COPY[name] || { title: name, desc: "", stats: [] };
return (
Full {c.title.toLowerCase()} view — design coming next iteration
);
}
Object.assign(window, { JobMiniKanban, JobSubtabPlaceholder });