feat(po): make TermsField a combobox (type-or-pick)
Per review: the five named PO T&C slots now allow a one-off custom clause as well as picking a catalogued one. TermsField becomes a native <input list> + <datalist> combobox (still plain FormData, no form/page changes). Any current/ custom value is preserved as the input value. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a99b2ed5df
commit
f4c8ec7585
2 changed files with 24 additions and 20 deletions
|
|
@ -106,7 +106,7 @@ The three PO forms (`new-po-form`, `edit-po-form`, `manager-edit-po-form`) rende
|
||||||
|
|
||||||
### Terms & Conditions catalogue (issue #11)
|
### Terms & Conditions catalogue (issue #11)
|
||||||
|
|
||||||
Same admin-list-feeds-PO-dropdown pattern as Delivery Locations. `TermsCondition` (`category: TermsCategory` enum + `text` + `isActive`) is an admin-managed clause library, managed at `/admin/terms` (gated by **`manage_terms`** — Manager + SuperUser + Admin; CRUD mirrors `/admin/delivery-locations`). The migration **seeds** the prior `TC_DEFAULTS` wording as the starting clauses. The five **named** PO T&C slots (Delivery / Dispatch / Inspection / Transit Insurance / Payment Terms — the `tc*` columns, mapped via `lib/terms.ts` `TC_FIELD_CATEGORY`) become a shared `<TermsField>` native `<select>` populated from the active clauses of that category (`lib/terms-data.ts` `getActiveTermsByCategory`). **"Others" stays free text**, and the fixed boilerplate lines (`TC_FIXED_LINE` / `TC_FIXED_LINE_2`) are not catalogued. The `tc*` columns stay **free-text snapshots** (export/import unchanged); a current value not among the active clauses is preserved as a "(current)" option. No "work order" type — POs only (per the issue's steer).
|
Same admin-list-feeds-PO-dropdown pattern as Delivery Locations. `TermsCondition` (`category: TermsCategory` enum + `text` + `isActive`) is an admin-managed clause library, managed at `/admin/terms` (gated by **`manage_terms`** — Manager + SuperUser + Admin; CRUD mirrors `/admin/delivery-locations`). The migration **seeds** the prior `TC_DEFAULTS` wording as the starting clauses. The five **named** PO T&C slots (Delivery / Dispatch / Inspection / Transit Insurance / Payment Terms — the `tc*` columns, mapped via `lib/terms.ts` `TC_FIELD_CATEGORY`) become a shared `<TermsField>` **combobox** (native `<input list>` + `<datalist>`) — type a one-off clause or pick a catalogued one — suggesting the active clauses of that category (`lib/terms-data.ts` `getActiveTermsByCategory`). **"Others" stays free text**, and the fixed boilerplate lines (`TC_FIXED_LINE` / `TC_FIXED_LINE_2`) are not catalogued. The `tc*` columns stay **free-text snapshots** (export/import unchanged); since the slot is a free-text combobox, any current/custom value is preserved as-is. No "work order" type — POs only (per the issue's steer).
|
||||||
|
|
||||||
### PO Numbering (`lib/po-number.ts`)
|
### PO Numbering (`lib/po-number.ts`)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A single PO Terms & Conditions slot (issue #11) — a native
|
* A single PO Terms & Conditions slot (issue #11) — a combobox: type a one-off
|
||||||
* <select name={field}> sourced from the admin-managed clauses for its category.
|
* clause OR pick a catalogued one. Implemented as a native <input list> +
|
||||||
* Plain HTML so it works with the forms' native FormData submission.
|
* <datalist> so it stays free-text (custom wording per PO) while suggesting the
|
||||||
|
* admin-managed clauses for this category, and submits via plain FormData.
|
||||||
*
|
*
|
||||||
* `options` are the active clause texts (also the stored value). `current` is the
|
* `options` are the active clause texts (suggestions). `current` is the PO's
|
||||||
* PO's existing/default value for this slot; if it isn't one of the active
|
* existing/default value for this slot; it's just the input's initial value, so
|
||||||
* options (a removed clause, or an older custom value) it is preserved as a
|
* a value not in the catalogue is preserved as-is.
|
||||||
* leading "(current)" option so an edit never silently drops it.
|
|
||||||
*/
|
*/
|
||||||
export function TermsField({
|
export function TermsField({
|
||||||
field,
|
field,
|
||||||
|
|
@ -21,18 +21,22 @@ export function TermsField({
|
||||||
current?: string | null;
|
current?: string | null;
|
||||||
className?: string;
|
className?: string;
|
||||||
}) {
|
}) {
|
||||||
const cur = (current ?? "").trim();
|
const listId = `terms-list-${field}`;
|
||||||
const currentMissing = cur.length > 0 && !options.includes(cur);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<select name={field} defaultValue={cur} className={className}>
|
<>
|
||||||
<option value="">—</option>
|
<input
|
||||||
{currentMissing && <option value={cur}>{cur} (current)</option>}
|
name={field}
|
||||||
{options.map((o) => (
|
list={listId}
|
||||||
<option key={o} value={o}>
|
defaultValue={current ?? ""}
|
||||||
{o}
|
autoComplete="off"
|
||||||
</option>
|
placeholder="Type a clause or pick one…"
|
||||||
))}
|
className={className}
|
||||||
</select>
|
/>
|
||||||
|
<datalist id={listId}>
|
||||||
|
{options.map((o) => (
|
||||||
|
<option key={o} value={o} />
|
||||||
|
))}
|
||||||
|
</datalist>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue