diff --git a/WooCommerce/Classes/Authentication/Epilogue/SwitchStoreUseCase.swift b/WooCommerce/Classes/Authentication/Epilogue/SwitchStoreUseCase.swift index 93eed3993d7..67f25b5b12f 100644 --- a/WooCommerce/Classes/Authentication/Epilogue/SwitchStoreUseCase.swift +++ b/WooCommerce/Classes/Authentication/Epilogue/SwitchStoreUseCase.swift @@ -1,5 +1,6 @@ import UIKit import Yosemite +import protocol Storage.StorageManagerType protocol SwitchStoreUseCaseProtocol { func switchStore(with storeID: Int64, onCompletion: @escaping (Bool) -> Void) @@ -10,9 +11,19 @@ protocol SwitchStoreUseCaseProtocol { final class SwitchStoreUseCase: SwitchStoreUseCaseProtocol { private let stores: StoresManager + private let storageManager: StorageManagerType - init(stores: StoresManager) { + private lazy var resultsController: ResultsController = { + return ResultsController(storageManager: storageManager, sortedBy: []) + }() + + private var wooCommerceSites: [Site] { + resultsController.fetchedObjects.filter { $0.isWooCommerceActive == true } + } + + init(stores: StoresManager, storageManager: StorageManagerType = ServiceLocator.storageManager) { self.stores = stores + self.storageManager = storageManager } /// The async version of `switchStore` that wraps the completion block version. @@ -28,6 +39,25 @@ final class SwitchStoreUseCase: SwitchStoreUseCaseProtocol { } } + /// Switches the to store with the given id if it was previously synced and stored. + /// This is done to check whether the user has access to that store, avoiding undetermined states if we log out + /// from the current one and try to switch to a store they don't have access to. + /// + /// - Parameter storeID: target store ID. + /// - Returns: a boolean that indicates whether the site was changed. + /// + func switchToStoreIfSiteIsStored(with storeID: Int64, onCompletion: @escaping (Bool) -> Void) { + refreshStoredSites() + + let siteWasStored = wooCommerceSites.first(where: { $0.siteID == storeID }) != nil + + guard siteWasStored else { + return onCompletion(false) + } + + switchStore(with: storeID, onCompletion: onCompletion) + } + /// A static method which allows easily to switch store. The boolean argument in `onCompletion` indicates that the site was changed. /// When `onCompletion` is called, the selected site ID is updated while `Site` might still not be available if the site does not exist in storage yet /// (e.g. a newly connected site). @@ -111,4 +141,8 @@ final class SwitchStoreUseCase: SwitchStoreUseCaseProtocol { AppDelegate.shared.authenticatorWasDismissed() } + + private func refreshStoredSites() { + try? resultsController.performFetch() + } } diff --git a/WooCommerce/Classes/ViewRelated/MainTabBarController.swift b/WooCommerce/Classes/ViewRelated/MainTabBarController.swift index e57328a2dcb..06c0427606b 100644 --- a/WooCommerce/Classes/ViewRelated/MainTabBarController.swift +++ b/WooCommerce/Classes/ViewRelated/MainTabBarController.swift @@ -337,9 +337,10 @@ extension MainTabBarController { } let siteID = Int64(note.meta.identifier(forKey: .site) ?? Int.min) - switchToStore(with: siteID, onCompletion: { - presentNotificationDetails(for: note) - + switchToStore(with: siteID, onCompletion: { siteChanged in + if siteChanged { + presentNotificationDetails(for: note) + } }) } ServiceLocator.stores.dispatch(action) @@ -368,14 +369,16 @@ extension MainTabBarController { "already_read": note.read ]) } - private static func switchToStore(with siteID: Int64, onCompletion: @escaping () -> Void) { - SwitchStoreUseCase(stores: ServiceLocator.stores).switchStore(with: siteID) { siteChanged in - if siteChanged { - let presenter = SwitchStoreNoticePresenter(siteID: siteID) - presenter.presentStoreSwitchedNoticeWhenSiteIsAvailable(configuration: .switchingStores) + private static func switchToStore(with siteID: Int64, onCompletion: @escaping (Bool) -> Void) { + SwitchStoreUseCase(stores: ServiceLocator.stores).switchToStoreIfSiteIsStored(with: siteID) { siteChanged in + guard siteChanged else { + return onCompletion(false) } - onCompletion() + let presenter = SwitchStoreNoticePresenter(siteID: siteID) + presenter.presentStoreSwitchedNoticeWhenSiteIsAvailable(configuration: .switchingStores) + + onCompletion(true) } } @@ -392,8 +395,11 @@ extension MainTabBarController { } static func navigateToOrderDetails(with orderID: Int64, siteID: Int64) { - switchToStore(with: siteID, onCompletion: { + switchToStore(with: siteID, onCompletion: { siteChanged in switchToOrdersTab { + guard siteChanged else { + return + } // We give some time to the orders tab transition to finish, otherwise it might prevent the second navigation from happening DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { presentDetails(for: orderID, siteID: siteID)