Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cleanup: refactor getTagListSections to TagsOptionsListUtils #52287

Merged
merged 11 commits into from
Nov 13, 2024
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
Loading