feat: dispatch card verification events and copy in tokenize-only che… - #278
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates Dynamic Checkout’s tokenize-only flow to behave like card verification (not payment) by emitting a parallel set of processout_dynamic_checkout_card_verification_* events and by rendering verification-specific status copy across the status views and button aria-label.
Changes:
- Added card-verification event names and routed existing Dynamic Checkout event dispatchers via an optional
isCardVerificationflag (payload/sanitization behavior unchanged). - Introduced
getStatusMessage()and verification message key mapping so tokenize-only flows show verification wording across status screens and the pay button aria-label. - Centralized tokenize-only detection via
DynamicCheckoutPaymentConfig.isTokenizeOnly()and ensured invoice details are set early enough for status/error handling to detect the mode; added tests covering predicate, locale copy, and event routing.
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| test/support/loadNamespace.ts | Adds a Dynamic Checkout loader shim for tests, including event capture and chunk ordering to simulate --outFile concatenation behavior. |
| test/dynamic-checkout/tokenize-only.test.ts | New tests for isTokenizeOnly(), status-message mapping across locales, and payment vs card-verification event name routing. |
| src/dynamic-checkout/views/payment-success.ts | Uses getStatusMessage() so tokenize-only flow shows verification success copy. |
| src/dynamic-checkout/views/payment-pending.ts | Uses getStatusMessage() so tokenize-only flow shows verification pending copy. |
| src/dynamic-checkout/views/payment-info.ts | Uses getStatusMessage() so tokenize-only flow shows verification info copy. |
| src/dynamic-checkout/views/payment-cancelled.ts | Uses getStatusMessage() so tokenize-only flow shows verification cancelled copy. |
| src/dynamic-checkout/views/payment-methods.ts | Uses getStatusMessage() for generic error copy and replaces the private tokenize-only predicate with paymentConfig.isTokenizeOnly(). |
| src/dynamic-checkout/utils/status-messages.ts | New helper mapping payment status keys to verification equivalents when isTokenizeOnly() is true. |
| src/dynamic-checkout/utils/events.ts | Adds CARD_VERIFICATION_* event constants and optional isCardVerification routing to existing dispatchers. |
| src/dynamic-checkout/references.ts | Ensures the new status-messages utility is included in the Dynamic Checkout reference chain/bundle order. |
| src/dynamic-checkout/payment-methods/card.ts | Passes isTokenizeOnly() to event dispatchers and resolves button aria-label via getStatusMessage(). |
| src/dynamic-checkout/dynamic-checkout.ts | Sets invoice details before the transaction-status check and routes the invalid-status error event using tokenize-only mode. |
| src/dynamic-checkout/config/payment-config.ts | Adds DynamicCheckoutPaymentConfig.isTokenizeOnly() predicate based on invoice payment methods. |
| src/dynamic-checkout/locales/ar.ts | Adds verification status and aria-label translation keys. |
| src/dynamic-checkout/locales/de.ts | Adds verification status and aria-label translation keys. |
| src/dynamic-checkout/locales/en.ts | Adds verification status and aria-label translation keys. |
| src/dynamic-checkout/locales/es.ts | Adds verification status and aria-label translation keys. |
| src/dynamic-checkout/locales/fi.ts | Adds verification status and aria-label translation keys. |
| src/dynamic-checkout/locales/fr.ts | Adds verification status and aria-label translation keys. |
| src/dynamic-checkout/locales/it.ts | Adds verification status and aria-label translation keys. |
| src/dynamic-checkout/locales/ja.ts | Adds verification status and aria-label translation keys. |
| src/dynamic-checkout/locales/ko.ts | Adds verification status and aria-label translation keys. |
| src/dynamic-checkout/locales/nb.ts | Adds verification status and aria-label translation keys. |
| src/dynamic-checkout/locales/pl.ts | Adds verification status and aria-label translation keys. |
| src/dynamic-checkout/locales/pt.ts | Adds verification status and aria-label translation keys. |
| src/dynamic-checkout/locales/ta.ts | Adds verification status and aria-label translation keys. |
| src/dynamic-checkout/locales/vi.ts | Adds verification status and aria-label translation keys. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Does this need some coordination with merchant experience team? |
Ah, good shout out. The only thing we need is to update this reference: https://docs.processout.com/docs/dynamic-checkout-web#event-reference. I should be able to edit it when this is merged. This task has been requested by the merchants, so mexp is already coordinating I think |
Docs updated: https://docs.processout.com/update/docs/dynamic-checkout-web |
|
|
||
| // Tokenize-only is exposed per payment method by the API, but it describes the whole | ||
| // checkout: the shopper is verifying a card, not paying for the invoice. | ||
| public isTokenizeOnly(): boolean { |
There was a problem hiding this comment.
nit: I can see it's specifically related to card tokenization only. Should we also explicitly mention card in the method's name? As far as I understand, this config can be either card or apm?
In the future, we could even consider creating a union type to explicitly decouple APM and card payments?
There was a problem hiding this comment.
The config here is checkout-wide rather than per-method, and isTokenizeOnly() describes the whole session ("this checkout verifies a card, it doesn't pay the invoice") — that's why the comment above it calls that out. The card.tokenize_only lookup is just where the API surfaces the flag. Adding "card" to the name would read as if it only affects the card method, but callers use it to change checkout-wide behavior (e.g. hiding saved payment methods). Happy to revisit as part of a card/APM config split later — agreed that'd be a nice cleanup.
Summary
In tokenize-only Dynamic Checkout no money moves — the shopper is verifying a card — but the widget still emitted
processout_dynamic_checkout_payment_*events and rendered "This payment is completed." This switches both to card-verification wording.Changes
processout_dynamic_checkout_card_verification_{submitted,success,pending,cancelled,error}names. The existing dispatchers take an optional trailingisCardVerificationthat selects the name — payload, sanitizing and theprocessout-js.field.unavailableswallow are unchanged.utils/status-messages.tsmaps each payment message key to a verification counterpart; success/cancelled/pending/info/generic-error views and the pay-button aria-label resolve through it. Six new keys × 14 locales.DynamicCheckoutPaymentConfig.isTokenizeOnly()replaces the privatehasTokenizeOnlyCard()inpayment-methods.ts.dynamic-checkout.tsnow callssetInvoiceDetailsbefore the transaction-status check, so that branch can see the mode (it previously always reportedfalse).Impact
payment_*events on a tokenize-only invoice must add listeners for thecard_verification_*names. Non-tokenize-only checkouts are unaffected — the flag defaults falsy, so the ~35 dispatch sites in the APM/wallet/saved-method files are untouched.Additional Context
card.tsanddynamic-checkout.tspass the flag:tokenize_onlylives on the card method, saved methods are already hidden in this flow, and APM/wallet flows can't be tokenize-only.tokenize-payment-button-textstill reads "Tokenize payment" — left as-is, but "Verify card" would match the new copy if we want it.