Files
cesnimda 83e6430a24 feat: structured salary fields (min/max/currency/period)
Adds SalaryMin/SalaryMax/SalaryCurrency/SalaryPeriod alongside the
existing free-text Salary field (kept for back-compat and display).

- JobApplication model + idempotent column bridging for SQLite and MySQL
- Create/Update DTOs with NormalizeSalary (clamps negatives, swaps
  inverted min/max, uppercases currency, whitelists period)
- JobApplicationDto exposes the fields; CSV export gains 4 columns
- UI: add/edit dialogs get min/max/currency/period inputs; job table
  renders a formatted range via shared salary.ts formatter (falls back
  to free-text when structured values are absent)
- EN/NB translations; backend + full frontend suites green

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 22:15:37 +02:00

22 lines
998 B
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { JobApplication } from "./types";
type SalaryFields = Pick<JobApplication, "salary" | "salaryMin" | "salaryMax" | "salaryCurrency" | "salaryPeriod">;
const PERIOD_SUFFIX: Record<string, string> = { year: "yr", month: "mo", hour: "hr" };
/** Structured salary when present ("60 00070 000 NOK/yr"), otherwise the free-text field. */
export function formatSalary(job: SalaryFields): string | null {
const { salaryMin, salaryMax, salaryCurrency, salaryPeriod } = job;
if (salaryMin == null && salaryMax == null) {
return job.salary?.trim() || null;
}
const fmt = (value: number) => value.toLocaleString();
const range = salaryMin != null && salaryMax != null && salaryMin !== salaryMax
? `${fmt(salaryMin)}${fmt(salaryMax)}`
: fmt((salaryMin ?? salaryMax) as number);
const currency = salaryCurrency ? ` ${salaryCurrency}` : "";
const period = salaryPeriod ? `/${PERIOD_SUFFIX[salaryPeriod] ?? salaryPeriod}` : "";
return `${range}${currency}${period}`;
}