Skip to content

feat(TWO-25326): unify Luma order-intent checking UI with the other plugins - #329

Merged
dgjlindsay merged 1 commit into
stagingfrom
doug/TWO-25326-luma-intent-ui
Aug 5, 2026
Merged

feat(TWO-25326): unify Luma order-intent checking UI with the other plugins#329
dgjlindsay merged 1 commit into
stagingfrom
doug/TWO-25326-luma-intent-ui

Conversation

@dgjlindsay

Copy link
Copy Markdown
Contributor

What

Unifies the order-intent checking UI on Luma with the other three plugins (TWO-25326).

Before, Luma showed a wordless spinner while the check ran, then stated an approval in the module's brand blue, a decline in a warm red, and an error only as a checkout toast. Each plugin looked different.

Now:

  1. During the check — the same spokes figure (images/loader.gif, already shipped) with the sentence "Checking availability" beside it. Translated in every locale this module ships (nb_NO, nl_NL, sv_SE); the retired Checking company row is removed from all of them. The visible text names the role="status" region, so the figure carries aria-hidden and the old aria-label is gone.
  2. The result — all three outcomes (approved, declined, errored) render in the one bordered box, with the semantic palette: success green for an approval, danger red for a decline, the box's neutral colours for an error. The intent message is the only thing inside it — no title above it. The error case previously had no persistent surface at all: it went to the checkout message region, which is cleared on the next checkout update.
  3. Stale verdict — the previous outcome is cleared as a new check starts, not when its answer arrives.

Why (3) was actually broken

The company-change subscriptions looked like they covered it, and they do not. They fire when a company observable changes; a check can start with those observables already holding the same values — a re-render re-applying the captured company, or a repeat pick of the company already in the field — and knockout notifies nobody. In exactly those cases the previous company's approval stayed on screen for the whole of the next request, under a spinner checking something else.

Tests

npm run test:js — 29 suites, 383 tests, green. New/changed coverage:

  • the in-flight row: spokes GIF retained, text beside it, aria-label gone, and every shipped locale CSV carries a non-stub translation of the new string (asserted against the CSVs on disk, so a locale added later is covered without editing the spec)
  • all three outcomes share the container class, each box holds only its text:-bound message and no heading
  • the semantic palette values
  • error goes to the box and not the toast; a brand suppressing the verdict does not silence it; SCHEMA_ERROR's per-field errors still go to the fields
  • the verdict is cleared during a new check, asserted with an observable that has real knockout's equality semantics — the AMD harness's double notifies on every write, which would have made that assertion vacuous

Mutation-checked: removing the clear-at-start call fails exactly one spec.

Notes

The palette values match the reference box style being normalised on PrestaShop in the same batch, so a buyer meeting two of the four plugins reads the same colour for the same outcome. No brand overlay styles these classes, so nothing downstream is silently overridden.

The order-intent check looked different on every plugin. Luma showed a
wordless spinner while it ran, then stated an approval in brand blue, a
decline in a warm red, and an error only as a checkout toast.

Converged on the shared target: the spokes figure with the sentence
"Checking availability" beside it while the check runs, and all three
outcomes — approved, declined, errored — in one bordered box carrying the
semantic palette (success green, danger red, neutral for an error), with
the intent message alone inside it and no title above it.

Also clears the previous verdict as a new check STARTS rather than when
its answer arrives. The company-change subscriptions did not cover that:
a re-render re-applying the captured company, or a repeat pick of the
company already in the field, writes unchanged values and knockout
notifies nobody — so the previous company's approval sat on screen for
the whole of the next request.

The specs pinning the "cleared at start" rule use an observable with real
knockout's equality semantics, because the AMD harness's double notifies
on every write and would have made that assertion vacuous.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@dgjlindsay

Copy link
Copy Markdown
Contributor Author

Adversarial self-review — round 1, clean

Reviewed the full diff against origin/staging...HEAD for knockout binding correctness, CSS specificity/overlay-override breakage, buyer-facing paths where a message could now be swallowed, observables read before they exist, vacuous tests, i18n CSV format, and missed call sites of the old behaviour.

No findings. Specifically checked and confirmed:

  • i18n: binding syntax matches the template's existing usage; the ko if: virtual binding still wraps the new row
  • all three locale CSVs carry the new string, and the retired Checking company row is gone from all of them
  • the indicator selectors stay single flat classes, per the rule documented on .two-company-search__spinner — brand overlays can still override at equal specificity
  • every new observable read is existence-guarded, and the error path falls back to the toast if its observable is not wired yet, so no error can be swallowed by the change of surface
  • SCHEMA_ERROR's per-field errors still go to the fields, not the box
  • no other call site depended on the old wordless spinner element or the old notice-clearing statements

The clear-at-start behaviour is mutation-checked: removing the call fails exactly one spec, so that assertion is not vacuous.

npm run test:js: 29 suites, 383 tests, green.


Review performed by Claude.

@dgjlindsay
dgjlindsay merged commit 7f3c154 into staging Aug 5, 2026
27 checks passed
@dgjlindsay
dgjlindsay deleted the doug/TWO-25326-luma-intent-ui branch August 5, 2026 18:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant