Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b43f7c0
pulling from, to filters
Guccio163 Aug 13, 2024
e2c5d62
in filter, selecting working but duplicates
Guccio163 Aug 19, 2024
23f13ce
Merge branch 'main' of github.com:software-mansion-labs/expensify-app…
Guccio163 Aug 19, 2024
2da8854
ts check
Guccio163 Aug 19, 2024
94166fe
updated look, workspaces saving problem
Guccio163 Aug 19, 2024
2a5f7e7
fixing adding bug wip
Guccio163 Aug 21, 2024
347c8c6
adding solved, but reading from props bugged
Guccio163 Aug 21, 2024
412393b
working until first save
Guccio163 Aug 23, 2024
a62369f
working version w/o adding from search and naming in allFilters page
Guccio163 Aug 23, 2024
4391c6f
Merge branch 'main' of github.com:software-mansion-labs/expensify-app…
Guccio163 Aug 23, 2024
47f2f0c
workspace chats' alternateText not ready
Guccio163 Aug 26, 2024
0c9f99d
Merge branch 'main' of github.com:software-mansion-labs/expensify-app…
Guccio163 Aug 26, 2024
755cd5f
temporary fix, alternateText doesn't work yet
Guccio163 Aug 26, 2024
7b8998e
working, ready for second look
Guccio163 Aug 27, 2024
9d45653
Merge branch 'main' of github.com:software-mansion-labs/expensify-app…
Guccio163 Aug 27, 2024
aa5ee46
stylistic touches
Guccio163 Aug 27, 2024
4f03335
PR review 1 changes
Guccio163 Aug 27, 2024
2499a0d
fix Navigation.goBack in filters
Guccio163 Aug 27, 2024
cecda50
name changes before PR
Guccio163 Aug 28, 2024
b7cf074
fix bug1
Guccio163 Aug 30, 2024
1aa2256
bug1 fixed 2
Guccio163 Aug 30, 2024
80de247
Merge branch 'main' of github.com:software-mansion-labs/expensify-app…
Guccio163 Aug 30, 2024
27bfd2f
Merge branch 'main' of github.com:software-mansion-labs/expensify-app…
Guccio163 Aug 30, 2024
97715e9
Merge branch 'main' of github.com:software-mansion-labs/expensify-app…
Guccio163 Aug 30, 2024
353f9c3
fixed conflicts with Has filter
Guccio163 Aug 30, 2024
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
1 change: 1 addition & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5323,6 +5323,7 @@ const CONST = {
CARD_ID: 'cardID',
REPORT_ID: 'reportID',
KEYWORD: 'keyword',
IN: 'in',
HAS: 'has',
},
},
Expand Down
1 change: 1 addition & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const ROUTES = {
SEARCH_ADVANCED_FILTERS_TAG: 'search/filters/tag',
SEARCH_ADVANCED_FILTERS_FROM: 'search/filters/from',
SEARCH_ADVANCED_FILTERS_TO: 'search/filters/to',
SEARCH_ADVANCED_FILTERS_IN: 'search/filters/in',
SEARCH_ADVANCED_FILTERS_HAS: 'search/filters/has',

SEARCH_REPORT: {
Expand Down
1 change: 1 addition & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const SCREENS = {
ADVANCED_FILTERS_TAG_RHP: 'Search_Advanced_Filters_Tag_RHP',
ADVANCED_FILTERS_FROM_RHP: 'Search_Advanced_Filters_From_RHP',
ADVANCED_FILTERS_TO_RHP: 'Search_Advanced_Filters_To_RHP',
ADVANCED_FILTERS_IN_RHP: 'Search_Advanced_Filters_In_RHP',
ADVANCED_FILTERS_HAS_RHP: 'Search_Advanced_Filters_Has_RHP',
TRANSACTION_HOLD_REASON_RHP: 'Search_Transaction_Hold_Reason_RHP',
BOTTOM_TAB: 'Search_Bottom_Tab',
Expand Down
188 changes: 188 additions & 0 deletions src/components/Search/SearchFiltersChatsSelector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {useOnyx} from 'react-native-onyx';
import Button from '@components/Button';
import {usePersonalDetails} from '@components/OnyxProvider';
import {useOptionsList} from '@components/OptionListContextProvider';
import SelectionList from '@components/SelectionList';
import InviteMemberListItem from '@components/SelectionList/InviteMemberListItem';
import useDebouncedState from '@hooks/useDebouncedState';
import useLocalize from '@hooks/useLocalize';
import useScreenWrapperTransitionStatus from '@hooks/useScreenWrapperTransitionStatus';
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import * as OptionsListUtils from '@libs/OptionsListUtils';
import type {Option} from '@libs/OptionsListUtils';
import type {OptionData} from '@libs/ReportUtils';
import Navigation from '@navigation/Navigation';
import * as Report from '@userActions/Report';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';

const defaultListOptions = {
recentReports: [],
personalDetails: [],
userToInvite: null,
currentUserOption: null,
categoryOptions: [],
tagOptions: [],
taxRatesOptions: [],
headerMessage: '',
};

function getSelectedOptionData(option: Option): OptionData {
return {...option, isSelected: true, reportID: option.reportID ?? '-1'};
}

type SearchFiltersParticipantsSelectorProps = {
initialReportIDs: string[];
onFiltersUpdate: (initialReportIDs: string[]) => void;
isScreenTransitionEnd: boolean;
};

function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreenTransitionEnd}: SearchFiltersParticipantsSelectorProps) {
const {translate} = useLocalize();
const personalDetails = usePersonalDetails();
const {didScreenTransitionEnd} = useScreenWrapperTransitionStatus();
const {options, areOptionsInitialized} = useOptionsList({
shouldInitialize: didScreenTransitionEnd,
});

const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT);
const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {initWithStoredValues: false});
const [selectedReportIDs, setSelectedReportIDs] = useState<string[]>(initialReportIDs);
const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState('');
const cleanSearchTerm = useMemo(() => searchTerm.trim().toLowerCase(), [searchTerm]);

