Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
1bb121d
wip
kubabutkiewicz Sep 4, 2025
29de46e
wip
kubabutkiewicz Sep 8, 2025
7f67e2b
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Sep 8, 2025
6a10149
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Sep 9, 2025
178792b
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Sep 10, 2025
9b22733
wip
kubabutkiewicz Sep 10, 2025
44b77ea
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Sep 10, 2025
8db51eb
wip
kubabutkiewicz Sep 10, 2025
226af7c
wip
kubabutkiewicz Sep 10, 2025
046c912
fix tests
kubabutkiewicz Sep 11, 2025
e36b95e
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Sep 15, 2025
fd11513
ts and lint fixes
kubabutkiewicz Sep 15, 2025
73a33c8
resolving comments
kubabutkiewicz Sep 17, 2025
edb9524
Refactor wip
kubabutkiewicz Sep 17, 2025
4c7ff24
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Sep 17, 2025
6e47d79
fixing typecheck
kubabutkiewicz Sep 17, 2025
59dc622
wip
kubabutkiewicz Sep 17, 2025
e05275f
resolving comments
kubabutkiewicz Sep 17, 2025
3884307
resolve lint issues
kubabutkiewicz Sep 17, 2025
104f226
fix lint
kubabutkiewicz Sep 17, 2025
52c0c5d
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Sep 18, 2025
a71b87f
fix comments
kubabutkiewicz Sep 18, 2025
32f5741
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Sep 29, 2025
53cab16
fix lint problems and tests
kubabutkiewicz Sep 29, 2025
abfbd93
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Sep 30, 2025
cd1a50e
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Oct 2, 2025
00dc392
resolve comments
kubabutkiewicz Oct 2, 2025
2f521e6
resolve comment
kubabutkiewicz Oct 3, 2025
6db7638
fix test
kubabutkiewicz Oct 3, 2025
bcc85e5
fix test
kubabutkiewicz Oct 3, 2025
ad8bb86
fix test finnally
kubabutkiewicz Oct 3, 2025
dea6dc1
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Oct 3, 2025
a1489ec
fix test
kubabutkiewicz Oct 3, 2025
23ea45b
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Oct 6, 2025
c8e5abd
fix test
kubabutkiewicz Oct 6, 2025
c556132
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Oct 8, 2025
ff33459
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Oct 9, 2025
4162b83
fix ts problems
kubabutkiewicz Oct 9, 2025
9fee042
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Oct 9, 2025
ff5d3cc
fix ts and lint
kubabutkiewicz Oct 9, 2025
64185bb
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Oct 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/components/LHNOptionsList/LHNOptionsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import useRootNavigationState from '@hooks/useRootNavigationState';
import useScrollEventEmitter from '@hooks/useScrollEventEmitter';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import {isValidDraftComment} from '@libs/DraftCommentUtils';
import getPlatform from '@libs/getPlatform';
import Log from '@libs/Log';
import {getMovedReportID} from '@libs/ModifiedExpenseMessage';
Expand Down Expand Up @@ -191,7 +190,7 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio
? (getOriginalMessage(itemParentReportAction)?.IOUTransactionID ?? CONST.DEFAULT_NUMBER_ID)
: CONST.DEFAULT_NUMBER_ID;
const itemTransaction = transactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
const hasDraftComment = isValidDraftComment(draftComments?.[`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`]);
const hasDraftComment = !!draftComments?.[`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`];

const isReportArchived = !!itemReportNameValuePairs?.private_isArchived;
const canUserPerformWrite = canUserPerformWriteActionUtil(item, isReportArchived);
Expand Down
4 changes: 3 additions & 1 deletion src/components/Search/FilterDropdowns/UserSelectPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ function UserSelectPopup({value, closeOverlay, onChange}: UserSelectPopupProps)
const [countryCode] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false});
const [searchTerm, setSearchTerm] = useState('');
const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {initWithStoredValues: false, canBeMissing: true});
const [draftComments] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, {canBeMissing: true});
const initialSelectedOptions = useMemo(() => {
return value.reduce<OptionData[]>((acc, id) => {
const participant = personalDetails?.[id];
Expand Down Expand Up @@ -87,12 +88,13 @@ function UserSelectPopup({value, closeOverlay, onChange}: UserSelectPopupProps)
reports: options.reports,
personalDetails: options.personalDetails,
},
draftComments,
{
excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT,
includeCurrentUser: true,
},
);
}, [options.reports, options.personalDetails]);
}, [options.reports, options.personalDetails, draftComments]);

