Repository navigation
Add the saved payment method row components 3/6 - #1887
jaxdesmarais merged 4 commits into
Conversation
6ee40a9 to
7deb3d1
Compare
|
/inner source |
|
Approving. Earlier feedback is addressed and the rows look good. Please check the pill’s tap height against the 44pt guideline, since the whole pill is the edit button. Also add the changelog entry, then /ready. |
| private func fiAccessibilityLabel(for summary: PayPalSavedPaymentMethod) -> String { | ||
| guard let lastDigits = lastDigits(for: summary) else { | ||
| return summary.label ?? "" | ||
| } | ||
| // Spaced so VoiceOver reads each digit instead of one number. | ||
| let spokenDigits = lastDigits.map(String.init).joined(separator: " ") | ||
| return [summary.label, "ending in \(spokenDigits)"].compactMap { $0 }.joined(separator: ", ") | ||
| } |
There was a problem hiding this comment.
Non-blocking: I don’t see anything wrong with this implementation—I like that it spaces the last
digits so VoiceOver reads them individually. Could we add coverage for the expected accessibility-
label output to prevent regressions?
For example:
// CARD, label: "Visa", lastDigits: "1234"
"Visa, ending in 1 2 3 4"// PAYPAL_CREDIT, label: "PayPal Credit", lastDigits: "1234"
"PayPal Credit"
This could be covered by making this helper testable within the module, or by asserting the button’s
accessibility label through an accessibility/UI test.
There was a problem hiding this comment.
I made fiAccessibilityLabel(for:) internal for testing and added a table-driven test covering card, bank, PayPal Credit, missing digits and a missing label.
Juan219
left a comment
There was a problem hiding this comment.
Added a Non-blocking comment, please check before requesting review from BT team.
|
/ready |
buzzamus
left a comment
There was a problem hiding this comment.
I am not sure if this is hooked up and able to yet, but is there any way to show some screenshots of what these new views look like?
| /// Internal for testing. | ||
| func fiAccessibilityLabel(for summary: PayPalSavedPaymentMethod) -> String { | ||
| guard let lastDigits = lastDigits(for: summary) else { | ||
| return summary.label ?? "" |
There was a problem hiding this comment.
Will this empty text cause issues for accessibility features if the label is actually empty?
There was a problem hiding this comment.
An empty label is now treated as missing, and if there's no label and no digits, VoiceOver reads "Saved payment method" instead of an empty string. Added test cases for both.
| Spacer(minLength: 0) | ||
| } | ||
| HStack(spacing: 0) { | ||
| fiCluster |
There was a problem hiding this comment.
stackedLayoutSpacing is 6, so if fiCluster renders an empty view I think this will add an extra gap spacing here won't it?
There was a problem hiding this comment.
Yes, it did. The stacked layout now leaves out the FI row for brand-only (and the brand row when it's hidden), so no spacing is added
| var text = AttributedString(message) | ||
| text.foregroundColor = style.resolvedTextColor | ||
|
|
||
| guard let learnMoreText, let url = learnMoreURL else { |
There was a problem hiding this comment.
it looks like the guard only checks learnMoreText != nil, not non-empty. can we add something like this:
| guard let learnMoreText, let url = learnMoreURL else { | |
| guard let learnMoreText, !learnMoreText.isEmpty, let url = learnMoreURL else { |
| )) { | ||
| if style.showPayPalLogo { | ||
| Image("PayPalBadge", bundle: .payPalSavedPaymentMethod) | ||
| .resizable() | ||
| .scaledToFit() | ||
| .frame(width: logoSide, height: logoSide) | ||
| .accessibilityLabel("PayPal") | ||
| // The label already reads "PayPal", so the logo only speaks when the label is hidden. |
There was a problem hiding this comment.
if a merchant sets both showPayPalLogo and showPayPalLabel to false, the brand cluster renders nothing — visually or for accessibility — leaving the pill looking orphaned.
should PayPalSavedPaymentMethodViewStyle guard against/disallow this combination
There was a problem hiding this comment.
I’ve kept hiding both as a supported merchant option, consistent with the JS alpha—for example, when merchants use their own PayPal header. I also fixed the orphaned pill spacing and VoiceOver label. In Part 4, brand-only with both flags off now hides the component entirely.
EditFIRow, CreditMessagingRow and PayPalBrandCluster, with the card, bank and pencil assets and their render tests. Rebased onto view-edit-fi-beta-feature after braintree#1886 merged.
2d2c91c to
054af26
Compare
…en the brand mark is hidden, and ignore empty Learn more text
These rows aren't wired into a screen until PR4, so I rendered the real views in a test and added a Screenshots section to the description covering each row state, a dark theme, large accessibility text and the logo/label settings. |
|
@saurabh-P9525 this PR is missing a XO Tech Lead review and is being moved back to draft |
XO tech lead - @Juan219 has reviewed , and has approved the PR. @jaxdesmarais |
|
Approved |
| .accessibilityElement(children: .ignore) | ||
| .accessibilityLabel(label) | ||
| .accessibilityAddTraits(.isButton) | ||
| .accessibilityHint("Change payment method") |
There was a problem hiding this comment.
it looks like this accessibility hint also applies to "PayPal" / "Saved payment method" / "ending in" nearby so should these VoiceOver strings be localized, or is that planned in a later PR in the stack?
There was a problem hiding this comment.
The SDK doesn't localize strings today, and PayPalButton and the card fields hard-code their accessibility text in English too, so I've kept these consistent with them
|
|
||
| /// The whole pill is the tap target, not just the pencil: a 20pt glyph is well under the 44pt | ||
| /// minimum and is the only affordance the buyer has to change what will be charged. | ||
| private func editable(label: String, @ViewBuilder _ content: () -> some View) -> some View { |
There was a problem hiding this comment.
minor: could we give this trailing closure a parameter label (e.g. content:) instead of _? slightly more readable at call sites and matches the labeled style used elsewhere in this file
There was a problem hiding this comment.
Done, editable now takes content:, and I made the same change to fiPill so both helpers match.
| import UIKit | ||
|
|
||
| /// The inline credit (Pay Later) messaging line rendered below the FI row. | ||
| /// |
There was a problem hiding this comment.
nit: can remove the empty line
agedd
left a comment
There was a problem hiding this comment.
thanks for making these changes, looks good!
buzzamus
left a comment
There was a problem hiding this comment.
Approved and re-ran the failing integration test CI that appears to be due to some backend flakiness
4364b8c
into
braintree:view-edit-fi-beta-feature
The public view, skeleton row and shimmer, edit loader, Learn more lander and LoadingSpinner asset, with render tests. Rebased onto view-edit-fi-beta-feature after braintree#1887 merged.
Part 3 of the View/Edit FI saved payment method component. Adds the SwiftUI rows the component is built from.
Summary of changes
EditFIRowrenders the brand mark (PayPal badge + label) and the funding-instrument pill: card art (or a card/bank fallback glyph) + masked last digits + edit pencil. Only regular cards and banks show••last4; PayPal products (PayPal Credit, PayPal Debit, PayPal balance, Pay in 4, ...) show their label. It also covers the email-only and brand-only fallbacks. At large accessibility text sizes it stacks instead of truncating the last digits.CreditMessagingRowrenders the Pay Later message with an inline "Learn more" link. It takes the message, link text and URL as plain values and hands the tap back throughonLearnMore, so the view model decides how the lander opens.EditFIStyleGuard.fontSize/dimension, and fonts follow the view's Dynamic Type size.Screenshots
The rows aren't on a screen until part 4, so these are rendered from the real
EditFIRowandCreditMessagingRowviews in a test.Row states and merchant styling
Card + Pay Later message
Bank
Card with no art (fallback glyph)
PayPal product (label instead of digits)
Pay in 4 (no art)
Email only, editable
Email only, not editable
Brand only (no FI or email)
Merchant link color (no underline)
Large accessibility text (stacked)
Dark merchant theme
showPayPalLogo: falseshowPayPalLabel: falseBoth off
Notes for reviewers
CreditMessageContentmoved to Add the saved payment method view model 2/6 #1886 (2/6) with the view model that builds it.SavedPaymentMethodRenderTestCaseholds the sharedImageRendererhelpers; the view's render tests in Add the BTPayPalSavedPaymentMethodView checkout component 4/6 #1888 (4/6) reuse it.AI Usage
Which AI Agent Was Used?
How was AI used?
Used Claude to write the row components and their render tests, and to split this part out.
Estimated AI Code Contribution
Checklist
Authors
Inner Source Process
Internal to PayPal contributors should fill out this section. All others can delete.
PR should follow these steps before codeowners review will begin:
/inner sourceon this PR — this will automatically add theinner sourceandtech lead review requiredlabels. Open the PR in a draft state./readyon this PR — this will automatically remove thetech lead review requiredlabel. Move the PR to ready to review.Inner Source Checklist