Change dispatch to single vendor select per dispatch

- Switch from checkbox multi-select to radio button single select
- One vendor per dispatch, can dispatch multiple times for multiple vendors
- Selected vendor shown as chip below the list
This commit is contained in:
Adam Moussa 2026-04-17 12:22:37 -04:00
parent 766ad20774
commit 0455fdf2ec
2 changed files with 16 additions and 16 deletions

View file

@ -526,7 +526,7 @@
background: #e6f0ff;
}
.woDispatchVendorItem input[type="checkbox"] {
.woDispatchVendorItem input[type="radio"] {
flex-shrink: 0;
width: 16px;
height: 16px;

View file

@ -162,7 +162,7 @@ function AuditTimeline({ entries }) {
function DispatchModal({ wo, onClose, onDispatched }) {
const [vendors, setVendors] = useState([]);
const [selectedIds, setSelectedIds] = useState([]);
const [selectedId, setSelectedId] = useState(null);
const [nteAmount, setNteAmount] = useState(wo.vendorNTE || "");
const [scheduledDate, setScheduledDate] = useState("");
const [description, setDescription] = useState(wo.description || "");
@ -177,8 +177,8 @@ function DispatchModal({ wo, onClose, onDispatched }) {
}).catch(() => setLoaded(true));
}, [wo.trade]);
const toggleVendor = (id) => {
setSelectedIds(prev => prev.includes(id) ? prev.filter(v => v !== id) : [...prev, id]);
const selectVendor = (id) => {
setSelectedId(prev => prev === id ? null : id);
};
const filteredVendors = vendors.filter((v) =>
@ -187,16 +187,16 @@ function DispatchModal({ wo, onClose, onDispatched }) {
);
const handleSubmit = async () => {
if (selectedIds.length === 0) { toast.error("Select at least one vendor"); return; }
if (!selectedId) { toast.error("Select a vendor"); return; }
setSending(true);
try {
await dispatchToVendor(wo.id, {
VendorIds: selectedIds,
VendorIds: [selectedId],
NTEAmount: nteAmount ? parseFloat(nteAmount) : null,
ScheduledDate: scheduledDate || null,
Description: description,
});
toast.success(`Dispatched to ${selectedIds.length} vendor(s)`);
toast.success("Dispatched successfully");
onDispatched();
onClose();
} catch {
@ -226,8 +226,8 @@ function DispatchModal({ wo, onClose, onDispatched }) {
{!loaded ? <div className="woDispatchLoading">Loading vendors...</div> : filteredVendors.length === 0 ? <div className="woDispatchLoading">No vendors found</div> : (
<div className="woDispatchVendorList">
{filteredVendors.map((v) => (
<div key={v.id} className={`woDispatchVendorItem ${selectedIds.includes(v.id) ? "selected" : ""}`} onClick={() => toggleVendor(v.id)}>
<input type="checkbox" checked={selectedIds.includes(v.id)} readOnly />
<div key={v.id} className={`woDispatchVendorItem ${selectedId === v.id ? "selected" : ""}`} onClick={() => selectVendor(v.id)}>
<input type="radio" name="vendorSelect" checked={selectedId === v.id} readOnly />
<div className="woDispatchVendorInfo">
<span className="woDispatchVendorName">{v.companyName}</span>
{v.tradeSpecialties && <span className="woDispatchVendorTrades">{v.tradeSpecialties}</span>}
@ -243,12 +243,12 @@ function DispatchModal({ wo, onClose, onDispatched }) {
))}
</div>
)}
{selectedIds.length > 0 && (
{selectedId && (
<div className="woDispatchSelected">
{selectedIds.map((id) => {
const v = vendors.find((x) => x.id === id);
return v ? <span key={id} className="woDispatchSelectedChip">{v.companyName} <button onClick={() => toggleVendor(id)}>&times;</button></span> : null;
})}
<span className="woDispatchSelectedChip">
{vendors.find((x) => x.id === selectedId)?.companyName}
<button onClick={() => setSelectedId(null)}>&times;</button>
</span>
</div>
)}
</div>
@ -269,8 +269,8 @@ function DispatchModal({ wo, onClose, onDispatched }) {
</div>
<div className="woDispatchFooter">
<button className="btn btn-default" onClick={onClose} disabled={sending}>Cancel</button>
<button className="btn btn-primary" onClick={handleSubmit} disabled={sending || selectedIds.length === 0}>
{sending ? "Dispatching..." : `Dispatch to ${selectedIds.length} Vendor(s)`}
<button className="btn btn-primary" onClick={handleSubmit} disabled={sending || !selectedId}>
{sending ? "Dispatching..." : "Dispatch"}
</button>
</div>
</div>