Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(POM-418): Dynamic Checkout success screen #232

Merged
merged 9 commits into from
Oct 18, 2024
1 change: 1 addition & 0 deletions sdk/src/main/res/values-ar/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<string name="po_dynamic_checkout_warning_redirect">سيتم إعادة توجيهك لإتمام هذه الدفعة.</string>
<string name="po_dynamic_checkout_error_generic">لم نتمكن من إتمام دفعتك. يرجى التحقق من التفاصيل أو تجربة طريقة دفع أخرى.</string>
<string name="po_dynamic_checkout_error_method_unavailable">طريقة الدفع المطلوبة غير متاحة، يرجى تجربة طريقة دفع أخرى.</string>
<string name="po_dynamic_checkout_success_message">نجاح! تمت الموافقة على الدفع</string>

<!-- Native Alternative Payment Method -->
<string name="po_native_apm_title_format">الدفع بواسطة %s</string>
Expand Down
1 change: 1 addition & 0 deletions sdk/src/main/res/values-fr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<string name="po_dynamic_checkout_warning_redirect">Vous serez redirigé pour finaliser ce paiement.</string>
<string name="po_dynamic_checkout_error_generic">Nous n\'avons pas pu finaliser votre paiement. Veuillez vérifier vos informations ou essayer un autre mode de paiement.</string>
<string name="po_dynamic_checkout_error_method_unavailable">Le mode de paiement demandé n\'est pas disponible, veuillez essayer un autre mode de paiement.</string>
<string name="po_dynamic_checkout_success_message">Succès !\nPaiement confirmé.</string>

<!-- Native Alternative Payment Method -->
<string name="po_native_apm_title_format">Payer avec %s</string>
Expand Down
1 change: 1 addition & 0 deletions sdk/src/main/res/values-pl/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<string name="po_dynamic_checkout_warning_redirect">Zostaniesz przekierowany, aby sfinalizować tę płatność.</string>
<string name="po_dynamic_checkout_error_generic">Nie byliśmy w stanie sfinalizować Twojej płatności. Zweryfikuj swoje dane lub wybierz inną metody płatności.</string>
<string name="po_dynamic_checkout_error_method_unavailable">Wybrana metoda płatności nie jest obsługiwana. Proszę wybierz inną metodę.</string>
<string name="po_dynamic_checkout_success_message">Sukces!\nPłatność przyjęta.</string>

<!-- Native Alternative Payment Method -->
<string name="po_native_apm_title_format">Zapłać przy pomocy %s</string>
Expand Down
1 change: 1 addition & 0 deletions sdk/src/main/res/values-pt/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<string name="po_dynamic_checkout_warning_redirect">Será redireccionado para finalizar este pagamento.</string>
<string name="po_dynamic_checkout_error_generic">Não foi possível concluir o seu pagamento. Por favor, verifique os detalhes ou tente outro método de pagamento.</string>
<string name="po_dynamic_checkout_error_method_unavailable">O método de pagamento escolhido não está disponível, por favor tente outro método de pagamento.</string>
<string name="po_dynamic_checkout_success_message">Successo!\nPagamento aprovado.</string>

<!-- Native Alternative Payment Method -->
<string name="po_native_apm_title_format">Pagar com %s</string>
Expand Down
1 change: 1 addition & 0 deletions sdk/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<string name="po_dynamic_checkout_warning_redirect">You will be redirected to finalise this payment.</string>
<string name="po_dynamic_checkout_error_generic">We were unable to process your payment. Please check your payment details or try another payment method.</string>
<string name="po_dynamic_checkout_error_method_unavailable">The requested payment method is not available, please try another payment method.</string>
<string name="po_dynamic_checkout_success_message">Success!\nPayment approved.</string>

<!-- Native Alternative Payment Method -->
<string name="po_native_apm_title_format">Pay with %s</string>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.processout.sdk.ui.checkout

