Skip to content

Conversation

@jaclync
Copy link
Contributor

@jaclync jaclync commented Jun 16, 2025

Closes WOOMOB-611

Why

Previously, POS eligibility is checked async based on a few API requests for displaying the POS tab. This results in a noticeable delay when the POS tab is shown (just the initial site settings API request for store country/currency already takes ~1.8 on my end for a Pressable site via Jetpack connection) after every launch / login / store switching. This PR aims to reduce the delay after the first POS eligibility check based on the assumption that merchants do not change store configurations that could affect POS eligibility often, by caching the POS eligibility and displaying the initial tab based on the cached value while checking POS eligibility async.

Please feel free to suggest other ways to optimize the POS tab visibility check, and any implementation details in this PR.

Description

This pull request introduces functionality to manage the visibility of the POS (Point of Sale) tab based on eligibility and initial visibility checks. Key changes include updates to caching POS eligibility via app settings, new methods for managing POS tab visibility, and associated unit tests.

Updates to GeneralStoreSettings:

  • Added two new properties, isPOSTabVisible and lastPOSTabVisibilityCheckDate, to the GeneralStoreSettings struct for tracking POS tab visibility and the last check date. (Storage/Storage/Model/GeneralStoreSettings.swift: [1] [2] [3] [4] [5]
  • Updated the Copiable extension for GeneralStoreSettings to include the new properties for copying and merging data. (Storage/Storage/Model/Copiable/Models+Copiable.generated.swift: [1] [2] [3]

POS Tab Visibility Management:

  • Introduced a new method, checkInitialVisibility, in POSTabEligibilityChecker to determine the initial visibility of the POS tab without relying on network requests. (WooCommerce/Classes/ViewRelated/Dashboard/Settings/POS/POSTabEligibilityChecker.swift: [1] [2]
  • Added logic in MainTabBarController to update the visibility of the POS tab based on initial visibility and eligibility checks, and to persist visibility state in app settings. (WooCommerce/Classes/ViewRelated/MainTabBarController.swift: [1] [2] [3]

Unit Tests:

  • Added a comprehensive test in MainTabBarControllerTests to verify POS tab visibility behavior under various conditions, including initial visibility and eligibility changes. (WooCommerce/WooCommerceTests/ViewRelated/MainTabBarControllerTests.swift: WooCommerce/WooCommerceTests/ViewRelated/MainTabBarControllerTests.swiftR454-R525)
  • Introduced mock implementations for POSEligibilityChecker and StoresManager to support testing of POS tab visibility logic. (WooCommerce/WooCommerceTests/Mocks/MockPOSEligibilityChecker.swift: [1] WooCommerce/WooCommerceTests/ViewRelated/MainTabBarControllerTests.swift: [2]
  • Passed storesManager as a dependency to various components, such as POSTabCoordinator, HubMenuCoordinator, and HubMenuViewController, to manage POS tab-related actions. (WooCommerce/Classes/POS/TabBar/POSTabCoordinator.swift: [1] WooCommerce/Classes/ViewRelated/Hub Menu/HubMenuCoordinator.swift: [2] WooCommerce/Classes/ViewRelated/Hub Menu/HubMenuViewController.swift: [3] WooCommerce/Classes/ViewRelated/Hub Menu/HubMenuViewModel.swift: [4]

Steps to reproduce

Prerequisite: a WPCOM account that has at least two connected stores, one eligible for POS and the other one not eligible.

  • Log out if needed
  • Log in to the account in the prerequisite with the store that is eligible for POS --> after logging in, the POS tab should appear shortly
  • Tap on the POS tab --> it should launch POS in full-screen
  • Exit POS
  • Go to Menu tab and switch to a store ineligible for POS --> after switching stores, the POS tab should not appear even after a while
  • Switch to a store eligible for POS again --> after switching stores, the POS tab should appear immediately
  • Tap on the POS tab --> it should launch POS in full-screen
  • Exit POS
  • Relaunch the app --> the POS tab should appear immediately
  • Go to Menu tab and switch to a store ineligible for POS --> after switching stores, the POS tab should not appear even after a while

Testing information

  • @jaclync tests that if the POS tab is initially visible, tapping on the tab to launch POS, then POS eligibility becomes ineligible async, the app should not crash and the POS tab is hidden after exiting POS (this should also be covered in the MainTabBarController test case)

Screenshots

Simulator.Screen.Recording.-.iPad.A16.-.2025-06-16.at.16.48.02.mp4

  • I have considered if this change warrants user-facing release notes and have added them to RELEASE-NOTES.txt if necessary.

jaclync added 3 commits June 16, 2025 16:29
…. DI `currentDate` to `AppSettingsAction.loadPOSTabVisibility` for unit tests.
…er selecting the tab with the tab being shown from initial value.
@jaclync jaclync added this to the 22.7 milestone Jun 16, 2025
@jaclync jaclync added type: task An internally driven task. feature: POS labels Jun 16, 2025
@wpmobilebot
Copy link
Collaborator

wpmobilebot commented Jun 16, 2025

App Icon📲 You can test the changes from this Pull Request in WooCommerce iOS Prototype by scanning the QR code below to install the corresponding build.

App NameWooCommerce iOS Prototype
Build Number30535
VersionPR #15753
Bundle IDcom.automattic.alpha.woocommerce
Commit7b29c57
Installation URL5i9bor3vr0b5o
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@jaclync jaclync marked this pull request as ready for review June 16, 2025 08:58
@staskus staskus self-assigned this Jun 16, 2025
Copy link
Contributor

@staskus staskus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the improvement!

I think it could be slightly improved by making a call to the initial cache synchronous and eliminating a delay entirely.

guard let self, let posEligibilityChecker else { return }
let eligibility = await posEligibilityChecker.checkEligibility()
let isPOSTabVisible = eligibility == .eligible
async let initialVisibility = posEligibilityChecker.checkInitialVisibility()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's still a slight delay for the Point of Sale tab to appear.

updateTabViewControllers(isPOSTabVisible: posEligibilityChecker.checkInitialVisibility())
Simulator.Screen.Recording.-.iPad.Air.13-inch.M3.-.2025-06-16.at.15.21.11.mp4

If we look at checkInitialVisibility implementation, it could be synchronous, and we could call it outside the posEligibilityCheckTask, allowing for the tab to appear as soon as possible. It would require getting around dispatching AppSettingsStore and accessing the data directly, but other than that, it would allow for a smoother appearance:

Simulator.Screen.Recording.-.iPad.Air.13-inch.M3.-.2025-06-16.at.15.31.22.mp4

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's interesting that I didn't observe the slight delay in iOS 18.4 simulator, as in the screencast 1:06. But then I tried the same simulator type in iOS 18.5, and I see the delay now. I tried the device type as in my original screencast but in iOS 18.5 and see the same, so likely a behavior difference (probably about the timing of Task) between iOS versions. I'm looking into using a service for loading the initial visibility to make it sync.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion, I updated the PR with a few commits to move the async initial value to a synchronous call from a new service in Yosemite POSEligibilityService behind a protocol for unit testing. Also moved the AppSettingsAction/store changes to the service for consistency. Please see if the delay is fixed after the initial load when you get a chance, thanks!

return onCompletion(nil)
}

let threeDaysInSeconds: TimeInterval = 3 * 24 * 60 * 60 // 3 days in seconds.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that three days is more than safe. I would even go as far as to say that this cache could always be considered valid since we update it every time the app gets launched.

You can always find a way to break POS, even with a 3-day cache:

  • Configure the wp-admin settings to support POS
  • Launch Woo App, open POS
  • Change the wp-admin settings to stop supporting POS
  • Continue using Woo POS, observe some failures

Therefore, we could choose not to overthink it and always return the last tab visibility value for simplicity.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea good point, this edge case can already happen in production and not worth adding complexity for. I removed the date check in 396d3a8, so that it's just using the cached value for initial tab visibility.

@jaclync jaclync changed the title [POS as a tab i1] Cache POS tab visibility value per site for 3 days [POS as a tab i1] Cache POS tab visibility per site for initial value while checking eligibility async Jun 17, 2025
@jaclync
Copy link
Contributor Author

jaclync commented Jun 17, 2025

Updated the PR for another pass!

Copy link
Contributor

@staskus staskus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works perfectly now! Thanks for addressing the comments. Nice job on the functionality. 👏

# Conflicts:
#	WooCommerce/WooCommerce.xcodeproj/project.pbxproj
@jaclync jaclync enabled auto-merge June 18, 2025 04:00
@jaclync jaclync merged commit c8788ef into trunk Jun 18, 2025
13 checks passed
@jaclync jaclync deleted the feat/WOOMOB-611-cache-pos-eligibility branch June 18, 2025 04:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature: POS type: task An internally driven task.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants