Files
Nexus/apps/web/src/components/staffing/StaffingSearchForm.tsx
T
Hartmut 05f6eba5d8 refactor(staffing): decompose 735-line StaffingPanel into focused components
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>
2026-04-09 13:17:55 +02:00

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>
);
}