feat(insights): add Top Categories suggested search#80102
feat(insights): add Top Categories suggested search#80102lakchote merged 11 commits intoExpensify:mainfrom
Conversation
|
Hey, I noticed you changed If you want to automatically generate translations for other locales, an Expensify employee will have to:
Alternatively, if you are an external contributor, you can run the translation script locally with your own OpenAI API key. To learn more, try running: npx ts-node ./scripts/generateTranslations.ts --helpTypically, you'd want to translate only what you changed by running |
|
All contributors have signed the CLA ✍️ ✅ |
|
I have read the CLA Document and I hereby sign the CLA |
9c6e968 to
01a88a8
Compare
01a88a8 to
743daa0
Compare
743daa0 to
4d5aff2
Compare
| [CONST.SEARCH.GROUP_BY.FROM]: 'De', | ||
| [CONST.SEARCH.GROUP_BY.CARD]: 'Tarjeta', | ||
| [CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID]: 'ID de retiro', | ||
| [CONST.SEARCH.GROUP_BY.CATEGORY]: 'Categoría', |
There was a problem hiding this comment.
I then posted it in #expensify-open-source and it was approved by an internal Expensify engineer. Link to Slack message:
i dont have access to slack, Can c+ reviewer please help me verify this 🙏
There was a problem hiding this comment.
Please read this guide to learn how to access Slack:
https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#slack-channels
When you update translations, Slack access is required to get confirmation. If you have any additional questions, you can post them in Slack.
There was a problem hiding this comment.
If any non-english text was added/modified, I used JaimeGPT to get English > Spanish translation. I then posted it in #expensify-open-source and it was approved by an internal Expensify engineer. Link to Slack message:
@ashu75575 https://expensify.slack.com/archives/C01GTK53T8Q/p1769138968997009 Please add this link to the checklist.
There was a problem hiding this comment.
Category exists in en.ts, this is fine.
Line 232 in 9ce6569
There was a problem hiding this comment.
(But generally agree with the process to follow for the future!)
src/libs/SearchUIUtils.ts
Outdated
| const isEligibleForReconciliationSuggestion = isPaidPolicy && isAdmin && ((isPaymentEnabled && hasVBBA && hasReimburser) || isECardEnabled); | ||
| const isAuditor = policy.role === CONST.POLICY.ROLE.AUDITOR; | ||
| const isEligibleForTopSpendersSuggestion = isPaidPolicy && (isAdmin || isAuditor || isApprover); | ||
| const isEligibleForTopCategoriesSuggestion = isPaidPolicy && (isAdmin || isAuditor || isApprover); |
There was a problem hiding this comment.
issue suggests "Add visibility logic in getSuggestedSearchesVisibility() to show for all accounts with at least one workspace (policy)" but i added same logic to be consistent with isEligibleForTopSpendersSuggestion please let me know if we want to change this
There was a problem hiding this comment.
@neil-marcellini can you please confirm this 🙏
There was a problem hiding this comment.
Nah, Top Spenders is shown to admins, approvers and auditors. Top Categories is shown to all workspace members.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 59f41f6401
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
src/libs/SearchUIUtils.ts
Outdated
| { | ||
| type: CONST.SEARCH.DATA_TYPES.EXPENSE, | ||
| groupBy: CONST.SEARCH.GROUP_BY.CATEGORY, | ||
| dateOn: CONST.SEARCH.DATE_PRESETS.LAST_MONTH, |
There was a problem hiding this comment.
Add UI support for category group-by or hide suggestion
This new suggested search sets groupBy to CATEGORY, but the search UI only handles group-by values for FROM, CARD, and WITHDRAWAL_ID (e.g., getSections/getSortedSections switches in SearchUIUtils.ts, and header rendering in SearchTableHeader.tsx/TransactionGroupListItem.tsx lack a category case). When a user taps “Top categories,” the backend will return grouped data, yet the UI falls back to the non-grouped path and ignores group entries, which typically yields empty or broken results with missing headers. Either implement category group rendering (sections, headers, list item type guards, sorting) or avoid surfacing this suggestion until support is in place.
Useful? React with 👍 / 👎.
|
@ashu75575 Please update the |
|
@ashu75575 Please set up data before recording the video so that Top categories has data to display. |
| return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID; | ||
| }, | ||
| }, | ||
| [CONST.SEARCH.SEARCH_KEYS.TOP_SPENDERS]: createTopSearchMenuItem(CONST.SEARCH.SEARCH_KEYS.TOP_SPENDERS, 'search.topSpenders', Expensicons.User, CONST.SEARCH.GROUP_BY.FROM), |
There was a problem hiding this comment.
We do not need to add the createTopSearchMenuItem util function here. Therefore, you only need to add the TOP_CATEGORIES case and follow the existing code pattern above.
There was a problem hiding this comment.
please check this ai comment #80102 (comment)
|
Sounds like this PR needs to come first before we can merge this one: #80333 |
|
Taking this off hold as we've merged #80333 |
|
🚧 @trjExpensify has triggered a test Expensify/App build. You can view the workflow run here. |
This comment has been minimized.
This comment has been minimized.
|
@ashu75575 @huult I just took the adhoc build for a spin and I'm getting nothing to show. Why is that?
|
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
|
@trjExpensify it looks like this PR hasn’t been merged into main yet, so the code changes don’t exist and there’s nothing showing up. @ashu75575 please merge main and double-check your changes after that, then ping me to review again. |
|
🚧 @lakchote has triggered a test Expensify/App build. You can view the workflow run here. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
It now works correctly:
cc @huult you can continue the review |
|
Looks good on my end too from a design perspective 👍 |
|
added limit filter as per issue #80036 |
|
@ashu75575 Is this PR is ready? |
|
yes |
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppScreen.Recording.2026-01-27.at.15.46.00.mp4Android: mWeb ChromeScreen.Recording.2026-01-27.at.15.46.44.mp4iOS: HybridAppScreen.Recording.2026-01-27.at.15.49.41.mp4iOS: mWeb SafariScreen.Recording.2026-01-27.at.15.50.40.mp4MacOS: Chrome / SafariScreen.Recording.2026-01-27.at.15.39.49.mp4 |
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🚀 Deployed to staging by https://github.com/lakchote in version: 9.3.10-0 🚀
|
|
🚀 Deployed to production by https://github.com/roryabraham in version: 9.3.10-6 🚀
|


Explanation of Change
Fixed Issues
$ #80036
PROPOSAL: #80036 (comment)
Tests
Same as Q/A
Same as Qa Steps
Offline tests
QA Steps
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectioncanBeMissingparam foruseOnyxtoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.ScrollViewcomponent to make it scrollable when more elements are added to the page.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Screen.Recording.2026-01-21.at.10.12.43.PM.mov
Android: mWeb Chrome
Screen.Recording.2026-01-21.at.10.11.34.PM.mov
iOS: Native
Screen.Recording.2026-01-21.at.5.54.43.PM.mov
iOS: mWeb Safari
Screen.Recording.2026-01-21.at.10.49.12.PM.mov
MacOS: Chrome / Safari
Screen.Recording.2026-01-21.at.5.47.38.PM.mov