Skip to content

Commit 78bc502

Browse files
Fix Forms when only one PM Available
1 parent 851734e commit 78bc502

File tree

8 files changed

+72
-7
lines changed

8 files changed

+72
-7
lines changed

paymentsheet/src/main/java/com/stripe/android/paymentsheet/navigation/PaymentSheetScreen.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import com.stripe.android.paymentsheet.ui.SavedPaymentMethodsTopContentPadding
2222
import com.stripe.android.paymentsheet.ui.SelectSavedPaymentMethodsInteractor
2323
import com.stripe.android.paymentsheet.ui.UpdatePaymentMethodInteractor
2424
import com.stripe.android.paymentsheet.ui.UpdatePaymentMethodUI
25+
import com.stripe.android.paymentsheet.utils.isOnlyOneNonCardPaymentMethod
2526
import com.stripe.android.paymentsheet.verticalmode.ManageScreenInteractor
2627
import com.stripe.android.paymentsheet.verticalmode.ManageScreenUI
2728
import com.stripe.android.paymentsheet.verticalmode.PaymentMethodVerticalLayoutInteractor
@@ -253,7 +254,7 @@ internal sealed interface PaymentSheetScreen {
253254

254255
override fun title(isCompleteFlow: Boolean, isWalletEnabled: Boolean): StateFlow<ResolvableString?> {
255256
return interactor.state.mapAsStateFlow { state ->
256-
if (isWalletEnabled) {
257+
if (isWalletEnabled || state.supportedPaymentMethods.isOnlyOneNonCardPaymentMethod()) {
257258
null
258259
} else if (isCompleteFlow) {
259260
R.string.stripe_paymentsheet_add_payment_method_title.resolvableString

paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/PaymentElement.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import com.stripe.android.paymentsheet.model.PaymentMethodIncentive
2929
import com.stripe.android.paymentsheet.paymentdatacollection.FormArguments
3030
import com.stripe.android.paymentsheet.paymentdatacollection.ach.USBankAccountForm
3131
import com.stripe.android.paymentsheet.paymentdatacollection.ach.USBankAccountFormArguments
32+
import com.stripe.android.paymentsheet.utils.isOnlyOneNonCardPaymentMethod
33+
import com.stripe.android.paymentsheet.verticalmode.VerticalModeFormHeaderUI
3234
import com.stripe.android.uicore.StripeTheme
3335
import com.stripe.android.uicore.elements.FormElement
3436
import com.stripe.android.uicore.getOuterFormInsets
@@ -76,6 +78,8 @@ internal fun PaymentElement(
7678
modifier = Modifier.padding(bottom = 12.dp),
7779
updatePaymentMethodVisibility = updatePaymentMethodVisibility,
7880
)
81+
} else if (supportedPaymentMethods.isOnlyOneNonCardPaymentMethod()) {
82+
VerticalModeFormHeaderUI(enabled, supportedPaymentMethods.first().asFormHeaderInformation(incentive))
7983
}
8084

8185
FormElement(
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.stripe.android.paymentsheet.utils
2+
3+
import com.stripe.android.lpmfoundations.luxe.SupportedPaymentMethod
4+
import com.stripe.android.model.PaymentMethod
5+
6+
internal fun List<SupportedPaymentMethod>.isOnlyOneNonCardPaymentMethod() =
7+
this.size == 1 && this.first().code != PaymentMethod.Type.Card.code

paymentsheet/src/main/java/com/stripe/android/paymentsheet/verticalmode/VerticalModeFormUI.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import androidx.compose.ui.platform.testTag
1919
import androidx.compose.ui.text.style.TextOverflow
2020
import androidx.compose.ui.unit.dp
2121
import com.stripe.android.lpmfoundations.FormHeaderInformation
22+
import com.stripe.android.model.PaymentMethod
2223
import com.stripe.android.paymentsheet.ui.FormElement
2324
import com.stripe.android.paymentsheet.ui.PaymentMethodIcon
2425
import com.stripe.android.paymentsheet.ui.PromoBadge
@@ -45,7 +46,7 @@ internal fun VerticalModeFormUI(
4546
Column(modifier) {
4647
val headerInformation = state.headerInformation
4748
val enabled = !state.isProcessing
48-
if (headerInformation != null && !showsWalletHeader) {
49+
if (headerInformation != null && shouldShowHeader(state.selectedPaymentMethodCode, showsWalletHeader)) {
4950
VerticalModeFormHeaderUI(isEnabled = enabled, formHeaderInformation = headerInformation)
5051
}
5152

@@ -71,6 +72,10 @@ internal fun VerticalModeFormUI(
7172
}
7273
}
7374

75+
private fun shouldShowHeader(selectedCode: String, showsWalletHeader: Boolean): Boolean {
76+
return if (selectedCode == PaymentMethod.Type.Card.code) !showsWalletHeader else true
77+
}
78+
7479
@Composable
7580
internal fun VerticalModeFormHeaderUI(
7681
isEnabled: Boolean,

paymentsheet/src/main/java/com/stripe/android/paymentsheet/verticalmode/VerticalModeInitialScreenFactory.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ internal object VerticalModeInitialScreenFactory {
2727
customerStateHolder = customerStateHolder,
2828
bankFormInteractor = bankFormInteractor,
2929
),
30-
showsWalletHeader = true,
30+
showsWalletHeader = paymentMethodMetadata.availableWallets.isNotEmpty(),
3131
)
3232
)
3333
}

paymentsheet/src/test/java/com/stripe/android/paymentsheet/navigation/PaymentSheetScreenAddFirstPaymentMethodTest.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import com.stripe.android.testing.CoroutineTestRule
1212
import kotlinx.coroutines.test.runTest
1313
import org.junit.Rule
1414
import org.junit.Test
15-
import com.stripe.android.R as PaymentsCoreR
1615

1716
internal class PaymentSheetScreenAddFirstPaymentMethodTest {
1817
@get:Rule
@@ -49,7 +48,7 @@ internal class PaymentSheetScreenAddFirstPaymentMethodTest {
4948
val interactor = FakeAddPaymentMethodInteractor(state)
5049
PaymentSheetScreen.AddFirstPaymentMethod(interactor)
5150
.title(isCompleteFlow = false, isWalletEnabled = false).test {
52-
assertThat(awaitItem()).isEqualTo(PaymentsCoreR.string.stripe_title_add_a_card.resolvableString)
51+
assertThat(awaitItem()).isEqualTo(null)
5352
}
5453
}
5554

@@ -66,7 +65,7 @@ internal class PaymentSheetScreenAddFirstPaymentMethodTest {
6665
val interactor = FakeAddPaymentMethodInteractor(state)
6766
PaymentSheetScreen.AddFirstPaymentMethod(interactor)
6867
.title(isCompleteFlow = false, isWalletEnabled = false).test {
69-
assertThat(awaitItem()).isEqualTo(R.string.stripe_paymentsheet_choose_payment_method.resolvableString)
68+
assertThat(awaitItem()).isEqualTo(null)
7069
}
7170
}
7271

paymentsheet/src/test/java/com/stripe/android/paymentsheet/verticalmode/VerticalModeFormUITest.kt

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,15 @@ internal class VerticalModeFormUITest {
8282
formPage.title.assert(hasText("Add new card"))
8383
}
8484

85+
@Test
86+
fun testCardDoesNotShowHeaderWhenShowWalletIsTrue() = runScenario(
87+
initialState = createCardState(customerHasSavedPaymentMethods = true),
88+
showsWalletHeader = true
89+
) {
90+
formPage.headerIcon.assertDoesNotExist()
91+
formPage.title.assertDoesNotExist()
92+
}
93+
8594
@Test
8695
fun testCardShowsAddCardHeader_whenCustomerHasNoSavedPMs() = runScenario(
8796
createCardState(customerHasSavedPaymentMethods = false)
@@ -98,6 +107,16 @@ internal class VerticalModeFormUITest {
98107
formPage.title.assert(hasText("Klarna"))
99108
}
100109

110+
@Test
111+
fun testLpmShowsHeaderWhenShowsWalletHeaderIsTrue() = runScenario(
112+
initialState = createKlarnaState(),
113+
showsWalletHeader = true
114+
) {
115+
formPage.headerIcon.assertExists()
116+
formPage.title.assertExists()
117+
formPage.title.assert(hasText("Klarna"))
118+
}
119+
101120
@Test
102121
fun testCardNumberErrorMessage() = runScenario(createCardState(customerHasSavedPaymentMethods = true)) {
103122
formPage.cardNumber.assertHasNoErrorMessage()
@@ -118,6 +137,7 @@ internal class VerticalModeFormUITest {
118137

119138
private fun runScenario(
120139
initialState: VerticalModeFormInteractor.State,
140+
showsWalletHeader: Boolean = false,
121141
block: Scenario.() -> Unit
122142
) {
123143
val stateFlow = MutableStateFlow(initialState)
@@ -130,7 +150,7 @@ internal class VerticalModeFormUITest {
130150
LocalCardNumberCompletedEventReporter provides { },
131151
LocalCardBrandDisallowedReporter provides { }
132152
) {
133-
VerticalModeFormUI(interactor, showsWalletHeader = false)
153+
VerticalModeFormUI(interactor, showsWalletHeader = showsWalletHeader)
134154
}
135155
}
136156

paymentsheet/src/test/java/com/stripe/android/paymentsheet/verticalmode/VerticalModeInitialScreenFactoryTest.kt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.stripe.android.isInstanceOf
66
import com.stripe.android.link.TestFactory
77
import com.stripe.android.lpmfoundations.paymentmethod.PaymentMethodMetadata
88
import com.stripe.android.lpmfoundations.paymentmethod.PaymentMethodMetadataFactory
9+
import com.stripe.android.lpmfoundations.paymentmethod.WalletType
910
import com.stripe.android.model.PaymentIntentFixtures
1011
import com.stripe.android.model.PaymentMethodFixtures
1112
import com.stripe.android.paymentsheet.CustomerStateHolder
@@ -35,6 +36,34 @@ class VerticalModeInitialScreenFactoryTest {
3536
assertThat(screens[0]).isInstanceOf<PaymentSheetScreen.VerticalModeForm>()
3637
}
3738

39+
@Test
40+
fun `showsWalletHeader is false for VerticalModeForm if no available wallets`() = runScenario(
41+
paymentMethodMetadata = PaymentMethodMetadataFactory.create(
42+
stripeIntent = PaymentIntentFixtures.PI_REQUIRES_PAYMENT_METHOD.copy(
43+
paymentMethodTypes = listOf("cashapp"),
44+
),
45+
availableWallets = listOf()
46+
)
47+
) {
48+
assertThat(screens).hasSize(1)
49+
assertThat(screens[0]).isInstanceOf<PaymentSheetScreen.VerticalModeForm>()
50+
assertThat(screens[0].showsWalletsHeader(false).value).isFalse()
51+
}
52+
53+
@Test
54+
fun `showsWalletHeader is true for VerticalModeForm if available wallets exist`() = runScenario(
55+
paymentMethodMetadata = PaymentMethodMetadataFactory.create(
56+
stripeIntent = PaymentIntentFixtures.PI_REQUIRES_PAYMENT_METHOD.copy(
57+
paymentMethodTypes = listOf("cashapp"),
58+
),
59+
availableWallets = listOf(WalletType.Link)
60+
)
61+
) {
62+
assertThat(screens).hasSize(1)
63+
assertThat(screens[0]).isInstanceOf<PaymentSheetScreen.VerticalModeForm>()
64+
assertThat(screens[0].showsWalletsHeader(false).value).isTrue()
65+
}
66+
3867
@Test
3968
fun `returns list screen when only one payment method available with saved payment methods`() = runScenario(
4069
paymentMethodMetadata = PaymentMethodMetadataFactory.create(

0 commit comments

Comments
 (0)