Replaces the free-text "Place of Delivery" with a dropdown sourced from a new admin-managed Delivery Locations list (each = a Company FK + free-text address). - schema + migration: new DeliveryLocation model (companyId, address, isActive). - permission: manage_delivery_locations granted to Manager + SuperUser + Admin (Manager-accessible, not admin-only, per the issue). - admin screen /admin/delivery-locations: table + Add/Edit dialogs + activate/deactivate + delete (mirrors /admin/sites); sidebar link under Administration for Manager/SuperUser/Admin. - PO forms (new / edit / manager-edit): shared <DeliveryLocationField> native select populated from active locations, formatted "Company — address". - PurchaseOrder.placeOfDelivery stays a free-text SNAPSHOT (no FK) — the dropdown only changes how the value is picked, so export/import/historical POs are unchanged, and an edit preserves a current value not in the list as a "(current)" option. Deleting a location is therefore always safe. - tests: delivery-location CRUD + permission guard (6). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
36 lines
1.2 KiB
TypeScript
36 lines
1.2 KiB
TypeScript
"use client";
|
|
|
|
/**
|
|
* Place-of-Delivery dropdown (issue #19) — a native <select name="placeOfDelivery">
|
|
* sourced from the admin-managed delivery locations. Plain HTML so it works with
|
|
* the forms' native FormData submission (no client state needed).
|
|
*
|
|
* `options` are the formatted "Company — address" strings (also the stored value).
|
|
* `current` is the PO's existing place-of-delivery; if it isn't one of the active
|
|
* options (legacy / imported / a since-removed location) it is preserved as a
|
|
* leading "(current)" option so an edit never silently drops it.
|
|
*/
|
|
export function DeliveryLocationField({
|
|
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="placeOfDelivery" defaultValue={cur} className={className}>
|
|
<option value="">— Select a delivery location —</option>
|
|
{currentMissing && <option value={cur}>{cur} (current)</option>}
|
|
{options.map((o) => (
|
|
<option key={o} value={o}>
|
|
{o}
|
|
</option>
|
|
))}
|
|
</select>
|
|
);
|
|
}
|