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)
|
||||
|
||||
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`)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
"use client";
|
||||
|
||||
/**
|
||||
* A single PO Terms & Conditions slot (issue #11) — a native
|
||||
* <select name={field}> sourced from the admin-managed clauses for its category.
|
||||
* Plain HTML so it works with the forms' native FormData submission.
|
||||
* A single PO Terms & Conditions slot (issue #11) — a combobox: type a one-off
|
||||
* clause OR pick a catalogued one. Implemented as a native <input list> +
|
||||
* <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
|
||||
* PO's existing/default value for this slot; if it isn't one of the active
|
||||
* options (a removed clause, or an older custom value) it is preserved as a
|
||||
* leading "(current)" option so an edit never silently drops it.
|
||||
* `options` are the active clause texts (suggestions). `current` is the PO's
|
||||
* existing/default value for this slot; it's just the input's initial value, so
|
||||
* a value not in the catalogue is preserved as-is.
|
||||
*/
|
||||
export function TermsField({
|
||||
field,
|
||||
|
|
@ -21,18 +21,22 @@ export function TermsField({
|
|||
current?: string | null;
|
||||
className?: string;
|
||||
}) {
|
||||
const cur = (current ?? "").trim();
|
||||
const currentMissing = cur.length > 0 && !options.includes(cur);
|
||||
|
||||
const listId = `terms-list-${field}`;
|
||||
return (
|
||||
<select name={field} defaultValue={cur} className={className}>
|
||||
<option value="">—</option>
|
||||
{currentMissing && <option value={cur}>{cur} (current)</option>}
|
||||
{options.map((o) => (
|
||||
<option key={o} value={o}>
|
||||
{o}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<>
|
||||
<input
|
||||
name={field}
|
||||
list={listId}
|
||||
defaultValue={current ?? ""}
|
||||
autoComplete="off"
|
||||
placeholder="Type a clause or pick one…"
|
||||
className={className}
|
||||
/>
|
||||
<datalist id={listId}>
|
||||
{options.map((o) => (
|
||||
<option key={o} value={o} />
|
||||
))}
|
||||
</datalist>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue