Container Selection Page¶
Route: /history/container
Component: src/pages/requester/ContainerSelectionPage.tsx
Auth: Protected
Entered from: Not directly accessible via bottom nav — accessed from CreateRequestPage (there is no bottom nav entry for containers). In the current prototype, the route exists but is not linked from a primary navigation entry. Operators navigate to it via the direct container order path.
Purpose¶
Allows the operator to browse container subtypes (Trolley, Pallet, Bin), set quantities per subtype, and proceed to container checkout. Uses a tab-based layout to switch between container types.
Layout¶
┌─────────────────────────────────────────┐
│ ← Order Container [Checkout(N)] │ ← Sub-header (fixed)
├─────────────────────────────────────────┤
│ [Trolley] [Pallet] [Bin] │ ← Type tabs (fixed)
├─────────────────────────────────────────┤
│ Select subtypes and quantities... │
│ │
│ [Card: Heavy Trolley 8 avail] │
│ [Card: Light Trolley 15 avail] │ ← Scrollable subtype grid
│ [Card: Flat Trolley 3 avail] │
│ │
└─────────────────────────────────────────┘
UI Components¶
Sub-header¶
- Back arrow (
useNavigate(-1)) - Title "Order Container" + caption
- Checkout button: Visible only when
selected.size > 0 - "Checkout (N)" showing selected count
- Navigates to
/history/container-checkoutafter callingcartStore.setContainerCart(items)
Container Type Tabs¶
MUI Tabs with one tab per container type from mockContainers:
- Trolley
- Pallet
- Bin
Switching tabs resets the selected Set (clears selections from previous type — this prevents cross-type selections which would be confusing).
Subtype Cards Grid¶
gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr))'
Card states:
| State | Border | Background | Cursor |
|---|---|---|---|
| Normal | divider |
white | pointer |
| Selected | PRIMARY (teal) |
rgba(0,150,136,0.04) |
pointer |
| Unavailable | divider |
white | not-allowed |
| Unavailable + hover | no change | no change | — |
Card structure:
┌─────────────────────────────┐
│ Heavy Trolley [8 avail.] │
│ ─────────────────────────── │
│ [−] 1 [+] │
│ (Selected) │
└─────────────────────────────┘
- Header row: Subtype name + availability chip
- Available: teal chip
{available} avail. - Unavailable: grey chip "Unavailable"
- Stepper:
[−][qty][+]with teal border when selected −disabled whenqty <= 1+has no upper limit (nomaxQtyon containers in the mock data)- Buttons use
e.stopPropagation()to prevent card click from also toggling selection - Selected label: "Selected" text in teal, visible when item is in
selectedSet
State¶
| Variable | Type | Initial | Description |
|---|---|---|---|
tabIdx |
number |
0 |
Active container type tab index |
quantities |
Record<string, number> |
{} |
Quantity per subtype ID; default 1 |
selected |
Set<string> |
new Set() |
Set of selected subtype IDs |
Store reads/writes: cartStore.setContainerCart, cartStore.clearContainerCart
UX Logic¶
Selection Toggle¶
const toggleSelect = (subtypeId: string) => {
setSelected((prev) => {
const next = new Set(prev);
if (next.has(subtypeId)) {
next.delete(subtypeId);
} else {
next.add(subtypeId);
}
return next;
});
};
Clicking an unavailable card does nothing (!unavailable && toggleSelect(subtype.id) guard).
Checkout Transition¶
const handleCheckout = () => {
const items: ContainerCartItem[] = Array.from(selected).map((subtypeId) => {
const subtype = activeContainer.subtypes.find((s) => s.id === subtypeId)!;
return {
containerId: activeContainer.id,
containerType: activeContainer.type,
subtypeId,
subtypeName: subtype.name,
quantity: getQty(subtypeId),
};
});
setContainerCart(items);
navigate('/history/container-checkout');
};
Important: Only the currently active tab's selections are sent to checkout. Selecting items from Trolley tab, switching to Pallet tab and selecting there, then checking out would only include the Pallet selections. This is because selected is reset on tab switch (setTabIdx(v); setSelected(new Set())).
This is by design — a single container order is scoped to one container type.
Edge Cases¶
| Scenario | Behaviour |
|---|---|
| No subtypes selected | Checkout button hidden |
| Select then deselect | Item removed from Set; button hides if Set empty |
| Switch tabs | Selection resets |
| Unavailable subtype clicked | No action (not-allowed cursor) |
Qty = 1 on selected item, press − |
Button disabled (min 1) |