Skip to content

WEBDEV-9053: Migrate the donation form payment layer into elements - #103

Merged
jbuckner merged 14 commits into
mainfrom
WEBDEV-9053-migrate-payment-layer
Oct 12, 2026
Merged

jbuckner merged 14 commits into
mainfrom
WEBDEV-9053-migrate-payment-layer

Conversation

@jbuckner

@jbuckner jbuckner commented Sep 15, 2026 •

Copy link
Copy Markdown
Collaborator

WEBDEV-9053. Stacked on #100. Fourth of the five in WEBDEV-8602.

The payment layer of donation-form: the Braintree manager, payment clients, the five provider handlers (credit card, PayPal, Venmo, Apple Pay, Google Pay), the recaptcha manager and the Venmo session restoration handler. It lands under src/elements/ia-donation-form/braintree/. No custom elements in this one, so no story, it's the logic and its tests. The flow handlers go with the modals in the last rung since they render them.

What changed beyond the move:

  • Real @types instead of the vendored 2020 copies. @types/braintree-web 3.143 splits the library module (typeof braintree.client, the thing with create()) from the instance (braintree.Client), where the old copy conflated them. PaymentClientsInterface and the handlers are typed that way now, and everything imports the types (import type * as braintree from 'braintree-web') rather than leaning on the UMD global. A globals.d.ts types window.braintree and window.paypal, which the CDN scripts create. The @types packages are regular dependencies because the published d.ts files reference them.
  • fee_amount_covered is calculated from the fields. submitDonation already recomputed the total because donationInfo can arrive as a plain object (Venmo in Chrome) with none of the class getters. The fee custom field read the feeAmountCovered getter and would have been undefined in that case. Both are calculated the same way now, with a test using a plain object.
  • The hosted fields retry is tidier. No async promise executor, and the timeout is cleared in a finally so a lost race can't leave a rejection with nowhere to go. Same behavior: our own timer races Braintree's create, a timer win retries, up to the max.
  • The recaptcha onload callback is namespaced (iaDonationFormGrecaptchaLoaded). The old package uses donationFormGrecaptchaLoadedCallback, and a page loading both during the switch-over would have had them overwrite each other's callback and hang one form's recaptcha.
  • HostedFieldContainer doesn't import BadgedInput. It only ever set .error on the parent, so it types the parent as an element with an error flag. The badged input element itself arrives with the form elements.
  • Enums are as const objects plus a type, as in the earlier rungs.
  • Two upstream changes are in. The Venmo restoration handler no longer throws in Safari private browsing when the storage global itself is blocked (iaux-donation-form#188). CreditCardHandler has a focusField the form uses to focus the card number (from iaux-donation-form#190). @types/braintree-web already has HostedFields.focus, so the vendored type patch isn't needed.

Tests moved from web-test-runner and sinon to Vitest, 88 of them. The mocks for the payment libraries live in braintree/test-helpers/*.test-helpers.ts, which the package's !dist/**/*.test* filter keeps out of the published tarball. The Apple Pay session mock now defines STATUS_SUCCESS and STATUS_FAILURE, which the old one didn't, so those assertions compared undefined to undefined and passed regardless.

Verified locally: build, full suite 1117 passing, eslint and prettier clean, no circular dependencies.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QnX6VHo3EJRzcKfhzBChCf

jbuckner and others added 3 commits September 14, 2026 16:32
… form section into elements

Bottom rung of the donation form stack. The data-models, currency-validator
and form-section packages from iaux-donation-form land in
src/elements/ia-donation-form/ as models/, currency-validator.ts and
form-elements/ia-donation-section.ts.

The 14 model files fold into six. The enums become as-const objects plus a
type, since erasableSyntaxOnly rules out enum. The classes stay classes:
offshoot, the monthly giving portal and the petabox banner all construct
them. The section is ia-donation-section, sized off a 10px base font size
variable like the item navigator so it renders the same under any root font
size, with its CSS variables renamed to --ia-donation-section-*.

story-template gets an importPath property so an element nested inside
another component's directory shows the right import snippet.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QnX6VHo3EJRzcKfhzBChCf
The edit-donation package from iaux-donation-form lands as
ia-donation-edit-donation under src/elements/ia-donation-form/form-elements/,
rendering ia-donation-section for its two steps. The petabox banner uses it
on its own, so it gets its own story.

Enums become as-const objects plus a type. CSS variables move to
--ia-donation-edit-*, sized off a 10px base font size that is passed through
to the sections. The strings go through msg(), the custom amount field gets
an accessible name, and currency.js becomes a dependency.

One inherited bug fixed: with the custom amount hidden, the "is the donor
typing in the custom field" check compared null to null and came out true,
so a preset set programmatically could end up with nothing selected. Guarded
on the field existing, with a test.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QnX6VHo3EJRzcKfhzBChCf
The Braintree manager, payment clients and the five provider handlers
(credit card, PayPal, Venmo, Apple Pay, Google Pay) land under
src/elements/ia-donation-form/braintree/, with the recaptcha manager, the
Venmo session restoration handler and DonationFormError alongside. No
custom elements in this rung. The flow handlers go with the modals next.

The vendored 2020 braintree-web and paypal-checkout-components d.ts files
are replaced by the real @types packages, which split the library module
(typeof braintree.client) from the instance (braintree.Client), so the
clients and handlers are typed that way. The fee_amount_covered custom
field is calculated from the fields like the total already was, since
donationInfo can arrive as a plain object. The hosted fields retry no
longer uses an async promise executor and clears its timer whichever way
the race goes. The recaptcha onload callback global is namespaced so it
can't collide with the old package's on a page that loads both.

Tests move from web-test-runner and sinon to Vitest, with the payment
library mocks under test-helpers/.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QnX6VHo3EJRzcKfhzBChCf
@jbuckner
jbuckner added this pull request to stack #101 September 15, 2026 05:05
@github-actions

github-actions Bot commented Sep 15, 2026 •

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-10-12 20:25 UTC

@codecov-commenter

codecov-commenter commented Sep 15, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.68707% with 43 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.96%. Comparing base (57a21ba) to head (64597da).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...aintree/test-helpers/mock-managers.test-helpers.ts 81.17% 16 Missing ⚠️
...raintree/test-helpers/mock-clients.test-helpers.ts 91.00% 9 Missing ⚠️
...ts/ia-donation-form/braintree/braintree-manager.ts 90.24% 2 Missing and 2 partials ⚠️
...providers/venmo/venmo-restoration-state-handler.ts 88.00% 2 Missing and 1 partial ⚠️
src/elements/ia-donation-form/recaptcha-manager.ts 89.65% 0 Missing and 3 partials ⚠️
...ts/ia-donation-form/braintree/payment-providers.ts 93.54% 2 Missing ⚠️
...ntree/payment-providers/credit-card/credit-card.ts 95.00% 1 Missing and 1 partial ⚠️
...-form/braintree/payment-providers/paypal/paypal.ts 85.71% 1 Missing and 1 partial ⚠️
...roviders/apple-pay/apple-pay-session-datasource.ts 96.96% 0 Missing and 1 partial ⚠️
...on-form/braintree/payment-providers/venmo/venmo.ts 94.11% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #103      +/-   ##
==========================================
+ Coverage   90.67%   90.96%   +0.28%     
==========================================
  Files          96      118      +22     
  Lines        3519     4107     +588     
  Branches      843      904      +61     
==========================================
+ Hits         3191     3736     +545     
- Misses        137      170      +33     
- Partials      191      201      +10     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

jbuckner and others added 2 commits September 24, 2026 11:18
…onation-form-models

* origin/main:
  1.1.1 (#118)
  WEBDEV-9132: Fix Safari image-viewer wide-layout breakpoint (#115)
  1.1.0 (#116)
  WEBDEV-9129: Exclude story files from coverage reporting (#113)
  WEBDEV-9121: Migrate histogram-date-range into elements (#112)
  WEBDEV-9130: Exclude nested dist and worktree tests from local runs (#114)
  v1.0.0 (#111)
  WEBDEV-9025: Add a CLAUDE.md covering the publish flow (#94)
  WEBDEV-9063: Typecheck in CI (#107)
  v0.4.1 (#108)
  WEBDEV-9066: Guard custom element registration against duplicate defines (#106)
  v0.4.0 (#99)
  WEBDEV-9022: Migrate the image viewer into elements (#93)
jbuckner and others added 8 commits October 6, 2026 17:18
…onation-form-models

Main removed src/elements/index.ts (WEBDEV-9214), so the donation form
re-exports this branch added to it go with it.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S8FoDPcJXekJd1rL9b9oJJ
…te-edit-donation

Keeps both currency.js and dayjs in package.json. Main removed
src/elements/index.ts (WEBDEV-9214), so the edit-donation re-export goes
with it.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S8FoDPcJXekJd1rL9b9oJJ
The lint rule that came in from main restricts customElement from
lit/decorators.js. Same change #98 made for the section.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S8FoDPcJXekJd1rL9b9oJJ
Ports iaux-donation-form#188 (WEBDEV-8781). Safari private browsing throws
a SecurityError from reading the localStorage or sessionStorage global, so
the lookup now happens inside the guarded probe.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S8FoDPcJXekJd1rL9b9oJJ
Ports the payment layer part of iaux-donation-form#190. The credit card form
focuses the card number field when the donor picks credit card. The vendored
braintree hosted-fields type patch isn't needed here since
@types/braintree-web already declares HostedFields.focus.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S8FoDPcJXekJd1rL9b9oJJ
…ent-layer

Main removed src/elements/index.ts (WEBDEV-9214), so the payment layer
re-exports go with it.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S8FoDPcJXekJd1rL9b9oJJ
…dit-donation

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S8FoDPcJXekJd1rL9b9oJJ

* origin/main:
  WEBDEV-9051: Migrate the donation form models, currency validator and form section into elements (#98)

# Conflicts:
#	src/elements/ia-donation-form/element-names.test.ts
…ent-layer

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S8FoDPcJXekJd1rL9b9oJJ

* WEBDEV-9052-migrate-edit-donation:
  WEBDEV-9051: Migrate the donation form models, currency validator and form section into elements (#98)

@latonv latonv left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, solid migration! Just flagged one oddity in the dependencies.

Comment thread package.json Outdated
Base automatically changed from WEBDEV-9052-migrate-edit-donation to main October 12, 2026 20:20
Use the stable promised-singleton 0.2.1.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012rHVriHUtoMwtEUwFdyZdS
@jbuckner
jbuckner merged commit 08d480a into main Oct 12, 2026
6 checks passed
@jbuckner
jbuckner deleted the WEBDEV-9053-migrate-payment-layer branch October 12, 2026 20:24
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.

3 participants