Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ function WorkspaceReportFieldsPage({

const toggleAllReportFields = () => {
const availableReportFields = Object.values(selectionFieldList).filter((reportField) => reportField.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE);
setSelectedReportFields(selectedReportFields.length > 0 ? [] : Object.keys(availableReportFields));
setSelectedReportFields(selectedReportFields.length > 0 ? [] : Object.values(availableReportFields).map((reportField) => getReportFieldKey(reportField.fieldID)));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We should use the object keys as the source of truth. The current solution could break if the object changes (e.g. if we remove getReportFieldKey or add more logic). I have already posted a solution #59648 (comment)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Your solution is not different from current solution, and we still need getReportFieldKey because we use it here

isSelected: selectedReportFields.includes(getReportFieldKey(reportField.fieldID)) && canSelectMultiple,

};

const navigateToReportFieldsSettings = (reportField: ReportFieldForList) => {
Expand Down
53 changes: 29 additions & 24 deletions src/pages/workspace/tags/WorkspaceViewTagsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import TableListItem from '@components/SelectionList/TableListItem';
import SelectionListWithModal from '@components/SelectionListWithModal';
import CustomListHeader from '@components/SelectionListWithModal/CustomListHeader';
import Switch from '@components/Switch';
import useFilteredSelection from '@hooks/useFilteredSelection';
import useLocalize from '@hooks/useLocalize';
import useMobileSelectionMode from '@hooks/useMobileSelectionMode';
import useNetwork from '@hooks/useNetwork';
Expand Down Expand Up @@ -45,6 +46,7 @@ import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
import type {PolicyTag} from '@src/types/onyx';
import type DeepValueOf from '@src/types/utils/DeepValueOf';
import type {TagListItem} from './types';

Expand All @@ -57,7 +59,6 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) {
const styles = useThemeStyles();
const theme = useTheme();
const {translate} = useLocalize();
const [selectedTags, setSelectedTags] = useState<Record<string, boolean>>({});
const dropdownButtonRef = useRef(null);
const [isDeleteTagsConfirmModalVisible, setIsDeleteTagsConfirmModalVisible] = useState(false);
const isFocused = useIsFocused();
Expand All @@ -74,6 +75,10 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) {
openPolicyTagsPage(policyID);
}, [policyID]);

const filterFunction = useCallback((tag: PolicyTag | undefined) => !!tag && tag.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, []);

const [selectedTags, setSelectedTags] = useFilteredSelection(currentPolicyTag?.tags, filterFunction);

const {isOffline} = useNetwork({onReconnect: fetchTags});
const canSelectMultiple = isSmallScreenWidth ? selectionMode?.isEnabled : true;

Expand All @@ -89,7 +94,7 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) {

useSearchBackPress({
onClearSelection: () => {
setSelectedTags({});
setSelectedTags([]);
},
onNavigationCallBack: () => Navigation.goBack(isQuickSettingsFlow ? ROUTES.SETTINGS_TAGS_ROOT.getRoute(policyID) : undefined),
});
Expand All @@ -109,7 +114,7 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) {
value: tag.name,
text: getCleanedTagName(tag.name),
keyForList: tag.name,
isSelected: selectedTags[tag.name] && canSelectMultiple,
isSelected: selectedTags.includes(tag.name) && canSelectMultiple,
pendingAction: tag.pendingAction,
errors: tag.errors ?? undefined,
enabled: tag.enabled,
Expand Down Expand Up @@ -142,17 +147,19 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) {
}

const toggleTag = (tag: TagListItem) => {
setSelectedTags((prev) => ({
...prev,
[tag.value]: !prev[tag.value],
}));
setSelectedTags((prev) => {
if (prev.includes(tag.value)) {
return prev.filter((selectedTag) => selectedTag !== tag.value);
}
return [...prev, tag.value];
});
};

const toggleAllTags = () => {
const availableTags = tagList.filter((tag) => tag.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE);
const anySelected = availableTags.some((tag) => !!selectedTags[tag.value]);
const anySelected = availableTags.some((tag) => selectedTags.includes(tag.value));

setSelectedTags(anySelected ? {} : Object.fromEntries(availableTags.map((t) => [t.value, true])));
setSelectedTags(anySelected ? [] : availableTags.map((tag) => tag.value));
};

const getCustomListHeader = () => {
Expand All @@ -173,29 +180,27 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) {
);
};

const selectedTagsArray = Object.keys(selectedTags).filter((key) => selectedTags[key]);

const deleteTags = () => {
setSelectedTags({});
deletePolicyTags(policyID, selectedTagsArray);
setSelectedTags([]);
deletePolicyTags(policyID, selectedTags);
setIsDeleteTagsConfirmModalVisible(false);
};

