Batch A: operational lists, money and stock
2. Batch A — Operational lists (ListLayout)
Section titled “2. Batch A — Operational lists (ListLayout)”A1. Payments — tab payments
Section titled “A1. Payments — tab payments”- Route
/admin/payments·features/staff/PaymentsPanel.tsx(+PaymentRefundDialog,SettlementDialog,RefundReceiptAmendDialog,payments/PaymentDocuments.tsx). Gate:view_financeorrecord_payment(forRecordingmode = record-only actor). - Job: see what money is owed, record cash/bank receipts, waive or refund, find a receipt.
- Reference: org2 (stats + tabs + card rows), mgr1 (“At a glance”), mgr2 (Undo).
- Layout:
ListLayout.title“Payments”,subtitle“Money owed to {space}, and how it was paid.”actions: primary none by default (nothing is created here). Outline secondary: “Receipts & credit notes” (opens a side drawer that hostsPaymentDocuments, instead of the inline show/hide section). More: Export CSV, Export Excel (if the export exists; today none is wired, so More is empty and hidden).callouts: whendue_state=overduecount > 0: “{n} charges are overdue. Oldest is {age} old.” → “Show overdue”.stats: Pending (count)[+query]· Overdue[+query]· Paid this month[+query](omit if no date filter exists; otherwise show Pending/Overdue/Waived). Hidden forforRecordingactors, who see only Pending.tabs(one tab per value of the existing single-valuedstatusfilter): To collect (pending) · Paid online · Paid in person · Waived · Cancelled · All. Record-only actors see To collect · Paid in person (matching today’sforRecordingfilter).toolbar: Due (All / Due today / Upcoming / Overdue) as chips on the To collect tab only; Subject select; sort menu; saved views (existingListViewControls). Bulk bar on select: “Mark paid in person ({n})” (primary in bar) · “Waive ({n})”.list:DataTableon desktop, stacked cards undermd. Columns: Subject (label + type as muted meta), Due (PaymentDueBadgeas soft pill), Amount (bold, right), Refunded (muted, only if > 0), Received (settlement summary, “corrected” pill). Row inline action: on pending → “Mark paid” (opens settlement dialog). Row overflow: Waive, Correct receipt, Refund / Release deposit, Correct refund #n.
- Wireframe
Payments [Receipts & credit notes]Money owed to Fab Lab, and how it was paid.┌ ! 3 charges are overdue. Oldest is 12 days old. Show overdue → ┐┌Pending──┐┌Overdue──┐┌Waived───┐│ 14 ││ 3 ││ 2 │└─────────┘└─────────┘└─────────┘ To collect 14 | Paid online | Paid in person | Waived | All [Due: All · Today · Upcoming · Overdue] [Subject v] [Sort v] [Views v]┌──────────────────────────────────────────────────────────────────────────┐│[ ] Laser job #A12 · Machine service Due in 2 days ₹450 Mark paid [...]││[ ] Monthly dues · Membership Overdue 12 d ₹800 Mark paid [...]│└──────────────────────────────────────────────────────────────────────────┘ ‹ 1 2 3 ›- Mobile: stats become a 2×2 grid; tabs scroll horizontally; rows stack as cards (subject, amount right, due pill under, “Mark paid” full-width).
- Dialogs: Settlement (“Record payment” / “Record payment for 3 charges”): method, reference
(optional), received date, then “Save receipt” + Cancel. Refund: amount (prefilled with refundable
balance), method/reference/date for manual rail, reason, then “Refund ₹450” (the verb carries the
amount). Release deposit uses the same dialog with title “Release deposit”. Amend: “Correct receipt”,
then “Save correction”. All four use the
Modalrestyle with footer Cancel (outline) + primary. - States: empty To collect: “Nothing to collect. Every charge here is paid or waived.” · empty All: “No payments yet. Charges appear here when someone books, registers or borrows.” · filtered: standard · conflict (409): inline callout on the row “Someone else updated this charge. Refreshed.” · load error: standard.
- Undo: none. Settlement writes an append-only receipt, so use the confirm dialog and do not fake an Undo.
A2. Ledger — tab ledger
Section titled “A2. Ledger — tab ledger”- Route
/admin/ledger·panels/Ledger.tsx,LedgerParts.tsx. Gateview_inventory. - Job: answer “what is out right now, with whom, and what is late?”
- Reference: org2 (stats + list), mgr1 (latest list).
- Layout:
ListLayout.title“Ledger”,subtitle“Everything that’s out right now.”actions: no primary (read-only). More: Export CSV, Export Excel. Superadmin: a toggle chip “All makerspaces” intoolbar(not a header action).stats: Items out (sum of qty)[loaded]· Records[loaded]· Overdue[+query overdue=1].callouts: overdue > 0: “{n} loans are overdue.” → “Show overdue” (sets the existing Overdue toggle). Ifaccountabilityis allowed, a secondary link “Open accountability →”.tabs: All · Reviewed · Self-checkout · Direct (the existing Source filter, promoted to tabs).toolbar: search “Holder, email, item or box”, “Overdue only” chip, sortable headers stay.list: card rows. Left: an identity chip (initials of the holder, stable tone). Title = item name (+ “Box: X” meta, unit tags). Meta = holder · out since {date}. Right = qty + due pill (“Due Fri” / “Overdue 3 d” red-tinted). Row click: if the record maps to a request or direct loan, open it (core request detail). Otherwise no click.
- Wireframe
Ledger [More v]Everything that's out right now.┌Items out┐┌Records┐┌Overdue┐│ 37 ││ 21 ││ 4 │ All | Reviewed | Self-checkout | Direct [Search holder, email, item or box........] (Overdue only)┌ (AK) Arduino Uno ×2 · Box B-04 Out since 3 Oct Due Fri ┐┌ (RM) Soldering station Out since 1 Oct Overdue 3 d ┐- States: empty: “Nothing is out right now. Loans appear here the moment they’re handed over.” · load error: standard.
A3. Transfers — tab transfers
Section titled “A3. Transfers — tab transfers”- Route
/admin/transfers·panels/StockTransferPanel.tsx,StockTransferTable.tsx. Gateedit_inventoryor superadmin. - Job: move stock between containers or makerspaces, with a reason, and see the history.
- Reference: org2 list + org3 (form in its own surface, not above the list).
- Layout:
ListLayoutfor history. The create form moves out of the page top into aFlowLayoutdialog “New transfer” (two steps: From and to → What’s moving, with Reason on step 2).title“Transfers”,subtitle“Stock moved between boxes and spaces.”actions: primary “New transfer” (hidden for read-only actors).callouts: read-only actor: “Transfers are managed by inventory staff. You can see the history but not move stock.” (replaces the warn box).list: rows with a direction chip (→ icon) + “{qty} {product}” title, meta “{from} → {to} · {reason}”, right = date + actor initials.- Dialog step 1: Source container, Destination container (superadmin also gets Source/Destination
makerspace, shown first). When cross-makerspace, an info callout replaces the long paragraph: “This
moves stock to {space}. A matching product is created there if needed and stays private until they
publish it.” with “Read the details” for the asset-tracked limitation. Step 2: line editor (product +
qty, “+ Add line” dashed row, remove via row
[...]), Reason. Footer: Back · “Move stock”.
- States: empty: “No transfers yet. Move stock between boxes or spaces with New transfer.” · validation: inline per line (“Only {n} available”).
A4. Stocktake — tab stocktake
Section titled “A4. Stocktake — tab stocktake”- Route
/admin/stocktake·panels/StocktakeSessionPanel.tsx,StocktakeCountSection.tsx,StocktakeDiscipline.tsx. Gateedit_inventory; policy needscanConfigure. - Job: start a count, count items (by scan), complete, approve, apply adjustments.
- Reference: org2 (session list with status), mgr4 (detail with sections), mgr2 (scan + recent with Undo).
- Split: today one page holds policy, schedules, a create form, every session and an inline count
table. Split into:
- Sessions list —
ListLayout. - Session detail —
DetailLayout(see B2), opened by?session={id}(query param, no route change). - Policy & schedules — a
SettingsLayoutsection reached from More: “Count policy and schedule” (opens as a side drawer holding settings rows). Shown only tocanConfigure.
- Sessions list —
- List slots:
title“Stocktake”,subtitle“Count what’s on the shelves and fix the numbers.”actions: primary “Start count” (opens a small dialog: Container (All containers), Notes, Visibility (Use space policy / Blind / Show expected)). More: “Count policy and schedule”.callouts: a schedule is due: “Monthly cycle count is due today.” → “Start it”.stats: In progress[loaded from list]· Awaiting approval[loaded]· Applied this month[+query].tabs: Active (draft+counting) · Needs approval (completed) · Ready to apply (approved) · Done (applied, cancelled). Rows: status pill, title = notes or “Count of {container|all containers}”, meta = started {date} · {n} lines counted. Inline action by status: Counting → “Continue”, Completed → “Approve”, Approved → “Apply”. - States: empty: “No counts yet. Start a count to check the shelves against the system.” · Needs approval empty: “Nothing waiting for approval.”
A5. To buy (procurement) — tab tobuy
Section titled “A5. To buy (procurement) — tab tobuy”- Route
/admin/to-buy·panels/ProcurementPanel.tsx,ProcurementPanelRows.tsx,ProcurementReceipts.tsx,ProcurementMoveModal.tsx,ReorderSuggestions.tsx. GatecanUseToBuy; kind chooser formanage_makerspace. - Job: keep a shopping list, track it from requested to received, then move it into inventory.
- Reference: org2 (tabs by lifecycle, rows with inline next-step action).
- Layout:
ListLayout.title“To buy”,subtitle“What the space needs, from request to shelf.”actions: primary “Add item” (dialog: Name, Qty, Link, Est. unit cost, Machine type when required, Kind for space managers). More: Export CSV, Export Excel.callouts:ReorderSuggestionsbecomes a callout: “{n} items are running low.” → “Review suggestions” (opens a drawer listing them with “Add to list”). Received but not moved: “{n} received items aren’t in inventory yet.” → “Move them”.stats(all[loaded], they are computed today): Estimated total (visible) · Open budget · Spent (received actual).tabs(status): Requested · Approved · Ordered · Received · Cancelled · All, with counts[loaded].toolbar: group-by chip “By machine type” (on by default when grouping exists today).list: replace the 14-column editable table (min-width 1180 px) with card rows: title = item × qty, meta = vendor · est. ₹ · purchaser, right = status pill + one next-step inline action by status: Requested → “Approve”, Approved → “Mark ordered”, Ordered → “Mark received”, Received → “Move to inventory”. Editing vendor, actual cost, status and receipts happens in a row drawer (“Edit” in the row[...]), which also hosts receipts (View / Delete). Delete is the last overflow item and confirms.
- Mobile: this fixes today’s horizontal scroll; cards are naturally stacked.
- States: empty: “Nothing on the list yet. Add the first thing your space needs.” · load error: “Couldn’t load the list. Try again.” (replaces “Unable to load list.”) · receipt errors inline in the drawer.
A6. To-be-fixed shelf — tab needsfix
Section titled “A6. To-be-fixed shelf — tab needsfix”- Route
/admin/to-be-fixed·panels/NeedsFixShelf.tsx. Gateedit_inventory. - Job: repair or scrap units that came back broken.
- Reference: org2 rows with an inline action, mgr2 Undo.
- Layout:
ListLayout.title“To be fixed”,subtitle“Units returned broken. Repair them back into stock, or scrap them.”actions: none (items arrive from returns).stats: Units to fix[loaded sum]· Products affected[loaded].list: rows with a warm “{n} to fix” pill, meta “{available} available · {total} total”. Right: a qty stepper (defaults to all), inline primary-text action “Repaired”, row[...]→ “Scrap…” (confirm: “Scrap 2 × Multimeter? They’re removed from inventory for good.”).- After “Repaired”: toast “2 × Multimeter back in stock.” There is no Undo, because the API has no reverse action.
- States: empty: “Nothing on the shelf. Broken returns land here for repair.” (success-tinted icon tile, not muted text).
Part of UX spec: long-tail screens (Space Works UX across all of SpaceWorks), published from docs/ux-screens-longtail.md. Edit it there.