Add Paid by search filter UI, table column, sorting, and export - #98326
Add Paid by search filter UI, table column, sorting, and export#98326c3024 wants to merge 14 commits into
Conversation
The payer filter is now shown in the advanced filters and filter bar as a multi-select user filter, and a Payer column is available on expense report search views. The column is derived from the actor of the latest payment report action returned in the search snapshot, matching how First approver is derived, and is sortable and exportable.
|
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 |
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
Matches the backend gate on report status, so canceled or reopened reports fall back to having no payer column value.
The payer filter keeps its existing responsible-payer meaning (hidden from the filters UI as before) and the payment-actor work moves to a new paidBy filter key, table column, and translations. The paid-by syntax also accepts paid-by: like the other multi-word keys.
|
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 bun ./scripts/generateTranslations.ts --helpTypically, you'd want to translate only what you changed by running |
…r-search-filter # Conflicts: # src/libs/SearchParser/autocompleteParser.js # src/libs/SearchParser/searchParser.js
…a/670393-payer-search-filter
|
@hoangzinh Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
| const formattedTo = !shouldShowBlankTo ? temporaryGetDisplayNameOrDefault({passedPersonalDetails: toDetails, translate, formatPhoneNumber}) : ''; | ||
| const formattedFirstApprover = firstApproverAccountID ? temporaryGetDisplayNameOrDefault({passedPersonalDetails: firstApproverDetails, translate, formatPhoneNumber}) : ''; | ||
|
|
||
| // The paid-by user is the actor on the latest payment action; blank until the report is paid. |
There was a problem hiding this comment.
❌ CONSISTENCY-16 (docs)
Comments should read like plain, natural sentences. This comment joins two clauses with a semicolon instead of using two separate sentences, which CONSISTENCY-16 flags.
Split it into two sentences:
// The paid-by user is the actor on the latest payment action. It stays blank until the report is paid.
const lastReimbursedAction = lastReimbursedActionByReportID.get(reportItem.reportID);Reviewed at: 03abca5 | Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 03abca58f7
ℹ️ 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".
| const FILTER_COMPONENT_MAP: Partial<Record<SearchFilter['key'], React.ComponentType<DropdownProps>>> = { | ||
| [CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM]: UserDropdown, | ||
| [CONST.SEARCH.SYNTAX_FILTER_KEYS.TO]: UserDropdown, | ||
| [CONST.SEARCH.SYNTAX_FILTER_KEYS.PAID_BY]: UserDropdown, |
There was a problem hiding this comment.
Preserve paid-by IDs for the user dropdown
When a Paid by filter is applied, getDisplayValue() does not classify PAID_BY/PAID_BY_NOT with the other user filters, so it joins the account-ID array into a string before this mapping passes it to UserDropdown. useFilterUserValue() explicitly returns no names for non-array input, leaving the Paid by filter chip/dropdown value blank even though the filter is active. Preserve the ID array for both paid-by keys as is done for From and To.
Useful? React with 👍 / 👎.
| [CONST.SEARCH.SYNTAX_FILTER_KEYS.PAID_BY]: { | ||
| labelKey: 'search.filters.paidBy', | ||
| icon: 'MoneyBag', | ||
| }, |
There was a problem hiding this comment.
Render paid-by values through the user formatter
Adding Paid by to FILTER_VIEW_MAP makes it appear in the applied-filters list on the save-search page, but SearchSavePage.FilterValue does not recognize this key as a user filter. Consequently, saving a search with Paid by selected displays raw account IDs rather than the users' names; route PAID_BY through FilterUserValue alongside From, To, Attendee, and Assignee.
Useful? React with 👍 / 👎.
|
Let us know when you have videos to review. |
joekaufmanexpensify
left a comment
There was a problem hiding this comment.
Great addition. Excited for this!
Explanation of Change
paidBy:filter (also typable aspaid-by:, likeexpense-type:) to the advanced filters and filter bar as a multi-select user filter for expense, expense report, invoice, and trip searches. It matches the user who actually paid a report. The existingpayer:filter (the responsible payer, powering the Pay to-do) is unchanged and stays hidden from the filters UI, per the Slack naming decision.Fixed Issues
$ https://github.com/Expensify/Expensify/issues/670393
PROPOSAL:
Tests
Screen.Recording.2026-08-17.at.3.41.21.PM.mov
Offline tests
NA
QA Steps
Same as tests.
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectionAvatar, 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.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
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari