Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions Modules/Sources/Experiments/DefaultFeatureFlagService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,6 @@ public struct DefaultFeatureFlagService: FeatureFlagService {
return true
case .productImageOptimizedHandling:
return true
case .pointOfSaleAsATabi2:
return true
case .pointOfSaleOrdersi1:
return true
case .pointOfSaleOrdersi2:
Expand Down
4 changes: 0 additions & 4 deletions Modules/Sources/Experiments/FeatureFlag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,6 @@ public enum FeatureFlag: Int {
///
case pointOfSaleReceipts

/// Enables displaying POS as a tab in the tab bar for stores in eligible countries
///
case pointOfSaleAsATabi2

/// Enables displaying Point Of Sale details in order list and order details
///
case pointOfSaleOrdersi1
Expand Down
39 changes: 0 additions & 39 deletions Modules/Sources/Yosemite/Tools/Plugins/PluginsService.swift
Original file line number Diff line number Diff line change
@@ -1,17 +1,8 @@
import Foundation
import WooFoundation
import protocol Storage.StorageManagerType

/// A service for system plugins.
public protocol PluginsServiceProtocol {
/// Waits for a specific plugin to be available in storage.
/// - Parameters:
/// - siteID: The site ID to search for the plugin.
/// - pluginPath: The plugin's file path (e.g., "woocommerce/woocommerce.php" for WooCommerce).
/// - isActive: Whether the plugin is active or not.
/// - Returns: The SystemPlugin when found in storage.
func waitForPluginInStorage(siteID: Int64, pluginPath: String, isActive: Bool) async -> SystemPlugin

/// Loads a specific plugin from storage synchronously.
/// - Parameters:
/// - siteID: The site ID to search for the plugin.
Expand All @@ -37,36 +28,6 @@ public class PluginsService: PluginsServiceProtocol {
self.storageManager = storageManager
}

@MainActor
public func waitForPluginInStorage(siteID: Int64, pluginPath: String, isActive: Bool) async -> SystemPlugin {
let predicate = \StorageSystemPlugin.siteID == siteID && \StorageSystemPlugin.plugin == pluginPath && \StorageSystemPlugin.active == isActive
let pluginDescriptor = NSSortDescriptor(keyPath: \StorageSystemPlugin.plugin, ascending: true)
let resultsController = ResultsController<StorageSystemPlugin>(storageManager: storageManager,
matching: predicate,
fetchLimit: 1,
sortedBy: [pluginDescriptor])
do {
try resultsController.performFetch()
if let plugin = resultsController.fetchedObjects.first {
return plugin
}
} catch {
DDLogError("Error loading plugin \(pluginPath) for site \(siteID) initially: \(error.localizedDescription)")
}

return await withCheckedContinuation { continuation in
var hasResumed = false
resultsController.onDidChangeContent = {
guard let plugin = resultsController.fetchedObjects.first,
!hasResumed else {
return
}
hasResumed = true
continuation.resume(returning: plugin)
}
}
}

@MainActor
public func loadPluginInStorage(siteID: Int64, plugin: Plugin, isActive: Bool?) -> SystemPlugin? {
storageManager.viewStorage.loadSystemPlugin(siteID: siteID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,40 +13,6 @@ struct PluginsServiceTests {
sut = PluginsService(storageManager: storageManager)
}

@Test func waitForPluginInStorage_returns_plugin_when_already_in_storage() async {
// Given
await storageManager.reset()
storageManager.insertPlugin(siteID: siteID, plugin: .wooCommerce, isActive: true, version: "1.0.0")

// When
let result = await sut.waitForPluginInStorage(siteID: siteID, pluginPath: "woocommerce/woocommerce.php", isActive: true)

// Then
#expect(result.siteID == siteID)
#expect(result.plugin == "woocommerce/woocommerce.php")
#expect(result.active == true)
#expect(result.version == "1.0.0")
}

@Test func waitForPluginInStorage_waits_to_return_plugin_when_not_in_storage_initially() async {
// Given
// Resets any existing state, otherwise test might fail if run multiple times.
await storageManager.reset()

// When
async let plugin = sut.waitForPluginInStorage(siteID: siteID, pluginPath: "woocommerce/woocommerce.php", isActive: true)
#expect(storageManager.viewStorage.loadSystemPlugins(siteID: siteID).count == 0)
storageManager.insertPlugin(siteID: siteID, plugin: .wooCommerce, isActive: true, version: "2.0.0")
#expect(storageManager.viewStorage.loadSystemPlugins(siteID: siteID).count == 1)

// Then
let result = await plugin
#expect(result.siteID == siteID)
#expect(result.plugin == "woocommerce/woocommerce.php")
#expect(result.active == true)
#expect(result.version == "2.0.0")
}

// MARK: - `loadPluginInStorage`

@Test(arguments: [(Plugin.wooCommerce, true, "1.5.0"),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import SwiftUI
import protocol Experiments.FeatureFlagService

protocol POSEntryPointEligibilityCheckerProtocol {
/// Determines whether the site is eligible for POS.
func checkEligibility() async -> POSEligibilityState
/// Refreshes the eligibility state based on the provided ineligible reason.
func refreshEligibility(ineligibleReason: POSIneligibleReason) async throws -> POSEligibilityState
}

@Observable final class POSEntryPointController {
private(set) var eligibilityState: POSEligibilityState?
private let posEligibilityChecker: POSEntryPointEligibilityCheckerProtocol
private let featureFlagService: POSFeatureFlagProviding

init(eligibilityChecker: POSEntryPointEligibilityCheckerProtocol,
featureFlagService: POSFeatureFlagProviding) {
init(eligibilityChecker: POSEntryPointEligibilityCheckerProtocol) {
self.posEligibilityChecker = eligibilityChecker
self.featureFlagService = featureFlagService

guard featureFlagService.isFeatureFlagEnabled(.pointOfSaleAsATabi2) else {
self.eligibilityState = .eligible
return
}
Task { @MainActor in
eligibilityState = await posEligibilityChecker.checkEligibility()
}
Expand Down
13 changes: 0 additions & 13 deletions WooCommerce/Classes/POS/Models/PointOfSaleSettingsController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,6 @@ final class MockPointOfSaleSettingsService: PointOfSaleSettingsServiceProtocol {
}

final class PluginsServicePreview: PluginsServiceProtocol {
func waitForPluginInStorage(siteID: Int64, pluginPath: String, isActive: Bool) async -> SystemPlugin {
return SystemPlugin(siteID: 1234,
plugin: "",
name: "",
version: "",
versionLatest: "",
url: "",
authorName: "",
authorUrl: "",
networkActivated: false,
active: true)
}

func loadPluginInStorage(siteID: Int64, plugin: Plugin, isActive: Bool?) -> SystemPlugin? {
return SystemPlugin(siteID: 1234,
plugin: "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ struct PointOfSaleEntryPointView: View {
self.searchHistoryService = searchHistoryService
self.popularPurchasableItemsController = popularPurchasableItemsController
self.barcodeScanService = barcodeScanService
self.posEntryPointController = POSEntryPointController(eligibilityChecker: posEligibilityChecker, featureFlagService: services.featureFlags)
self.posEntryPointController = POSEntryPointController(eligibilityChecker: posEligibilityChecker)
self.orderListModel = POSOrderListModel(ordersController: ordersController, receiptSender: receiptSender)
self.siteTimezone = siteTimezone
self.services = services
Expand Down Expand Up @@ -129,7 +129,7 @@ struct PointOfSaleEntryPointView: View {
searchHistoryService: PointOfSalePreviewHistoryService(),
popularPurchasableItemsController: PointOfSalePreviewItemsController(),
barcodeScanService: PointOfSalePreviewBarcodeScanService(),
posEligibilityChecker: POSTabEligibilityChecker(site: .defaultMock()),
posEligibilityChecker: POSTabEligibilityChecker(siteID: 1),
services: POSPreviewServices())
}

Expand Down
52 changes: 8 additions & 44 deletions WooCommerce/Classes/POS/TabBar/POSTabCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ import class WooFoundationCore.CurrencyFormatter
import struct NetworkingCore.JetpackSite
import struct Combine.AnyPublisher

protocol POSTabVisibilityCheckerProtocol {
/// Checks the initial visibility of the POS tab.
func checkInitialVisibility() -> Bool
/// Checks the final visibility of the POS tab.
func checkVisibility() async -> Bool
}

/// View controller that provides the tab bar item for the Point of Sale tab.
/// It is never visible on the screen, only used to provide the tab bar item as all POS UI is full-screen.
final class POSTabViewController: UIViewController {
Expand All @@ -23,7 +30,7 @@ final class POSTabViewController: UIViewController {
/// Coordinator for the Point of Sale tab.
///
final class POSTabCoordinator {
private(set) var siteID: Int64
private let siteID: Int64
private let tabContainerController: TabContainerController
private let viewControllerToPresent: UIViewController
private let storesManager: StoresManager
Expand Down Expand Up @@ -109,49 +116,6 @@ final class POSTabCoordinator {
func onTabSelected() {
presentPOSView(siteID: siteID)
}

func didSwitchStore(id: Int64) {
self.siteID = id

// Resets lazy properties so they get recreated with new siteID
posItemFetchStrategyFactory = PointOfSaleItemFetchStrategyFactory(
siteID: siteID,
credentials: credentials,
selectedSite: defaultSitePublisher,
appPasswordSupportState: isAppPasswordSupported
)

posPopularItemFetchStrategyFactory =
PointOfSaleFixedItemFetchStrategyFactory(
fixedStrategy: posItemFetchStrategyFactory.popularStrategy()
)

posCouponFetchStrategyFactory = PointOfSaleCouponFetchStrategyFactory(
siteID: siteID,
currencySettings: currencySettings,
credentials: credentials,
selectedSite: defaultSitePublisher,
appPasswordSupportState: isAppPasswordSupported,
storage: storageManager
)

posCouponProvider = PointOfSaleCouponService(
siteID: siteID,
currencySettings: currencySettings,
credentials: credentials,
selectedSite: defaultSitePublisher,
appPasswordSupportState: isAppPasswordSupported,
storage: storageManager
)

barcodeScanService = PointOfSaleBarcodeScanService(
siteID: siteID,
credentials: credentials,
selectedSite: defaultSitePublisher,
appPasswordSupportState: isAppPasswordSupported,
currencySettings: currencySettings
)
}
}

private extension POSTabCoordinator {
Expand Down
12 changes: 7 additions & 5 deletions WooCommerce/Classes/POS/Utils/PreviewHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -221,13 +221,10 @@ struct POSPreviewHelpers {
searchHistoryService: POSSearchHistoryProviding = PointOfSalePreviewHistoryService(),
popularItemsController: PointOfSaleItemsControllerProtocol = PointOfSalePreviewItemsController(),
barcodeScanService: PointOfSaleBarcodeScanServiceProtocol = PointOfSalePreviewBarcodeScanService(),
analytics: POSAnalyticsProviding = EmptyPOSAnalytics(),
featureFlags: POSFeatureFlagProviding = EmptyPOSFeatureFlags()
analytics: POSAnalyticsProviding = EmptyPOSAnalytics()
) -> PointOfSaleAggregateModel {
return PointOfSaleAggregateModel(
entryPointController: POSEntryPointController(
eligibilityChecker: LegacyPOSTabEligibilityChecker(site: Site.defaultMock()),
featureFlagService: featureFlags),
entryPointController: POSEntryPointController(eligibilityChecker: PointOfSalePreviewTabEligibilityChecker()),
itemsController: itemsController,
purchasableItemsSearchController: purchasableItemsSearchController,
couponsController: couponsController,
Expand Down Expand Up @@ -402,6 +399,11 @@ final class PointOfSalePreviewBarcodeScanService: PointOfSaleBarcodeScanServiceP
}
}

final class PointOfSalePreviewTabEligibilityChecker: POSEntryPointEligibilityCheckerProtocol {
func checkEligibility() async -> POSEligibilityState { .eligible }
func refreshEligibility(ineligibleReason: POSIneligibleReason) async throws -> POSEligibilityState { .eligible }
}

final class POSReceiptSenderPreview: POSReceiptSending {
func sendReceipt(orderID: Int64, recipientEmail: String) async throws {}
}
Expand Down
Loading