Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public final class PONativeAlternativePaymentComponent {

/// Cancels the ongoing payment.
public func cancel() {
interactor.cancel()
interactor.cancel(reason: .programmatic)
}

// MARK: - Internal
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// NativeAlternativePaymentCancellationReason.swift
// ProcessOut
//
// Created by Andrii Vysotskyi on 10.08.2026.
//

import Foundation

/// Describes the reason why the payment flow was cancelled.
enum NativeAlternativePaymentCancellationReason {

/// The customer explicitly cancelled the payment flow (for example, by tapping a Cancel button).
case customer

/// The payment flow was cancelled because the associated objects were released as part of the
/// lifecycle.
///
/// This commonly happens when the screen is dismissed, but it can also occur for other reasons
/// that result in the flow being deallocated.
case lifecycle

/// The payment flow was explicitly cancelled by the application code.
case programmatic
}
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,15 @@ final class NativeAlternativePaymentDefaultInteractor:
state = .redirecting(newState)
}

func didRequestCancelConfirmation() {
send(event: .didRequestCancelConfirmation)
}

override func cancel() {
cancel(reason: .programmatic)
}

func cancel(reason: NativeAlternativePaymentCancellationReason) {
switch state {
case .starting(let currentState):
currentState.task.cancel()
Expand All @@ -168,11 +176,12 @@ final class NativeAlternativePaymentDefaultInteractor:
default:
break
}
setFailureState(error: POFailure(message: "Alternative payment has been canceled.", code: .Mobile.cancelled))
}

func didRequestCancelConfirmation() {
send(event: .didRequestCancelConfirmation)
setFailureState(
error: POFailure(
message: "Alternative payment has been canceled. Reason: '\(reason)'.",
code: .Mobile.cancelled
)
)
}

// MARK: - Private Properties
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,7 @@ protocol NativeAlternativePaymentInteractor: Interactor<NativeAlternativePayment

/// Notifies interactor that user requested cancel confirmation.
func didRequestCancelConfirmation()

/// Explicitly cancels payment with specified reason.
func cancel(reason: NativeAlternativePaymentCancellationReason)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ final class DefaultNativeAlternativePaymentViewModel: ViewModel {
}

deinit {
Task { @MainActor [interactor] in interactor.cancel() }
Task { @MainActor [interactor] in interactor.cancel(reason: .lifecycle) }
}

// MARK: - NativeAlternativePaymentViewModel
Expand Down Expand Up @@ -413,7 +413,7 @@ final class DefaultNativeAlternativePaymentViewModel: ViewModel {
accessibilityLabel: configuration.title ?? defaultTitle,
confirmation: nil,
action: { [weak self] in
self?.interactor.cancel()
self?.interactor.cancel(reason: .customer)
}
)
return .button(viewModel)
Expand Down Expand Up @@ -833,7 +833,7 @@ final class DefaultNativeAlternativePaymentViewModel: ViewModel {
}
},
action: { [weak self] in
self?.interactor.cancel()
self?.interactor.cancel(reason: .customer)
}
)
return action
Expand Down
Loading