const selectedOptions = useMemo<OptionData[]>(() => {
return selectedReportIDs.map((id) => {
const report = getSelectedOptionData(OptionsListUtils.createOptionFromReport({...reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`], reportID: id}, personalDetails));
const alternateText = OptionsListUtils.getAlternateText(report, {showChatPreviewLine: true});
return {...report, alternateText};
});
}, [personalDetails, reports, selectedReportIDs]);

const defaultOptions = useMemo(() => {
if (!areOptionsInitialized || !isScreenTransitionEnd) {
return defaultListOptions;
}
return OptionsListUtils.getSearchOptions(options);
}, [areOptionsInitialized, isScreenTransitionEnd, options]);

const chatOptions = useMemo(() => {
return OptionsListUtils.filterOptions(defaultOptions, cleanSearchTerm, {
selectedOptions,
excludeLogins: CONST.EXPENSIFY_EMAILS,
maxRecentReportsToShow: 0,
});
}, [defaultOptions, cleanSearchTerm, selectedOptions]);

const {sections, headerMessage} = useMemo(() => {
const newSections: OptionsListUtils.CategorySection[] = [];
if (!areOptionsInitialized) {
return {sections: [], headerMessage: undefined};
}

const formattedResults = OptionsListUtils.formatSectionsFromSearchTerm(
cleanSearchTerm,
selectedOptions,
chatOptions.recentReports,
chatOptions.personalDetails,
personalDetails,
false,
);

newSections.push(formattedResults.section);

const visibleReportsWhenSearchTermNonEmpty = chatOptions.recentReports.map((report) => (selectedReportIDs.includes(report.reportID) ? getSelectedOptionData(report) : report));
const visibleReportsWhenSearchTermEmpty = chatOptions.recentReports.filter((report) => !selectedReportIDs.includes(report.reportID));
const reportsFiltered = cleanSearchTerm === '' ? visibleReportsWhenSearchTermEmpty : visibleReportsWhenSearchTermNonEmpty;

newSections.push({
title: undefined,
data: reportsFiltered,
shouldShow: chatOptions.recentReports.length > 0,
});

const areResultsFound = didScreenTransitionEnd && formattedResults.section.data.length === 0 && reportsFiltered.length === 0;
const message = areResultsFound ? translate('common.noResultsFound') : undefined;

return {
sections: newSections,
headerMessage: message,
};
}, [
areOptionsInitialized,
chatOptions.personalDetails,
chatOptions.recentReports,
cleanSearchTerm,
didScreenTransitionEnd,
personalDetails,
selectedOptions,
selectedReportIDs,
translate,
]);

useEffect(() => {
Report.searchInServer(debouncedSearchTerm.trim());
}, [debouncedSearchTerm]);

const handleParticipantSelection = useCallback(
(selectedOption: Option) => {
const optionReportID = selectedOption.reportID;
if (!optionReportID) {
return;
}
const foundOptionIndex = selectedReportIDs.findIndex((reportID: string) => {
return reportID && reportID !== '' && selectedOption.reportID === reportID;
});

if (foundOptionIndex < 0) {
setSelectedReportIDs([...selectedReportIDs, optionReportID]);
} else {
const newSelectedReports = [...selectedReportIDs.slice(0, foundOptionIndex), ...selectedReportIDs.slice(foundOptionIndex + 1)];
setSelectedReportIDs(newSelectedReports);
}
},
[selectedReportIDs],
);

const footerContent = (
<Button
success
text={translate('common.save')}
pressOnEnter
onPress={() => {
onFiltersUpdate(selectedReportIDs);
Navigation.goBack(ROUTES.SEARCH_ADVANCED_FILTERS);
}}
large
/>
);
Comment on lines +149 to +160
Copy link
Contributor

Choose a reason for hiding this comment

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

{bz checklist} coming from #70550, Reset button is not included in footer component here, while its included in other screens we added it in #70869


const isLoadingNewOptions = !!isSearchingForReports;
const showLoadingPlaceholder = !didScreenTransitionEnd || !areOptionsInitialized || !initialReportIDs || !personalDetails;

return (
<SelectionList
canSelectMultiple
sections={sections}
ListItem={InviteMemberListItem}
textInputLabel={translate('selectionList.nameEmailOrPhoneNumber')}
headerMessage={headerMessage}
textInputValue={searchTerm}
footerContent={footerContent}
showScrollIndicator
shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()}
onChangeText={(value) => {
setSearchTerm(value);
}}
onSelectRow={handleParticipantSelection}
isLoadingNewOptions={isLoadingNewOptions}
showLoadingPlaceholder={showLoadingPlaceholder}
/>
);
}

SearchFiltersChatsSelector.displayName = 'SearchFiltersChatsSelector';

export default SearchFiltersChatsSelector;
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ export default {
center: 'Center',
from: 'From',
to: 'To',
in: 'In',
optional: 'Optional',
new: 'New',
search: 'Search',
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ export default {
attachment: 'Archivo adjunto',
from: 'De',
to: 'A',
in: 'En',
optional: 'Opcional',
new: 'Nuevo',
center: 'Centrar',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,7 @@ const SearchAdvancedFiltersModalStackNavigator = createModalStackNavigator<Searc
[SCREENS.SEARCH.ADVANCED_FILTERS_TAG_RHP]: () => require<ReactComponentModule>('../../../../pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage').default,
[SCREENS.SEARCH.ADVANCED_FILTERS_FROM_RHP]: () => require<ReactComponentModule>('@pages/Search/SearchAdvancedFiltersPage/SearchFiltersFromPage').default,
[SCREENS.SEARCH.ADVANCED_FILTERS_TO_RHP]: () => require<ReactComponentModule>('@pages/Search/SearchAdvancedFiltersPage/SearchFiltersToPage').default,
[SCREENS.SEARCH.ADVANCED_FILTERS_IN_RHP]: () => require<ReactComponentModule>('@pages/Search/SearchAdvancedFiltersPage/SearchFiltersInPage').default,
[SCREENS.SEARCH.ADVANCED_FILTERS_HAS_RHP]: () => require<ReactComponentModule>('@pages/Search/SearchAdvancedFiltersPage/SearchFiltersHasPage').default,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const CENTRAL_PANE_TO_RHP_MAPPING: Partial<Record<CentralPaneName, string[]>> =
SCREENS.SEARCH.ADVANCED_FILTERS_TAG_RHP,
SCREENS.SEARCH.ADVANCED_FILTERS_FROM_RHP,
SCREENS.SEARCH.ADVANCED_FILTERS_TO_RHP,
SCREENS.SEARCH.ADVANCED_FILTERS_IN_RHP,
],
[SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: [
SCREENS.SETTINGS.SUBSCRIPTION.ADD_PAYMENT_CARD,
Expand Down
1 change: 1 addition & 0 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,7 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
[SCREENS.SEARCH.ADVANCED_FILTERS_TAG_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_TAG,
[SCREENS.SEARCH.ADVANCED_FILTERS_FROM_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_FROM,
[SCREENS.SEARCH.ADVANCED_FILTERS_TO_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_TO,
[SCREENS.SEARCH.ADVANCED_FILTERS_IN_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_IN,
[SCREENS.SEARCH.ADVANCED_FILTERS_HAS_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_HAS,
},
},
Expand Down
1 change: 1 addition & 0 deletions src/libs/OptionsListUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2542,6 +2542,7 @@ export {
getCurrentUserSearchTerms,
getEmptyOptions,
shouldUseBoldText,
getAlternateText,
};

export type {MemberForList, CategorySection, CategoryTreeSection, Options, OptionList, SearchOption, PayeePersonalDetails, Category, Tax, TaxRatesOption, Option, OptionTree};
1 change: 1 addition & 0 deletions src/libs/SearchUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,7 @@ function buildQueryStringFromFilters(filterValues: Partial<SearchAdvancedFilters
filterKey === FILTER_KEYS.CURRENCY ||
filterKey === FILTER_KEYS.FROM ||
filterKey === FILTER_KEYS.TO ||
filterKey === FILTER_KEYS.IN ||
filterKey === FILTER_KEYS.HAS) &&
Array.isArray(filterValue) &&
filterValue.length > 0
Expand Down
Loading