diff --git a/Example/FinancialConnections Example/FinancialConnections Example/Playground/PlaygroundConfiguration.swift b/Example/FinancialConnections Example/FinancialConnections Example/Playground/PlaygroundConfiguration.swift index e8ceb7cd253..5df6ccaaa2e 100644 --- a/Example/FinancialConnections Example/FinancialConnections Example/Playground/PlaygroundConfiguration.swift +++ b/Example/FinancialConnections Example/FinancialConnections Example/Playground/PlaygroundConfiguration.swift @@ -370,6 +370,36 @@ final class PlaygroundConfiguration { configurationStore[Self.phoneKey] = newValue } } + + // MARK: - Relink Authorization + + private static let customerIdKey = "customer_id" + var customerId: String { + get { + if let customerId = configurationStore[Self.customerIdKey] as? String { + return customerId + } else { + return "" + } + } + set { + configurationStore[Self.customerIdKey] = newValue + } + } + + private static let relinkAuthorizationKey = "relink_authorization" + var relinkAuthorization: String { + get { + if let relinkAuthorization = configurationStore[Self.relinkAuthorizationKey] as? String { + return relinkAuthorization + } else { + return "" + } + } + set { + configurationStore[Self.relinkAuthorizationKey] = newValue + } + } // MARK: - Permissions diff --git a/Example/FinancialConnections Example/FinancialConnections Example/Playground/PlaygroundView.swift b/Example/FinancialConnections Example/FinancialConnections Example/Playground/PlaygroundView.swift index 684c91de027..7d08c651c9a 100644 --- a/Example/FinancialConnections Example/FinancialConnections Example/Playground/PlaygroundView.swift +++ b/Example/FinancialConnections Example/FinancialConnections Example/Playground/PlaygroundView.swift @@ -114,6 +114,17 @@ struct PlaygroundView: View { .accessibility(identifier: "playground-phone") } } + + Section(header: Text("Relink")) { + TextField("Customer", text: viewModel.customerId) + .keyboardType(.default) + .autocapitalization(.none) + .accessibility(identifier: "playground-customer-id") + + TextField("Relink authorization", text: viewModel.relinkAuthorization) + .keyboardType(.default) + .accessibility(identifier: "playground-relink-authorization") + } Section(header: Text("PERMISSIONS")) { Toggle("Balances", isOn: viewModel.balancesPermission) diff --git a/Example/FinancialConnections Example/FinancialConnections Example/Playground/PlaygroundViewModel.swift b/Example/FinancialConnections Example/FinancialConnections Example/Playground/PlaygroundViewModel.swift index 69290e1dec4..16196f92790 100644 --- a/Example/FinancialConnections Example/FinancialConnections Example/Playground/PlaygroundViewModel.swift +++ b/Example/FinancialConnections Example/FinancialConnections Example/Playground/PlaygroundViewModel.swift @@ -155,6 +155,30 @@ final class PlaygroundViewModel: ObservableObject { } ) } + + var customerId: Binding { + Binding( + get: { + self.playgroundConfiguration.customerId + }, + set: { + self.playgroundConfiguration.customerId = $0 + self.objectWillChange.send() + } + ) + } + + var relinkAuthorization: Binding { + Binding( + get: { + self.playgroundConfiguration.relinkAuthorization + }, + set: { + self.playgroundConfiguration.relinkAuthorization = $0 + self.objectWillChange.send() + } + ) + } var balancesPermission: Binding { Binding( diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NativeFlowController.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NativeFlowController.swift index f1df80fe17f..92d2edc9277 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NativeFlowController.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/NativeFlowController.swift @@ -179,7 +179,10 @@ extension NativeFlowController { // // keeping this logic in `pushPane` is helpful because we want to // reuse `skipSuccessPane` and `manualEntryMode == .custom` logic - clearNavigationStack: Bool = false + clearNavigationStack: Bool = false, + // Useful for cases where we want to prevent the current pane from being shown again, + // but not affect any previous panes. + removeCurrent: Bool = false ) { if pane == .success && dataManager.manifest.skipSuccessPane == true { closeAuthFlow(error: nil) @@ -192,8 +195,11 @@ extension NativeFlowController { nativeFlowController: self, dataManager: dataManager ) - if clearNavigationStack, let paneViewController = paneViewController { + if clearNavigationStack, let paneViewController { setNavigationControllerViewControllers([paneViewController], animated: animated) + } else if removeCurrent, let paneViewController { + let viewControllers = Array(navigationController.viewControllers.dropLast()) + setNavigationControllerViewControllers(viewControllers + [paneViewController], animated: animated) } else { pushViewController(paneViewController, animated: animated) } @@ -829,6 +835,14 @@ extension NativeFlowController: PartnerAuthViewControllerDelegate { showErrorPane(forError: error, referrerPane: .partnerAuth) } + + func partnerAuthViewController( + _ viewController: PartnerAuthViewController, + didRequestNextPane nextPane: FinancialConnectionsSessionManifest.NextPane + ) { + dataManager.authSession = nil // clear any lingering auth sessions + pushPane(nextPane, animated: true, removeCurrent: true) + } } // MARK: - AccountPickerViewControllerDelegate diff --git a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/PartnerAuth/PartnerAuthViewController.swift b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/PartnerAuth/PartnerAuthViewController.swift index 0addc6998c8..8399f4488d2 100644 --- a/StripeFinancialConnections/StripeFinancialConnections/Source/Native/PartnerAuth/PartnerAuthViewController.swift +++ b/StripeFinancialConnections/StripeFinancialConnections/Source/Native/PartnerAuth/PartnerAuthViewController.swift @@ -25,6 +25,10 @@ protocol PartnerAuthViewControllerDelegate: AnyObject { _ viewController: PartnerAuthViewController, didReceiveError error: Error ) + func partnerAuthViewController( + _ viewController: PartnerAuthViewController, + didRequestNextPane nextPane: FinancialConnectionsSessionManifest.NextPane + ) } final class PartnerAuthViewController: SheetViewController { @@ -157,7 +161,12 @@ final class PartnerAuthViewController: SheetViewController { }, didSelectCancel: { [weak self] in guard let self = self else { return } - self.delegate?.partnerAuthViewControllerDidRequestToGoBack(self) + + if panePresentationStyle == .fullscreen { + self.delegate?.partnerAuthViewController(self, didRequestNextPane: .institutionPicker) + } else { + self.delegate?.partnerAuthViewControllerDidRequestToGoBack(self) + } } ) self.prepaneViews = prepaneViews