const filteredOptions = useMemo(() => {
return filterAndOrderOptions(optionsList, cleanSearchTerm, countryCode, {
Expand Down
50 changes: 43 additions & 7 deletions src/components/Search/SearchAutocompleteList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ function SearchAutocompleteList({
const {shouldUseNarrowLayout} = useResponsiveLayout();

const [betas] = useOnyx(ONYXKEYS.BETAS, {canBeMissing: true});
const [draftComments] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, {canBeMissing: true});
const [recentSearches] = useOnyx(ONYXKEYS.RECENT_SEARCHES, {canBeMissing: true});
const taxRates = getAllTaxRates();

Expand All @@ -187,8 +188,20 @@ function SearchAutocompleteList({
if (!areOptionsInitialized) {
return defaultListOptions;
}
return getSearchOptions(options, betas ?? [], true, true, autocompleteQueryValue, CONST.AUTO_COMPLETE_SUGGESTER.MAX_AMOUNT_OF_SUGGESTIONS, true, true, false, true);
}, [areOptionsInitialized, betas, options, autocompleteQueryValue]);
return getSearchOptions({
options,
draftComments,
betas: betas ?? [],
isUsedInChatFinder: true,
includeReadOnly: true,
searchQuery: autocompleteQueryValue,
maxResults: CONST.AUTO_COMPLETE_SUGGESTER.MAX_AMOUNT_OF_SUGGESTIONS,
includeUserToInvite: true,
includeRecentReports: true,
includeCurrentUser: true,
shouldShowGBR: false,
});
}, [areOptionsInitialized, options, draftComments, betas, autocompleteQueryValue]);

const [isInitialRender, setIsInitialRender] = useState(true);
const parsedQuery = parseForAutocomplete(autocompleteQueryValue);
Expand Down Expand Up @@ -378,9 +391,19 @@ function SearchAutocompleteList({
case CONST.SEARCH.SYNTAX_FILTER_KEYS.PAYER:
case CONST.SEARCH.SYNTAX_FILTER_KEYS.ATTENDEE:
case CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPORTER: {
const participants = getSearchOptions(options, betas ?? [], true, true, autocompleteValue, 10, false, false, true, true).personalDetails.filter(
(participant) => participant.text && !alreadyAutocompletedKeys.includes(participant.text.toLowerCase()),
);
const participants = getSearchOptions({
options,
draftComments,
betas: betas ?? [],
isUsedInChatFinder: true,
includeReadOnly: true,
searchQuery: autocompleteValue,
maxResults: 10,
includeUserToInvite: false,
includeRecentReports: false,
includeCurrentUser: true,
shouldShowGBR: true,
}).personalDetails.filter((participant) => participant.text && !alreadyAutocompletedKeys.includes(participant.text.toLowerCase()));

return participants.map((participant) => ({
filterKey: autocompleteKey,
Expand All @@ -390,7 +413,19 @@ function SearchAutocompleteList({
}));
}
case CONST.SEARCH.SYNTAX_FILTER_KEYS.IN: {
const filteredReports = getSearchOptions(options, betas ?? [], true, true, autocompleteValue, 10, false, true, false, true).recentReports;
const filteredReports = getSearchOptions({
options,
draftComments,
betas: betas ?? [],
isUsedInChatFinder: true,
includeReadOnly: true,
searchQuery: autocompleteValue,
maxResults: 10,
includeUserToInvite: false,
includeRecentReports: true,
includeCurrentUser: false,
shouldShowGBR: true,
}).recentReports;

return filteredReports.map((chat) => ({
filterKey: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.IN,
Expand Down Expand Up @@ -547,7 +582,9 @@ function SearchAutocompleteList({
recentCurrencyAutocompleteList,
taxAutocompleteList,
options,
draftComments,
betas,
currentUserLogin,
typeAutocompleteList,
groupByAutocompleteList,
statusAutocompleteList,
Expand All @@ -557,7 +594,6 @@ function SearchAutocompleteList({
cardAutocompleteList,
booleanTypes,
workspaceList,
currentUserLogin,
isAutocompleteList,
hasAutocompleteList,
]);
Expand Down
5 changes: 3 additions & 2 deletions src/components/Search/SearchFiltersChatsSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen
const [selectedReportIDs, setSelectedReportIDs] = useState<string[]>(initialReportIDs);
const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState('');
const cleanSearchTerm = useMemo(() => searchTerm.trim().toLowerCase(), [searchTerm]);
const [draftComments] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, {canBeMissing: true});

const selectedOptions = useMemo<OptionData[]>(() => {
return selectedReportIDs.map((id) => {
Expand All @@ -66,8 +67,8 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen
if (!areOptionsInitialized || !isScreenTransitionEnd) {
return defaultListOptions;
}
return getSearchOptions(options, undefined, false);
}, [areOptionsInitialized, isScreenTransitionEnd, options]);
return getSearchOptions({options, draftComments, betas: undefined, isUsedInChatFinder: false});
}, [areOptionsInitialized, draftComments, isScreenTransitionEnd, options]);

const chatOptions = useMemo(() => {
return filterAndOrderOptions(defaultOptions, cleanSearchTerm, countryCode, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate}:
const [selectedOptions, setSelectedOptions] = useState<OptionData[]>([]);
const [searchTerm, setSearchTerm] = useState('');
const cleanSearchTerm = useMemo(() => searchTerm.trim().toLowerCase(), [searchTerm]);
const [draftComments] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, {canBeMissing: true});

const defaultOptions = useMemo(() => {
if (!areOptionsInitialized) {
Expand All @@ -63,12 +64,13 @@ function SearchFiltersParticipantsSelector({initialAccountIDs, onFiltersUpdate}:
reports: options.reports,
personalDetails: options.personalDetails,
},
draftComments,
{
excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT,
includeCurrentUser: true,
},
);
}, [areOptionsInitialized, options.personalDetails, options.reports]);
}, [areOptionsInitialized, draftComments, options.personalDetails, options.reports]);

const unselectedOptions = useMemo(() => {
return filterSelectedOptions(defaultOptions, new Set(selectedOptions.map((option) => option.accountID)));
Expand Down
19 changes: 15 additions & 4 deletions src/hooks/useSearchSelector.base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ function useSearchSelectorBase({
const [selectedOptions, setSelectedOptions] = useState<OptionData[]>(initialSelected ?? []);
const [maxResults, setMaxResults] = useState(maxResultsPerPage);
const [countryCode] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false});
const [draftComments] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, {canBeMissing: true});

const onListEndReached = useCallback(() => {
setMaxResults((previous) => previous + maxResultsPerPage);
Expand All @@ -169,9 +170,18 @@ function useSearchSelectorBase({

switch (searchContext) {
case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_SEARCH:
return getSearchOptions(optionsWithContacts, betas ?? [], true, true, computedSearchTerm, maxResults, includeUserToInvite);
return getSearchOptions({
options: optionsWithContacts,
draftComments,
betas: betas ?? [],
isUsedInChatFinder: true,
includeReadOnly: true,
searchQuery: computedSearchTerm,
maxResults,
includeUserToInvite,
});
case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_MEMBER_INVITE:
return getValidOptions(optionsWithContacts, {
return getValidOptions(optionsWithContacts, draftComments, {
betas: betas ?? [],
includeP2P: true,
includeSelectedOptions: false,
Expand All @@ -183,7 +193,7 @@ function useSearchSelectorBase({
includeUserToInvite,
});
case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_GENERAL:
return getValidOptions(optionsWithContacts, {
return getValidOptions(optionsWithContacts, draftComments, {
...getValidOptionsConfig,
betas: betas ?? [],
searchString: computedSearchTerm,
Expand All @@ -193,7 +203,7 @@ function useSearchSelectorBase({
loginsToExclude: excludeLogins,
});
case CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_SHARE_DESTINATION:
return getValidOptions(optionsWithContacts, {
return getValidOptions(optionsWithContacts, draftComments, {
betas,
selectedOptions,
includeMultipleParticipantReports: true,
Expand All @@ -217,6 +227,7 @@ function useSearchSelectorBase({
areOptionsInitialized,
searchContext,
optionsWithContacts,
draftComments,
betas,
computedSearchTerm,
maxResults,
Expand Down
27 changes: 14 additions & 13 deletions src/hooks/useSidebarOrderedReports.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,10 @@ function SidebarOrderedReportsContextProvider({
const [transactions, {sourceValue: transactionsUpdates}] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION, {canBeMissing: true});
const [transactionViolations, {sourceValue: transactionViolationsUpdates}] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, {canBeMissing: true});
const [reportNameValuePairs, {sourceValue: reportNameValuePairsUpdates}] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, {canBeMissing: true});
const [, {sourceValue: reportsDraftsUpdates}] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, {canBeMissing: true});
const [reportsDrafts, {sourceValue: reportsDraftsUpdates}] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, {canBeMissing: true});
const [betas] = useOnyx(ONYXKEYS.BETAS, {canBeMissing: true});
const [reportAttributes] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {selector: reportsSelector, canBeMissing: true});
const [currentReportsToDisplay, setCurrentReportsToDisplay] = useState<ReportsToDisplayInLHN>({});

const {shouldUseNarrowLayout} = useResponsiveLayout();
const {accountID} = useCurrentUserPersonalDetails();
const currentReportIDValue = useCurrentReportID();
Expand Down Expand Up @@ -152,25 +151,26 @@ function SidebarOrderedReportsContextProvider({
const shouldDoIncrementalUpdate = updatedReports.length > 0 && Object.keys(currentReportsToDisplay).length > 0;
let reportsToDisplay = {};
if (shouldDoIncrementalUpdate) {
reportsToDisplay = SidebarUtils.updateReportsToDisplayInLHN(
currentReportsToDisplay,
chatReports,
updatedReports,
derivedCurrentReportID,
priorityMode === CONST.PRIORITY_MODE.GSD,
reportsToDisplay = SidebarUtils.updateReportsToDisplayInLHN({
displayedReports: currentReportsToDisplay,
reports: chatReports,
updatedReportsKeys: updatedReports,
currentReportId: derivedCurrentReportID,
isInFocusMode: priorityMode === CONST.PRIORITY_MODE.GSD,
betas,
policies,
transactionViolations,
reportNameValuePairs,
reportAttributes,
);
draftComments: reportsDrafts,
});
} else {
reportsToDisplay = SidebarUtils.getReportsToDisplayInLHN(
derivedCurrentReportID,
chatReports,
betas,
policies,
priorityMode,
reportsDrafts,
transactionViolations,
reportNameValuePairs,
reportAttributes,
Expand All @@ -180,19 +180,20 @@ function SidebarOrderedReportsContextProvider({
return reportsToDisplay;
// Rule disabled intentionally — triggering a re-render on currentReportsToDisplay would cause an infinite loop
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
}, [getUpdatedReports, chatReports, derivedCurrentReportID, priorityMode, betas, policies, transactionViolations, reportNameValuePairs, reportAttributes]);
}, [getUpdatedReports, chatReports, derivedCurrentReportID, priorityMode, betas, policies, transactionViolations, reportNameValuePairs, reportAttributes, reportsDrafts]);

const deepComparedReportsToDisplayInLHN = useDeepCompareRef(reportsToDisplayInLHN);
const deepComparedReportsDrafts = useDeepCompareRef(reportsDrafts);

useEffect(() => {
setCurrentReportsToDisplay(reportsToDisplayInLHN);
}, [reportsToDisplayInLHN]);

const getOrderedReportIDs = useCallback(
() => SidebarUtils.sortReportsToDisplayInLHN(deepComparedReportsToDisplayInLHN ?? {}, priorityMode, localeCompare, reportNameValuePairs, reportAttributes),
() => SidebarUtils.sortReportsToDisplayInLHN(deepComparedReportsToDisplayInLHN ?? {}, priorityMode, localeCompare, deepComparedReportsDrafts, reportNameValuePairs, reportAttributes),
// Rule disabled intentionally - reports should be sorted only when the reportsToDisplayInLHN changes
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
[reportsToDisplayInLHN, localeCompare],
[deepComparedReportsToDisplayInLHN, localeCompare, deepComparedReportsDrafts],
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need to add deepComparedReportsDrafts to dependency list? It is intentional to keep reportsToDisplayInLHN and localeCompare only in the dependency list (see detail here: #63980)

Copy link
Contributor

Choose a reason for hiding this comment

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

@kubabutkiewicz Kindly bump

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes I am on it, earlier without deepComparedReportsDrafts there was a problem that when we add the draft message, the LHN wasnt updated, I want to check it but have some problems with running the native app locally

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, I was able to test this, so without deepComparedReportsDrafts in the dependecy array we are not sorting the LHN items when we add draft to some report, so I think it needs to be there + also tests for useSidebarOrderedReports is passing which means that this hook only rerenderes when the report id is changing which is what we want

);

const orderedReportIDs = useMemo(() => getOrderedReportIDs(), [getOrderedReportIDs]);
Expand Down
3 changes: 3 additions & 0 deletions src/libs/DebugUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1338,6 +1338,7 @@ function getReasonForShowingRowInLHN({
isReportArchived = false,
isInFocusMode = false,
betas = undefined,
draftComment,
}: {
report: OnyxEntry<Report>;
chatReport: OnyxEntry<Report>;
Expand All @@ -1346,6 +1347,7 @@ function getReasonForShowingRowInLHN({
isReportArchived?: boolean;
isInFocusMode?: boolean;
betas?: OnyxEntry<Beta[]>;
draftComment: string | undefined;
}): TranslationPaths | null {
if (!report) {
return null;
Expand All @@ -1362,6 +1364,7 @@ function getReasonForShowingRowInLHN({
doesReportHaveViolations,
includeSelfDM: true,
isReportArchived,
draftComment,
});

if (!([CONST.REPORT_IN_LHN_REASONS.HAS_ADD_WORKSPACE_ROOM_ERRORS, CONST.REPORT_IN_LHN_REASONS.HAS_IOU_VIOLATIONS] as Array<typeof reason>).includes(reason) && hasRBR) {
Expand Down
47 changes: 0 additions & 47 deletions src/libs/DraftCommentUtils.ts

This file was deleted.

Loading
Loading