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
58 changes: 55 additions & 3 deletions src/pages/workspace/categories/WorkspaceCategoriesPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import usePolicyData from '@hooks/usePolicyData';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useSearchBackPress from '@hooks/useSearchBackPress';
import useSearchResults from '@hooks/useSearchResults';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import {isConnectionInProgress, isConnectionUnverified} from '@libs/actions/connections';
import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode';
Expand All @@ -46,9 +47,10 @@ import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types';
import {isDisablingOrDeletingLastEnabledCategory} from '@libs/OptionsListUtils';
import {getConnectedIntegration, getCurrentConnectionName, hasAccountingConnections, shouldShowSyncError} from '@libs/PolicyUtils';
import {getConnectedIntegration, getCurrentConnectionName, hasAccountingConnections, isControlPolicy, shouldShowSyncError} from '@libs/PolicyUtils';
import tokenizedSearch from '@libs/tokenizedSearch';
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
import variables from '@styles/variables';
import {close} from '@userActions/Modal';
import {clearCategoryErrors, deleteWorkspaceCategories, downloadCategoriesCSV, openPolicyCategoriesPage, setWorkspaceCategoryEnabled} from '@userActions/Policy/Category';
import CONST from '@src/CONST';
Expand All @@ -71,6 +73,7 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) {
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
const {shouldUseNarrowLayout, isSmallScreenWidth} = useResponsiveLayout();
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const {translate, localeCompare} = useLocalize();
const [isOfflineModalVisible, setIsOfflineModalVisible] = useState(false);
const [isDownloadFailureModalVisible, setIsDownloadFailureModalVisible] = useState(false);
Expand All @@ -92,6 +95,7 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) {

const [selectedCategories, setSelectedCategories] = useState<string[]>([]);
const canSelectMultiple = isSmallScreenWidth ? isMobileSelectionModeEnabled : true;
const isControlPolicyWithWideLayout = !shouldUseNarrowLayout && isControlPolicy(policy);
const icons = useMemoizedLazyExpensifyIcons(['Download', 'Gear', 'Table']);
const illustrations = useMemoizedLazyIllustrations(['FolderOpen']);

Expand Down Expand Up @@ -175,6 +179,10 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) {
],
);

const glCodeContainerStyle = useMemo(() => [styles.flex1], [styles.flex1]);
const glCodeTextStyle = useMemo(() => [styles.alignSelfStart], [styles.alignSelfStart]);
Comment thread
Julesssss marked this conversation as resolved.
const switchContainerStyle = useMemo(() => [StyleUtils.getMinimumWidth(variables.w72)], [StyleUtils]);

const categoryList = useMemo<PolicyOption[]>(() => {
const categories = Object.values(policyCategories ?? {});
return categories.reduce<PolicyOption[]>((acc, value) => {
Expand All @@ -190,7 +198,33 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) {
isDisabled,
pendingAction: value.pendingAction,
errors: value.errors ?? undefined,
rightElement: (
rightElement: isControlPolicyWithWideLayout ? (
Comment thread
daledah marked this conversation as resolved.
<>
<View style={glCodeContainerStyle}>
<Text
numberOfLines={1}
style={glCodeTextStyle}
>
{value['GL Code']}
</Text>
</View>
<View style={switchContainerStyle}>
<Switch
isOn={value.enabled}
disabled={isDisabled}
accessibilityLabel={translate('workspace.categories.enableCategory')}
onToggle={(newValue: boolean) => {
if (isDisablingOrDeletingLastEnabledCategory(policy, policyCategories, [value])) {
setIsCannotDeleteOrDisableLastCategoryModalVisible(true);
return;
}
updateWorkspaceCategoryEnabled(newValue, value.name);
}}
showLockIcon={isDisablingOrDeletingLastEnabledCategory(policy, policyCategories, [value])}
/>
</View>
</>
) : (
<Switch
isOn={value.enabled}
disabled={isDisabled}
Expand All @@ -209,7 +243,7 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) {

return acc;
}, []);
}, [policyCategories, isOffline, translate, updateWorkspaceCategoryEnabled, policy]);
}, [policyCategories, isOffline, translate, updateWorkspaceCategoryEnabled, policy, isControlPolicyWithWideLayout, glCodeContainerStyle, glCodeTextStyle, switchContainerStyle]);

