Skip to content

Commit

Permalink
Merge branch 'refactor-integration-health-sdk' into IPC-401-replace-s…
Browse files Browse the repository at this point in the history
…hare-with-onboarding-screen
  • Loading branch information
razvancapra committed Nov 21, 2024
2 parents 154f6dc + 3d010f2 commit eb7c110
Show file tree
Hide file tree
Showing 15 changed files with 158 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ extension PaymentViewController {
errorLabel = recipientErrorLabel
case .ibanFieldTag:
errorLabel = ibanErrorLabel
errorMessage = NSLocalizedStringPreferredFormat("ginipaybusiness.errors.failed.iban.validation.check",
errorMessage = NSLocalizedStringPreferredFormat("ginipaybank.errors.failed.iban.validation.check",
comment: "iban failed validation check")
case .amountFieldTag:
errorLabel = amountErrorLabel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import UIKit
public enum PaymentComponentScreenType {
case paymentComponent
case bankPicker
case paymentReview
}

public struct PaymentComponentsConfiguration {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// UINavigationController.swift
//
// Copyright © 2024 Gini GmbH. All rights reserved.
//

import UIKit

extension UINavigationController {
public func pushViewController(viewController: UIViewController, animated: Bool, completion: @escaping () -> Void) {
pushViewController(viewController, animated: animated)

if animated, let coordinator = transitionCoordinator {
coordinator.animate(alongsideTransition: nil) { _ in
completion()
}
} else {
completion()
}
}

public func popViewController(animated: Bool, completion: @escaping () -> Void) {
popViewController(animated: animated)

if animated, let coordinator = transitionCoordinator {
coordinator.animate(alongsideTransition: nil) { _ in
completion()
}
} else {
completion()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,17 @@ public struct DataForReview {
public var paymentService: PaymentService
/// delegate to inform about the current status of the Gini Health SDK.
public weak var delegate: GiniHealthDelegate?
/// delegate to inform about the changes into PaymentComponentsController
public weak var paymentDelegate: PaymentComponentsControllerProtocol?

private var bankProviders: [PaymentProvider] = []

/// Configuration for the payment component, controlling its branding and display options.
public var paymentComponentConfiguration: PaymentComponentConfiguration = PaymentComponentConfiguration(isPaymentComponentBranded: true,
showPaymentComponentInOneRow: false,
hideInfoForReturningUser: (GiniHealthConfiguration.shared.showPaymentReviewScreen ? false : true))

public var paymentComponentsController: PaymentComponentsController!

/**
Initializes a new instance of GiniHealth.
Expand All @@ -96,6 +100,9 @@ public struct DataForReview {
self.giniApiLib = GiniHealthAPI.Builder(client: client, api: .default, logLevel: logLevel.toHealthLogLevel()).build()
self.documentService = DefaultDocumentService(docService: giniApiLib.documentService())
self.paymentService = giniApiLib.paymentService(apiDomain: APIDomain.default, apiVersion: apiVersion)
super.init()
self.paymentComponentsController = PaymentComponentsController(giniHealth: self)
self.paymentComponentsController.delegate = self
}

/**
Expand All @@ -107,8 +114,34 @@ public struct DataForReview {
self.giniApiLib = giniApiLib
self.documentService = DefaultDocumentService(docService: giniApiLib.documentService())
self.paymentService = giniApiLib.paymentService(apiDomain: .default, apiVersion: Constants.defaultVersionAPI)
super.init()
self.paymentComponentsController = PaymentComponentsController(giniHealth: self)
}

/**
Initiates the payment flow for a specified document and payment information.

- Parameters:
- documentId: An optional identifier for the document associated with the payment flow.
- paymentInfo: An optional `PaymentInfo` object containing the payment details.
- navigationController: The `UINavigationController` used to present subsequent view controllers in the payment flow.

This method sets up the payment flow by storing the provided document ID, payment information, and navigation controller.
If a `selectedPaymentProvider` is available, it either presents the payment review screen or the payment view bottom sheet,
depending on the configuration. If no payment provider is selected, it directly presents the payment view bottom sheet.
*/
public func startPaymentFlow(documentId: String?, paymentInfo: GiniHealthSDK.PaymentInfo?, navigationController: UINavigationController, trackingDelegate: GiniHealthTrackingDelegate?) {
paymentComponentsController.startPaymentFlow(documentId: documentId, paymentInfo: paymentInfo, navigationController: navigationController, trackingDelegate: trackingDelegate)
}

/**
Fetches bank logos for the available payment providers.

- Returns: A tuple containing an array of logo data and the count of additional banks, if any.
*/
public func fetchBankLogos() -> (logos: [Data]?, additionalBankCount: Int?) {
return paymentComponentsController.fetchBankLogos()
}
/**
Getting a list of the installed banking apps which support Gini Pay Connect functionality.

Expand Down Expand Up @@ -494,6 +527,18 @@ public struct DataForReview {
}
}

extension GiniHealth: PaymentComponentsControllerProtocol {
public func isLoadingStateChanged(isLoading: Bool) {
paymentDelegate?.isLoadingStateChanged(isLoading: isLoading)
}

public func didFetchedPaymentProviders() {
paymentDelegate?.didFetchedPaymentProviders()
}


}

extension GiniHealth {
public enum Constants {
public static let defaultVersionAPI = 4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ protocol PaymentProvidersBottomViewProtocol: AnyObject {
}

extension PaymentComponentsController {

// MARK: - Payment Provider Selection

/**
Expand Down Expand Up @@ -90,17 +89,15 @@ extension PaymentComponentsController {
}
}


// MARK: - Bottom sheets

/**
Provides a custom Gini for the payment view that is going to be presented as a bottom sheet.

- Parameter documentId: An optional identifier for the document associated with the payment.
- Returns: A configured `UIViewController` for displaying the payment bottom view.
*/
public func paymentViewBottomSheet(documentId: String?) -> UIViewController {
previousPresentedView = .paymentComponent
previousPresentedView = [.paymentComponent]
let paymentComponentBottomView = PaymentComponentBottomView(paymentView: paymentView(), bottomSheetConfiguration: configurationProvider.bottomSheetConfiguration)
return paymentComponentBottomView
}
Expand Down Expand Up @@ -153,7 +150,10 @@ extension PaymentComponentsController {
- Returns: A configured `UIViewController` for displaying the bank selection options.
*/
public func bankSelectionBottomSheet() -> UIViewController {
previousPresentedView = .bankPicker
if previousPresentedView.first != .paymentReview {
previousPresentedView.removeAll()
}
previousPresentedView.append(.bankPicker)
let paymentProvidersBottomViewModel = BanksBottomViewModel(paymentProviders: paymentProviders,
selectedPaymentProvider: healthSelectedPaymentProvider,
configuration: configurationProvider.bankSelectionConfiguration,
Expand Down Expand Up @@ -182,7 +182,7 @@ extension PaymentComponentsController {
`GiniHealthError` once the loading process is complete.
*/
func loadPaymentReviewScreenFor(trackingDelegate: GiniHealthTrackingDelegate?, completion: @escaping (UIViewController?, GiniHealthError?) -> Void) {
previousPresentedView = nil
previousPresentedView.append(.paymentReview)
if !GiniHealthConfiguration.shared.useInvoiceWithoutDocument {
guard let documentId else {
completion(nil, nil)
Expand All @@ -208,7 +208,6 @@ extension PaymentComponentsController {
}

private func loadPaymentReviewScreenWithoutDocument(paymentInfo: GiniInternalPaymentSDK.PaymentInfo?, trackingDelegate: GiniHealthTrackingDelegate?, completion: @escaping (UIViewController?, GiniHealthError?) -> Void) {
previousPresentedView = nil
preparePaymentReviewViewController(data: nil, paymentInfo: paymentInfo, completion: completion)
}

Expand Down Expand Up @@ -243,7 +242,6 @@ extension PaymentComponentsController {
completion(vc, nil)
}


/**
Provides a custom Gini view for displaying payment more information view.

Expand All @@ -270,7 +268,7 @@ extension PaymentComponentsController {
- Returns: A configured `BottomSheetViewController` for the app installation process.
*/
public func installAppBottomSheet() -> BottomSheetViewController {
previousPresentedView = nil
previousPresentedView.removeAll()
let installAppBottomViewModel = InstallAppBottomViewModel(selectedPaymentProvider: healthSelectedPaymentProvider,
installAppConfiguration: configurationProvider.installAppConfiguration,
strings: stringsProvider.installAppStrings,
Expand All @@ -293,7 +291,7 @@ extension PaymentComponentsController {
- Returns: A configured `BottomSheetViewController` for sharing invoices.
*/
public func shareInvoiceBottomSheet(qrCodeData: Data) -> BottomSheetViewController {
previousPresentedView = nil
previousPresentedView.removeAll()
let shareInvoiceBottomViewModel = ShareInvoiceBottomViewModel(selectedPaymentProvider: healthSelectedPaymentProvider,
configuration: configurationProvider.shareInvoiceConfiguration,
strings: stringsProvider.shareInvoiceStrings,
Expand All @@ -316,6 +314,9 @@ extension PaymentComponentsController {
*/
public func updatedPaymentProvider(_ paymentProvider: GiniHealthAPILibrary.PaymentProvider) {
self.selectedPaymentProvider = PaymentProvider(healthPaymentProvider: paymentProvider)
if let provider = selectedPaymentProvider {
storeDefaultPaymentProvider(paymentProvider: provider)
}
}

/**
Expand All @@ -328,19 +329,23 @@ extension PaymentComponentsController {
}

// MARK: - Other helpers

func setupObservers() {
NotificationCenter.default.addObserver(self, selector: #selector(paymentInfoDissapeared), name: .paymentInfoDissapeared, object: nil)
}

@objc
private func paymentInfoDissapeared() {
if previousPresentedView == .bankPicker {
didTapOnBankPicker()
} else if previousPresentedView == .paymentComponent {
didTapOnPayButton()
switch previousPresentedView.first {
case .bankPicker:
didTapOnBankPicker(documentId: documentId)
case .paymentComponent:
presentPaymentViewBottomSheet()
case .paymentReview:
didTapOnPayInvoice()
default:
break
}
previousPresentedView = nil
previousPresentedView.removeAll()
}

/// Checks if the payment provider app can be opened based on the selected payment provider and GPC(Gini Pay Connect) support.
Expand All @@ -353,7 +358,6 @@ extension PaymentComponentsController {
return false
}


/// Checks if the selected payment provider supports the "Open With" feature on iOS.
public func supportsOpenWith() -> Bool {
if healthSelectedPaymentProvider?.openWithSupportedPlatforms.contains(.ios) == true {
Expand Down Expand Up @@ -479,7 +483,6 @@ extension PaymentComponentsController {
}

// MARK: - Payment Review Screen functions

/**
Creates a payment request using the provided payment information.

Expand Down Expand Up @@ -604,9 +607,23 @@ extension PaymentComponentsController: PaymentComponentViewProtocol {
}

private func pushOrDismissAndPush(_ viewController: UIViewController) {
if let presentedVC = navigationControllerProvided?.presentedViewController {
if let doublePresentedVC = navigationControllerProvided?.presentedViewController?.presentedViewController {
doublePresentedVC.dismiss(animated: true) { [weak self] in
if let presentedVC = self?.navigationControllerProvided?.presentedViewController {
presentedVC.dismiss(animated: true) { [weak self] in
self?.navigationControllerProvided?.pushViewController(viewController, animated: true)
}
}
}
} else if let presentedVC = navigationControllerProvided?.presentedViewController {
presentedVC.dismiss(animated: true) { [weak self] in
self?.navigationControllerProvided?.pushViewController(viewController, animated: true)
if self?.navigationControllerProvided?.viewControllers.last is PaymentReviewViewController {
self?.navigationControllerProvided?.popViewController(animated: true, completion: {
self?.navigationControllerProvided?.pushViewController(viewController, animated: true)
})
} else {
self?.navigationControllerProvided?.pushViewController(viewController, animated: true)
}
}
} else {
navigationControllerProvided?.pushViewController(viewController, animated: true)
Expand All @@ -626,7 +643,7 @@ extension PaymentComponentsController: PaymentComponentViewProtocol {
/// Handles the action when the pay invoice button is tapped on the payment component view, using the provided document ID.
public func didTapOnPayInvoice(documentId: String?) {
GiniUtilites.Log("Tapped on Pay Invoice on :\(documentId ?? "")", event: .success)
if GiniHealthConfiguration.shared.showPaymentReviewScreen {
if GiniHealthConfiguration.shared.showPaymentReviewScreen || !GiniHealthConfiguration.shared.useInvoiceWithoutDocument {
loadPaymentReviewScreenFor(trackingDelegate: self) { [weak self] viewController, error in
if let error = error {
self?.handleError(error)
Expand Down Expand Up @@ -812,8 +829,6 @@ extension PaymentComponentsController: PaymentProvidersBottomViewProtocol {
}
}



extension PaymentComponentsController: ShareInvoiceBottomViewProtocol {
/// Notifies the delegate to continue sharing the invoice with the provided document ID.
public func didTapOnContinueToShareInvoice() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public final class PaymentComponentsController: BottomSheetsProviderProtocol, Gi
}

/// Previous presented view
var previousPresentedView: PaymentComponentScreenType?
var previousPresentedView: [PaymentComponentScreenType] = []
// Client's navigation controller provided in order to handle all HealthSDK flows
weak var navigationControllerProvided: UINavigationController?
// Payment Information from the invoice that contains a document or not
Expand Down Expand Up @@ -147,10 +147,14 @@ public final class PaymentComponentsController: BottomSheetsProviderProtocol, Gi
presentPaymentViewBottomSheet()
return
}
if GiniHealthConfiguration.shared.showPaymentReviewScreen {
didTapOnPayInvoice(documentId: documentId)
if GiniHealthConfiguration.shared.useInvoiceWithoutDocument {
if GiniHealthConfiguration.shared.showPaymentReviewScreen {
didTapOnPayInvoice(documentId: documentId)
} else {
presentPaymentViewBottomSheet()
}
} else {
presentPaymentViewBottomSheet()
didTapOnPayInvoice(documentId: documentId)
}
}

Expand Down Expand Up @@ -247,7 +251,7 @@ extension PaymentComponentsController: PaymentReviewProtocol {

- Returns: A tuple containing an array of logo data and the count of additional banks, if any.
*/
public func fetchBankLogos() -> (logos: [Data]?, additionalBankCount: Int?) {
func fetchBankLogos() -> (logos: [Data]?, additionalBankCount: Int?) {
guard !paymentProviders.isEmpty else { return ([], nil)}
let maxShownProviders = min(paymentProviders.count, 2)
let additionalBankCount = paymentProviders.count > 2 ? paymentProviders.count - 2 : nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ final class AppCoordinator: Coordinator {
}()

private lazy var health = GiniHealth(id: clientID, secret: clientPassword, domain: clientDomain)
private lazy var paymentComponentsController = PaymentComponentsController(giniHealth: health)

private lazy var giniHealthConfiguration: GiniHealthConfiguration = {
let configuration = GiniHealthConfiguration()
Expand Down Expand Up @@ -163,7 +162,7 @@ final class AppCoordinator: Coordinator {
domain: clientDomain),
documentMetadata: metadata,
hardcodedInvoicesController: HardcodedInvoicesController(),
paymentComponentController: paymentComponentsController)
paymentComponentController: health.paymentComponentsController)

screenAPICoordinator.delegate = self

Expand Down Expand Up @@ -315,12 +314,11 @@ final class AppCoordinator: Coordinator {
health.delegate = self

let invoicesListCoordinator = InvoicesListCoordinator()
paymentComponentsController = PaymentComponentsController(giniHealth: health)
health.paymentComponentConfiguration.isPaymentComponentBranded = isBrandedPaymentComponent
DispatchQueue.main.async {
invoicesListCoordinator.start(documentService: self.health.documentService,
hardcodedInvoicesController: HardcodedInvoicesController(),
paymentComponentsController: self.paymentComponentsController,
health: self.health,
invoices: invoices)
self.add(childCoordinator: invoicesListCoordinator)
self.rootViewController.present(invoicesListCoordinator.rootViewController, animated: true)
Expand All @@ -337,10 +335,9 @@ final class AppCoordinator: Coordinator {
health.delegate = self

let orderListCoordinator = OrderListCoordinator()
paymentComponentsController = PaymentComponentsController(giniHealth: health)
orderListCoordinator.start(documentService: health.documentService,
hardcodedOrdersController: HardcodedOrdersController(),
paymentComponentsController: paymentComponentsController,
health: health,
orders: orders)
add(childCoordinator: orderListCoordinator)
rootViewController.present(orderListCoordinator.rootViewController, animated: true)
Expand Down
Loading

0 comments on commit eb7c110

Please sign in to comment.