Skip to content

feat(react-ui)!: remove built-in submit button from payment-method-management - #2236

Merged
manu-xmint merged 9 commits into
mainfrom
devin/1793134270-pmm-remove-submit-button
Nov 6, 2026
Merged

manu-xmint merged 9 commits into
mainfrom
devin/1793134270-pmm-remove-submit-button

Conversation

@manu-xmint

@manu-xmint manu-xmint commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Description

BREAKING — CrossmintPaymentMethodManagement no longer renders a built-in submit button.

  • The hideSubmitButton prop is removed. The iframe URL always carries hideSubmitButton=true, so the iframe's button never renders for this SDK major.
  • The iframe URL also carries hostShowsSubmitErrors=true. The host shows the message of an invalid or failed result from ref.submit(), so the iframe draws only field errors and does not show the message twice (Paella-Labs/crossbit-main#33628).
  • The host-side submit path (ref.submit() → payment-method:submit → PaymentMethodSubmitResult) is now the only submit API. It is unchanged and already public.
  • Companion change in crossbit-main: the PMM iframe reads sdkMetadata (already sent in the URL) and never renders the button for @crossmint/client-sdk-react-ui majors >= 5, independent of the URL param (Paella-Labs/crossbit-main#33136). Old SDKs (<= 4.x) keep the current behavior.
  • CrossmintAgentCardAuthorization renders its own submit button and calls ref.submit(), since the iframe never shows one under the new major. The button inherits appearance.paymentMethodManagement.rules.PrimaryButton styling where provided, matching the iframe's old defaults otherwise.
  • New onReady and onChange({ mode, empty, complete }) props, like Stripe's ready and change events, so the host's button can stay disabled until a submit can succeed. They fire only for the live iframe, and again after it reloads.
  • invalid, failed and unavailable results carry a code: incomplete_card, invalid_billing_address, incomplete_bank_account, save_failed, select_failed, not_ready, and timeout (SDK side). A missing or unknown code from the iframe becomes unknown, so the result still resolves. Each status has one exported as const code list (PAYMENT_METHOD_SUBMIT_INVALID_CODES, ..._FAILED_CODES, ..._UNAVAILABLE_CODES); the code types and the zod validation both come from it. The lists, the code types and PaymentMethodManagementChangeEvent are exported from react-ui.
  • The iframe side of these is Paella-Labs/crossbit-main#33628. Merge this PR only after #33628 is in production: until then onChange never fires, and a button disabled on complete stays disabled.
  • The CrossmintPaymentMethodManagement example in examples.json (SDK reference docs) wires its own button to ref.current.submit(), enables it on onReady and onChange, and shows the result message. The payments demo page does the same and prints the form state.
  • The iframe in crossbit-main keeps both modes so older SDKs are unaffected; no versioned page needed.

Test plan

  • Unit tests updated: paymentMethodManagementService.test.ts asserts hideSubmitButton and hostShowsSubmitErrors are always sent; crossmint-agent-card-authorization.test.tsx covers the new host-button submit path.
  • pnpm --filter @crossmint/client-sdk-react-ui... build passes.
  • pnpm turbo test:vitest typecheck --filter @crossmint/client-sdk-react-ui --filter @crossmint/client-sdk-base passes, 151 + 119 tests. pnpm lint passes.
  • incoming.test.ts: each result code is kept; a missing or unknown code becomes unknown; payment-method:ready and payment-method:change parse, and a change without its state is rejected.
  • crossmint-payment-method-management.test.tsx: onReady and onChange get the iframe's events, and a retired iframe's events are ignored; a failed handshake answers not_ready and a timeout timeout.
  • Payments playground payment-method-management page renders its own button (pre-existing pattern).

Package updates

Changeset olive-buttons-hide marks @crossmint/client-sdk-base and @crossmint/client-sdk-react-ui as major — ships with the next major release.

@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access that start with 'Devin'.

  • Disable automatic comment, CI, and merge conflict monitoring

Original prompt from Manuel

Read this: https://crossmint.slack.com/archives/C05KCC0H61J/p1792668591297239
and tell me next steps

@changeset-bot

changeset-bot Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 11ab4c6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 17 packages
Name Type
@crossmint/client-sdk-base Major
@crossmint/client-sdk-react-ui Major
@crossmint/client-sdk-nextjs-starter Patch
@crossmint/client-sdk-auth Patch
@crossmint/client-sdk-react-base Patch
@crossmint/client-sdk-react-native-ui Patch
@crossmint/client-sdk-verifiable-credentials Patch
@crossmint/client-sdk-smart-wallet Patch
@crossmint/common-sdk-auth Patch
@crossmint/auth-ssr-nextjs-demo Patch
@crossmint/wallets-quickstart-devkit Patch
@crossmint/wallets-playground-react Patch
@crossmint/wallets-playground-expo Patch
@crossmint/server-sdk Patch
@crossmint/wallets-sdk Patch
crossmint-auth-node Patch
@crossmint/integration-tests Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-27T20:51:31.737126Z
We couldn’t complete this review. Comment @codex review to try again.
4f20f63 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

devin-ai-integration[bot]

This comment was marked as resolved.

@greptile-apps

greptile-apps Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] The change affects hosts and workflows that use payment-method management.

Update CrossmintAgentCardAuthorization with a working submit button before merging.

Reviews (1) · Last reviewed commit: "feat(react-ui)!: remove built-in submit ..." · Reviewed by Greptile

greptile-apps[bot]

This comment was marked as resolved.

…nagement

The component always hides the iframe submit button; hosts submit via
ref.submit() from their own button. hideSubmitButton prop removed.
@devin-ai-integration
devin-ai-integration Bot force-pushed the devin/1793134270-pmm-remove-submit-button branch from 4f20f63 to bcdb88b Compare October 27, 2026 20:57
devin-ai-integration[bot]

This comment was marked as resolved.

CrossmintAgentCardAuthorization renders its own button instead of relying
on the iframe's built-in one, so the payment-method iframe never needs a
submit affordance for SDK majors >= 5.
@devin-ai-integration

Copy link
Copy Markdown
Contributor

E2E verified: real component mount saves a card through ref.submit()

Built @crossmint/client-sdk-react-ui from this branch and mounted the real CrossmintPaymentMethodManagement in a host page:

  • Generated iframe URL carries hideSubmitButton=true + sdkMetadata (v4.12.0) — the in-iframe button is absent, as intended
  • Host "Continue" button → ref.submit() → {"status":"saved"} + onPaymentMethodSelected fired; card persisted server-side (GET /api/unstable/payment-methods confirms)
  • Deploy-order safety confirmed: hideSubmitButton=true alone in the URL hides the button even without sdkMetadata

SDK component mount — hidden in-iframe button, host Continue saves

Full version matrix (v4 shown / v5 hidden / malformed metadata falls back) verified on Paella-Labs/crossbit-main#33136.

CrossmintAgentCardAuthorization verified via build + source inspection (own Continue button → pmm.current.submit(), "Saving…" state, error slot) — not mounted live since it needs auth-provider context; its PMM sibling exercised the same iframe plumbing end-to-end.

Devin session: https://crossmint.devinenterprise.com/sessions/52d81324264c406d9632cf76b5aa29f0

manu-xmint and others added 5 commits November 5, 2026 19:05
…submit errors

The SDK now sends hostShowsSubmitErrors=true with hideSubmitButton=true. The
host gets the message of an invalid or failed submit from ref.submit() and
shows it, so the iframe draws only field errors and does not show the message
twice (Paella-Labs/crossbit-main#33628).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…remove-submit-button

# Conflicts:
#	apps/payments/nextjs/app/payment-method-management/page.tsx
#	packages/client/base/src/types/payment-method-management/CrossmintPaymentMethodManagementProps.ts
…ample

The component renders no submit button, so the example wires its own
button to ref.current.submit() and shows the message of a failed submit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ult codes

A host with its own submit button needs what Stripe's Payment Element gives
it: onReady when a submit can first succeed, onChange({ mode, empty,
complete }) to enable the button, and a code on invalid, failed and
unavailable results. A code the component does not know becomes "unknown".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ange reloads the form

A change of jwt or form configuration reloads the iframe. A host that enabled
its button on complete kept it enabled until the new form reported. The
example also clears the error when the buyer edits again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
devin-ai-integration[bot]

This comment was marked as resolved.

manu-xmint and others added 2 commits November 6, 2026 02:42
The code types and the result validation both come from one exported const
list per status, so a new code cannot reach one and miss the other. The
change event schema is checked against its type.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e reloads in place

A navigation inside the iframe keeps the URL but starts the form over. The
reset that a URL change sends now runs for that reload too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@antonio-xm antonio-xm left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be good to add a test for the agent-card submit button con Continue, but this is good to go

@manu-xmint
manu-xmint merged commit a55b5e4 into main Nov 6, 2026
10 checks passed
@manu-xmint
manu-xmint deleted the devin/1793134270-pmm-remove-submit-button branch November 6, 2026 13:30
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.

2 participants