const filterCategory = useCallback((categoryOption: PolicyOption, searchInput: string) => {
const results = tokenizedSearch([categoryOption], searchInput, (option) => [option.text ?? '', option.alternateText ?? '']);
Expand Down Expand Up @@ -247,6 +281,24 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) {
if (filteredCategoryList.length === 0) {
return null;
}

// Show GL Code column only on wide screens for control policies
if (isControlPolicyWithWideLayout) {
return (
<View style={[styles.flex1, styles.flexRow, styles.justifyContentBetween, styles.pl3]}>
<View style={[styles.flex1, StyleUtils.getPaddingRight(variables.w52 + variables.w12)]}>
<Text style={[styles.textMicroSupporting, styles.alignSelfStart]}>{translate('common.name')}</Text>
</View>
<View style={[styles.flex1, styles.pr16]}>
<Text style={[styles.textMicroSupporting, styles.alignSelfStart]}>{translate('workspace.categories.glCode')}</Text>
</View>
<View style={[StyleUtils.getMinimumWidth(variables.w72), styles.mr5]}>
<Text style={[styles.textMicroSupporting, styles.alignSelfStart]}>{translate('common.enabled')}</Text>
</View>
</View>
);
}

return (
<CustomListHeader
canSelectMultiple={canSelectMultiple}
Expand Down
68 changes: 66 additions & 2 deletions src/pages/workspace/tags/WorkspaceTagsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import usePolicyData from '@hooks/usePolicyData';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useSearchBackPress from '@hooks/useSearchBackPress';
import useSearchResults from '@hooks/useSearchResults';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import {isConnectionInProgress, isConnectionUnverified} from '@libs/actions/connections';
import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode';
Expand All @@ -57,11 +58,13 @@ import {
getTagLists,
hasAccountingConnections as hasAccountingConnectionsPolicyUtils,
hasDependentTags as hasDependentTagsPolicyUtils,
isControlPolicy,
isMultiLevelTags as isMultiLevelTagsPolicyUtils,
shouldShowSyncError,
} from '@libs/PolicyUtils';
import tokenizedSearch from '@libs/tokenizedSearch';
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
import variables from '@styles/variables';
import {close} from '@userActions/Modal';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
Expand All @@ -80,6 +83,7 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) {
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
const {shouldUseNarrowLayout, isSmallScreenWidth} = useResponsiveLayout();
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const {translate, localeCompare} = useLocalize();
const [isDownloadFailureModalVisible, setIsDownloadFailureModalVisible] = useState(false);
const [isDeleteTagsConfirmModalVisible, setIsDeleteTagsConfirmModalVisible] = useState(false);
Expand All @@ -105,6 +109,7 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) {
);

const canSelectMultiple = !hasDependentTags && (shouldUseNarrowLayout ? isMobileSelectionModeEnabled : true);
const isControlPolicyWithWideLayout = !shouldUseNarrowLayout && isControlPolicy(policy);
const fetchTags = useCallback(() => {
openPolicyTagsPage(policyID);
}, [policyID]);
Expand Down Expand Up @@ -213,6 +218,9 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) {
},
[policyData],
);
const glCodeContainerStyle = useMemo(() => [styles.flex1], [styles.flex1]);
const glCodeTextStyle = useMemo(() => [styles.alignSelfStart], [styles.alignSelfStart]);
const switchContainerStyle = useMemo(() => [StyleUtils.getMinimumWidth(variables.w72)], [StyleUtils]);

const tagList = useMemo<TagListItem[]>(() => {
if (isMultiLevelTags) {
Expand Down Expand Up @@ -264,7 +272,33 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) {
errors: tag.errors ?? undefined,
enabled: tag.enabled,
isDisabled: tag.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
rightElement: (
rightElement: isControlPolicyWithWideLayout ? (
Comment thread
daledah marked this conversation as resolved.
<>
<View style={glCodeContainerStyle}>
<Text
numberOfLines={1}
style={glCodeTextStyle}
>
{tag['GL Code']}
</Text>
</View>
<View style={switchContainerStyle}>
<Switch
isOn={tag.enabled}
disabled={tag.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE}
accessibilityLabel={translate('workspace.tags.enableTag')}
onToggle={(newValue: boolean) => {
if (isDisablingOrDeletingLastEnabledTag(policyTagLists.at(0), [tag])) {
setIsCannotDeleteOrDisableLastTagModalVisible(true);
return;
}
updateWorkspaceTagEnabled(newValue, tag.name);
}}
showLockIcon={isDisablingOrDeletingLastEnabledTag(policyTagLists.at(0), [tag])}
/>
</View>
</>
) : (
<Switch
isOn={tag.enabled}
disabled={tag.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE}
Expand All @@ -280,7 +314,20 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) {
/>
),
}));
}, [isMultiLevelTags, policyTagLists, hasDependentTags, translate, policy, policyTags, updateWorkspaceRequiresTag, updateWorkspaceTagEnabled]);
}, [
isMultiLevelTags,
policyTagLists,
hasDependentTags,
translate,
policy,
policyTags,
updateWorkspaceRequiresTag,
updateWorkspaceTagEnabled,
isControlPolicyWithWideLayout,
glCodeContainerStyle,
glCodeTextStyle,
switchContainerStyle,
]);

const filterTag = useCallback((tag: TagListItem, searchInput: string) => {
const results = tokenizedSearch([tag], searchInput, (option) => [option.text ?? '', option.value ?? '']);
Expand Down Expand Up @@ -334,6 +381,23 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) {
);
}

// Show GL Code column only on wide screens for control policies
if (isControlPolicyWithWideLayout && !isMultiLevelTags) {
Comment thread
Julesssss marked this conversation as resolved.
return (
<View style={[styles.flex1, styles.flexRow, styles.justifyContentBetween, styles.pl3]}>
<View style={[styles.flex1, StyleUtils.getPaddingRight(variables.w52 + variables.w12)]}>
<Text style={[styles.textMicroSupporting, styles.alignSelfStart]}>{translate('common.name')}</Text>
</View>
<View style={[styles.flex1, styles.pr16]}>
<Text style={[styles.textMicroSupporting, styles.alignSelfStart]}>{translate('workspace.tags.glCode')}</Text>
</View>
<View style={[StyleUtils.getMinimumWidth(variables.w72), styles.mr5]}>
<Text style={[styles.textMicroSupporting, styles.alignSelfStart]}>{translate('common.enabled')}</Text>
</View>
</View>
);
}

return (
<CustomListHeader
canSelectMultiple={canSelectMultiple}
Expand Down
Loading