Replaces the hardcoded PROJECT_CODES array with an admin-managed `ProjectCode` model, mirroring the Delivery Locations pattern (PR #100): - ProjectCode model (unique `code` + isActive) + migration seeding the five previously-hardcoded codes; PO.projectCode stays a free-text snapshot (no FK) so history/exports/imports are unchanged. - manage_project_codes permission (Manager + SuperUser + Admin). - /admin/project-codes CRUD screen (table + Add/Edit + activate/delete) and an Administration sidebar link. - ProjectCodeField now takes `options` from the active codes; the three PO forms + pages fetch them from the DB. Static list removed. - Unit test reworked to the options API; CRUD integration test added; documented in App/CLAUDE.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
35 lines
1.2 KiB
TypeScript
35 lines
1.2 KiB
TypeScript
/**
|
|
* Project Code dropdown (issue #124) — a native <select name="projectCode">
|
|
* sourced from the admin-managed project codes, plus an empty "— none —" option
|
|
* (the field stays optional). Plain HTML so it works with the forms' native
|
|
* FormData submission (no client state needed), matching DeliveryLocationField.
|
|
*
|
|
* `options` are the active project-code strings (also the stored value).
|
|
* `current` is the PO's existing project code; if it isn't one of the active
|
|
* options (legacy / imported / a since-removed code) it is preserved as a
|
|
* leading "(current)" option so an edit never silently drops it.
|
|
*/
|
|
export function ProjectCodeField({
|
|
options,
|
|
current,
|
|
className,
|
|
}: {
|
|
options: string[];
|
|
current?: string | null;
|
|
className?: string;
|
|
}) {
|
|
const cur = (current ?? "").trim();
|
|
const currentMissing = cur.length > 0 && !options.includes(cur);
|
|
|
|
return (
|
|
<select name="projectCode" defaultValue={cur} className={className}>
|
|
<option value="">— none —</option>
|
|
{currentMissing && <option value={cur}>{cur} (current)</option>}
|
|
{options.map((code) => (
|
|
<option key={code} value={code}>
|
|
{code}
|
|
</option>
|
|
))}
|
|
</select>
|
|
);
|
|
}
|