Skip to content

Add network and data layer for category leaderboards#15580

Draft
JorgeMucientes wants to merge 5 commits intotrunkfrom
issue/top-categories-data-layer
Draft

Add network and data layer for category leaderboards#15580
JorgeMucientes wants to merge 5 commits intotrunkfrom
issue/top-categories-data-layer

Conversation

@JorgeMucientes
Copy link
Copy Markdown
Contributor

Description

Adds FluxC and app-layer data infrastructure for fetching top performer categories from the WooCommerce Analytics leaderboards API (wc-analytics/leaderboards/categories). This lays the groundwork for a new "Top Categories" dashboard card (UI in follow-up PR).

FluxC Data Layer

  • LeaderboardCategoryItem parser for category API responses
  • WCCategoryLeaderboardsMapper for mapping API data to Room entities
  • TopPerformerCategoryEntity and TopPerformerCategoriesDao for local persistence
  • Database migration to v80 for the new entity table
  • WCLeaderboardsStore methods for category leaderboard operations
  • ReportsRestClient method for fetching products by category

App Data Layer

  • StatsRepository methods for fetching and caching top performer categories
  • GetTopPerformerCategories use case with cache-first data loading (1-hour expiry)
  • GetProductsByCategory use case for drill-down into category products
  • TopCategoriesCustomDateRangeDataStore for custom date range persistence
  • TopPerformerCategoryUiModel for the presentation layer

Infrastructure Wiring

  • DataStoreType and DataStoreModule entries for custom date range persistence
  • AnalyticsUpdateDataStore entry for cache tracking
  • AppPrefs / AppPrefsWrapper methods for date range selection preference

Test Steps

  1. Build the app and verify it compiles without errors
  2. Navigate to the dashboard — existing widgets should work as before (no UI changes in this PR)
  3. Verify no regressions in existing top performers (products) card
  4. Switch between date ranges on existing cards to confirm nothing is broken

RELEASE-NOTES.txt

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

Add support for fetching top performer categories from the WC
leaderboards API. This includes:
- LeaderboardCategoryItem parser for category API responses
- WCCategoryLeaderboardsMapper for mapping API data to entities
- TopPerformerCategoryEntity Room entity and DAO
- Database migration to v80 for new entity table
- WCLeaderboardsStore methods for category leaderboard operations
- ReportsRestClient method for fetching products by category
Add the app data layer for the top categories dashboard card:
- StatsRepository methods for fetching/caching top performer categories
- GetTopPerformerCategories use case with cache-first data loading
- GetProductsByCategory use case for drill-down into category products
- TopPerformerCategoryUiModel for the presentation layer
- TopCategoriesCustomDateRangeDataStore for custom date range persistence
Add DataStoreType and DataStoreModule entries for top categories
custom date range persistence, AnalyticsUpdateDataStore entry for
cache tracking, and AppPrefs/AppPrefsWrapper methods for date range
selection preference.
@dangermattic
Copy link
Copy Markdown
Collaborator

dangermattic commented Mar 30, 2026

2 Errors
🚫 Please add tests for class GetProductsByCategory (or add unit-tests-exemption label to ignore this).
🚫 Please add tests for class LeaderboardCategoryItem (or add unit-tests-exemption label to ignore this).
1 Warning
⚠️ This PR is larger than 300 lines of changes. Please consider splitting it into smaller PRs for easier and faster reviews.
1 Message
📖 This PR is still a Draft: some checks will be skipped.

Generated by 🚫 Danger

@wpmobilebot
Copy link
Copy Markdown
Collaborator

wpmobilebot commented Mar 30, 2026

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

App NameWooCommerce Android
Platform📱 Mobile
FlavorJalapeno
Build TypeDebug
Build Number736
Version24.4-rc-1
Application IDcom.woocommerce.android.prealpha
Commit615e2c5
Installation URL2vmhjbuo6l848
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@JorgeMucientes JorgeMucientes marked this pull request as draft March 30, 2026 10:02
@JorgeMucientes JorgeMucientes added the feature: analytics In-app store analytics label Mar 30, 2026
@JorgeMucientes JorgeMucientes added this to the 24.5 milestone Mar 30, 2026
Add tests for the GetTopPerformerCategories use case covering:
- Fetch success with and without cached data
- Fetch failure with cached data
- Returning cached data when up-to-date (skip fetch)
- Empty cache with no refresh needed
- Sorting by quantity desc then total desc

Add tests for StatsRepository category methods covering:
- fetchTopPerformerCategories success and failure scenarios
- Cache freshness check (skip fetch when cache is fresh)
- fetchTopPerformerProductsByCategory success and failure scenarios
Update the test to pass the new categoryMapper and
topPerformerCategoriesDao parameters added to WCLeaderboardsStore.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds FluxC + app-layer infrastructure to fetch, persist, and expose “Top Categories” leaderboard data (and product drill-down by category) to support a forthcoming dashboard card.

Changes:

  • Introduces Room persistence for top performer categories (entity/DAO + DB v80 migration + DI wiring).
  • Adds category leaderboard parsing/mapping and new WCLeaderboardsStore / ReportsRestClient APIs for categories and products-by-category.
  • Adds app-layer repository + use cases + DataStore/AppPrefs wiring and unit tests for cache-first loading.

