Batch A: notifications, logs, devices and catalogues
A7. Notifications (personal inbox + broadcast) — tab notifications
Section titled “A7. Notifications (personal inbox + broadcast) — tab notifications”- Route
/admin/notifications·panels/NotificationInbox.tsx→notifications/PersonalInbox.tsx,staff/BroadcastComposer.tsx. Gate any staff action. - Job: catch up on what happened that needs me; managers can also send a member announcement.
- Reference: org1/org2 Recent activity rail (this page is its “See all →” destination).
- Layout:
ListLayout.title“Notifications”,subtitle“{n} unread” (live; keep the unread count in anaria-liveregion and in the sidebar item’s accessible name, as pinned today).actions: primary “Mark all read” (disabled at 0). Outline secondary, managers withmembership.broadcasts: “Send announcement”. It opens a dialog with the existing composer fields (Title, Body, Audience) and the button “Send announcement”. The composer card is no longer pinned above the inbox.tabs: Unread {n} · All.toolbar: Family chips (Hardware, Printing, Events, Bookings, Maintenance, Members, Payments, Stock, Certifications, Devices, API access). Raw keys become labels.list: activity-style rows (activity rail, full width). Avatar/icon tile by family · bold title + summary (2 lines, clamp) · relative time (“2 min ago”) · unread dot. Inline action “Open” when there is a safe link. Row click marks it read. Unread rows get a teal left rule, not a teal border box.- Date group headers: Today · Yesterday · Earlier this week · Older.
- States: empty Unread: “You’re all caught up.” · empty All: “No notifications yet. Activity from your space shows up here.” · load error: standard.
A8. Delivery logs (+ suppressions) — tab email-logs
Section titled “A8. Delivery logs (+ suppressions) — tab email-logs”- Route
/admin/email-log·panels/DeliveryLogPanel.tsx→notifications/DeliveryLogScreen.tsx,notifications/SuppressionAdmin.tsx. Gatemanage_makerspace. (panels/EmailLogPanel.tsxis still exported fromStaffPanels.tsxbut no route mounts it. Flag it for deletion as a separate cleanup, not in this revamp.) - Job: check that alerts and emails went out, retry failures, send a test, manage suppressed addresses.
- Reference: org2 (tabs + rows + inline action), org6 (developer-ish surface kept calm).
- Layout:
ListLayoutwith two tabs that split today’s stacked sections.title“Delivery logs”,subtitle“Every email and alert this space sent, and whether it arrived.”actions: primary “Send test”. It opens a small dialog “Send a test to…” (Email to my account / each active destination) and the result shows as a toast with “View in log”.callouts: failed in the current filter > 0: “{n} deliveries failed.” → “Show failed”.tabs: Deliveries · Suppressed addresses.- Deliveries
toolbar: Status chips (All, Sent, Failed, Pending, Skipped), Channel select, Destination select, Family select, Event text in More filters.listrows: channel icon tile · title “{Family} · {event}” humanised · meta “{destination or Personal devices} · {n} attempts · {time}” · status pill (Sent / Failed / Skipped “blocked by Email module” / Sending) · inline “Retry” on failed rows. The error text shows under the row in muted red. - Suppressed tab:
actionschanges to primary “Suppress an address” (dialog). Rows: address, reason, date, inline “Remove”.
- States: empty Deliveries: “Nothing sent yet. Send a test to check your setup.” · filtered: standard · empty Suppressed: “No suppressed addresses. Bounced or blocked addresses appear here.”
A9. Accountability — tab accountability
Section titled “A9. Accountability — tab accountability”- Route
/admin/accountability·panels/AccountabilityPanel.tsx. Gateview_audit. - Job: follow up on overdue loans and reported problems, and restrict or restore repeat offenders.
- Reference: org2 (stats + tabs), mgr1 (“Latest …” lists).
- Layout:
ListLayoutwith tabs that replace the four stackedPanels and the “Show all accountability sections” button. The existingsectionlist filter becomes the tab key.title“Accountability”,subtitle“Late, lost or damaged — and who it’s tied to.”stats(each a tab shortcut): Overdue loans[loaded count]· Open problems[loaded]· Repeat offenders[loaded]· Restricted[loaded].tabs: Overdue · Problems · Repeat offenders · Restricted.- Overdue rows: identity chip (holder) · item · “Overdue {n} d” pill · inline “Open loan”.
- Problems rows: item · reporter · reported {date} · problem text (2-line clamp).
- Repeat offenders rows: person · damage/loss counts · status pill · inline “Restrict…” (dialog with required reason; button “Restrict {name}”) or “Restore access” if restricted.
- Restricted rows: person · reason · since · inline “Restore access”.
- States: Overdue empty: “No overdue loans. Nice.” · Problems empty: “No open problem reports.” · Offenders empty (named): “No damage or loss on record against a named person.” · Restricted empty: “No one is restricted here.”
A10. Warranties — tab warranty
Section titled “A10. Warranties — tab warranty”- Route
/admin/warranty·panels/WarrantyPanel.tsx(+WarrantySection,WarrantyStatusBadge). Gateedit_inventoryor printing/machines. - Job: see what’s covered, what’s expiring, and what’s missing documents.
- Reference: org2.
- Layout:
ListLayout.title“Warranties”,subtitle“Coverage for {scope} in {space}.”stats: Active · Expiring soon · Expired · Missing docs. Each is[+query]filtered count. If that is too costly, keep only the total[loaded]in the subtitle.tabs: All · Active · Expiring soon · Expired · Not covered (the existing status filter).toolbar: “Expires before” date, “Missing docs” chip.list: rows. Identity chip (machine or asset) · host name · vendor · purchased → expires · status pill · docs count. Inline “Manage” opens the existingWarrantySectionin a side drawer instead of an inline expanded table row.
- States: empty: “No warranties recorded yet. Add one from a machine or asset.” · filtered: standard.
A11. Organized events — tab organized
Section titled “A11. Organized events — tab organized”- Route
/admin/organized-events·panels/OrganizedEventsPanel.tsx(+EventDrawer). Gate: non-superadmin, not single-tenant. - Job: an organization organizer sees the events they run across venues.
- Reference: org2 exactly (date-chip rows, going/capacity progress).
- Layout:
ListLayout.title“Organized events”,subtitle“Events you run with your organization, across spaces.”tabs: Upcoming · Past (client split by date on the loaded page, or a query param if the API supports it; otherwise a single list in chronological order with a “Past” divider).list: date chip (MON/DD, tone by host space) · title · meta “{location or Online} · {host space}” · right: “{going} / {capacity} going” + thin progress bar, status pill. Row click opens the existingEventDrawer.
- States: empty: “No organized events. Events your organization runs will appear here.” · load error with “Try again”.
A12. Member cards — tab cards
Section titled “A12. Member cards — tab cards”- Route
/admin/member-cards·panels/MemberCardsPanel.tsx,memberCards/*. Gate member-card actions; modulemembership. - Job: issue, print, reissue and revoke member cards; scan a card at the desk.
- Reference: org4 (invite card on top + table), mgr2 (scan block).
- Split: today one long page holds the cards table, a scan box, an issue roster and the card layout form. Use tabs: Cards · Issue · Scan · Card layout.
- Layout:
ListLayout.title“Member cards”,subtitle“Printable cards that open the member area at the desk.”actions: primary “Print sheet” (label “Print sheet (3 selected)” when there is a selection, else “Print all active”). Secondary outline: “Scan a card” (jumps to the Scan tab).stats: Active cards[loaded]· Members without a card[loaded from roster].- Cards tab: status segmented control Active / Revoked (existing),
DataTablewith Card number, Name, Status pill, Prints, Photo (✓ / —). Row inline “Print”. Row[...]“Reissue…” and “Revoke…” (existing dialogs, restyled). - Issue tab: org4-style list “Members without a card”, each row with inline “Issue card”.
- Scan tab: the shared ScanWorkbench section (§11.2) with the card result panel.
- Card layout tab: a
SettingsLayoutbody (settings rows) with Save.
- States: Active empty: “No cards yet. Issue one from the Issue tab.” · Issue empty: “Every active member has a card.” · Revoked empty: “No revoked cards.”
A13. Devices — tab devices
Section titled “A13. Devices — tab devices”- Route
/admin/devices·panels/DevicesPanel.tsx,DeviceIdentitySection.tsx,DeviceEnrollmentModal.tsx. Gatemanage_devices; moduledevices. - Job: register printers and label printers, see which are offline, enrol or revoke them.
- Reference: org4 (people table → device table), org6 (one-time secret handling).
- Layout:
ListLayout+ detail drawer.title“Devices”,subtitle“Printers and other hardware that talk to Space Works.”actions: primary “Add device” (dialog: Name, Kind (Generic / Printer / Label printer), then “Create device”; on success it opens the enrollment dialog straight away).stats: Online · Offline · Revoked ([loaded]from the current page only, or[+query]).list: rows. Kind icon tile · name · meta “Last seen 4 min ago” / “No heartbeat yet” · status pill (Online / Offline since {time} / Revoked). Row click opens a drawer (replaces thearia-pressedbutton + section below the table) with settings rows: Name, Offline threshold, then Save; actions “New enrollment token”; danger zone “Revoke device”.- Enrollment dialog (org6 pattern): yellow strip “Copy this now. It won’t be shown again.” · dark code block with the token and Copy · purpose and expiry as meta · footer primary “I’ve copied it” (replaces “Close and discard token”).
- States: empty: “No devices yet. Add a printer to send jobs straight to it.” · load error with “Try again”.
A14. Data export — tab exports
Section titled “A14. Data export — tab exports”- Route
/admin/data-export·features/staff/DataExportsPanel.tsx. Gatemanage_makerspace. - Job: get a readable archive of this space’s records.
- Reference: org6 (warning strip + clients list), auth7 (callout with action).
- Layout:
ListLayout.title“Data export”,subtitle“A readable copy of your space’s records. Not a backup.”actions: primary “Request export” (disabled while one is running; tooltip “An export is already being built”).callouts: one yellow callout replaces the three-paragraph disclosure: “Exports include member names, emails and phone numbers. Handle the file like any personal data.” → “Read what’s included” (expands the full existing text, unchanged).list: job rows. Icon tile · “Export · {date}” · meta “{rows} rows” · status pill (Queued / Building / Ready / Failed) · inline “Download” when ready. Failure detail as a muted red line.- Running jobs also show in the Job tray.
- States: empty: “No exports yet. Request one when you need a copy of your records.” · deadline-exceeded failure: “This export took too long. Try again at a quieter time.”
A15. Categories — tab categories
Section titled “A15. Categories — tab categories”- Route
/admin/categories·panels/Categories.tsx. Gateedit_inventory. - Job: organise products into categories.
- Reference: org4 (simple table) + org3 (create in a focused surface).
- Layout:
ListLayout.title“Categories”,subtitle“How items are grouped in the catalogue.”actions: primary “Add category”. A dialog replaces the always-visible 5-field inline row: Name, Slug (“Leave blank to use the name”), Icon, Order.list:DataTable(Name, Products, Order, Icon) with inline “Edit” (same dialog) and row[...]“Delete…” (existing confirm: “Delete {name}? {n} items lose this category.”).- Reorder: keep the numeric order field. Drag reordering is out of scope.
- States: empty: “No categories yet. Add one to group your catalogue.” · load error: standard.
A16. Containers — tab containers
Section titled “A16. Containers — tab containers”- Route
/admin/containers·panels/ContainersPanel.tsx. Gatemanage_qr; modulecontainers. - Job: find a box, see what’s in it and its scan history, edit its label or location.
- Reference: org2 list → mgr1 detail with tabs.
- Layout:
ListLayout; each container opens a detail drawer with tabs (B3), replacing the inline Edit / Contents / History toggles inside each card.title“Containers”,subtitle“Boxes, bins and shelves with QR labels.”actions: primary “New container”, which links to QR tools (today: “Create one in QR tools”), labelled “Create in QR tools”. More: none.toolbar: search, Active / Inactive chips.list: rows. Code chip (the container code in the identity chip) · label · meta location · Inactive pill when inactive · right: “{n} items” if loaded.
- States: empty: “No containers yet. Create labelled boxes in QR tools.” with the button.
A17. Job handover (machine service) — tab handover
Section titled “A17. Job handover (machine service) — tab handover”- Route
/admin/handover·panels/machine/HandoverConsole.tsx. Gatecollect_service_requestormanage_machines; modulemachine_service. - Job: at the desk, hand finished jobs to the people who requested them.
- Reference: mgr2 “Recent check-ins” rows with an inline action; org2 rows.
- Layout:
ListLayout.title“Ready to collect” (today the panel title is “Awaiting collection”; the tab label “Job handover” stays in the nav),subtitle“Finished jobs waiting for their owners.”stats: Waiting[loaded]· Unpaid[loaded].toolbar: search by requester (client-side filter on the loaded list).list: rows. Identity chip (requester initials) · job title · meta “{machine} · finished {relative}” · payment pill (Paid / Unpaid ₹x) · inline primary-text “Hand over”. When unpaid, the inline action becomes “Collect payment” and links to the payment, and “Hand over” moves to the row[...], but only if the API allows handover while unpaid (today it does, so keep “Hand over” inline and show the unpaid pill as a warning).- After handover: the row collapses with toast “Handed to {name}.” No Undo, because there is no API reverse.
- States: empty: “Nothing waiting. Finished jobs show up here for handover.” · error (action): “Couldn’t mark that job collected. It may have been handed over already.”
A18. Email templates (index) — tab emailtemplates
Section titled “A18. Email templates (index) — tab emailtemplates”- Route
/admin/email-templates·panels/EmailTemplatesPanel.tsx. Gate inventory, printing or devices. - Job: find the email to customise.
- Reference: org2 list → mgr1/mgr3 detail.
- Layout:
ListLayoutindex, thenDetailLayouteditor (B1). This replaces the 18rem left button column plus an always-mounted editor.title“Email templates”,subtitle“What people receive from {space}, in your words.”tabs: one per stream (Hardware, Printing, …)[loaded].list: grouped by audience (header “To members” / “To staff”). Rows: template name · meta “Sent when {humanised key}” · “Edited” pill if overridden (space default or any machine type).- Row click goes to
?template={stream}:{audience}:{key}→ editor.
- States: empty: “No editable templates here.” (rare).
Part of UX spec: long-tail screens (Space Works UX across all of SpaceWorks), published from docs/ux-screens-longtail.md. Edit it there.