Skip to content

Commit 1ba7a70

Browse files
committed
Use POS visibility for catalog checks
1 parent d402747 commit 1ba7a70

File tree

7 files changed

+65
-43
lines changed

7 files changed

+65
-43
lines changed

Modules/Sources/PointOfSale/Protocols/POSLocalCatalogEligibilityServiceProtocol.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public enum POSLocalCatalogEligibilityState: Equatable {
1212

1313
/// Reasons why local catalog is ineligible
1414
public enum POSLocalCatalogIneligibleReason: Equatable {
15-
case posTabNotEligible
15+
case posTabNotVisible
1616
case featureFlagDisabled
1717
case catalogSizeTooLarge(totalCount: Int, limit: Int)
1818
case catalogSizeCheckFailed(underlyingError: String)
@@ -31,6 +31,10 @@ public protocol POSLocalCatalogEligibilityServiceProtocol {
3131
/// Current eligibility state (synchronously accessible on main thread)
3232
var eligibilityState: POSLocalCatalogEligibilityState { get }
3333

34+
/// Update the POS tab visibility state and refresh eligibility
35+
/// - Parameter isPOSTabVisible: Whether the POS tab is visible
36+
func updateVisibility(isPOSTabVisible: Bool) async
37+
3438
/// Force refresh eligibility (bypasses cache and updates eligibilityState)
3539
/// - Returns: Fresh eligibility state with reason if ineligible
3640
@discardableResult func refreshEligibilityState() async -> POSLocalCatalogEligibilityState

Modules/Tests/PointOfSaleTests/Mocks/MockPOSLocalCatalogEligibilityService.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@ public final class MockPOSLocalCatalogEligibilityService: POSLocalCatalogEligibi
1515
refreshCallCount += 1
1616
return eligibilityState
1717
}
18+
19+
public func updateVisibility(isPOSTabVisible: Bool) async { }
1820
}

WooCommerce/Classes/POS/Eligibility/POSLocalCatalogEligibilityService.swift

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,14 @@ import Experiments
55
import protocol PointOfSale.POSLocalCatalogEligibilityServiceProtocol
66
import enum PointOfSale.POSLocalCatalogEligibilityState
77
import enum PointOfSale.POSLocalCatalogIneligibleReason
8-
import enum PointOfSale.POSEligibilityState
9-
import enum PointOfSale.POSIneligibleReason
108

119
@MainActor
1210
final class POSLocalCatalogEligibilityService: POSLocalCatalogEligibilityServiceProtocol {
1311
private let siteID: Int64
1412
private let catalogSizeChecker: POSCatalogSizeCheckerProtocol
1513
private let catalogSizeLimit: Int
1614
private let featureFlagService: FeatureFlagService
17-
private let posTabEligibilityState: POSEligibilityState
15+
private var isPOSTabVisible: Bool
1816

1917
// Current eligibility state
2018
private(set) var eligibilityState: POSLocalCatalogEligibilityState
@@ -24,25 +22,31 @@ final class POSLocalCatalogEligibilityService: POSLocalCatalogEligibilityService
2422
siteID: Int64,
2523
catalogSizeChecker: POSCatalogSizeCheckerProtocol,
2624
featureFlagService: FeatureFlagService = ServiceLocator.featureFlagService,
27-
posTabEligibilityState: POSEligibilityState,
25+
isPOSTabVisible: Bool,
2826
catalogSizeLimit: Int? = nil
2927
) async {
3028
self.siteID = siteID
3129
self.catalogSizeChecker = catalogSizeChecker
3230
self.featureFlagService = featureFlagService
33-
self.posTabEligibilityState = posTabEligibilityState
31+
self.isPOSTabVisible = isPOSTabVisible
3432
self.catalogSizeLimit = catalogSizeLimit ?? Constants.defaultCatalogSizeLimit
3533

3634
// Perform initial check
3735
self.eligibilityState = .eligible // Temporary
38-
_ = await self.refreshEligibilityState()
36+
await self.refreshEligibilityState()
37+
}
38+
39+
/// Update the visibility state and refresh eligibility
40+
func updateVisibility(isPOSTabVisible: Bool) async {
41+
self.isPOSTabVisible = isPOSTabVisible
42+
await refreshEligibilityState()
3943
}
4044

4145
@discardableResult func refreshEligibilityState() async -> POSLocalCatalogEligibilityState {
42-
// Check POS tab eligibility FIRST - no point in checking catalog if POS tab isn't eligible
43-
if case .ineligible = posTabEligibilityState {
44-
eligibilityState = .ineligible(reason: .posTabNotEligible)
45-
DDLogInfo("📋 POSLocalCatalogEligibilityService: POS tab not eligible for site \(siteID)")
46+
// Check POS tab visibility FIRST - no point in checking catalog if POS tab isn't visible
47+
guard isPOSTabVisible else {
48+
eligibilityState = .ineligible(reason: .posTabNotVisible)
49+
DDLogInfo("📋 POSLocalCatalogEligibilityService: POS tab not visible for site \(siteID)")
4650
return eligibilityState
4751
}
4852

WooCommerce/Classes/POS/TabBar/POSTabCoordinator.swift

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ final class POSTabCoordinator {
107107
storageManager: StorageManagerType = ServiceLocator.storageManager,
108108
currencySettings: CurrencySettings = ServiceLocator.currencySettings,
109109
pushNotesManager: PushNotesManager = ServiceLocator.pushNotesManager,
110-
eligibilityChecker: POSEntryPointEligibilityCheckerProtocol) {
110+
eligibilityChecker: POSEntryPointEligibilityCheckerProtocol,
111+
initialPOSTabVisibility: Bool) {
111112
self.siteID = siteID
112113
self.storesManager = storesManager
113114
self.defaultSitePublisher = storesManager.sessionManager.defaultSitePublisher
@@ -128,26 +129,32 @@ final class POSTabCoordinator {
128129
tabContainerController.wrappedController = POSTabViewController()
129130

130131
// Create local catalog eligibility service asynchronously
131-
// Check POS tab eligibility first, then create service with that state
132+
// Use initial POS tab visibility from cached check
132133
Task { @MainActor [weak self] in
133134
guard let self else { return }
134135

135-
let posEligibility = await eligibilityChecker.checkEligibility()
136-
137136
let service = await POSLocalCatalogEligibilityService(
138137
siteID: siteID,
139138
catalogSizeChecker: POSCatalogSizeChecker(
140139
credentials: credentials,
141140
selectedSite: defaultSitePublisher,
142141
appPasswordSupportState: isAppPasswordSupported
143142
),
144-
posTabEligibilityState: posEligibility
143+
isPOSTabVisible: initialPOSTabVisibility
145144
)
146145

147146
self.localCatalogEligibilityService = service
148147
}
149148
}
150149

150+
/// Update local catalog eligibility when POS tab visibility changes
151+
func updatePOSTabVisibility(_ isPOSTabVisible: Bool) {
152+
Task { @MainActor [weak self] in
153+
guard let self, let service = self.localCatalogEligibilityService else { return }
154+
await service.updateVisibility(isPOSTabVisible: isPOSTabVisible)
155+
}
156+
}
157+
151158
func onTabSelected() {
152159
setPOSHasBeenOpened()
153160
presentPOSView(siteID: siteID)
@@ -171,11 +178,8 @@ private extension POSTabCoordinator {
171178
let isLocalCatalogEligible: Bool
172179
if let service = localCatalogEligibilityService {
173180
// Retry transient failures before using the value
174-
switch service.eligibilityState {
175-
case .ineligible(reason: .catalogSizeCheckFailed), .ineligible(reason: .posTabNotEligible):
181+
if case .ineligible(reason: .catalogSizeCheckFailed) = service.eligibilityState {
176182
await service.refreshEligibilityState()
177-
default:
178-
break
179183
}
180184
isLocalCatalogEligible = service.eligibilityState == .eligible
181185
} else {

WooCommerce/Classes/ViewRelated/MainTabBarController.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,9 @@ private extension MainTabBarController {
721721
updateTabViewControllers(isPOSTabVisible: isPOSTabVisible, isBookingsTabVisible: isBookingsTabVisible)
722722
viewModel.loadHubMenuTabBadge()
723723

724+
// Update POS tab coordinator with new visibility state for local catalog eligibility
725+
posTabCoordinator?.updatePOSTabVisibility(isPOSTabVisible)
726+
724727
// Begin foreground synchronization if POS tab becomes visible
725728
await isPOSTabVisible ? posSyncDispatcher.start() : posSyncDispatcher.stop()
726729
}
@@ -826,12 +829,15 @@ private extension MainTabBarController {
826829
selectedIndex = WooTab.myStore.visibleIndex(isPOSTabVisible: isPOSTabVisible,
827830
isBookingsTabVisible: isBookingsTabVisible)
828831

832+
// Create POS tab coordinator with initial visibility from cache
833+
let initialPOSTabVisibility = posTabVisibilityChecker?.checkInitialVisibility() ?? false
829834
posTabCoordinator = POSTabCoordinator(
830835
siteID: siteID,
831836
tabContainerController: posContainerController,
832837
viewControllerToPresent: self,
833838
storesManager: stores,
834-
eligibilityChecker: POSTabEligibilityChecker(siteID: siteID)
839+
eligibilityChecker: POSTabEligibilityChecker(siteID: siteID),
840+
initialPOSTabVisibility: initialPOSTabVisibility
835841
)
836842

837843
// Updates site ID for the bookings tab to display correct bookings

WooCommerce/WooCommerceTests/POS/Eligibility/POSLocalCatalogEligibilityServiceTests.swift

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ struct POSLocalCatalogEligibilityServiceTests {
2323
siteID: siteID,
2424
catalogSizeChecker: sizeChecker,
2525
featureFlagService: featureFlagService,
26-
posTabEligibilityState: .eligible,
26+
isPOSTabVisible: true,
2727
catalogSizeLimit: 1000
2828
)
2929

@@ -40,7 +40,7 @@ struct POSLocalCatalogEligibilityServiceTests {
4040
siteID: siteID,
4141
catalogSizeChecker: sizeChecker,
4242
featureFlagService: featureFlagService,
43-
posTabEligibilityState: .eligible,
43+
isPOSTabVisible: true,
4444
catalogSizeLimit: 1000
4545
)
4646

@@ -59,7 +59,7 @@ struct POSLocalCatalogEligibilityServiceTests {
5959
siteID: siteID,
6060
catalogSizeChecker: sizeChecker,
6161
featureFlagService: featureFlagService,
62-
posTabEligibilityState: .eligible,
62+
isPOSTabVisible: true,
6363
catalogSizeLimit: 1000
6464
)
6565

@@ -92,7 +92,7 @@ struct POSLocalCatalogEligibilityServiceTests {
9292
siteID: siteID,
9393
catalogSizeChecker: sizeChecker,
9494
featureFlagService: featureFlagService,
95-
posTabEligibilityState: .eligible,
95+
isPOSTabVisible: true,
9696
catalogSizeLimit: 1000
9797
)
9898

@@ -123,7 +123,7 @@ struct POSLocalCatalogEligibilityServiceTests {
123123
siteID: siteID,
124124
catalogSizeChecker: sizeChecker,
125125
featureFlagService: featureFlagService,
126-
posTabEligibilityState: .eligible,
126+
isPOSTabVisible: true,
127127
catalogSizeLimit: 1000
128128
)
129129

@@ -148,7 +148,7 @@ struct POSLocalCatalogEligibilityServiceTests {
148148
siteID: siteID,
149149
catalogSizeChecker: sizeChecker,
150150
featureFlagService: featureFlagService,
151-
posTabEligibilityState: .eligible,
151+
isPOSTabVisible: true,
152152
catalogSizeLimit: 1000
153153
)
154154

@@ -173,7 +173,7 @@ struct POSLocalCatalogEligibilityServiceTests {
173173
siteID: siteID,
174174
catalogSizeChecker: sizeChecker,
175175
featureFlagService: featureFlagService,
176-
posTabEligibilityState: .eligible,
176+
isPOSTabVisible: true,
177177
catalogSizeLimit: 1000
178178
)
179179

@@ -213,7 +213,7 @@ struct POSLocalCatalogEligibilityServiceTests {
213213
siteID: siteID,
214214
catalogSizeChecker: sizeChecker,
215215
featureFlagService: featureFlagService,
216-
posTabEligibilityState: .eligible,
216+
isPOSTabVisible: true,
217217
catalogSizeLimit: 1000
218218
)
219219

@@ -245,7 +245,7 @@ struct POSLocalCatalogEligibilityServiceTests {
245245
siteID: siteID,
246246
catalogSizeChecker: sizeChecker,
247247
featureFlagService: featureFlagService,
248-
posTabEligibilityState: .eligible,
248+
isPOSTabVisible: true,
249249
catalogSizeLimit: 100 // Custom lower limit
250250
)
251251

@@ -265,10 +265,10 @@ struct POSLocalCatalogEligibilityServiceTests {
265265
#expect(limit == 100)
266266
}
267267

268-
// MARK: - POS Tab Eligibility
268+
// MARK: - POS Tab Visibility
269269

270-
@Test("POS tab not eligible returns ineligible")
271-
func testPOSTabNotEligibleReturnsIneligible() async {
270+
@Test("POS tab not visible returns ineligible")
271+
func testPOSTabNotVisibleReturnsIneligible() async {
272272
let sizeChecker = MockPOSCatalogSizeChecker(
273273
sizeToReturn: .success(POSCatalogSize(productCount: 500, variationCount: 400))
274274
)
@@ -277,7 +277,7 @@ struct POSLocalCatalogEligibilityServiceTests {
277277
siteID: siteID,
278278
catalogSizeChecker: sizeChecker,
279279
featureFlagService: featureFlagService,
280-
posTabEligibilityState: .ineligible(reason: .featureSwitchDisabled),
280+
isPOSTabVisible: false,
281281
catalogSizeLimit: 1000
282282
)
283283

@@ -288,17 +288,17 @@ struct POSLocalCatalogEligibilityServiceTests {
288288
return
289289
}
290290

291-
guard case .posTabNotEligible = reason else {
292-
Issue.record("Expected posTabNotEligible reason")
291+
guard case .posTabNotVisible = reason else {
292+
Issue.record("Expected posTabNotVisible reason")
293293
return
294294
}
295295

296296
// Should not have checked catalog size
297297
#expect(sizeChecker.checkCatalogSizeCallCount == 0)
298298
}
299299

300-
@Test("POS tab eligibility checked before catalog size")
301-
func testPOSTabEligibilityCheckedFirst() async {
300+
@Test("POS tab visibility checked before catalog size")
301+
func testPOSTabVisibilityCheckedFirst() async {
302302
let sizeChecker = MockPOSCatalogSizeChecker(
303303
sizeToReturn: .success(POSCatalogSize(productCount: 2000, variationCount: 0))
304304
)
@@ -307,22 +307,22 @@ struct POSLocalCatalogEligibilityServiceTests {
307307
siteID: siteID,
308308
catalogSizeChecker: sizeChecker,
309309
featureFlagService: featureFlagService,
310-
posTabEligibilityState: .ineligible(reason: .wooCommercePluginNotFound),
310+
isPOSTabVisible: false,
311311
catalogSizeLimit: 1000
312312
)
313313

314-
// Should be ineligible due to POS tab, not catalog size
314+
// Should be ineligible due to POS tab not visible, not catalog size
315315
guard case .ineligible(let reason) = service.eligibilityState else {
316316
Issue.record("Expected ineligible state")
317317
return
318318
}
319319

320-
guard case .posTabNotEligible = reason else {
321-
Issue.record("Expected posTabNotEligible reason, not catalogSizeTooLarge")
320+
guard case .posTabNotVisible = reason else {
321+
Issue.record("Expected posTabNotVisible reason, not catalogSizeTooLarge")
322322
return
323323
}
324324

325-
// Should not have checked catalog size since POS tab wasn't eligible
325+
// Should not have checked catalog size since POS tab wasn't visible
326326
#expect(sizeChecker.checkCatalogSizeCallCount == 0)
327327
}
328328
}

WooCommerce/WooCommerceTests/POS/Mocks/MockPOSLocalCatalogEligibilityService.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@ public final class MockPOSLocalCatalogEligibilityService: POSLocalCatalogEligibi
1515
refreshCallCount += 1
1616
return eligibilityState
1717
}
18+
19+
public func updateVisibility(isPOSTabVisible: Bool) async { }
1820
}

0 commit comments

Comments
 (0)