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 Nov 29, 2024
1 parent 3c134f9 commit 883d0a8
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ import com.adyen.checkout.core.internal.util.adyenLog
import com.adyen.checkout.dropin.R
import com.adyen.checkout.dropin.databinding.FragmentStoredPaymentMethodBinding
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.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.dropin.internal.util.arguments
Expand Down Expand Up @@ -170,6 +174,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 +212,40 @@ 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 = 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,)
}
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 @@ -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 883d0a8

Please sign in to comment.