Reviewed changes

Copilot reviewed 22 out of 23 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/wc/leaderboards/WCLeaderboardsStoreTest.kt Updates store construction to include category mapper + DAO dependencies.
libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/store/WCLeaderboardsStore.kt Adds observe/cache/fetch/invalidate APIs for category leaderboards and fetch products-by-category.
libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/entity/TopPerformerCategoryEntity.kt Adds Room entity for cached top performer categories.
libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TopPerformerCategoriesDao.kt Adds DAO queries and update helpers for category leaderboard persistence.
libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt Bumps DB to v80 and registers new entity/DAO + auto-migration.
libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/reports/ReportsRestClient.kt Adds report endpoint call to fetch top products filtered by category.
libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/leaderboards/LeaderboardsApiResponse.kt Adds categories accessor mapping leaderboard rows to category items.
libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/leaderboards/LeaderboardCategoryItem.kt Adds parser/model for “category” leaderboard row arrays.
libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/model/leaderboards/WCCategoryLeaderboardsMapper.kt Maps category leaderboard API models into Room entities.
libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/di/WCDatabaseModule.kt Provides TopPerformerCategoriesDao from the database.
libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/80.json Adds generated Room schema for DB version 80.
WooCommerce/src/test/kotlin/com/woocommerce/android/ui/dashboard/domain/GetTopPerformerCategoriesTest.kt Adds unit tests for cache-first + refresh behavior and sorting.
WooCommerce/src/test/kotlin/com/woocommerce/android/ui/dashboard/data/StatsRepositoryTests.kt Adds repository tests for categories fetch/cache behavior and products-by-category fetching.
WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/domain/GetTopPerformerCategories.kt Adds use case to load top categories with caching/outdated tracking.
WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/domain/GetProductsByCategory.kt Adds use case to fetch products for a selected category (drill-down).
WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/data/TopCategoriesCustomDateRangeDataStore.kt Adds DataStore wrapper for persisting custom date range selection for top categories.
WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/data/StatsRepository.kt Adds repository APIs for category leaderboards and products-by-category + expiry logic.
WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/TopPerformerCategoryUiModel.kt Adds UI model for rendering top categories items.
WooCommerce/src/main/kotlin/com/woocommerce/android/ui/analytics/hub/sync/AnalyticsUpdateDataStore.kt Adds new analytic data key for category leaderboard cache tracking.
WooCommerce/src/main/kotlin/com/woocommerce/android/datastore/DataStoreType.kt Adds new DataStoreType for top performer categories.
WooCommerce/src/main/kotlin/com/woocommerce/android/datastore/DataStoreModule.kt Wires DataStore instance for the top categories custom date range configuration.
WooCommerce/src/main/kotlin/com/woocommerce/android/AppPrefsWrapper.kt Exposes AppPrefs get/set for active top categories tab selection.
WooCommerce/src/main/kotlin/com/woocommerce/android/AppPrefs.kt Adds preference key + accessors for active top categories tab selection.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +182 to +193
fetchAllLeaderboards(
site = site,
startDate = startDate,
endDate = endDate,
quantity = quantity,
addProductsPath = false,
forceRefresh = true,
interval = ""
)
.model
?.firstOrNull { it.type == CATEGORIES }
?.run {
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

fetchAllLeaderboards(...) can return a WooResult with error set and model == null. In that case this implementation falls through to WooResult(WooError(GENERIC_ERROR, UNKNOWN)), discarding the original error details. Consider checking the result from fetchAllLeaderboards first and returning WooResult(it.error) (or equivalent) when it’s an error, so callers get the real failure reason.

Copilot uses AI. Check for mistakes.
Comment on lines +59 to +61
Html.fromHtml(priceAmountHtmlTag, Html.FROM_HTML_MODE_LEGACY)
.toString()
.replace(Regex("[0-9.,]"), "")
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

plainTextCurrency calls Html.fromHtml(priceAmountHtmlTag, ...) where priceAmountHtmlTag is nullable. If the API omits the third row or its display, this will crash at runtime. Make this parsing null-safe (e.g., return an empty string when priceAmountHtmlTag is null) to avoid NPEs on unexpected responses.

Suggested change
Html.fromHtml(priceAmountHtmlTag, Html.FROM_HTML_MODE_LEGACY)
.toString()
.replace(Regex("[0-9.,]"), "")
priceAmountHtmlTag
?.let { Html.fromHtml(it, Html.FROM_HTML_MODE_LEGACY).toString() }
?.replace(Regex("[0-9.,]"), "")
?: ""

Copilot uses AI. Check for mistakes.
Comment on lines +79 to +85
private val link by lazy {
Html.fromHtml(itemHtmlTag, Html.FROM_HTML_MODE_LEGACY)
.run { this as? SpannableStringBuilder }
?.spansAsList()
?.firstOrNull()
?.url
}
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

link uses Html.fromHtml(itemHtmlTag, ...) with itemHtmlTag being nullable. If the API returns a row with a null display, this will throw at runtime. Consider guarding with itemHtmlTag?.let { Html.fromHtml(it, ...) } (or similar) and returning null when missing.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature: analytics In-app store analytics

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants