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

STPAddCardViewController with SwiftUI navigation bar buttons not showing #1601

Closed
zackperdue opened this issue Jul 6, 2020 · 6 comments
Closed
Assignees
Labels
triaged Issue has been reviewed by Stripe and is being tracked internally

Comments

@zackperdue
Copy link

Summary

I'm trying to convert STPAddCardViewController to work with SwiftUI. So far it renders ok with the exception of the NavigationBar items. I've wrapped it in a NavigationView when I present it in a sheet but nothing works.

Code to reproduce

import SwiftUI
import Stripe

struct AddCardView: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> STPAddCardViewController {
        let controller = STPAddCardViewController()
        controller.delegate = context.coordinator
        return controller
    }
    
    func updateUIViewController(_ uiViewController: STPAddCardViewController, context: Context) {
        
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, STPAddCardViewControllerDelegate, UINavigationControllerDelegate {
        var parent: AddCardView
        
        func addCardViewControllerDidCancel(_ addCardViewController: STPAddCardViewController) {
            
        }
        
        func addCardViewController(_ addCardViewController: STPAddCardViewController, didCreatePaymentMethod paymentMethod: STPPaymentMethod, completion: @escaping STPErrorBlock) {
            
        }
        
        init(_ parent: AddCardView) {
            self.parent = parent
        }
    }
}
HStack {
                        Image(systemName: "plus").foregroundColor(.gray)
                        Text("Add a payment method")
                        Spacer()
                        Button(action: {
                            self.showAddCardView.toggle()
                        }) {
                            Text("Add")
                        }
                    }.sheet(isPresented: $showAddCardView) {
                        NavigationView {
                            AddCardView()
                        }
                    }

iOS version

13.5

Installation method

Pods

SDK version

19.3.0

Screenshot

Screen Shot 2020-07-06 at 23 19 43

@csabol-stripe
Copy link
Contributor

csabol-stripe commented Jul 16, 2020

Hi @zackperdue , I've spent some time looking at this. I don't have a ton of SwiftUI experience so it's not totally clear what the intended behavior from Apple is here (maybe they haven't implemented UINavigationController -> NavigationView yet or maybe they are different conceptually?), but I was able to find a kind of hacky workaround:


  func updateUIViewController(_ uiViewController: STPAddCardViewController, context: Context) {
        if let navController = uiViewController.navigationController,
            let navItem = navController.navigationBar.topItem {
            navItem.title = uiViewController.title
            navItem.rightBarButtonItem = uiViewController.navigationItem.rightBarButtonItem
        }
    }

Let me know if this helps unblock you or if you think there's something else we could change in the Stripe SDK to help with this!

@csabol-stripe csabol-stripe added the triaged Issue has been reviewed by Stripe and is being tracked internally label Jul 16, 2020
@csabol-stripe csabol-stripe self-assigned this Jul 16, 2020
@IvanStanojevic
Copy link

@csabol-stripe any luck for this problem?

@IvanStanojevic
Copy link

@csabol-stripe
func updateUIViewController(_ uiViewController: STPAddCardViewController, context: Context) {
if let navController = uiViewController.navigationController,
let navItem = navController.navigationBar.topItem {
navItem.title = uiViewController.title
navItem.rightBarButtonItem = uiViewController.navigationItem.rightBarButtonItem
}
}

I tried this. but still I can't see title.
Please help me if you have any solutions.
Thanks

@zackperdue
Copy link
Author

Here is my solution. You just need to wrap the STPAddCardViewController controller with a UINavigationViewController inside your UIViewControllerRepresentable. Stripes implementation is a little wonky with the SwiftUI stuff. You will also want to remove any NavigationView's that you might be wrapping it in above - could end up in a double nav view.

struct AddCardView: UIViewControllerRepresentable {
    @Environment(\.presentationMode) var presentation
    
    @ObservedObject var model: PaymentMethodViewModel
    