import android.app.Application
import android.os.Handler
import android.os.Looper
import androidx.core.os.postDelayed
import coil.imageLoader
import coil.request.CachePolicy
import coil.request.ImageRequest
Expand Down Expand Up @@ -87,6 +90,8 @@ internal class DynamicCheckoutInteractor(
private val _submitEvents = Channel<DynamicCheckoutSubmitEvent>()
val submitEvents = _submitEvents.receiveAsFlow()

private val handler = Handler(Looper.getMainLooper())

private var latestInvoiceRequest: PODynamicCheckoutInvoiceRequest? = null

init {
Expand Down Expand Up @@ -155,7 +160,7 @@ internal class DynamicCheckoutInteractor(
.onSuccess { invoice ->
when (invoice.transaction?.status()) {
WAITING -> setStartedState(invoice)
AUTHORIZED, COMPLETED -> _completion.update { Success }
AUTHORIZED, COMPLETED -> handleSuccess()
else -> _completion.update {
Failure(
ProcessOutResult.Failure(
Expand Down Expand Up @@ -404,8 +409,12 @@ internal class DynamicCheckoutInteractor(
// TODO
}
is Dismiss -> {
POLogger.warn("Dismissed: %s", event.failure)
_completion.update { Failure(event.failure) }
if (_state.value.delayedSuccess) {
_completion.update { Success }
} else {
POLogger.warn("Dismissed: %s", event.failure)
_completion.update { Failure(event.failure) }
}
}
}
}
Expand Down Expand Up @@ -594,6 +603,29 @@ internal class DynamicCheckoutInteractor(
}
}

fun handleGooglePay(result: ProcessOutResult<POGooglePayCardTokenizationData>) {
result.onSuccess { response ->
authorizeInvoice(source = response.card.id)
}.onFailure { failure ->
invalidateInvoice(
reason = PODynamicCheckoutInvoiceInvalidationReason.Failure(failure)
)
}
}

fun handleAlternativePayment(result: ProcessOutResult<POAlternativePaymentMethodResponse>) {
result.onSuccess { response ->
authorizeInvoice(
source = response.gatewayToken,
allowFallbackToSale = true
)
}.onFailure { failure ->
invalidateInvoice(
reason = PODynamicCheckoutInvoiceInvalidationReason.Failure(failure)
)
}
}

private fun cancel() {
_completion.update {
Failure(
Expand Down Expand Up @@ -735,7 +767,7 @@ internal class DynamicCheckoutInteractor(
cardTokenizationEventDispatcher.complete(result)
} else {
result.onSuccess {
_completion.update { Success }
handleSuccess()
}.onFailure { failure ->
invalidateInvoice(
reason = PODynamicCheckoutInvoiceInvalidationReason.Failure(failure)
Expand All @@ -750,7 +782,7 @@ internal class DynamicCheckoutInteractor(
interactorScope.launch {
cardTokenization.completion.collect { completion ->
when (completion) {
is CardTokenizationCompletion.Success -> _completion.update { Success }
is CardTokenizationCompletion.Success -> handleSuccess()
is CardTokenizationCompletion.Failure -> invalidateInvoice(
reason = PODynamicCheckoutInvoiceInvalidationReason.Failure(completion.failure)
)
Expand All @@ -761,7 +793,7 @@ internal class DynamicCheckoutInteractor(
interactorScope.launch {
nativeAlternativePayment.completion.collect { completion ->
when (completion) {
NativeAlternativePaymentCompletion.Success -> _completion.update { Success }
NativeAlternativePaymentCompletion.Success -> handleSuccess()
is NativeAlternativePaymentCompletion.Failure -> invalidateInvoice(
reason = PODynamicCheckoutInvoiceInvalidationReason.Failure(completion.failure)
)
Expand All @@ -771,30 +803,17 @@ internal class DynamicCheckoutInteractor(
}
}

fun handleGooglePay(result: ProcessOutResult<POGooglePayCardTokenizationData>) {
result.onSuccess { response ->
authorizeInvoice(source = response.card.id)
}.onFailure { failure ->
invalidateInvoice(
reason = PODynamicCheckoutInvoiceInvalidationReason.Failure(failure)
)
}
}

fun handleAlternativePayment(result: ProcessOutResult<POAlternativePaymentMethodResponse>) {
result.onSuccess { response ->
authorizeInvoice(
source = response.gatewayToken,
allowFallbackToSale = true
)
}.onFailure { failure ->
invalidateInvoice(
reason = PODynamicCheckoutInvoiceInvalidationReason.Failure(failure)
)
}
private fun handleSuccess() {
configuration.paymentSuccess?.let { paymentSuccess ->
_state.update { it.copy(delayedSuccess = true) }
handler.postDelayed(delayInMillis = paymentSuccess.durationSeconds * 1000L) {
_completion.update { Success }
}
} ?: _completion.update { Success }
}

fun onCleared() {
threeDSService.close()
handler.removeCallbacksAndMessages(null)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ internal data class DynamicCheckoutInteractorState(
val selectedPaymentMethodId: String? = null,
val processingPaymentMethodId: String? = null,
val pendingSubmitPaymentMethodId: String? = null,
val errorMessage: String? = null
val errorMessage: String? = null,
val delayedSuccess: Boolean = false
) {

sealed interface PaymentMethod {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,12 @@ internal class DynamicCheckoutViewModel private constructor(
Started(
expressPayments = expressPayments(interactorState),
regularPayments = regularPayments(interactorState, cardTokenizationState, nativeAlternativePaymentState),
cancelAction = cancelAction,
errorMessage = interactorState.errorMessage
cancelAction = if (interactorState.delayedSuccess) null else cancelAction,
errorMessage = interactorState.errorMessage,
successMessage = if (interactorState.delayedSuccess) {
configuration.paymentSuccess?.message
?: app.getString(R.string.po_dynamic_checkout_success_message)
} else null
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,8 @@ internal sealed interface DynamicCheckoutViewModelState {
val expressPayments: POImmutableList<ExpressPayment>,
val regularPayments: POImmutableList<RegularPayment>,
val cancelAction: POActionState?,
val errorMessage: String? = null
) : DynamicCheckoutViewModelState

@Immutable
data class Success(
val message: String
val errorMessage: String? = null,
val successMessage: String? = null
) : DynamicCheckoutViewModelState

//endregion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ data class PODynamicCheckoutConfiguration(
val alternativePayment: AlternativePaymentConfiguration = AlternativePaymentConfiguration(),
val submitButtonText: String? = null,
val cancelButton: CancelButton? = CancelButton(),
val paymentSuccess: PaymentSuccess? = PaymentSuccess(),
val style: Style? = null
) : Parcelable {

Expand Down Expand Up @@ -113,6 +114,12 @@ data class PODynamicCheckoutConfiguration(
val confirmation: POActionConfirmationConfiguration? = null
) : Parcelable

@Parcelize
data class PaymentSuccess(
val message: String? = null,
val durationSeconds: Int = 3
) : Parcelable

@Parcelize
data class Style(
val googlePayButton: POGooglePayButtonStyle? = null,
Expand All @@ -134,7 +141,8 @@ data class PODynamicCheckoutConfiguration(
@ColorRes
val progressIndicatorColorResId: Int? = null,
@ColorRes
val controlsTintColorResId: Int? = null
val controlsTintColorResId: Int? = null,
val paymentSuccess: PaymentSuccessStyle? = null
) : Parcelable

@Parcelize
Expand All @@ -145,4 +153,13 @@ data class PODynamicCheckoutConfiguration(
@DrawableRes
val descriptionIconResId: Int? = null
) : Parcelable

@Parcelize
data class PaymentSuccessStyle(
val message: POTextStyle,
@DrawableRes
val successImageResId: Int? = null,
@ColorRes
val backgroundColorResId: Int? = null
) : Parcelable
}
Loading
Loading