Fix/move preselected items to top#80322
Fix/move preselected items to top#80322marufsharifi wants to merge 51 commits intoExpensify:mainfrom
Conversation
|
@linhvovan29546 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] |
|
Hey! I see that you made changes to our Form component. Make sure to update the docs in FORMS.md accordingly. Cheers! |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 05b55479e2
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
trjExpensify
left a comment
There was a problem hiding this comment.
Agreed change with @Expensify/design team! Tagging 'em in though, if they want to check it out. 👍
linhvovan29546
left a comment
There was a problem hiding this comment.
@marufsharifi I’ll continue the review after you address the feedback from the AI reviewer.
|
Been a while for this one! I also thought we wanted to make sure all selected items would be at the top of the list if they were already selected before opening up the list? Does that sound familiar? Pretty sure we had asked for that a while ago, but I'm not sure where we stand there. |
The previous PR took a long time, and the contributor couldn’t find a working solution after the selection list refactor, so we’re reopening proposals. |
Thanks for the hard work! |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a1194a3c94
ℹ️ 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".
|
@linhvovan29546, thanks for the review. I've addressed your comments; please take another look. |
|
Great momentum. Would love to get this one merged this week. |
|
@codex review |
|
Reviewing... |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ba473bb84a
ℹ️ 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 selectedSectionBaseData = searchTerm.trim().length === 0 && initialSelectedOptions.length > 0 ? initialSelectedOptions : formattedSelectedOptions; | ||
| const selectedSectionData = |
There was a problem hiding this comment.
Keep newly selected participants visible in split selector
When this screen has preselected participants and the search box is empty, selectedSectionBaseData is pinned to initialSelectedOptions, so participants selected during the current interaction are not added to the selected section. The lower sections are built from availableOptions, which already excludes selected rows, so newly selected participants disappear from the list entirely (until search text is entered), making them hard to review or unselect before submitting.
Useful? React with 👍 / 👎.
| ); | ||
|
|
||
| const orderedOptions = useMemo(() => { | ||
| const shouldReorderInitialSelection = initialSelectedValues.length > 0 && options.length > CONST.MOVE_SELECTED_ITEMS_TO_TOP_OF_LIST_THRESHOLD; |
There was a problem hiding this comment.
The moveInitialSelectionToTopByValue already handles shouldReorderInitialSelection itself.
if (initialSelectedValues.length === 0 || items.length <= CONST.MOVE_SELECTED_ITEMS_TO_TOP_OF_LIST_THRESHOLD) {
return items;
}
So I think this is unnecessary. Could you please remove it here and in the other place(s) too?
| * Reorders items that contain a `value` field by moving the initially selected values to the top. | ||
| * Preserves the original ordering within the selected and remaining groups. | ||
| */ | ||
| function moveInitialSelectionToTopByValue<T extends {value: string}>(items: T[], initialSelectedValues: string[]): T[] { |
There was a problem hiding this comment.
This function uses 4 loops to reorder the items.
Why do we need 4 separate loops instead of doing it in just one loop like this?
function moveInitialSelectionToTopByValue<T extends {value: string}>(items: T[], initialSelectedValues: string[]): T[] {
if (initialSelectedValues.length === 0 || items.length <= CONST.MOVE_SELECTED_ITEMS_TO_TOP_OF_LIST_THRESHOLD) {
return items;
}
const initialSelectionSet = new Set(initialSelectedValues);
const selected: T[] = [];
const unselected: T[] = [];
for (const item of items) {
if (initialSelectionSet.has(item.value)) {
selected.push(item);
continue;
}
unselected.push(item);
}
return [...selected, ...unselected];
}
Same issue for reorderItemsByInitialSelection
| if (initiallySelectedCurrencyCode) { | ||
| codes.add(initiallySelectedCurrencyCode); | ||
| } | ||
| for (const currencyCode of selectedCurrencies) { |
There was a problem hiding this comment.
NAB: selectedCurrencies is no longer used, so we can safely remove this prop and all related logic
| const isEmpty = searchValue.trim() && !filteredCurrencies.length; | ||
| const shouldReorderInitialSelection = !searchValue && initialSelectedCurrencySnapshot.length > 0; | ||
| const displayCurrencies = shouldReorderInitialSelection | ||
| ? moveInitialSelectionToTopByValue( |
There was a problem hiding this comment.
I think we can just use reorderItemsByInitialSelection instead of moveInitialSelectionToTopByValue. That way we don't need an extra .map() to create a new list
There was a problem hiding this comment.
Why do we need to modify this file? SearchAutocompleteList is an autocomplete/search router — not a selection list where users pick items that should stay pinned at the top.
There's no concept of "selected items" here that would benefit from reordering.
| style={[ | ||
| wrapperStyle, | ||
| isFocused && | ||
| (!!isFocused || !!item.isSelected) && |
There was a problem hiding this comment.
| onSelectRow={(option) => { | ||
| Keyboard.dismiss(); | ||
| onYearChange?.(option.value); | ||
| onYearChange?.(Number(option.keyForList)); |
There was a problem hiding this comment.
Why do we need to update this?
I tried using option.value and it seems to work fine, no problems
| ListItem={RadioListItem} | ||
| onSelectRow={(countryOption) => { | ||
| setSelectedCountry(countryOption.value ?? null); | ||
| setSelectedCountry(countryOption.keyForList?.toString() ?? null); |
There was a problem hiding this comment.
Why do we need to update this?
I tried using option.value and it seems to work fine, no problems
| return filteredDays; | ||
| } | ||
|
|
||
| return moveInitialSelectionToTopByValue( |
There was a problem hiding this comment.
I think we can just use reorderItemsByInitialSelection instead of moveInitialSelectionToTopByValue. That way we don't need an extra .map() to create a new list
| return mappedItems; | ||
| } | ||
|
|
||
| return moveInitialSelectionToTopByValue(mappedItems, initialSelectedValues); |
There was a problem hiding this comment.
NAB: this re-render every time selectedItem changes
|
This PR is quite large(Affects >100 files). Reasons:
Proposed split approach:
2–N. Later PRs: apply the shared logic to each specific flow @JmillsExpensify Could you please confirm which place the user wants to go to fix for first one? |
|
Defer to other reviews on splitting up the PR. As for this
I don't think I understand the question. Can you ask it a different way? |
@JmillsExpensify I just want to know where in the app the user is mentioned in this comment. |
Ah, I meant that our customer support team is getting feedback from customers that switching the selection around is confusing. It's just general product feedback. |
|
@linhvovan29546, what is the final decision here? Should we continue this pr or create separate PRs? thanks. |
|
Going with separate PRs makes sense to me. There are a lot of flows. |
|
@linhvovan29546, could you please specify how many PRs we should have and which parts should go first? thanks. |
I’m not sure exactly how many PRs we’ll end up with, but we can start with a
|
@linhvovan29546, thanks, the new pr will be ready tomorrow. |
|
@marufsharifi Is there any update on the new PR? |
|
@linhvovan29546, I've resolved the conflicts. Here, I am working on a new PR. thanks. It will be ready today. |
|
@linhvovan29546, I've created the first pr, but it is still in draft, since I am testing and creating records. Please feel free to review and give me your feedback. I will make it ready for review after finishing the checklist. thanks. |
|
@marufsharifi Could you please close this PR? |
Explanation of Change
This will fix the behavior of jumping the lists. When the user selects/deselects, it shouldn't jump. However, when it goes away and comes back, the selected items should be at the very top.
Fixed Issues
$ #69184
PROPOSAL: #69184 (comment)
Tests
Offline tests
Same as Tests
QA Steps
Same as Tests
// TODO: These must be filled out, or the issue title must include "[No QA]."
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
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari
1. Workspace > Members > Invite new members.
1-v.mp4
2. Workspace > Workflows > Approvals > Approver > set Approver.
Screen.Recording.2026-03-10.at.1.38.17.PM.mov
3. Workspace Chat > Chat Details > Members > Invite New Members.
3-v.mp4
4. Workspace > Company Cards > Add Card
Screen.Recording.1404-10-28.at.6.15.28.PM.mov
5. Reports > Search Drop downs > Timezones
Screen.Recording.1404-10-28.at.6.56.03.PM.mov
6. Reports > Filters > Workspace
Screen.Recording.1404-10-28.at.7.12.22.PM.mov
7. Reports > Filters > Purchase currency
Screen.Recording.1404-10-28.at.7.29.56.PM.mov
8. Reports > Filters > Currency
Screen.Recording.1404-10-28.at.7.30.38.PM.mov
9. Reports > Filters > Category
Screen.Recording.1404-10-28.at.7.32.24.PM.mov
10. Reports > Filters > From
Screen.Recording.1404-10-28.at.7.37.30.PM.mov
11. Reports > Filters > To
Screen.Recording.1404-10-28.at.7.38.17.PM.mov
12. Workspace > Overview > Default Currency
Screen.Recording.1404-10-28.at.7.57.06.PM.mov
13. Expense details > Amount (tag value)
Screen.Recording.1404-10-28.at.8.07.01.PM.mov
14. Expense details > attendees.
Screen.Recording.1404-11-05.at.12.25.51.PM.mp4
15. Workspace > expensify card > state
Screen.Recording.1404-11-05.at.10.34.22.AM.mov
16. Workspace > workflows > payment account > State
Screen.Recording.1404-11-05.at.10.36.19.AM.mov
17. Profile > Address > Country
Screen.Recording.1404-11-05.at.10.50.14.AM.mov
18. Subscriptions > Add payment card > Currency
Screen.Recording.1404-11-05.at.10.52.08.AM.mov
19. Preferences > Payment Currency
Screen.Recording.1404-11-05.at.10.53.19.AM.mov
20. Reports > Search Drop downs > Workspace
Screen.Recording.1404-11-05.at.12.45.14.PM.mov
21. Wallet > Add Bank account
Screen.Recording.1404-11-05.at.2.10.50.PM.mov
22. Wallet > Add Bank account > Currency
Screen.Recording.1404-11-05.at.2.11.27.PM.mov
23. Profile > Address > State
Screen.Recording.1404-11-05.at.2.13.03.PM.mov
24. Group Chat > Details > members > invite new members
Screen.Recording.1404-11-05.at.1.03.11.PM.mp4
25. Workspace > Workflows > Submissions > Frequency > Monthly > Date of Month
Screen.Recording.2026-03-10.at.1.54.17.PM.mov
26. Preferences > Language
Screen.Recording.1404-11-05.at.3.25.28.PM.mov
27. workflows > approvals > first approver > addetional approver
workflows.approvals.first.approver.addetional.approver.mov
28. workspace > per diem > currency
workspace.per.diem.currency.mov
29. workspace > New workspace > Default currency
add-workspace._.default.currency.mov
30. workspace chat > Create Expense > Select a currency
create.expense._.manual._.currency.mov
31. Chat Room > Debug-Report > currency
Screen.Recording.2026-03-10.at.11.42.52.AM.mov
32. Expense Details > Amount > currency
expense.details._.amont._.currency.mov
33. Workspace > Expensify Cards > Incorporation state
expensify.card._.incorporation.state.mov
34. FAB > Create Expense > Manual > To > Choose recipient
Screen.Recording.2026-03-10.at.1.59.57.PM.mov
35. Onboarding > Confirm workspace > Default Currency
onboarding._.workspace.currency.mov
36. Account > Expense Rules > Category
Screen.Recording.1404-11-19.at.9.37.45.AM.mov
37. Reports > Filters > Tag
Screen.Recording.1404-11-19.at.9.57.16.AM.mov
38. Account > Expense Rules > Tag
Screen.Recording.1404-11-20.at.3.05.38.PM.mov
39. Reports > Dates > On
Screen.Recording.1404-12-17.at.2.35.34.PM.mov
40. Workspace > Rules > Cash Expense Default
Screen.Recording.1404-12-17.at.3.07.25.AM.mov
41. Workspace > Rules > Billable Default
Screen.Recording.1404-12-17.at.3.08.04.AM.mov
42. Workspace > Rules > add merchant rule > category
Screen.Recording.1404-12-17.at.3.09.10.AM.mov
43. Workspace > Rules > add merchant rule > Reimbursable
Screen.Recording.1404-12-17.at.3.12.51.AM.mov
44. Workspace > Rules > Add Merchant Rule > Billable
Screen.Recording.1404-12-17.at.3.13.16.AM.mov
45. Workspace > Per Diem > more > Settings > Default Category
Screen.Recording.1404-12-17.at.3.14.14.AM.mov
46. Workspace > Distance Rate > Settings > Unit
Screen.Recording.1404-12-17.at.3.16.07.AM.mov
47. Workspace > Distance Rate > Settings > Default Category
Screen.Recording.1404-12-17.at.3.16.40.AM.mov
48. FAB > Create Expense > Per Diem
Screen.Recording.1404-12-17.at.3.21.03.AM.mov
49. Create Expense flow > amount > Select a currency
Screen.Recording.1404-12-17.at.3.22.08.AM.mov
50. Create Expense flow > Date > Year
Screen.Recording.2026-03-09.at.5.36.17.PM.mov
51. Create Expense flow > Subrate
Screen.Recording.2026-03-09.at.5.38.24.PM.mov
52. Reports > Filters > Approved > On > Year
Screen.Recording.1404-12-17.at.7.50.34.PM.mov
53. Reports > Filters > Date > On > Year
Screen.Recording.1404-12-17.at.7.53.09.PM.mov
54. Reports > Type, Status & Date
Screen.Recording.1404-12-17.at.7.59.07.PM.mov
55. Reports > Unappproved cash > Group by
Screen.Recording.1404-12-17.at.8.55.46.PM.mov
56. Chat Room > Debug Report > lastactiontype
Screen.Recording.1404-12-17.at.9.18.41.PM.mov
57. Chat Room > Debug Report > Chat type
Screen.Recording.1404-12-17.at.9.17.41.PM.mov
59. FAB > send invoice > Select a currency
Screen.Recording.1404-12-17.at.9.23.35.PM.mov
60. FAB > send invoice > To
Screen.Recording.1404-12-17.at.10.07.58.PM.mp4
61. FAB > send invoice > Date > Year
Screen.Recording.1404-12-17.at.10.09.38.PM.mov
62. Chat room > split expense > select a currency
Screen.Recording.1404-12-17.at.10.29.58.PM.mov
63. Chat room > Assign task > Assignee
Screen.Recording.2026-03-10.at.2.14.48.PM.mp4
64. Chat room > Assign task flow > Assignee
Screen.Recording.1404-12-17.at.10.53.44.PM.mov
65. Workspace chat> Per diem > Date > Year
Screen.Recording.1404-12-17.at.12.31.58.PM.mov
66. Workspace > Company Cards > Custom day of month > Custom close date
Screen.Recording.1404-12-18.at.12.12.31.AM.mov
67. Reports > Filters > assignee
search._.filters._.assignee.mov
68. Reports > Filters > Tax rate
Screen.Recording.2026-03-10.at.2.26.25.PM.mov
69. Reports > Filters > Attendees
search.page._.filters._.attendees.mov
70. FAB > Start Chat
Screen.Recording.2026-03-09.at.9.29.07.PM.mov
71. Expense Rule > Add Rule > Tax
Screen.Recording.2026-03-10.at.2.34.29.PM.mov
72. Workspaces > Taxes > Settings > Workspace Currency Default
Screen.Recording.2026-03-09.at.9.40.58.PM.mov
73. Workspaces > Taxes > Settings > Foreign Currency Default
Screen.Recording.2026-03-10.at.3.18.40.PM.mov
74. Profile > Date of Birth > Year
profile.dob.mov
75. Workspace > Rules > Add merchant rule > Destination
Screen.Recording.1404-12-17.at.3.09.43.AM.mov
76. Workspace > Rules > Add merchant rule > Subrate
Screen.Recording.1404-12-17.at.3.10.21.AM.mov
77. Workspace > Rules > Add merchant rule > Amount
Screen.Recording.1404-12-17.at.3.11.36.AM.mov
78. Workspace > Company Cards > add cards (add two cards) > Search Drop down
Screen.Recording.1404-12-18.at.12.15.04.AM.mov