auto suggest fix

This commit is contained in:
2026-03-14 23:07:43 -05:00
parent 8bf69c67e0
commit d44d97e47b
4 changed files with 78 additions and 16 deletions

View File

@@ -17,6 +17,8 @@ export function SalesFormPage({ entity, mode }: { entity: SalesDocumentEntity; m
const [form, setForm] = useState<SalesDocumentInput>(emptySalesDocumentInput);
const [status, setStatus] = useState(mode === "create" ? `Create a new ${config.singularLabel.toLowerCase()}.` : `Loading ${config.singularLabel.toLowerCase()}...`);
const [customers, setCustomers] = useState<SalesCustomerOptionDto[]>([]);
const [customerSearchTerm, setCustomerSearchTerm] = useState("");
const [customerPickerOpen, setCustomerPickerOpen] = useState(false);
const [itemOptions, setItemOptions] = useState<InventoryItemOptionDto[]>([]);
const [lineSearchTerms, setLineSearchTerms] = useState<string[]>([]);
const [activeLinePicker, setActiveLinePicker] = useState<number | null>(null);
@@ -54,6 +56,7 @@ export function SalesFormPage({ entity, mode }: { entity: SalesDocumentEntity; m
position: line.position,
})),
});
setCustomerSearchTerm(document.customerName);
setLineSearchTerms(document.lines.map((line: SalesDocumentDetailDto["lines"][number]) => line.itemSku));
setStatus(`${config.singularLabel} loaded.`);
})
@@ -67,6 +70,10 @@ export function SalesFormPage({ entity, mode }: { entity: SalesDocumentEntity; m
setForm((current: SalesDocumentInput) => ({ ...current, [key]: value }));
}
function getSelectedCustomerName(customerId: string) {
return customers.find((customer) => customer.id === customerId)?.name ?? "";
}
function updateLine(index: number, nextLine: SalesLineInput) {
setForm((current: SalesDocumentInput) => ({
...current,
@@ -152,18 +159,73 @@ export function SalesFormPage({ entity, mode }: { entity: SalesDocumentEntity; m
<div className="grid gap-3 xl:grid-cols-4">
<label className="block xl:col-span-2">
<span className="mb-2 block text-sm font-semibold text-text">Customer</span>
<select
value={form.customerId}
onChange={(event) => updateField("customerId", event.target.value)}
className="w-full rounded-2xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
>
<option value="">Select customer</option>
{customers.map((customer) => (
<option key={customer.id} value={customer.id}>
{customer.name}
</option>
))}
</select>
<div className="relative">
<input
value={customerSearchTerm}
onChange={(event) => {
setCustomerSearchTerm(event.target.value);
updateField("customerId", "");
setCustomerPickerOpen(true);
}}
onFocus={() => setCustomerPickerOpen(true)}
onBlur={() => {
window.setTimeout(() => {
setCustomerPickerOpen(false);
if (form.customerId) {
setCustomerSearchTerm(getSelectedCustomerName(form.customerId));
}
}, 120);
}}
placeholder="Search customer"
className="w-full rounded-2xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
/>
{customerPickerOpen ? (
<div className="absolute z-20 mt-2 max-h-64 w-full overflow-y-auto rounded-2xl border border-line/70 bg-surface shadow-panel">
{customers
.filter((customer) => {
const query = customerSearchTerm.trim().toLowerCase();
if (!query) {
return true;
}
return (
customer.name.toLowerCase().includes(query) ||
customer.email.toLowerCase().includes(query)
);
})
.slice(0, 12)
.map((customer) => (
<button
key={customer.id}
type="button"
onMouseDown={(event) => {
event.preventDefault();
updateField("customerId", customer.id);
setCustomerSearchTerm(customer.name);
setCustomerPickerOpen(false);
}}
className="block w-full border-b border-line/50 px-4 py-2 text-left text-sm transition last:border-b-0 hover:bg-page/70"
>
<div className="font-semibold text-text">{customer.name}</div>
<div className="mt-1 text-xs text-muted">{customer.email}</div>
</button>
))}
{customers.filter((customer) => {
const query = customerSearchTerm.trim().toLowerCase();
if (!query) {
return true;
}
return customer.name.toLowerCase().includes(query) || customer.email.toLowerCase().includes(query);
}).length === 0 ? (
<div className="px-2 py-2 text-sm text-muted">No matching customers found.</div>
) : null}
</div>
) : null}
</div>
<div className="mt-2 min-h-5 text-xs text-muted">
{form.customerId ? getSelectedCustomerName(form.customerId) : "No customer selected"}
</div>
</label>
<label className="block">
<span className="mb-2 block text-sm font-semibold text-text">Status</span>