Panel Customers: QA fixes, prototype parity, order-value chart, and UX polish#2565
Merged
Conversation
Index: - KPI strip now shows real counts (total, new in 30 days, business, linked to a user account) instead of hardcoded placeholder values - Search also matches linked user emails, as the placeholder promises - Remove the non-functional Export button; Docs links to the docs site - Row avatars build initials from first/last name, not the full name with title Edit: - Address forms (new and edit) share AddressFormFields, cover every address field (title, line 3, state, contact email/phone, tax id) and show inline validation errors — the edit form previously failed silently - Unlink-user confirm button says "Unlink user" instead of "Delete" - Activity timeline translates descriptions, formats timestamps, and picks icons for the customer events - Title selects translate their labels and keep an unknown stored title as a selectable option instead of displaying blank Core: - Customer address create/update/delete and user link/unlink actions log an explicit activity on the customer (same pattern as order actions), so the panel timeline reflects them Accessibility: - FieldLabel renders a real <label for> when given a target id; all customer form inputs are now programmatically labelled - Back link on the create page has an accessible name Translations: new keys mirrored across all 16 locales. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both pages went straight to PageHeader; they now render the same breadcrumb bar as the index (Sales > Customers > current page) with the Docs link in the actions slot. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Header shows the linked user's email when the customer has exactly one storefront user; it stays out of the edit form (the user record owns it) - Lifetime stats side card: total spend, order count, average order, and latest order date over placed orders, reported in the default currency via each order's captured exchange rate (the prototype's duplicate top-of-page stat strip is intentionally not implemented) - Order history tab: read-only list of placed orders (reference, date, lifecycle status, total); rows link nowhere until an Orders section exists - Notes side card with inline editing, backed by a new nullable customers.notes column (new migration on top of the flat baseline) and a panel notes endpoint - UpdatesCustomer now takes a nullable group set: null leaves group membership untouched (used by the notes endpoint), an empty array still clears it - No "email customer" action, per review - Spec 0049 updated: order history and purchase stats are no longer deferred Translations: new keys mirrored across all 16 locales. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
With one linked user the header shows their email; with several there
is no single address to show, so it shows "{n} users" instead
(pluralised via vue-i18n, keys in all 16 locales).
Also fold the customers.notes column into the flat baseline migration:
while v2 is in alpha, schema changes update the existing migrations
rather than adding change migrations (CLAUDE.md updated to match).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The sidebar card, edit action, empty state, and flash now say "Admin notes" across all 16 locales so the field's audience is explicit. The customers.notes column and lang keys are unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Matches the "Admin notes" label: baseline migration column, model property, notes request/controller field, edit page prop and form all use admin_notes. Route names and lang keys are unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Draft spec for a dependency-free TimeSeriesChart on the add-on surface and an order-value-over-time card on the customer edit page (12m default, zoom to 3y/5y/10y via partial reloads). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…customer edit (spec 0050) - TimeSeriesChart: dependency-free SVG area/line chart styled with the panel theme tokens — recessive halved gridlines, thinned x labels, crosshair hover tooltip (value leads), keyboard navigation, required aria label. Exported via ui.ts, mirrored in @lunarphp/panel index.js, types regenerated; the example add-on renders one to prove the public surface. - Customer edit gains an "Order value" card above the details form: placed-order value bucketed over a validated chart_range (12m monthly default; 3y/5y quarterly; 10y yearly), zero-filled and valued in the default currency on the same basis as the lifetime stats. The range switcher partial-reloads only the chart prop and holds the previous render at reduced opacity while in flight. - Translations for the chart card across all 16 locales. - Spec 0050 accepted with all slices landed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The line draws left to right (dash math normalised via pathLength) and the area fades in beneath it; keying the series paths on the data replays the animation when a range switch swaps the buckets, and prefers-reduced-motion disables it entirely. Also keep a full step of clearance before the final x label so long ranges don't collide at the right edge. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The inline form rendered below the address cards and was easy to miss. "Add address" now opens the panel Dialog (footer submit associated to the form via the form attribute); errors keep the dialog open, success closes it, and stale errors clear on reopen. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The edit form no longer swaps in place of its card; the Edit action opens the shared Dialog prefilled, titled with a new edit_address key across all 16 locales. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Animated slide/fade in and out, a dismiss button, auto-dismiss after 6s (paused while hovered), and re-triggering on every server response so repeat saves with identical text still flash. Errors and the forgot-password status pass timeout 0 and persist until dismissed. Swapped into the customers pages, SettingsShell (success + error), account security, forgot password, and the example add-on; exported on the public add-on surface. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Rows carry per-customer order stats via correlated subqueries on the same placed-order, default-currency basis as the edit page: placed order count, formatted total spend, and latest order date replace the Created column (recency stays available through the sort dropdown) - The first linked user's email shows under the customer name, falling back to the account ref - Avatars take one of the three soft theme tints, assigned by customer id so a customer keeps their colour across reloads - Column labels reuse the existing stat_* lang keys; the unused column_created key is dropped from all 16 locales Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The fourth KPI card is now the prototype's avg lifetime value: one aggregate over placed orders (default-currency basis via captured exchange rates) divided by distinct customers with orders, plus a delta chip against the average as it stood 30 days ago (neutral tone when negative). The whole KPI block is cached for five minutes since every value is a whole-table aggregate and the strip does not need to be second-accurate on large stores. Replaces the interim "can sign in" count; lang keys swapped across all 16 locales. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sits to the right of the filter dropdowns, only while a search, filter, or add-on filter is active; plain underlined text, reusing the existing clearFilters behaviour and lang key. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An inline X shows while a clearable input holds a value (hidden when disabled); clicking it empties the value and refocuses the input. New common.clear key across all 16 locales. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The stat tiles looked clickable (button element, hover/press styles) but did nothing. A card now only becomes a button with hover and press affordances when an onClick is actually attached, so genuinely interactive tiles keep the treatment. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A full pass over the panel's Customers section: browser-QA fixes, design-prototype parity on the index and edit pages, a new charting primitive on the add-on surface (spec 0050), and a series of UX refinements.
QA fixes
AddressFormFieldsFieldLabel for+ ids), named back link, stored titles outside the base list still displayPrototype parity
customers.admin_notescolumn (folded into the flat baseline per the alpha migration policy)Charting (spec 0050)
TimeSeriesChart: dependency-free SVG area/line chart on the public add-on surface — crosshair tooltip, keyboard navigation, draw-in animation (prefers-reduced-motionaware), theme-token stylingchart_rangeparamUX polish
Dialog)FlashMessagecomponent: animated, dismissible, 6s auto-dismiss with hover pause; swapped into all six flash call sites and exported to add-onsTextInput clearable)KpiCardrenders as a static div unless a click handler is boundContract-surface notes for review
UpdatesCustomer::execute()third parameter is now?array $customerGroupIds = null— null leaves group membership untouched,[]still clears (used by the notes endpoint; all existing callers pass explicitly)TimeSeriesChart,FlashMessage;TextInputgainsclearable,FieldLabelgainsfor,Selectgainsinvalidcustomers.admin_notes(alpha policy: baseline edited in place, no change migration)Translations
All new keys mirrored across the 16 locales with real translations; orphaned keys removed. Every locale file parses with identical key counts.
Tests
🤖 Generated with Claude Code