    func makeUIViewController(context: Context) -> UINavigationController {
        let controller = STPAddCardViewController()
        controller.delegate = context.coordinator
        controller.edgesForExtendedLayout = .all
        let navigationController = UINavigationController(rootViewController: controller)
        navigationController.navigationBar.prefersLargeTitles = true
        return navigationController
    }
    
    func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {
        
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
        
    class Coordinator: NSObject, STPAddCardViewControllerDelegate, UINavigationControllerDelegate {
        var parent: AddCardView
        
        func addCardViewControllerDidCancel(_ addCardViewController: STPAddCardViewController) {
            parent.presentation.wrappedValue.dismiss()
        }
        
        func addCardViewController(_ addCardViewController: STPAddCardViewController, didCreatePaymentMethod paymentMethod: STPPaymentMethod, completion: @escaping STPErrorBlock) {
            print(paymentMethod)
            parent.model.isCards = true
            parent.presentation.wrappedValue.dismiss()
        }
        
        init(_ parent: AddCardView) {
            self.parent = parent
        }
    }
}

@daigok
Copy link

daigok commented Feb 3, 2021

I'm not sure this is related to this issue.

We are also using the similar solution above and it works perfect using Stripe SDK lower than 21.0.1, the SDK written in Objective-C. However, after I've updated to the latest one, 21.2.1, the above solution doesn't work.

If a customer doesn't have payment methods, an addCardViewController callback is not getting called and a Done button is in loading state when a user try to add a card. Also I've checked the log on the Stripe dashboard and POST /v1/payment_methods/pm_.../attach is not getting called too.

Once a user have a payment methods, for example if I manually add a card to a customer, everything works fine. All callbacks are getting called expectedly.

Here is our code snippet.

struct StripePaymentOptionsView: UIViewControllerRepresentable {
    @Environment(\.presentationMode) private var presentationMode
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    func makeUIViewController(context: Context) -> UINavigationController {
        let theme = STPTheme()
        
        let config = STPPaymentConfiguration()
        config.requiredBillingAddressFields = .none
        config.cardScanningEnabled = true
        config.canDeletePaymentOptions = false
        let viewController = STPPaymentOptionsViewController(configuration: config,
                                                             theme: theme,
                                                             customerContext: STPCustomerContext(keyProvider: EphemeralKeyProvider()),
                                                             delegate: context.coordinator)
        let navigationController = UINavigationController(rootViewController: viewController)
        return navigationController
    }
    
    func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {
    }
}

// MARK: - STPPaymentOptionsViewControllerDelegate
extension StripePaymentOptionsView {
    final class Coordinator: NSObject, STPPaymentOptionsViewControllerDelegate {

        var parent: StripePaymentOptionsView
        
        init(_ parent: StripePaymentOptionsView) {
            self.parent = parent
        }

        func paymentOptionsViewController(_ paymentOptionsViewController: STPPaymentOptionsViewController, didFailToLoadWithError error: Error) {
        }
        
        func paymentOptionsViewControllerDidFinish(_ paymentOptionsViewController: STPPaymentOptionsViewController) {
            paymentOptionsViewController.dismiss(withCompletion: nil)
        }
        
        func paymentOptionsViewControllerDidCancel(_ paymentOptionsViewController: STPPaymentOptionsViewController) {
            paymentOptionsViewController.dismiss(withCompletion: nil)
        }
        
        func paymentOptionsViewController(_ paymentOptionsViewController: STPPaymentOptionsViewController, didSelect paymentOption: STPPaymentOption) {
        }
    }
}

@davidme-stripe
Copy link
Contributor

davidme-stripe commented May 7, 2021

We released a new Payments UI beta in SDK version 21.5.0, which has better SwiftUI support. We don't plan to add official SwiftUI support to STPAddCardViewController.

(That said, if you do run into any critical bugs with STPAddCardViewController + SwiftUI, let us know and we'll try to help you out!)

kgaidis-stripe added a commit that referenced this issue Dec 2, 2022
Financial Connections: update with latest on master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
triaged Issue has been reviewed by Stripe and is being tracked internally
Projects
None yet
Development

No branches or pull requests

5 participants