Skip to content

Commit

Permalink
Display confirmation popup before triggering payment in PreselectedSt…
Browse files Browse the repository at this point in the history
…oredPaymentMethodFragment

COAND-974
  • Loading branch information
ozgur00 committed Dec 2, 2024
1 parent 3c134f9 commit 3a20952
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ internal class PaymentMethodAdapter @JvmOverloads constructor(
val title: String,
val subtitle: String?,
val imageId: String,
val environment: Environment
val environment: Environment,
val popUpMessage: String?
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,10 @@ import com.adyen.checkout.core.internal.util.adyenLog
import com.adyen.checkout.dropin.R
import com.adyen.checkout.dropin.databinding.FragmentPaymentMethodsListBinding
import com.adyen.checkout.dropin.internal.provider.getComponentFor
import com.adyen.checkout.dropin.internal.ui.model.GenericStoredModel
import com.adyen.checkout.dropin.internal.ui.model.PaymentMethodHeader
import com.adyen.checkout.dropin.internal.ui.model.PaymentMethodModel
import com.adyen.checkout.dropin.internal.ui.model.StoredACHDirectDebitModel
import com.adyen.checkout.dropin.internal.ui.model.StoredCardModel
import com.adyen.checkout.dropin.internal.ui.model.StoredPayByBankUSModel
import com.adyen.checkout.dropin.internal.ui.model.StoredPaymentMethodModel
import com.adyen.checkout.dropin.internal.ui.model.mapToStoredPaymentMethodItem
import com.adyen.checkout.ui.core.internal.ui.view.AdyenSwipeToRevealLayout
import com.adyen.checkout.ui.core.internal.util.PayButtonFormatter
import kotlinx.coroutines.flow.launchIn
Expand Down Expand Up @@ -215,14 +212,7 @@ internal class PaymentMethodListDialogFragment :
paymentMethodsListViewModel.onClickConfirmationButton()
}

val message = when (storedPaymentMethodModel) {
is StoredCardModel ->
requireActivity().getString(R.string.last_four_digits_format, storedPaymentMethodModel.lastFour)
is GenericStoredModel -> null
is StoredPayByBankUSModel -> storedPaymentMethodModel.name
is StoredACHDirectDebitModel ->
requireActivity().getString(R.string.last_four_digits_format, storedPaymentMethodModel.lastFour,)
}
val message = storedPaymentMethodModel.mapToStoredPaymentMethodItem(requireContext()).popUpMessage
dialog.setMessage(message)
dialog.show()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ internal class PreselectedStoredPaymentMethodFragment : DropInBottomSheetDialogF
protocol.showStoredComponentDialog(storedPaymentMethod, true)
}

is PreselectedStoredEvent.ShowConfirmationPopup -> {
showConfirmationPopup(event.paymentMethodName, event.storedPaymentMethodModel)
}

is PreselectedStoredEvent.RequestPaymentsCall -> {
protocol.requestPaymentsCall(event.state)
}
Expand Down Expand Up @@ -204,6 +208,33 @@ internal class PreselectedStoredPaymentMethodFragment : DropInBottomSheetDialogF
.show()
}

private fun showConfirmationPopup(paymentMethodName: String, storedPaymentMethodModel: StoredPaymentMethodModel) {
val dialog = AlertDialog.Builder(requireContext())
.setTitle(
String.format(
resources.getString(R.string.checkout_stored_payment_confirmation_message),
paymentMethodName,
),
)
.setNegativeButton(R.string.checkout_stored_payment_confirmation_cancel_button) { dialog, _ ->
dialog.dismiss()
}
.setPositiveButton(
PayButtonFormatter.getPayButtonText(
amount = dropInViewModel.dropInParams.amount,
locale = dropInViewModel.dropInParams.shopperLocale,
localizedContext = requireContext(),
),
) { dialog, _ ->
dialog.dismiss()
storedPaymentViewModel.onConfirmed()
}

val message = storedPaymentMethodModel.mapToStoredPaymentMethodItem(binding.root.context).popUpMessage
dialog.setMessage(message)
dialog.show()
}

override fun onBackPressed() = performBackAction()

