Skip to content

Commit 6a1c368

Browse files
authored
Refactor POS tab: separate visibility and eligibility logic while removing POS as a tab i2 feature flag (#16173)
2 parents 2c9fd8a + d610283 commit 6a1c368

31 files changed

+678
-1606
lines changed

Modules/Sources/Experiments/DefaultFeatureFlagService.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,6 @@ public struct DefaultFeatureFlagService: FeatureFlagService {
8686
return false
8787
case .productImageOptimizedHandling:
8888
return true
89-
case .pointOfSaleAsATabi2:
90-
return true
9189
case .pointOfSaleOrdersi1:
9290
return true
9391
case .pointOfSaleOrdersi2:

Modules/Sources/Experiments/FeatureFlag.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,10 +179,6 @@ public enum FeatureFlag: Int {
179179
///
180180
case inventoryProductLabelsInPOS
181181

182-
/// Enables displaying POS as a tab in the tab bar for stores in eligible countries
183-
///
184-
case pointOfSaleAsATabi2
185-
186182
/// Enables displaying Point Of Sale details in order list and order details
187183
///
188184
case pointOfSaleOrdersi1

Modules/Sources/Yosemite/Tools/Plugins/PluginsService.swift

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,8 @@
11
import Foundation
2-
import WooFoundation
32
import protocol Storage.StorageManagerType
43

54
/// A service for system plugins.
65
public protocol PluginsServiceProtocol {
7-
/// Waits for a specific plugin to be available in storage.
8-
/// - Parameters:
9-
/// - siteID: The site ID to search for the plugin.
10-
/// - pluginPath: The plugin's file path (e.g., "woocommerce/woocommerce.php" for WooCommerce).
11-
/// - isActive: Whether the plugin is active or not.
12-
/// - Returns: The SystemPlugin when found in storage.
13-
func waitForPluginInStorage(siteID: Int64, pluginPath: String, isActive: Bool) async -> SystemPlugin
14-
156
/// Loads a specific plugin from storage synchronously.
167
/// - Parameters:
178
/// - siteID: The site ID to search for the plugin.
@@ -37,36 +28,6 @@ public class PluginsService: PluginsServiceProtocol {
3728
self.storageManager = storageManager
3829
}
3930

40-
@MainActor
41-
public func waitForPluginInStorage(siteID: Int64, pluginPath: String, isActive: Bool) async -> SystemPlugin {
42-
let predicate = \StorageSystemPlugin.siteID == siteID && \StorageSystemPlugin.plugin == pluginPath && \StorageSystemPlugin.active == isActive
43-
let pluginDescriptor = NSSortDescriptor(keyPath: \StorageSystemPlugin.plugin, ascending: true)
44-
let resultsController = ResultsController<StorageSystemPlugin>(storageManager: storageManager,
45-
matching: predicate,
46-
fetchLimit: 1,
47-
sortedBy: [pluginDescriptor])
48-
do {
49-
try resultsController.performFetch()
50-
if let plugin = resultsController.fetchedObjects.first {
51-
return plugin
52-
}
53-
} catch {
54-
DDLogError("Error loading plugin \(pluginPath) for site \(siteID) initially: \(error.localizedDescription)")
55-
}
56-
57-
return await withCheckedContinuation { continuation in
58-
var hasResumed = false
59-
resultsController.onDidChangeContent = {
60-
guard let plugin = resultsController.fetchedObjects.first,
61-
!hasResumed else {
62-
return
63-
}
64-
hasResumed = true
65-
continuation.resume(returning: plugin)
66-
}
67-
}
68-
}
69-
7031
@MainActor
7132
public func loadPluginInStorage(siteID: Int64, plugin: Plugin, isActive: Bool?) -> SystemPlugin? {
7233
storageManager.viewStorage.loadSystemPlugin(siteID: siteID,

Modules/Tests/YosemiteTests/Tools/Plugins/PluginsServiceTests.swift

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,40 +13,6 @@ struct PluginsServiceTests {
1313
sut = PluginsService(storageManager: storageManager)
1414
}
1515

16-
@Test func waitForPluginInStorage_returns_plugin_when_already_in_storage() async {
17-
// Given
18-
await storageManager.reset()
19-
storageManager.insertPlugin(siteID: siteID, plugin: .wooCommerce, isActive: true, version: "1.0.0")
20-
21-
// When
22-
let result = await sut.waitForPluginInStorage(siteID: siteID, pluginPath: "woocommerce/woocommerce.php", isActive: true)
23-
24-
// Then
25-
#expect(result.siteID == siteID)
26-
#expect(result.plugin == "woocommerce/woocommerce.php")
27-
#expect(result.active == true)
28-
#expect(result.version == "1.0.0")
29-
}
30-
31-
@Test func waitForPluginInStorage_waits_to_return_plugin_when_not_in_storage_initially() async {
32-
// Given
33-
// Resets any existing state, otherwise test might fail if run multiple times.
34-
await storageManager.reset()
35-
36-
// When
37-
async let plugin = sut.waitForPluginInStorage(siteID: siteID, pluginPath: "woocommerce/woocommerce.php", isActive: true)
38-
#expect(storageManager.viewStorage.loadSystemPlugins(siteID: siteID).count == 0)
39-
storageManager.insertPlugin(siteID: siteID, plugin: .wooCommerce, isActive: true, version: "2.0.0")
40-
#expect(storageManager.viewStorage.loadSystemPlugins(siteID: siteID).count == 1)
41-
42-
// Then
43-
let result = await plugin
44-
#expect(result.siteID == siteID)
45-
#expect(result.plugin == "woocommerce/woocommerce.php")
46-
#expect(result.active == true)
47-
#expect(result.version == "2.0.0")
48-
}
49-
5016
// MARK: - `loadPluginInStorage`
5117

5218
@Test(arguments: [(Plugin.wooCommerce, true, "1.5.0"),

WooCommerce/Classes/POS/Analytics/WooAnalyticsEvent+PointOfSaleIneligibleUI.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ private extension POSIneligibleReason {
2626
return "feature_switch_disabled"
2727
case .wooCommercePluginNotFound:
2828
return "unknown_wc_plugin"
29-
case .unsupportedIOSVersion:
30-
return "ios_version"
31-
case .unsupportedInCIABSites:
32-
return "feature_unsupported_in_ciab"
3329
case .siteSettingsNotAvailable,
3430
.selfDeallocated:
3531
return "other"

WooCommerce/Classes/POS/Controllers/POSEntryPointController.swift

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
import SwiftUI
2-
import protocol Experiments.FeatureFlagService
2+
3+
protocol POSEntryPointEligibilityCheckerProtocol {
4+
/// Determines whether the site is eligible for POS.
5+
func checkEligibility() async -> POSEligibilityState
6+
/// Refreshes the eligibility state based on the provided ineligible reason.
7+
func refreshEligibility(ineligibleReason: POSIneligibleReason) async throws -> POSEligibilityState
8+
}
39

410
@Observable final class POSEntryPointController {
511
private(set) var eligibilityState: POSEligibilityState?
612
private let posEligibilityChecker: POSEntryPointEligibilityCheckerProtocol
7-
private let featureFlagService: POSFeatureFlagProviding
813

9-
init(eligibilityChecker: POSEntryPointEligibilityCheckerProtocol,
10-
featureFlagService: POSFeatureFlagProviding) {
14+
init(eligibilityChecker: POSEntryPointEligibilityCheckerProtocol) {
1115
self.posEligibilityChecker = eligibilityChecker
12-
self.featureFlagService = featureFlagService
1316

14-
guard featureFlagService.isFeatureFlagEnabled(.pointOfSaleAsATabi2) else {
15-
self.eligibilityState = .eligible
16-
return
17-
}
1817
Task { @MainActor in
1918
eligibilityState = await posEligibilityChecker.checkEligibility()
2019
}

WooCommerce/Classes/POS/Models/POSIneligibleReason.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@ import enum WooFoundation.CurrencyCode
44

55
/// Represents the reasons why a site may be ineligible for POS.
66
enum POSIneligibleReason: Equatable {
7-
case unsupportedIOSVersion
87
case unsupportedWooCommerceVersion(minimumVersion: String)
98
case siteSettingsNotAvailable
109
case wooCommercePluginNotFound
1110
case featureSwitchDisabled
1211
case unsupportedCurrency(countryCode: CountryCode, supportedCurrencies: [CurrencyCode])
1312
case selfDeallocated
14-
case unsupportedInCIABSites
1513
}
1614

1715
/// Represents the eligibility state for POS.

WooCommerce/Classes/POS/Models/PointOfSaleSettingsController.swift

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -89,19 +89,6 @@ final class MockPointOfSaleSettingsService: PointOfSaleSettingsServiceProtocol {
8989
}
9090

9191
final class PluginsServicePreview: PluginsServiceProtocol {
92-
func waitForPluginInStorage(siteID: Int64, pluginPath: String, isActive: Bool) async -> SystemPlugin {
93-
return SystemPlugin(siteID: 1234,
94-
plugin: "",
95-
name: "",
96-
version: "",
97-
versionLatest: "",
98-
url: "",
99-
authorName: "",
100-
authorUrl: "",
101-
networkActivated: false,
102-
active: true)
103-
}
104-
10592
func loadPluginInStorage(siteID: Int64, plugin: Plugin, isActive: Bool?) -> SystemPlugin? {
10693
return SystemPlugin(siteID: 1234,
10794
plugin: "",

WooCommerce/Classes/POS/Presentation/PointOfSaleEntryPointView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ struct PointOfSaleEntryPointView: View {
5656
self.searchHistoryService = searchHistoryService
5757
self.popularPurchasableItemsController = popularPurchasableItemsController
5858
self.barcodeScanService = barcodeScanService
59-
self.posEntryPointController = POSEntryPointController(eligibilityChecker: posEligibilityChecker, featureFlagService: services.featureFlags)
59+
self.posEntryPointController = POSEntryPointController(eligibilityChecker: posEligibilityChecker)
6060
self.orderListModel = POSOrderListModel(ordersController: ordersController, receiptSender: receiptSender)
6161
self.siteTimezone = siteTimezone
6262
self.services = services
@@ -129,7 +129,7 @@ struct PointOfSaleEntryPointView: View {
129129
searchHistoryService: PointOfSalePreviewHistoryService(),
130130
popularPurchasableItemsController: PointOfSalePreviewItemsController(),
131131
barcodeScanService: PointOfSalePreviewBarcodeScanService(),
132-
posEligibilityChecker: POSTabEligibilityChecker(site: .defaultMock()),
132+
posEligibilityChecker: POSTabEligibilityChecker(siteID: 1),
133133
services: POSPreviewServices())
134134
}
135135

WooCommerce/Classes/POS/TabBar/POSIneligibleView.swift

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,6 @@ struct POSIneligibleView: View {
112112

113113
private var suggestionText: String {
114114
switch reason {
115-
case .unsupportedIOSVersion:
116-
return NSLocalizedString("pos.ineligible.suggestion.unsupportedIOSVersion.1",
117-
value: "The POS system requires iOS 17 or later. Please update your device to iOS 17+ to use this feature.",
118-
comment: "Suggestion for unsupported iOS version: update iOS")
119115
case let .unsupportedWooCommerceVersion(minimumVersion):
120116
let format = NSLocalizedString("pos.ineligible.suggestion.unsupportedWooCommerceVersion",
121117
value: "Your WooCommerce version is not supported. " +
@@ -155,12 +151,6 @@ struct POSIneligibleView: View {
155151
return NSLocalizedString("pos.ineligible.suggestion.selfDeallocated",
156152
value: "Try relaunching the app to resolve this issue.",
157153
comment: "Suggestion for self deallocated: relaunch")
158-
case .unsupportedInCIABSites:
159-
return NSLocalizedString(
160-
"pos.ineligible.suggestion.notSupportedForCIAB",
161-
value: "The POS system is not supported for your store.",
162-
comment: "Suggestion for CIAB sites: feature is not supported"
163-
)
164154
}
165155
}
166156
}
@@ -184,9 +174,6 @@ private extension POSIneligibleView {
184174
private extension POSIneligibleReason {
185175
var shouldShowRetryButton: Bool {
186176
switch self {
187-
case .unsupportedIOSVersion,
188-
.unsupportedInCIABSites:
189-
return false
190177
case .unsupportedWooCommerceVersion,
191178
.siteSettingsNotAvailable,
192179
.wooCommercePluginNotFound,
@@ -205,8 +192,7 @@ private extension POSIneligibleReason {
205192
value: "Enable POS feature",
206193
comment: "Button title to enable the POS feature switch and refresh POS eligibility check"
207194
)
208-
case .unsupportedIOSVersion,
209-
.unsupportedWooCommerceVersion,
195+
case .unsupportedWooCommerceVersion,
210196
.siteSettingsNotAvailable,
211197
.wooCommercePluginNotFound,
212198
.unsupportedCurrency,
@@ -216,9 +202,6 @@ private extension POSIneligibleReason {
216202
value: "Retry",
217203
comment: "Button title to refresh POS eligibility check"
218204
)
219-
case .unsupportedInCIABSites:
220-
assertionFailure("Retry button should not be shown for `unsupportedInCIABSites`")
221-
return String()
222205
}
223206
}
224207
}
@@ -234,15 +217,6 @@ private extension POSIneligibleReason {
234217
}
235218
}
236219

237-
#Preview("Unsupported iOS version") {
238-
if #available(iOS 17.0, *) {
239-
POSIneligibleView(
240-
reason: .unsupportedIOSVersion,
241-
onRefresh: {}
242-
)
243-
}
244-
}
245-
246220
#Preview("WooCommerce plugin not found") {
247221
if #available(iOS 17.0, *) {
248222
POSIneligibleView(

0 commit comments

Comments
 (0)