Skip to content

Commit

Permalink
Merge pull request Expensify#52287 from margelo/cleanup/refactor-getT…
Browse files Browse the repository at this point in the history
…agListSections
  • Loading branch information
dangrous authored Nov 13, 2024
2 parents e902c04 + 650bc45 commit 2f8a878
Show file tree
Hide file tree
Showing 8 changed files with 752 additions and 747 deletions.
3 changes: 2 additions & 1 deletion src/components/MoneyRequestConfirmationListFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import * as OptionsListUtils from '@libs/OptionsListUtils';
import * as PolicyUtils from '@libs/PolicyUtils';
import * as ReceiptUtils from '@libs/ReceiptUtils';
import {getDefaultWorkspaceAvatar} from '@libs/ReportUtils';
import * as TagsOptionsListUtils from '@libs/TagsOptionsListUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
import ToggleSettingOptionRow from '@pages/workspace/workflows/ToggleSettingsOptionRow';
Expand Down Expand Up @@ -224,7 +225,7 @@ function MoneyRequestConfirmationListFooter({
// A flag and a toggler for showing the rest of the form fields
const [shouldExpandFields, toggleShouldExpandFields] = useReducer((state) => !state, false);

const shouldShowTags = useMemo(() => isPolicyExpenseChat && OptionsListUtils.hasEnabledTags(policyTagLists), [isPolicyExpenseChat, policyTagLists]);
const shouldShowTags = useMemo(() => isPolicyExpenseChat && TagsOptionsListUtils.hasEnabledTags(policyTagLists), [isPolicyExpenseChat, policyTagLists]);
const isMultilevelTags = useMemo(() => PolicyUtils.isMultiLevelTags(policyTags), [policyTags]);
const shouldShowAttendees = useMemo(() => TransactionUtils.shouldShowAttendees(iouType, policy), [iouType, policy]);

Expand Down
3 changes: 2 additions & 1 deletion src/components/ReportActionItem/MoneyRequestView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import * as ReceiptUtils from '@libs/ReceiptUtils';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import * as ReportUtils from '@libs/ReportUtils';
import type {TransactionDetails} from '@libs/ReportUtils';
import * as TagsOptionsListUtils from '@libs/TagsOptionsListUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import ViolationsUtils from '@libs/Violations/ViolationsUtils';
import Navigation from '@navigation/Navigation';
Expand Down Expand Up @@ -182,7 +183,7 @@ function MoneyRequestView({report, shouldShowAnimatedBackground, readonly = fals
const shouldShowCategory = isPolicyExpenseChat && (transactionCategory || OptionsListUtils.hasEnabledOptions(policyCategories ?? {}));
// transactionTag can be an empty string
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
const shouldShowTag = isPolicyExpenseChat && (transactionTag || OptionsListUtils.hasEnabledTags(policyTagLists));
const shouldShowTag = isPolicyExpenseChat && (transactionTag || TagsOptionsListUtils.hasEnabledTags(policyTagLists));
const shouldShowBillable = isPolicyExpenseChat && (!!transactionBillable || !(policy?.disabledFields?.defaultBillable ?? true) || !!updatedTransaction?.billable);
const shouldShowAttendees = useMemo(() => TransactionUtils.shouldShowAttendees(iouType, policy), [iouType, policy]);

Expand Down
18 changes: 4 additions & 14 deletions src/components/TagPicker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,11 @@ import useThemeStyles from '@hooks/useThemeStyles';
import * as OptionsListUtils from '@libs/OptionsListUtils';
import * as PolicyUtils from '@libs/PolicyUtils';
import type * as ReportUtils from '@libs/ReportUtils';
import type {SelectedTagOption} from '@libs/TagsOptionsListUtils';
import * as TagOptionListUtils from '@libs/TagsOptionsListUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {PolicyTag, PolicyTags} from '@src/types/onyx';
import type {PendingAction} from '@src/types/onyx/OnyxCommon';

type SelectedTagOption = {
name: string;
enabled: boolean;
isSelected?: boolean;
accountID: number | undefined;
pendingAction?: PendingAction;
};

type TagPickerProps = {
/** The policyID we are getting tags for */
Expand Down Expand Up @@ -81,15 +74,12 @@ function TagPicker({selectedTag, tagListName, policyID, tagListIndex, shouldShow

const sections = useMemo(
() =>
OptionsListUtils.getFilteredOptions({
TagOptionListUtils.getTagListSections({
searchValue,
selectedOptions,
includeP2P: false,
includeTags: true,
tags: enabledTags,
recentlyUsedTags: policyRecentlyUsedTagsList,
canInviteUser: false,
}).tagOptions,
}),
[searchValue, enabledTags, selectedOptions, policyRecentlyUsedTagsList],
);

Expand Down
190 changes: 0 additions & 190 deletions src/libs/OptionsListUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import Onyx from 'react-native-onyx';
import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
import type {SetNonNullable} from 'type-fest';
import {FallbackAvatar} from '@components/Icon/Expensicons';
import type {SelectedTagOption} from '@components/TagPicker';
import type {IOUAction} from '@src/CONST';
import CONST from '@src/CONST';
import type {TranslationPaths} from '@src/languages/types';
Expand All @@ -24,8 +23,6 @@ import type {
PolicyCategories,
PolicyCategory,
PolicyTag,
PolicyTagLists,
PolicyTags,
Report,
ReportAction,
ReportActions,
Expand All @@ -42,7 +39,6 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject';
import times from '@src/utils/times';
import Timing from './actions/Timing';
import filterArrayByMatch from './filterArrayByMatch';
import localeCompare from './LocaleCompare';
import * as LocalePhoneNumber from './LocalePhoneNumber';
import * as Localize from './Localize';
import * as LoginUtils from './LoginUtils';
Expand Down Expand Up @@ -162,9 +158,6 @@ type GetOptionsConfig = {
includeCategories?: boolean;
categories?: PolicyCategories;
recentlyUsedCategories?: string[];
includeTags?: boolean;
tags?: PolicyTags | Array<SelectedTagOption | PolicyTag>;
recentlyUsedTags?: string[];
canInviteUser?: boolean;
includeSelectedOptions?: boolean;
includeTaxRates?: boolean;
Expand Down Expand Up @@ -212,7 +205,6 @@ type Options = {
userToInvite: ReportUtils.OptionData | null;
currentUserOption: ReportUtils.OptionData | null | undefined;
categoryOptions: CategoryTreeSection[];
tagOptions: CategorySection[];
taxRatesOptions: CategorySection[];
};

Expand Down Expand Up @@ -978,16 +970,6 @@ function sortCategories(categories: Record<string, Category>): Category[] {
return flatHierarchy(hierarchy);
}

/**
* Sorts tags alphabetically by name.
*/
function sortTags(tags: Record<string, PolicyTag | SelectedTagOption> | Array<PolicyTag | SelectedTagOption>) {
const sortedTags = Array.isArray(tags) ? tags : Object.values(tags);

// Use lodash's sortBy to ensure consistency with oldDot.
return lodashSortBy(sortedTags, 'name', localeCompare);
}

/**
* Builds the options for the category tree hierarchy via indents
*
Expand Down Expand Up @@ -1170,141 +1152,6 @@ function getCategoryListSections(
return categorySections;
}

/**
* Transforms the provided tags into option objects.
*
* @param tags - an initial tag array
*/
function getTagsOptions(tags: Array<Pick<PolicyTag, 'name' | 'enabled' | 'pendingAction'>>, selectedOptions?: SelectedTagOption[]): Option[] {
return tags.map((tag) => {
// This is to remove unnecessary escaping backslash in tag name sent from backend.
const cleanedName = PolicyUtils.getCleanedTagName(tag.name);
return {
text: cleanedName,
keyForList: tag.name,
searchText: tag.name,
tooltipText: cleanedName,
isDisabled: !tag.enabled || tag.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
isSelected: selectedOptions?.some((selectedTag) => selectedTag.name === tag.name),
pendingAction: tag.pendingAction,
};
});
}

/**
* Build the section list for tags
*/
function getTagListSections(
tags: Array<PolicyTag | SelectedTagOption>,
recentlyUsedTags: string[],
selectedOptions: SelectedTagOption[],
searchInputValue: string,
maxRecentReportsToShow: number,
) {
const tagSections = [];
const sortedTags = sortTags(tags) as PolicyTag[];
const selectedOptionNames = selectedOptions.map((selectedOption) => selectedOption.name);
const enabledTags = sortedTags.filter((tag) => tag.enabled);
const enabledTagsNames = enabledTags.map((tag) => tag.name);
const enabledTagsWithoutSelectedOptions = enabledTags.filter((tag) => !selectedOptionNames.includes(tag.name));
const selectedTagsWithDisabledState: SelectedTagOption[] = [];
const numberOfTags = enabledTags.length;

selectedOptions.forEach((tag) => {
if (enabledTagsNames.includes(tag.name)) {
selectedTagsWithDisabledState.push({...tag, enabled: true});
return;
}
selectedTagsWithDisabledState.push({...tag, enabled: false});
});

// If all tags are disabled but there's a previously selected tag, show only the selected tag
if (numberOfTags === 0 && selectedOptions.length > 0) {
tagSections.push({
// "Selected" section
title: '',
shouldShow: false,
data: getTagsOptions(selectedTagsWithDisabledState, selectedOptions),
});

return tagSections;
}

if (searchInputValue) {
const enabledSearchTags = enabledTagsWithoutSelectedOptions.filter((tag) => PolicyUtils.getCleanedTagName(tag.name.toLowerCase()).includes(searchInputValue.toLowerCase()));
const selectedSearchTags = selectedTagsWithDisabledState.filter((tag) => PolicyUtils.getCleanedTagName(tag.name.toLowerCase()).includes(searchInputValue.toLowerCase()));
const tagsForSearch = [...selectedSearchTags, ...enabledSearchTags];

tagSections.push({
// "Search" section
title: '',
shouldShow: true,
data: getTagsOptions(tagsForSearch, selectedOptions),
});

return tagSections;
}

if (numberOfTags < CONST.STANDARD_LIST_ITEM_LIMIT) {
tagSections.push({
// "All" section when items amount less than the threshold
title: '',
shouldShow: false,
data: getTagsOptions([...selectedTagsWithDisabledState, ...enabledTagsWithoutSelectedOptions], selectedOptions),
});

return tagSections;
}

const filteredRecentlyUsedTags = recentlyUsedTags
.filter((recentlyUsedTag) => {
const tagObject = tags.find((tag) => tag.name === recentlyUsedTag);
return !!tagObject?.enabled && !selectedOptionNames.includes(recentlyUsedTag) && tagObject?.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE;
})
.map((tag) => ({name: tag, enabled: true}));

if (selectedOptions.length) {
tagSections.push({
// "Selected" section
title: '',
shouldShow: true,
data: getTagsOptions(selectedTagsWithDisabledState, selectedOptions),
});
}

if (filteredRecentlyUsedTags.length > 0) {
const cutRecentlyUsedTags = filteredRecentlyUsedTags.slice(0, maxRecentReportsToShow);

tagSections.push({
// "Recent" section
title: Localize.translateLocal('common.recent'),
shouldShow: true,
data: getTagsOptions(cutRecentlyUsedTags, selectedOptions),
});
}

tagSections.push({
// "All" section when items amount more than the threshold
title: Localize.translateLocal('common.all'),
shouldShow: true,
data: getTagsOptions(enabledTagsWithoutSelectedOptions, selectedOptions),
});

return tagSections;
}

/**
* Verifies that there is at least one enabled tag
*/
function hasEnabledTags(policyTagList: Array<PolicyTagLists[keyof PolicyTagLists]>) {
const policyTagValueList = policyTagList
.filter((tag) => tag && tag.tags)
.map(({tags}) => Object.values(tags))
.flat();

return hasEnabledOptions(policyTagValueList);
}

/**
* Sorts tax rates alphabetically by name.
*/
Expand Down Expand Up @@ -1638,9 +1485,6 @@ function getOptions(
includeCategories = false,
categories = {},
recentlyUsedCategories = [],
includeTags = false,
tags = {},
recentlyUsedTags = [],
canInviteUser = true,
includeSelectedOptions = false,
transactionViolations = {},
Expand All @@ -1664,21 +1508,6 @@ function getOptions(
userToInvite: null,
currentUserOption: null,
categoryOptions,
tagOptions: [],
taxRatesOptions: [],
};
}

if (includeTags) {
const tagOptions = getTagListSections(Object.values(tags), recentlyUsedTags, selectedOptions as SelectedTagOption[], searchInputValue, maxRecentReportsToShow);

return {
recentReports: [],
personalDetails: [],
userToInvite: null,
currentUserOption: null,
categoryOptions: [],
tagOptions,
taxRatesOptions: [],
};
}
Expand All @@ -1692,7 +1521,6 @@ function getOptions(
userToInvite: null,
currentUserOption: null,
categoryOptions: [],
tagOptions: [],
taxRatesOptions,
};
}
Expand Down Expand Up @@ -1953,7 +1781,6 @@ function getOptions(
userToInvite: canInviteUser ? userToInvite : null,
currentUserOption,
categoryOptions: [],
tagOptions: [],
taxRatesOptions: [],
};
}
Expand Down Expand Up @@ -2040,9 +1867,6 @@ type FilteredOptionsParams = {
includeCategories?: boolean;
categories?: PolicyCategories;
recentlyUsedCategories?: string[];
includeTags?: boolean;
tags?: PolicyTags | Array<PolicyTag | SelectedTagOption>;
recentlyUsedTags?: string[];
canInviteUser?: boolean;
includeSelectedOptions?: boolean;
includeTaxRates?: boolean;
Expand Down Expand Up @@ -2078,9 +1902,6 @@ function getFilteredOptions(params: FilteredOptionsParamsWithDefaultSearchValue
includeCategories = false,
categories = {},
recentlyUsedCategories = [],
includeTags = false,
tags = {},
recentlyUsedTags = [],
canInviteUser = true,
includeSelectedOptions = false,
includeTaxRates = false,
Expand All @@ -2105,9 +1926,6 @@ function getFilteredOptions(params: FilteredOptionsParamsWithDefaultSearchValue
includeCategories,
categories,
recentlyUsedCategories,
includeTags,
tags,
recentlyUsedTags,
canInviteUser,
includeSelectedOptions,
includeTaxRates,
Expand Down Expand Up @@ -2146,9 +1964,6 @@ function getAttendeeOptions(
includeCategories: false,
categories: {},
recentlyUsedCategories: [],
includeTags: false,
tags: {},
recentlyUsedTags: [],
canInviteUser,
includeSelectedOptions: false,
includeTaxRates: false,
Expand Down Expand Up @@ -2445,7 +2260,6 @@ function filterOptions(options: Options, searchInputValue: string, config?: Filt
userToInvite: null,
currentUserOption,
categoryOptions: [],
tagOptions: [],
taxRatesOptions: [],
};
}, options);
Expand Down Expand Up @@ -2481,7 +2295,6 @@ function filterOptions(options: Options, searchInputValue: string, config?: Filt
userToInvite,
currentUserOption: matchResults.currentUserOption,
categoryOptions: [],
tagOptions: [],
taxRatesOptions: [],
};
}
Expand All @@ -2497,7 +2310,6 @@ function getEmptyOptions(): Options {
userToInvite: null,
currentUserOption: null,
categoryOptions: [],
tagOptions: [],
taxRatesOptions: [],
};
}
Expand Down Expand Up @@ -2532,9 +2344,7 @@ export {
hasEnabledOptions,
sortCategories,
sortAlphabetically,
sortTags,
getCategoryOptionTree,
hasEnabledTags,
formatMemberForList,
formatSectionsFromSearchTerm,
getShareLogOptions,
Expand Down
Loading

0 comments on commit 2f8a878

Please sign in to comment.