private fun performBackAction(): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,19 @@ internal class PreselectedStoredPaymentViewModel(
} else {
// component does not require user input -> we should submit it directly instead of switching to a new
// screen
eventsChannel.trySend(PreselectedStoredEvent.RequestPaymentsCall(componentState))
eventsChannel.trySend(
PreselectedStoredEvent.ShowConfirmationPopup(
storedPaymentMethod.name.orEmpty(),
_uiStateFlow.value.storedPaymentMethodModel,
),
)
}
}

fun onConfirmed() {
val componentState = componentState ?: return
eventsChannel.trySend(PreselectedStoredEvent.RequestPaymentsCall(componentState))
}
}

internal data class PreselectedStoredState(
Expand All @@ -114,7 +124,12 @@ internal sealed class ButtonState {
}

internal sealed class PreselectedStoredEvent {
object ShowStoredPaymentScreen : PreselectedStoredEvent()
data object ShowStoredPaymentScreen : PreselectedStoredEvent()
data class ShowConfirmationPopup(
val paymentMethodName: String,
val storedPaymentMethodModel: StoredPaymentMethodModel
) : PreselectedStoredEvent()

data class RequestPaymentsCall(val state: PaymentComponentState<*>) : PreselectedStoredEvent()
data class ShowError(val componentError: ComponentError) : PreselectedStoredEvent()
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,31 +69,38 @@ internal fun StoredPaymentMethodModel.mapToStoredPaymentMethodItem(context: Cont
title = context.getString(R.string.last_four_digits_format, lastFour),
subtitle = DateUtils.parseDateToView(expiryMonth, expiryYear),
imageId = imageId,
environment = environment
environment = environment,
popUpMessage = context.getString(R.string.last_four_digits_format, lastFour),
)
}

is GenericStoredModel -> {
StoredPaymentMethodItem(
title = name,
subtitle = description,
imageId = imageId,
environment = environment
environment = environment,
popUpMessage = null,
)
}

is StoredPayByBankUSModel -> {
StoredPaymentMethodItem(
title = name,
subtitle = description,
imageId = imageId,
environment = environment
environment = environment,
popUpMessage = name,
)
}

is StoredACHDirectDebitModel -> {
StoredPaymentMethodItem(
title = context.getString(R.string.last_four_digits_format, lastFour),
subtitle = null,
imageId = imageId,
environment = environment
environment = environment,
popUpMessage = context.getString(R.string.last_four_digits_format, lastFour),
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import com.adyen.checkout.core.exception.CheckoutException
import com.adyen.checkout.dropin.dropIn
import com.adyen.checkout.dropin.internal.ui.model.DropInParamsMapper
import com.adyen.checkout.dropin.internal.ui.model.GenericStoredModel
import com.adyen.checkout.dropin.internal.util.mapStoredModel
import com.adyen.checkout.test.TestDispatcherExtension
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions.assertEquals
Expand Down Expand Up @@ -144,14 +145,36 @@ internal class PreselectedStoredPaymentViewModelTest {
}

@Test
fun `when button is clicked with a valid input then view model should request payments call`() =
fun `when button is clicked with a valid input then view model should display confirmation popup`() =
runTest {
viewModel.eventsFlow.test {
val componentState =
TestComponentState(PaymentComponentData(null, null, null), isInputValid = true, isReady = true)
viewModel.onStateChanged(componentState)
viewModel.onButtonClicked()

assertEquals(
PreselectedStoredEvent.ShowConfirmationPopup(
storedPaymentMethod.name.orEmpty(),
storedPaymentMethod.mapStoredModel(
dropInParams.isRemovingStoredPaymentMethodsEnabled,
dropInParams.environment,
),
),
awaitItem(),
)
}
}

@Test
fun `when confirmation button is clicked then view model should request payments call`() =
runTest {
viewModel.eventsFlow.test {
val componentState =
TestComponentState(PaymentComponentData(null, null, null), isInputValid = true, isReady = true)
viewModel.onStateChanged(componentState)
viewModel.onConfirmed()

assertEquals(PreselectedStoredEvent.RequestPaymentsCall(componentState), awaitItem())
}
}
Expand Down

0 comments on commit 3a20952

Please sign in to comment.