Skip to content

feat(network): overview, stores with status tabs and bulk actions, invite panel and invitation lifecycle - #124

Closed
roncodes wants to merge 11 commits into
release/v0.4.25from
feat/network-screens
Closed

roncodes wants to merge 11 commits into
release/v0.4.25from
feat/network-screens

Conversation

@roncodes

Copy link
Copy Markdown
Member

Summary

Network screens from the design canvas, boards 3a (overview), 3b (stores) and 3c (invite stores). Stacked on #123 (context switcher); review the top commit.

  • Overview (networks.index.network.index): stat tiles (stores and how many are online, pending invitations, orders and revenue over 7 days with tips, customers and new this month), member stores with their 7-day order and revenue share, open invitations with resend/revoke/invite-again, the shareable link, and the five most recent network orders. Settings moved to networks.index.network.settings (same template and controller, renamed).
  • Stores: the store column is a table/cell/identity typed store (new descriptor), status tabs All / Online / Offline / Invited with counts, a bulk bar while rows are selected (assign category, remove from network, clear), invitation rows under the table with their state badge and actions, and the remove-store copy from the design.
  • Invite panel (Storefront::Network::InvitePanel, right overlay, 600px) with three tabs: by email (chips, duplicate/member flagging, category on joining, expiry, message, require approval), shareable link (toggle, copy), add a store you manage (multi-select of the organisation's non-member stores plus category). Replaces the share-network and add-stores-to-network modals.
  • Backend: GET networks/{id}/overview, GET networks/{id}/invitations, POST networks/{id}/invitations/{invitationId}/resend, DELETE networks/{id}/invitations/{invitationId} on the internal API. sendInvites now creates one Invite per recipient and stores category_uuid, message, require_approval and status in meta, with expires_at from expires_in_days; state is derived (pending, expired, declined, accepted, revoked) without a core migration.
  • Bug fix: network orders and customers were filtered on meta.storefront_id, which is always the store; the network is meta.storefront_network_id. OrderFilter::network and CustomerFilter::network added and the network routes pass network instead of storefront.
  • Store and network resource descriptors registered with the shared identity registry (pill, identity cell, select option, summary for free); SelectOption::Store wrapper; width-style helper for share bars.

Not here: accept/decline flow for the invited store (/join/network/:token landing, store-side banner and switcher badge), approval queue when "require my approval" is on, suspend-from-network (needs a status column on network_stores), categories page.

Related Issue

Storefront UX overhaul, design canvas boards 3a–3c.

Type of Change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Test
  • Chore

Implementation Notes

The overview reads orders by meta->storefront_network_id and groups shares by meta->storefront_id, mirroring how checkout writes them. Invitation state lives in Invite.meta.status plus expires_at; revoke deletes the row (core Invite has no soft deletes). Status tabs on the stores page filter client-side (a network's members are few and the route already loads them all).

Validation

  • Tests — not run locally per the maintainer's request; new unit coverage was not added for this PR (follow-up).
  • Lint — not run locally (CI).
  • Build — not run locally (CI).
  • Manual validation — maintainer.
php -l on the three changed PHP files: no syntax errors

Documentation Impact

  • No documentation changes needed
  • Documentation updated in fleetbase/fleetbase.io
  • Documentation needed but not included

API Reference Impact

  • No API reference changes needed
  • Updated fleetbase/postman
  • API reference updates required but not included

API reference notes: all new endpoints are on the internal console namespace (storefront/int/v1), not the public API.

Documentation Notes

fleetbase/fleetbase.io docs/storefront → networks: overview, inviting stores (email, link, own stores), invitation states. needs-docs for the series.

Risk

networks.index.network.index changed meaning (settings → overview); any bookmark to the settings tab now lands on the overview. sendInvites creates one invite per recipient instead of one with many recipients; the mail template is unchanged. Existing multi-recipient invites render their first recipient.

Screenshots / Recordings

Design canvas boards 3a–3c: https://claude.ai/artifact/771ptEFmi4BLmYHBZuUhWF

The dummy app never ran: ember-classic-decorator (unused) crashes on Ember 5,
lazy loading kept the engine's modules out of the test bundle, and the host
services, config and intl data the panels need were missing. Mirrors what
fleetops already does: eager loading when `ember test` runs from this package,
an inert stand-in for the console's extensions module, the API config the
core adapter reads at module scope, and the legacy built-in components the
engine's templates still use.

The dummy intl service ignores missing locale data, since headless Chrome has
no number formats for every bundled locale, and the order details and network
controller tests stub the host router, fetch and app cache the way the widget
tests already do.
…rce card

Catalog, truck and network index pages use Layout::Resource::CardsGrid with
one card each on Layout::Resource::Card, following the Fleet-Ops anatomy:
identity and subtitle in the header, media or facts in the body, status,
icon actions and meta in the footer, with registry slots at each end.

A catalog card shows its categories with product counts, its hours as a
seven-day strip (the new Storefront::HoursStrip) and its product total; a
draft is dashed. A truck card is a Vehicle::Pill with the online dot, the
vehicle photo, where it serves, and a presence badge that says serving,
offline, inactive, or online with no catalog. A network card shows the logo on
its backdrop, the online state, the currency and member count.

"Food trucks" reads "Trucks" in the UI; the food-truck model, routes and
permissions keep their names. The catalogs and trucks pages gain the search
the header already offered.
… and crashed createRecord; the store summary is store_summary
…s own sidebar for each

- storefront service tracks a network context derived from the network route
- StoreSelector becomes the context switcher with a Networks group and create-network
- application route loads networks; sidebar rewrites for the network context
- network page is a full page with an identity strip; the list hides while one is open
- new Trucks section for a network backed by FoodTruckFilter::network
- network orders and customers are scoped to the network being viewed, not the active store
- createNewNetwork lives on the storefront service
…enu without Networks

- trigger: context icon, name, STORE/NETWORK label and caret; blue for a store, indigo for a network; invitation badge
- menu: Stores and Networks groups with tiles, currency or member count, a check on the active one, readable in dark mode; footer actions read New store / New network
- store navigation follows the design order (Dashboard, Orders, Products, Catalogs, Customers, Trucks, Promotions, Settings); networks live in the switcher, not the menu
- network page loses the All networks button; leaving a network is the switcher's job
@roncodes
roncodes force-pushed the feat/network-screens branch from e31ed1e to 7885582 Compare October 10, 2026 09:30
…e sidebar re-renders on a switch; networks report their store count
…d an invite panel

- network index is now an Overview (stat tiles, members with 7-day share, invitations, recent orders); settings move to networks.index.network.settings
- NetworkController gains overview, invitations, resend and revoke; one Invite per recipient carrying category, expiry, message and approval in meta
- OrderFilter/CustomerFilter gain a network filter on meta.storefront_network_id; the network orders and customers routes use it
- Storefront::Network::InvitePanel (by email, shareable link, add a store you manage) replaces the share-network and add-stores modals
- stores page: store identity column via a new store descriptor, All/Online/Offline/Invited tabs, bulk assign category and remove, invitation rows with resend/revoke/invite again
- store and network resource descriptors registered with the shared identity registry; SelectOption::Store wrapper; width-style helper
…ost re-export broke console boot before the lazy engine loaded
@roncodes
roncodes force-pushed the feat/network-screens branch from 7885582 to 184b5e3 Compare October 10, 2026 10:19
@roncodes

Copy link
Copy Markdown
Member Author

Superseded by the single overhaul PR (one branch, one PR targeting release/v0.4.25, per maintainer request).

@roncodes roncodes closed this Oct 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-docs Requires documentation updates needs-human-review Requires human review before proceeding type:feature Feature or enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant