refactor(ui): drive status from a single shared pipeline module

Introduces pipeline.ts (mirrors backend JobPipeline) as the one frontend
source of truth for canonical stages, synonym normalization, tone, and
localized labels. Replaces the status list/logic previously duplicated
across KanbanBoard, JobTable, AddJobModal and EditJobDialog.

- KanbanBoard/AddJobModal/EditJobDialog render from PIPELINE_STATUSES
- JobTable uses shared statusTone + statusLabel (status chips now
  localized; NB gets proper labels, English unchanged)
- Edit dialog status dropdown is now localized too
- 5 unit tests; full frontend suite green (19 suites / 41 tests)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
cesnimda
2026-07-03 03:37:14 +02:00
parent bb736d1183
commit 5a306f51a1
7 changed files with 125 additions and 71 deletions
@@ -24,6 +24,7 @@ import { useToast } from "../toast";
import { useCompanies } from "../hooks/useCompanies";
import TagsInput from "./TagsInput";
import { useI18n } from "../i18n/I18nProvider";
import { PIPELINE_STATUSES, statusLabel } from "../pipeline";
interface Props {
open: boolean;
@@ -32,7 +33,6 @@ interface Props {
onSaved: () => void;
}
const STATUS_OPTIONS = ["Applied", "Waiting", "Interview", "Offer", "Rejected", "Ghosted"] as const;
const FIELD_SX = { "& .MuiInputBase-root": { minHeight: 56 } };
const PICKER_TEXT_FIELD_PROPS = { fullWidth: true, sx: FIELD_SX };
@@ -207,7 +207,7 @@ export default function EditJobDialog({ open, jobId, onClose, onSaved }: Props)
<Typography variant="overline" sx={{ color: "text.secondary" }}>{t("editJobStatusUpdate")}</Typography>
<Box sx={{ display: "grid", gridTemplateColumns: { xs: "1fr", md: "1fr 1fr 1fr" }, gap: 2, mt: 1 }}>
<TextField select label={t("editJobCurrentStatus")} value={status} onChange={(e) => setStatus(e.target.value)} sx={FIELD_SX}>
{STATUS_OPTIONS.map((s) => <MenuItem key={s} value={s}>{s}</MenuItem>)}
{PIPELINE_STATUSES.map((s) => <MenuItem key={s} value={s}>{statusLabel(t, s)}</MenuItem>)}
</TextField>
<DatePicker label={t("editJobStatusChangedOn")} value={parsePickerDate(statusChangedAt)} onChange={(value) => setStatusChangedAt(toPickerIso(value))} slotProps={{ textField: { ...PICKER_TEXT_FIELD_PROPS, helperText: status === initialStatus ? t("editJobStatusChangedHelpIdle") : t("editJobStatusChangedHelpActive") } }} />
<Box sx={{ display: "flex", alignItems: "center" }}><FormControlLabel control={<Checkbox checked={responseReceived} onChange={(e) => setResponseReceived(e.target.checked)} />} label={t("editJobReplyReceived")} /></Box>