Skip to content

feat(customers): customer panel with lifetime strip, overview, places and activity tabs - #130

Closed
roncodes wants to merge 19 commits into
release/v0.4.25from
feat/customer-panel
Closed

roncodes wants to merge 19 commits into
release/v0.4.25from
feat/customer-panel

Conversation

@roncodes

Copy link
Copy Markdown
Member

Summary

Customer details from design board 10a: one panel, four tabs. Stacked on #129; review the top commit.

  • Header: the customer identity at panel scale (photo, name, type badge, "Prefers delivery/pickup" badge, copyable public id, since-date, email) and a lifetime strip: orders, lifetime spend, average order, last order. Actions: New order for this customer (opens the create order route with the customer as a query param), Edit, and a menu with copy id / copy email.
  • Overview: contact facts (email, phone, preferred fulfillment, account, internal id, title), saved places as Place::Pills with the default marked, the stores ordered from (shown in network context or when more than one), and the five most recent orders with store, fulfillment, total and status.
  • Orders: unchanged table (filtered to the customer).
  • Places: the customer's Fleet-Ops places with Set default; a pill opens the Fleet-Ops place panel on demand through the shared descriptor.
  • Activity and notes: first and last order, cancellations, created date, and internal notes via CommentThread on the contact.
  • Backend: GET customers/{id}/insights (internal) returns orders, canceled, spend, average, currency, first/last order, preferred fulfillment, stores ordered from and the customer's since-date, scoped by storefront or network.

Not here: segments the customer belongs to (membership is rule-evaluated, no stored membership to list), reviews and pushes received, add/edit place from the panel (opens in Fleet-Ops instead), the four-tab edit form (edit still uses the existing context panel form).

Related Issue

Storefront UX overhaul, design canvas board 10a.

Type of Change

  • Feature
  • Refactor

Implementation Notes

The panel keeps the component:customer-panel registry so other extensions can add tabs; built-in tabs come first. Insights load once when the panel opens and refresh after a place default changes.

Validation

  • Tests / Lint / Build — not run locally per the maintainer's request (CI).
  • Manual validation — maintainer.
php -l server/src/Http/Controllers/CustomerController.php: no syntax errors

Documentation Impact

  • Documentation needed but not included

API Reference Impact

  • No API reference changes needed
  • API reference updates required but not included

API reference notes: internal console endpoint GET storefront/int/v1/customers/{id}/insights?storefront=|network=; no public API change.

Documentation Notes

docs/storefront → customers: the panel tabs and lifetime numbers. needs-docs for the series.

Risk

The former "Details" tab is replaced by Overview (it contained the same facts). Panel width 570 → 600px.

Screenshots / Recordings

Design canvas board 10a: 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.
@roncodes roncodes added needs-docs Requires documentation updates needs-api-spec Requires API specification updates needs-human-review Requires human review before proceeding type:feature Feature or enhancement labels Oct 10, 2026
@roncodes
roncodes force-pushed the feat/customer-panel branch 2 times, most recently from 254cb48 to 3c91360 Compare October 10, 2026 08:16
… 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/customer-panel branch from 3c91360 to c29a773 Compare October 10, 2026 09:31
…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
…ore stacks and next actions

- a multi-store checkout is one expandable row (customer, stores, fulfillment, total with tip split, shared driver, least-advanced status) that opens into each store's order
- status tabs (needs action, preparing, ready for pickup, out for delivery, completed, canceled) drive the status query param; grouped/flat toggle
- new cells: reference, stores (identity stack of store pills), fulfillment, total, driver (inline assign), status, placed, actions (next action promoted, rest behind an ellipsis)
- order index resource keeps meta.checkout_id so the console can group
…lide with the networks list's page, sort and query
…ive questions first

- header: id, status and store/network badges, the next workflow action promoted to a button, Edit, the rest behind a menu
- Storefront::Order::FlowSteps renders the activity flow as steps (custom order configs contribute their own)
- Storefront::Order::IdentityStrip: customer, driver with inline assign, fulfillment and timing, total with tip and promotion
- tabs: Items (with store block and the other orders of the checkout), Route (with tracking), Payment, Activity (with comments), Customer, Data (metadata and documents); registered tabs still appended
- panel widened to 600px
…out rules and a save bar

- settings shell: store identity header with copy-store-key, a section rail (General, Branding and media, Locations, Checkout rules, Payment gateways, Notification channels, Alerts, API keys); anchors on the General page, routes for the rest
- General page restructured into always-open sections: general, branding and media, checkout rules, alerts
- every rule the server honours is a Storefront::SettingRule row with its consequence written under it, detail inputs appear when it is on
- sticky save bar with unsaved-change count and the sections touched; Discard rolls back attributes, options and alerts
…f categories, products, hours and who serves it

- new full-page route catalogs.index.edit: categories on the left (add, rename, reorder, remove), the selected category's products in the middle with an in-place picker over the store's products that hides what is already in the catalog, health on the right; Hours (ScheduleManager), Served by (stores and trucks) and Details sections; sticky save bar with a summary of unsaved changes
- a store can now serve a catalog like a truck: Store gains catalog relations, PUT catalogs/{id}/subjects syncs stores and trucks, the catalog resource exposes hours and subjects
- category order persists; the catalog list opens the editor, the create modal only asks for name, description and status, and the card shows who serves the catalog
… issue badges and a save bar

- Storefront::Product::Form gains tabs: Details (basics, pricing, flags, a folded More for translations and metadata), Variants and add-ons, Availability, Media (images and videos)
- inline validation: missing name or price, sale price not below price, published without category or image; the tab holding the field carries a badge and the save bar links to it
- status select moves into the panel header; the save bar counts unsaved changes across the product, its variants, add-ons and queued uploads, with Discard
…ns on one screen

- header rebuilt: photo, name, type and preference badges, copyable id, since-date, and a lifetime strip (orders, spend, average, last order) from a new customers/{id}/insights endpoint scoped to the store or network
- actions: New order for this customer, Edit, copy id/email
- tabs: Overview (contact facts, saved places with the default marked, stores ordered from in network context, recent orders), Orders, Places (set default, open in Fleet-Ops from the pill), Activity and notes (first/last order, cancellations, internal notes via CommentThread); registered tabs keep working
- panel widened to 600px
@roncodes
roncodes force-pushed the feat/customer-panel branch from c29a773 to 76a110e 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-api-spec Requires API specification updates 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