05f6eba5d8
Splits StaffingPanel.tsx into: - StaffingSearchForm: skill tags, dates, hours input, submit button - ScoringExplanation: the 3-column scoring breakdown card - StaffingResultCard: individual suggestion card with details and assign form - StaffingResultsList: list orchestration with loading/empty states - StaffingPanel: thin orchestrator (~100 lines) managing state and tRPC query Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
88 lines
2.7 KiB
TypeScript
88 lines
2.7 KiB
TypeScript
"use client";
|
|
|
|
import { DateInput } from "~/components/ui/DateInput.js";
|
|
import { SkillTagInput } from "~/components/ui/SkillTagInput.js";
|
|
import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
|
|
|
|
export interface SearchCriteria {
|
|
startDate: string;
|
|
endDate: string;
|
|
hoursPerDay: number;
|
|
}
|
|
|
|
interface StaffingSearchFormProps {
|
|
requiredSkills: string[];
|
|
onSkillsChange: (skills: string[]) => void;
|
|
startDate: string;
|
|
onStartDateChange: (date: string) => void;
|
|
endDate: string;
|
|
onEndDateChange: (date: string) => void;
|
|
hoursPerDay: number;
|
|
onHoursPerDayChange: (hours: number) => void;
|
|
onSubmit: () => void;
|
|
}
|
|
|
|
export function StaffingSearchForm({
|
|
requiredSkills,
|
|
onSkillsChange,
|
|
startDate,
|
|
onStartDateChange,
|
|
endDate,
|
|
onEndDateChange,
|
|
hoursPerDay,
|
|
onHoursPerDayChange,
|
|
onSubmit,
|
|
}: StaffingSearchFormProps) {
|
|
return (
|
|
<div className="app-surface-strong p-6">
|
|
<h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100">Search Criteria</h2>
|
|
<p className="mt-1 text-sm text-gray-500">
|
|
Define the role needs and let the matching engine rank the best candidates.
|
|
</p>
|
|
|
|
<div className="mt-6 space-y-5">
|
|
<div>
|
|
<label className="app-label">
|
|
Required Skills
|
|
<InfoTooltip content="Skills the candidate must have. The engine scores overlap and proficiency against this list." />
|
|
</label>
|
|
<SkillTagInput value={requiredSkills} onChange={onSkillsChange} placeholder="Add skill..." />
|
|
</div>
|
|
|
|
<div className="grid gap-4 sm:grid-cols-2 xl:grid-cols-1">
|
|
<div>
|
|
<label className="app-label">Start Date</label>
|
|
<DateInput value={startDate} onChange={onStartDateChange} className="app-input" />
|
|
</div>
|
|
<div>
|
|
<label className="app-label">End Date</label>
|
|
<DateInput value={endDate} onChange={onEndDateChange} min={startDate} className="app-input" />
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="app-label">
|
|
Hours per Day
|
|
<InfoTooltip content="Required hours per day for the role. Used to check conflicts and estimate capacity." />
|
|
</label>
|
|
<input
|
|
type="number"
|
|
value={hoursPerDay}
|
|
onChange={(e) => onHoursPerDayChange(Number(e.target.value))}
|
|
min={1}
|
|
max={24}
|
|
className="app-input"
|
|
/>
|
|
</div>
|
|
|
|
<button
|
|
onClick={onSubmit}
|
|
className="inline-flex w-full items-center justify-center rounded-xl bg-brand-600 px-4 py-3 text-sm font-semibold text-white transition hover:bg-brand-700"
|
|
>
|
|
Find Matches
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|