Skip to content

Commit

Permalink
[MOBILESDK-2685] Add “Set as default” checkbox to new bank account fo…
Browse files Browse the repository at this point in the history
…rm (#10248)

* add setAsDefaultPaymentMethod to usbankaccount form

* tests

* lint

* CI paparazzi

* isPaymentMethodSetAsDefaultEnabled to shouldShowSetAsDefaultCheckbox

* addressing comments

* remove skip items for another assert
  • Loading branch information
tianzhao-stripe authored Feb 21, 2025
1 parent 4e152d5 commit 3c2f7db
Show file tree
Hide file tree
Showing 15 changed files with 503 additions and 399 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.stripe.android.ui.core.elements

import androidx.annotation.RestrictTo
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
Expand All @@ -10,7 +11,8 @@ import com.stripe.android.uicore.utils.collectAsState
internal const val SET_AS_DEFAULT_PAYMENT_METHOD_TEST_TAG = "SET_AS_DEFAULT_PAYMENT_METHOD_TEST_TAG"

@Composable
internal fun SetAsDefaultPaymentMethodElementUI(
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun SetAsDefaultPaymentMethodElementUI(
enabled: Boolean,
element: SetAsDefaultPaymentMethodElement,
modifier: Modifier = Modifier,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -837,7 +837,8 @@ internal class CustomerSheetViewModel(
onUpdatePrimaryButtonState = { /* no-op, CustomerSheetScreen does not use PrimaryButton.State */ },
onError = { error ->
handleViewAction(CustomerSheetViewAction.OnFormError(error))
}
},
shouldShowSetAsDefaultCheckbox = false,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import com.stripe.android.paymentsheet.ui.Mandate
import com.stripe.android.paymentsheet.ui.PromoBadge
import com.stripe.android.ui.core.elements.SaveForFutureUseElement
import com.stripe.android.ui.core.elements.SaveForFutureUseElementUI
import com.stripe.android.ui.core.elements.SetAsDefaultPaymentMethodElement
import com.stripe.android.ui.core.elements.SetAsDefaultPaymentMethodElementUI
import com.stripe.android.ui.core.elements.SimpleDialogElementUI
import com.stripe.android.uicore.elements.AddressController
import com.stripe.android.uicore.elements.AddressElementUI
Expand Down Expand Up @@ -86,6 +88,7 @@ internal fun USBankAccountForm(
onBehalfOf = usBankAccountFormArgs.onBehalfOf,
savedPaymentMethod = usBankAccountFormArgs.draftPaymentSelection as? New.USBankAccount,
shippingDetails = usBankAccountFormArgs.shippingDetails,
shouldShowSetAsDefaultCheckbox = usBankAccountFormArgs.shouldShowSetAsDefaultCheckbox
)
},
)
Expand All @@ -104,14 +107,15 @@ internal fun USBankAccountForm(
formArgs = formArgs,
instantDebits = usBankAccountFormArgs.instantDebits,
isPaymentFlow = usBankAccountFormArgs.isPaymentFlow,
showCheckbox = usBankAccountFormArgs.showCheckbox,
showCheckboxes = usBankAccountFormArgs.showCheckbox,
nameController = viewModel.nameController,
emailController = viewModel.emailController,
phoneController = viewModel.phoneController,
addressController = viewModel.addressElement.controller,
lastTextFieldIdentifier = lastTextFieldIdentifier,
sameAsShippingElement = viewModel.sameAsShippingElement,
saveForFutureUseElement = viewModel.saveForFutureUseElement,
setAsDefaultPaymentMethodElement = viewModel.setAsDefaultPaymentMethodElement,
onRemoveAccount = viewModel::reset,
modifier = modifier,
enabled = isEnabled
Expand All @@ -124,14 +128,15 @@ internal fun BankAccountForm(
formArgs: FormArguments,
instantDebits: Boolean,
isPaymentFlow: Boolean,
showCheckbox: Boolean,
showCheckboxes: Boolean,
nameController: TextFieldController,
emailController: TextFieldController,
phoneController: PhoneNumberController,
addressController: AddressController,
lastTextFieldIdentifier: IdentifierSpec?,
sameAsShippingElement: SameAsShippingElement?,
saveForFutureUseElement: SaveForFutureUseElement,
setAsDefaultPaymentMethodElement: SetAsDefaultPaymentMethodElement,
modifier: Modifier = Modifier,
enabled: Boolean,
onRemoveAccount: () -> Unit,
Expand All @@ -153,11 +158,12 @@ internal fun BankAccountForm(
state.linkedBankAccount?.let { linkedBankAccount ->
AccountDetailsForm(
modifier = Modifier.padding(top = 16.dp),
showCheckbox = showCheckbox,
showCheckboxes = showCheckboxes,
bankName = linkedBankAccount.bankName,
last4 = linkedBankAccount.last4,
promoBadgeState = state.promoBadgeState,
saveForFutureUseElement = saveForFutureUseElement,
setAsDefaultPaymentMethodElement = setAsDefaultPaymentMethodElement,
onRemoveAccount = onRemoveAccount,
enabled = enabled
)
Expand Down Expand Up @@ -366,16 +372,16 @@ private fun AddressSection(
@Composable
private fun AccountDetailsForm(
modifier: Modifier = Modifier,
showCheckbox: Boolean,
showCheckboxes: Boolean,
enabled: Boolean,
bankName: String?,
last4: String?,
promoBadgeState: PromoBadgeState?,
saveForFutureUseElement: SaveForFutureUseElement,
setAsDefaultPaymentMethodElement: SetAsDefaultPaymentMethodElement,
onRemoveAccount: () -> Unit,
) {
var openDialog by rememberSaveable { mutableStateOf(false) }
val bankIcon = remember(bankName) { TransformToBankIcon(bankName) }

Column(
modifier
Expand All @@ -387,89 +393,133 @@ private fun AccountDetailsForm(
modifier = Modifier.padding(bottom = 8.dp)
)

SectionCard(modifier = Modifier.fillMaxWidth()) {
Row(
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 56.dp)
.padding(vertical = 12.dp)
.padding(start = 16.dp)
.padding(end = 8.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.weight(1f)
) {
Image(
painter = painterResource(bankIcon),
contentDescription = null,
modifier = Modifier.size(24.dp),
)

Text(
text = "$bankName •••• $last4",
color = MaterialTheme.stripeColors.onComponent,
overflow = TextOverflow.Ellipsis,
modifier = Modifier
.alpha(if (!enabled) 0.5f else 1f)
.weight(1f, fill = false),
)

promoBadgeState?.let { badgeState ->
PromoBadge(
text = badgeState.promoText,
eligible = badgeState.eligible,
)
}
}

IconButton(
enabled = enabled,
onClick = { openDialog = true },
modifier = Modifier.size(24.dp),
) {
Icon(
painter = painterResource(StripeR.drawable.stripe_ic_clear),
contentDescription = null,
)
}
BankAccountDetails(
enabled = enabled,
bankName = bankName,
last4 = last4,
promoBadgeState = promoBadgeState,
onIconButtonClick = {
openDialog = true
}
}
if (showCheckbox) {
)
if (showCheckboxes) {
SaveForFutureUseElementUI(
enabled = true,
element = saveForFutureUseElement,
modifier = Modifier.padding(top = 8.dp)
)

SetAsDefaultPaymentMethodElementUI(
enabled = true,
element = setAsDefaultPaymentMethodElement,
modifier = Modifier.padding(top = 8.dp),
)
}
}

if (openDialog && last4 != null) {
SimpleDialogElementUI(
titleText = stringResource(
id = R.string.stripe_paymentsheet_remove_bank_account_title
),
messageText = stringResource(
id = R.string.stripe_bank_account_ending_in,
last4
),
confirmText = stringResource(
id = StripeR.string.stripe_remove
),
dismissText = stringResource(
id = StripeR.string.stripe_cancel
),
destructive = true,
onConfirmListener = {
AccountDetailsRemoveBankDialog(
onDismiss = {
openDialog = false
},
onRemoveAccount = {
onRemoveAccount()
},
onDismissListener = {
openDialog = false
}
last4 = last4
)
}
}

@Composable
private fun BankAccountDetails(
bankName: String?,
enabled: Boolean,
last4: String?,
promoBadgeState: PromoBadgeState?,
onIconButtonClick: () -> Unit,
) {
val bankIcon = remember(bankName) { TransformToBankIcon(bankName) }

SectionCard(modifier = Modifier.fillMaxWidth()) {
Row(
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 56.dp)
.padding(vertical = 12.dp)
.padding(start = 16.dp)
.padding(end = 8.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.weight(1f)
) {
Image(
painter = painterResource(bankIcon),
contentDescription = null,
modifier = Modifier.size(24.dp),
)

Text(
text = "$bankName •••• $last4",
color = MaterialTheme.stripeColors.onComponent,
overflow = TextOverflow.Ellipsis,
modifier = Modifier
.alpha(if (!enabled) 0.5f else 1f)
.weight(1f, fill = false),
)

promoBadgeState?.let { badgeState ->
PromoBadge(
text = badgeState.promoText,
eligible = badgeState.eligible,
)
}
}

IconButton(
enabled = enabled,
onClick = { onIconButtonClick() },
modifier = Modifier.size(24.dp),
) {
Icon(
painter = painterResource(StripeR.drawable.stripe_ic_clear),
contentDescription = null,
)
}
}
}
}

@Composable
private fun AccountDetailsRemoveBankDialog(
onDismiss: () -> Unit,
onRemoveAccount: () -> Unit,
last4: String,
) {
SimpleDialogElementUI(
titleText = stringResource(
id = R.string.stripe_paymentsheet_remove_bank_account_title
),
messageText = stringResource(
id = R.string.stripe_bank_account_ending_in,
last4
),
confirmText = stringResource(
id = StripeR.string.stripe_remove
),
dismissText = stringResource(
id = StripeR.string.stripe_cancel
),
destructive = true,
onConfirmListener = {
onDismiss()
onRemoveAccount()
},
onDismissListener = {
onDismiss()
}
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.stripe.android.paymentsheet.paymentdatacollection.ach

import com.stripe.android.core.strings.ResolvableString
import com.stripe.android.lpmfoundations.luxe.isSaveForFutureUseValueChangeable
import com.stripe.android.lpmfoundations.paymentmethod.IS_PAYMENT_METHOD_SET_AS_DEFAULT_ENABLED_DEFAULT_VALUE
import com.stripe.android.lpmfoundations.paymentmethod.PaymentMethodMetadata
import com.stripe.android.model.LinkMode
import com.stripe.android.model.PaymentIntent
Expand Down Expand Up @@ -58,6 +59,7 @@ internal class USBankAccountFormArguments(
val onUpdatePrimaryButtonUIState: ((PrimaryButton.UIState?) -> (PrimaryButton.UIState?)) -> Unit,
val onUpdatePrimaryButtonState: (PrimaryButton.State) -> Unit,
val onError: (ResolvableString?) -> Unit,
val shouldShowSetAsDefaultCheckbox: Boolean
) {
companion object {
fun create(
Expand Down Expand Up @@ -101,6 +103,9 @@ internal class USBankAccountFormArguments(
onUpdatePrimaryButtonState = viewModel::updatePrimaryButtonState,
onError = viewModel::onError,
incentive = paymentMethodMetadata.paymentMethodIncentive,
shouldShowSetAsDefaultCheckbox =
paymentMethodMetadata.customerMetadata?.isPaymentMethodSetAsDefaultEnabled
?: IS_PAYMENT_METHOD_SET_AS_DEFAULT_ENABLED_DEFAULT_VALUE,
)
}

Expand Down Expand Up @@ -145,6 +150,9 @@ internal class USBankAccountFormArguments(
},
onError = onError,
incentive = paymentMethodMetadata.paymentMethodIncentive,
shouldShowSetAsDefaultCheckbox =
paymentMethodMetadata.customerMetadata?.isPaymentMethodSetAsDefaultEnabled
?: IS_PAYMENT_METHOD_SET_AS_DEFAULT_ENABLED_DEFAULT_VALUE,
)
}
}
Expand Down
Loading

0 comments on commit 3c2f7db

Please sign in to comment.