const isLoading = !isOffline && policyTags === undefined;

const getHeaderButtons = () => {
if ((!isSmallScreenWidth && selectedTagsArray.length === 0) || (isSmallScreenWidth && !selectionMode?.isEnabled)) {
if ((!isSmallScreenWidth && selectedTags.length === 0) || (isSmallScreenWidth && !selectionMode?.isEnabled)) {
return null;
}

const options: Array<DropdownOption<DeepValueOf<typeof CONST.POLICY.BULK_ACTION_TYPES>>> = [];
const isThereAnyAccountingConnection = Object.keys(policy?.connections ?? {}).length !== 0;
const isMultiLevelTags = isMultiLevelTagsPolicyUtils(policyTags);

if (!isThereAnyAccountingConnection && !isMultiLevelTags && selectedTagsArray.length > 0) {
if (!isThereAnyAccountingConnection && !isMultiLevelTags && selectedTags.length > 0) {
options.push({
icon: Expensicons.Trashcan,
text: translate(selectedTagsArray.length === 1 ? 'workspace.tags.deleteTag' : 'workspace.tags.deleteTags'),
text: translate(selectedTags.length === 1 ? 'workspace.tags.deleteTag' : 'workspace.tags.deleteTags'),
value: CONST.POLICY.BULK_ACTION_TYPES.DELETE,
onSelected: () => setIsDeleteTagsConfirmModalVisible(true),
});
Expand All @@ -205,7 +210,7 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) {
const tagsToDisable: Record<string, {name: string; enabled: boolean}> = {};
let disabledTagCount = 0;
const tagsToEnable: Record<string, {name: string; enabled: boolean}> = {};
for (const tagName of selectedTagsArray) {
for (const tagName of selectedTags) {
if (tagListKeyedByName[tagName]?.enabled) {
enabledTagCount++;
tagsToDisable[tagName] = {
Expand All @@ -227,7 +232,7 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) {
text: translate(enabledTagCount === 1 ? 'workspace.tags.disableTag' : 'workspace.tags.disableTags'),
value: CONST.POLICY.BULK_ACTION_TYPES.DISABLE,
onSelected: () => {
setSelectedTags({});
setSelectedTags([]);
setWorkspaceTagEnabled(policyID, tagsToDisable, route.params.orderWeight);
},
});
Expand All @@ -239,7 +244,7 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) {
text: translate(disabledTagCount === 1 ? 'workspace.tags.enableTag' : 'workspace.tags.enableTags'),
value: CONST.POLICY.BULK_ACTION_TYPES.ENABLE,
onSelected: () => {
setSelectedTags({});
setSelectedTags([]);
setWorkspaceTagEnabled(policyID, tagsToEnable, route.params.orderWeight);
},
});
Expand All @@ -253,10 +258,10 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) {
pressOnEnter
isSplitButton={false}
buttonSize={CONST.DROPDOWN_BUTTON_SIZE.MEDIUM}
customText={translate('workspace.common.selected', {count: selectedTagsArray.length})}
customText={translate('workspace.common.selected', {count: selectedTags.length})}
options={options}
style={[shouldUseNarrowLayout && styles.flexGrow1, shouldUseNarrowLayout && styles.mb3]}
isDisabled={!selectedTagsArray.length}
isDisabled={!selectedTags.length}
/>
);
};
Expand Down Expand Up @@ -290,7 +295,7 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) {
title={selectionModeHeader ? translate('common.selectMultiple') : currentTagListName}
onBackButtonPress={() => {
if (selectionMode?.isEnabled) {
setSelectedTags({});
setSelectedTags([]);
turnOffMobileSelectionMode();
return;
}
Expand All @@ -304,8 +309,8 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) {
isVisible={isDeleteTagsConfirmModalVisible}
onConfirm={deleteTags}
onCancel={() => setIsDeleteTagsConfirmModalVisible(false)}
title={translate(selectedTagsArray.length === 1 ? 'workspace.tags.deleteTag' : 'workspace.tags.deleteTags')}
prompt={translate(selectedTagsArray.length === 1 ? 'workspace.tags.deleteTagConfirmation' : 'workspace.tags.deleteTagsConfirmation')}
title={translate(selectedTags.length === 1 ? 'workspace.tags.deleteTag' : 'workspace.tags.deleteTags')}
prompt={translate(selectedTags.length === 1 ? 'workspace.tags.deleteTagConfirmation' : 'workspace.tags.deleteTagsConfirmation')}
confirmText={translate('common.delete')}
cancelText={translate('common.cancel')}
danger
Expand Down