Skip to content

Commit

Permalink
Adding standalone payment mode
Browse files Browse the repository at this point in the history
  • Loading branch information
alleus committed Nov 8, 2023
1 parent 05c195f commit 0a0cba7
Show file tree
Hide file tree
Showing 18 changed files with 713 additions and 46 deletions.
91 changes: 84 additions & 7 deletions Example-app.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions Example-app/Base.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//General
"general_checkout" = "Checkout";

// Stand-alone URL View Controller
"stand_alone_url_payment_successful" = "Payment completed";
"stand_alone_url_payment_cancelled" = "Payment cancelled";

"stand_alone_url_payment_view_checkout_url" = "View checkout URL";
"stand_alone_url_payment_base_url" = "Base URL";
"stand_alone_url_payment_complete_url" = "Complete URL";
"stand_alone_url_payment_cancel_url" = "Cancel URL";
"stand_alone_url_payment_checkout_v3" = "Use Checkout V3";
"stand_alone_url_payment_payment_url" = "Payment URL";
"stand_alone_url_payment_payment_url_scheme" = "swedbankexample://";
145 changes: 109 additions & 36 deletions Example-app/Base.lproj/Main.storyboard

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions Example-app/Extensions/String+Localize.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Foundation

extension String {
var localize: String {
return NSLocalizedString(self, comment: "")
}

func localize(_ arguments: CVarArg...) -> String {
return String(format: self.localize, arguments: arguments)
}
}
6 changes: 3 additions & 3 deletions Example-app/Images.xcassets/Contents.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"images" : [
{
"filename" : "download-2.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "original"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"images" : [
{
"filename" : "download.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "original"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions Example-app/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
<false/>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>Scanning QR codes</string>
<key>UIAppFonts</key>
<array>
<string>IBMPlexMono-Medium.ttf</string>
Expand Down
23 changes: 23 additions & 0 deletions Example-app/Models/ScanUrl.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
enum ScanUrl: String {
case checkout
case base
case complete
case cancel
case payment
case unknown

func toKey() -> StorageHelper.Key? {
switch self {
case .base:
return .baseUrl
case .complete:
return .completeUrl
case .cancel:
return .cancelUrl
case .payment:
return .paymentUrl
default:
return nil
}
}
}
29 changes: 29 additions & 0 deletions Example-app/Utilities/StorageHelper.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Foundation

struct StorageHelper {

enum Key: String, CaseIterable {
case baseUrl
case completeUrl
case cancelUrl
case useCheckoutV3
case paymentUrl

var storageString: String {
return "Storage\(self.rawValue)"
}
}

static let shared = StorageHelper()

private let store = UserDefaults.standard

// MARK: Generic methods
func save<T>(value: T, forKey key: Key) {
store.set(value, forKey: key.storageString)
}

func value<T>(for key: Key) -> T? {
return store.value(forKey: key.storageString) as? T
}
}
36 changes: 36 additions & 0 deletions Example-app/Utilities/SwedbankPayConfiguration.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Foundation
import SwedbankPaySDK

enum SwedbankPayConfigurationError: Error {
case notImplemented
}

class SwedbankPayConfiguration {
let orderInfo: SwedbankPaySDK.ViewPaymentOrderInfo

init(isV3: Bool = true, webViewBaseURL: URL?,
viewPaymentLink: URL, completeUrl: URL, cancelUrl: URL?,
paymentUrl: URL? = nil, termsOfServiceUrl: URL? = nil) {
self.orderInfo = SwedbankPaySDK.ViewPaymentOrderInfo(
isV3: isV3,
webViewBaseURL: webViewBaseURL,
viewPaymentLink: viewPaymentLink,
completeUrl: completeUrl,
cancelUrl: cancelUrl,
paymentUrl: paymentUrl,
termsOfServiceUrl: termsOfServiceUrl
)
}
}

extension SwedbankPayConfiguration: SwedbankPaySDKConfiguration {

// This delegate method is not used but required
func postConsumers(consumer: SwedbankPaySDK.Consumer?, userData: Any?, completion: @escaping (Result<SwedbankPaySDK.ViewConsumerIdentificationInfo, Error>) -> Void) {
completion(.failure(SwedbankPayConfigurationError.notImplemented))
}

func postPaymentorders(paymentOrder: SwedbankPaySDK.PaymentOrder?, userData: Any?, consumerProfileRef: String?, options: SwedbankPaySDK.VersionOptions, completion: @escaping (Result<SwedbankPaySDK.ViewPaymentOrderInfo, Error>) -> Void) {
completion(.success(orderInfo))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Foundation
import SwiftUI
import UIKit

class PaymentAlternativesViewController: UIViewController {

@IBSegueAction func showStandaloneUrlView(_ coder: NSCoder) -> UIViewController? {
return UIHostingController(coder: coder, rootView: StandaloneUrlView())
}
}
85 changes: 85 additions & 0 deletions Example-app/ViewModels/StandaloneUrlViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import Foundation
import SwedbankPaySDK

extension StandaloneUrlView {
class StandaloneUrlViewModel: ObservableObject, SwedbankPaySDKDelegate {
@Published var viewCheckoutUrl: String = ""
@Published var baseUrl: String
@Published var completeUrl: String
@Published var cancelUrl: String
@Published var useCheckoutV3: Bool

@Published var paymentUrlAuthorityAndPath: String
@Published var paymentUrlScheme: String

@Published var displaySwedbankPayController: Bool = false
@Published var displayScannerSheet: Bool = false

@Published var paymentResultIcon: String?
@Published var paymentResultMessage: String?

init() {
baseUrl = String(StorageHelper.shared.value(for: .baseUrl) ?? "")
completeUrl = String(StorageHelper.shared.value(for: .completeUrl) ?? "")
cancelUrl = String(StorageHelper.shared.value(for: .cancelUrl) ?? "")
useCheckoutV3 = Bool(StorageHelper.shared.value(for: .useCheckoutV3) ?? true)
paymentUrlAuthorityAndPath = String(StorageHelper.shared.value(for: .paymentUrl) ?? "")
paymentUrlScheme = "stand_alone_url_payment_payment_url_scheme".localize
}

var isCheckoutEnabled: Bool {
return !viewCheckoutUrl.isEmpty && !completeUrl.isEmpty
}

func configurePayment() -> SwedbankPayConfiguration? {
guard let viewCheckoutUrl = URL(string: viewCheckoutUrl), let completeUrl = URL(string: completeUrl) else {
return nil
}

StorageHelper.shared.save(value: baseUrl, forKey: .baseUrl)
StorageHelper.shared.save(value: self.completeUrl, forKey: .completeUrl)
StorageHelper.shared.save(value: cancelUrl, forKey: .cancelUrl)
StorageHelper.shared.save(value: useCheckoutV3, forKey: .useCheckoutV3)
StorageHelper.shared.save(value: paymentUrlAuthorityAndPath, forKey: .paymentUrl)

let paymentUrl = paymentUrlScheme+paymentUrlAuthorityAndPath

let configuration = SwedbankPayConfiguration(
isV3: useCheckoutV3,
webViewBaseURL: URL(string: baseUrl),
viewPaymentLink: viewCheckoutUrl,
completeUrl: completeUrl,
cancelUrl: URL(string: cancelUrl),
paymentUrl: URL(string: paymentUrl)
)

return configuration
}

func saveUrl(urlType: ScanUrl, url: String) {
if let key = urlType.toKey() {
StorageHelper.shared.save(value: url, forKey: key)
}
}

private func setPaymentResult(success: Bool, resultText: String) {
paymentResultIcon = success ? "payment_success_icon" : "payment_failed_icon"

paymentResultMessage = resultText

displaySwedbankPayController = false
}

func paymentComplete() {
setPaymentResult(success: true, resultText: "stand_alone_url_payment_successful".localize)
}

func paymentFailed(error: Error) {
setPaymentResult(success: false, resultText: error.localizedDescription)
}

func paymentCanceled() {
setPaymentResult(success: false, resultText: "stand_alone_url_payment_cancelled".localize)
}
}
}
Loading

0 comments on commit 0a0cba7

Please sign in to comment.