Candidate shortlist
Rank people by dragging.
Built with
- Avatar
- AvatarLabel
- Badge
- Button
- SortableItem
- SortableList
Shortlist: Senior frontend engineer
Rank the final four for the hiring committee. The top candidate gets the first offer.
Ranking
Zara Siddiqui Frontend engineer, 6 yrs
Panel: Strong yesPanel 12 Oct · Referred by Luis OrtegaHina Baig Frontend engineer, 4 yrs
Panel: YesPanel 9 Oct · Strong accessibility workOmar Farooq Full-stack engineer, 8 yrs
Panel: YesPanel 8 Oct · Notice period 3 monthsSana Malik Frontend engineer, 3 yrs
Panel: MixedPanel 7 Oct · Needs mentoring on testingcandidate-shortlist.tsx
"use client";
import { useState } from "react";
import { LuSend } from "react-icons/lu";
import { Avatar, AvatarLabel, Badge, Button, SortableItem, SortableList } from "@nexera-ui/react";
interface Candidate {
id: string;
name: string;
initials: string;
role: string;
detail: string;
score: "Strong yes" | "Yes" | "Mixed";
}
const SHORTLIST: Candidate[] = [
{
id: "zara",
name: "Zara Siddiqui",
initials: "ZS",
role: "Frontend engineer, 6 yrs",
detail: "Panel 12 Oct · Referred by Luis Ortega",
score: "Strong yes",
},
{
id: "hina",
name: "Hina Baig",
initials: "HB",
role: "Frontend engineer, 4 yrs",
detail: "Panel 9 Oct · Strong accessibility work",
score: "Yes",
},
{
id: "omar",
name: "Omar Farooq",
initials: "OF",
role: "Full-stack engineer, 8 yrs",
detail: "Panel 8 Oct · Notice period 3 months",
score: "Yes",
},
{
id: "sana",
name: "Sana Malik",
initials: "SM",
role: "Frontend engineer, 3 yrs",
detail: "Panel 7 Oct · Needs mentoring on testing",
score: "Mixed",
},
];
const TONE = { "Strong yes": "success", Yes: "info", Mixed: "warning" } as const;
/**
* Candidate shortlist: rank the final candidates by dragging. Drag a row, or use the keyboard (arrow to the handle, Enter,
* arrows, Enter), or the Move menu (Move up / Move down).
*/
export default function CandidateShortlist() {
const [items, setItems] = useState(SHORTLIST);
const [sent, setSent] = useState(false);
return (
<div className="@container bg-page px-4 py-8 @3xl:px-8">
<div className="mx-auto grid w-full max-w-2xl gap-5 rounded-xl border border-default bg-surface p-5 shadow-xs @3xl:p-6">
<header className="grid gap-1">
<h2 className="text-heading-h3 text-primary">Shortlist: Senior frontend engineer</h2>
<p className="text-body-default text-secondary">
Rank the final four for the hiring committee. The top candidate gets the first offer.
</p>
</header>
<div className="grid gap-2">
<h3 id="shortlist-title" className="text-heading-h4 text-primary">
Ranking
</h3>
<SortableList
aria-labelledby="shortlist-title"
items={items}
onReorder={(next) => {
setItems(next);
setSent(false);
}}
>
{(candidate) => (
<SortableItem
textValue={candidate.name}
label={
<span className="flex flex-wrap items-center justify-between gap-2">
<AvatarLabel
name={candidate.name}
subtitle={candidate.role}
size="md"
avatar={<Avatar initials={candidate.initials} isDecorative />}
/>
<Badge tone={TONE[candidate.score]} label={`Panel: ${candidate.score}`} />
</span>
}
meta={candidate.detail}
/>
)}
</SortableList>
</div>
<div className="flex flex-wrap items-center justify-end gap-3">
<p role="status" className="text-body-small text-secondary">
{sent ? `Ranking sent. ${items[0]?.name ?? ""} is first.` : ""}
</p>
<Button
leadingIcon={<LuSend />}
onPress={() => {
setSent(true);
}}
>
Send to hiring committee
</Button>
</div>
</div>
</div>
);
}