diff --git a/src/CONST.ts b/src/CONST.ts index 55f0dafd8517..ca3738cd272e 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -741,7 +741,6 @@ const CONST = { REPORT_FIELDS_FEATURE: 'reportFieldsFeature', NETSUITE_USA_TAX: 'netsuiteUsaTax', COMBINED_TRACK_SUBMIT: 'combinedTrackSubmit', - CATEGORY_AND_TAG_APPROVERS: 'categoryAndTagApprovers', PER_DIEM: 'newDotPerDiem', NEWDOT_MERGE_ACCOUNTS: 'newDotMergeAccounts', NEWDOT_MANAGER_MCTEST: 'newDotManagerMcTest', diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts index 9ed5881513f2..d26ff8c245a9 100644 --- a/src/libs/Permissions.ts +++ b/src/libs/Permissions.ts @@ -18,10 +18,6 @@ function canUseNetSuiteUSATax(betas: OnyxEntry): boolean { return !!betas?.includes(CONST.BETAS.NETSUITE_USA_TAX) || canUseAllBetas(betas); } -function canUseCategoryAndTagApprovers(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.CATEGORY_AND_TAG_APPROVERS) || canUseAllBetas(betas); -} - function canUsePerDiem(betas: OnyxEntry): boolean { return !!betas?.includes(CONST.BETAS.PER_DIEM) || canUseAllBetas(betas); } @@ -58,7 +54,6 @@ export default { canUseLinkPreviews, canUseSpotnanaTravel, canUseNetSuiteUSATax, - canUseCategoryAndTagApprovers, canUsePerDiem, canUseMergeAccounts, canUseManagerMcTest, diff --git a/src/pages/workspace/categories/CategorySettingsPage.tsx b/src/pages/workspace/categories/CategorySettingsPage.tsx index 016cbe91cb72..983795fd3e7c 100644 --- a/src/pages/workspace/categories/CategorySettingsPage.tsx +++ b/src/pages/workspace/categories/CategorySettingsPage.tsx @@ -3,7 +3,7 @@ import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import ConfirmModal from '@components/ConfirmModal'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import * as Expensicons from '@components/Icon/Expensicons'; +import {Trashcan} from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -13,21 +13,25 @@ import Switch from '@components/Switch'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; -import usePermissions from '@hooks/usePermissions'; import usePolicy from '@hooks/usePolicy'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as CategoryUtils from '@libs/CategoryUtils'; -import * as CurrencyUtils from '@libs/CurrencyUtils'; -import * as ErrorUtils from '@libs/ErrorUtils'; +import {formatDefaultTaxRateText, formatRequireReceiptsOverText, getCategoryApproverRule, getCategoryDefaultTaxRate} from '@libs/CategoryUtils'; +import {convertToDisplayString} from '@libs/CurrencyUtils'; +import {getLatestErrorMessageField} from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; -import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; -import {isControlPolicy} from '@libs/PolicyUtils'; -import * as PolicyUtils from '@libs/PolicyUtils'; +import {getPersonalDetailByEmail} from '@libs/PersonalDetailsUtils'; +import {getWorkflowApprovalsUnavailable, isControlPolicy} from '@libs/PolicyUtils'; import type {SettingsNavigatorParamList} from '@navigation/types'; import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; -import * as Category from '@userActions/Policy/Category'; +import { + clearCategoryErrors, + deleteWorkspaceCategories, + setPolicyCategoryDescriptionRequired, + setWorkspaceCategoryDescriptionHint, + setWorkspaceCategoryEnabled, +} from '@userActions/Policy/Category'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -44,7 +48,6 @@ function CategorySettingsPage({ const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`); const styles = useThemeStyles(); const {translate} = useLocalize(); - const {canUseCategoryAndTagApprovers} = usePermissions(); const [deleteCategoryConfirmModalVisible, setDeleteCategoryConfirmModalVisible] = useState(false); const policy = usePolicy(policyID); @@ -71,19 +74,19 @@ function CategorySettingsPage({ return ''; } - return `${CurrencyUtils.convertToDisplayString(policyCategory?.maxExpenseAmount, policyCurrency)} ${CONST.DOT_SEPARATOR} ${translate( + return `${convertToDisplayString(policyCategory?.maxExpenseAmount, policyCurrency)} ${CONST.DOT_SEPARATOR} ${translate( `workspace.rules.categoryRules.expenseLimitTypes.${policyCategoryExpenseLimitType}`, )}`; }, [policyCategory?.maxExpenseAmount, policyCategoryExpenseLimitType, policyCurrency, translate]); const approverText = useMemo(() => { - const categoryApprover = CategoryUtils.getCategoryApproverRule(policy?.rules?.approvalRules ?? [], categoryName)?.approver ?? ''; - const approver = PersonalDetailsUtils.getPersonalDetailByEmail(categoryApprover); + const categoryApprover = getCategoryApproverRule(policy?.rules?.approvalRules ?? [], categoryName)?.approver ?? ''; + const approver = getPersonalDetailByEmail(categoryApprover); return approver?.displayName ?? categoryApprover; }, [categoryName, policy?.rules?.approvalRules]); const defaultTaxRateText = useMemo(() => { - const taxID = CategoryUtils.getCategoryDefaultTaxRate(policy?.rules?.expenseRules ?? [], categoryName, policy?.taxRates?.defaultExternalID); + const taxID = getCategoryDefaultTaxRate(policy?.rules?.expenseRules ?? [], categoryName, policy?.taxRates?.defaultExternalID); if (!taxID) { return ''; @@ -95,14 +98,14 @@ function CategorySettingsPage({ return ''; } - return CategoryUtils.formatDefaultTaxRateText(translate, taxID, taxRate, policy?.taxRates); + return formatDefaultTaxRateText(translate, taxID, taxRate, policy?.taxRates); }, [categoryName, policy?.rules?.expenseRules, policy?.taxRates, translate]); const requireReceiptsOverText = useMemo(() => { if (!policy) { return ''; } - return CategoryUtils.formatRequireReceiptsOverText(translate, policy, policyCategory?.maxAmountNoReceipt); + return formatRequireReceiptsOverText(translate, policy, policyCategory?.maxAmountNoReceipt); }, [policy, policyCategory?.maxAmountNoReceipt, translate]); if (!policyCategory) { @@ -110,7 +113,7 @@ function CategorySettingsPage({ } const updateWorkspaceRequiresCategory = (value: boolean) => { - Category.setWorkspaceCategoryEnabled(policyID, {[policyCategory.name]: {name: policyCategory.name, enabled: value}}); + setWorkspaceCategoryEnabled(policyID, {[policyCategory.name]: {name: policyCategory.name, enabled: value}}); }; const navigateToEditCategory = () => { @@ -120,13 +123,13 @@ function CategorySettingsPage({ }; const deleteCategory = () => { - Category.deleteWorkspaceCategories(policyID, [categoryName]); + deleteWorkspaceCategories(policyID, [categoryName]); setDeleteCategoryConfirmModalVisible(false); navigateBack(); }; const isThereAnyAccountingConnection = Object.keys(policy?.connections ?? {}).length !== 0; - const workflowApprovalsUnavailable = PolicyUtils.getWorkflowApprovalsUnavailable(policy); + const workflowApprovalsUnavailable = getWorkflowApprovalsUnavailable(policy); const approverDisabled = !policy?.areWorkflowsEnabled || workflowApprovalsUnavailable; return ( @@ -158,10 +161,10 @@ function CategorySettingsPage({ /> Category.clearCategoryErrors(policyID, categoryName)} + onClose={() => clearCategoryErrors(policyID, categoryName)} > @@ -247,9 +250,9 @@ function CategorySettingsPage({ accessibilityLabel={translate('workspace.rules.categoryRules.requireDescription')} onToggle={() => { if (policyCategory.commentHint && areCommentsRequired) { - Category.setWorkspaceCategoryDescriptionHint(policyID, categoryName, ''); + setWorkspaceCategoryDescriptionHint(policyID, categoryName, ''); } - Category.setPolicyCategoryDescriptionRequired(policyID, categoryName, !areCommentsRequired); + setPolicyCategoryDescriptionRequired(policyID, categoryName, !areCommentsRequired); }} /> @@ -267,30 +270,26 @@ function CategorySettingsPage({ /> )} - {!!canUseCategoryAndTagApprovers && ( - <> - { - Navigation.navigate(ROUTES.WORSKPACE_CATEGORY_APPROVER.getRoute(policyID, policyCategory.name)); - }} - shouldShowRightIcon - disabled={approverDisabled} - /> - {approverDisabled && ( - - {translate('workspace.rules.categoryRules.goTo')}{' '} - Navigation.navigate(ROUTES.WORKSPACE_MORE_FEATURES.getRoute(policyID))} - > - {translate('workspace.common.moreFeatures')} - {' '} - {translate('workspace.rules.categoryRules.andEnableWorkflows')} - - )} - + { + Navigation.navigate(ROUTES.WORSKPACE_CATEGORY_APPROVER.getRoute(policyID, policyCategory.name)); + }} + shouldShowRightIcon + disabled={approverDisabled} + /> + {approverDisabled && ( + + {translate('workspace.rules.categoryRules.goTo')}{' '} + Navigation.navigate(ROUTES.WORKSPACE_MORE_FEATURES.getRoute(policyID))} + > + {translate('workspace.common.moreFeatures')} + {' '} + {translate('workspace.rules.categoryRules.andEnableWorkflows')} + )} {!!policy?.tax?.trackingEnabled && ( setDeleteCategoryConfirmModalVisible(true)} /> diff --git a/src/pages/workspace/tags/TagSettingsPage.tsx b/src/pages/workspace/tags/TagSettingsPage.tsx index 5160fe915d5c..5615d13985d4 100644 --- a/src/pages/workspace/tags/TagSettingsPage.tsx +++ b/src/pages/workspace/tags/TagSettingsPage.tsx @@ -12,19 +12,25 @@ import Switch from '@components/Switch'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; -import usePermissions from '@hooks/usePermissions'; import usePolicy from '@hooks/usePolicy'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as ErrorUtils from '@libs/ErrorUtils'; +import {getLatestErrorMessageField} from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; -import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; -import * as PolicyUtils from '@libs/PolicyUtils'; +import {getPersonalDetailByEmail} from '@libs/PersonalDetailsUtils'; +import { + getCleanedTagName, + getTagApproverRule, + getTagList, + getWorkflowApprovalsUnavailable, + hasAccountingConnections as hasAccountingConnectionsPolicyUtils, + isControlPolicy, + isMultiLevelTags as isMultiLevelTagsPolicyUtils, +} from '@libs/PolicyUtils'; import type {SettingsNavigatorParamList} from '@navigation/types'; import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; -import {setWorkspaceTagEnabled} from '@userActions/Policy/Tag'; -import * as Tag from '@userActions/Policy/Tag'; +import {clearPolicyTagErrors, deletePolicyTags, setWorkspaceTagEnabled} from '@userActions/Policy/Tag'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -37,14 +43,13 @@ function TagSettingsPage({route, navigation}: TagSettingsPageProps) { const {orderWeight, policyID, tagName, backTo} = route.params; const styles = useThemeStyles(); const {translate} = useLocalize(); - const policyTag = useMemo(() => PolicyUtils.getTagList(policyTags, orderWeight), [policyTags, orderWeight]); + const policyTag = useMemo(() => getTagList(policyTags, orderWeight), [policyTags, orderWeight]); const policy = usePolicy(policyID); - const hasAccountingConnections = PolicyUtils.hasAccountingConnections(policy); - const {canUseCategoryAndTagApprovers} = usePermissions(); + const hasAccountingConnections = hasAccountingConnectionsPolicyUtils(policy); const [isDeleteTagModalOpen, setIsDeleteTagModalOpen] = React.useState(false); const isQuickSettingsFlow = !!backTo; - const tagApprover = PolicyUtils.getTagApproverRule(policyID, route.params?.tagName)?.approver ?? ''; - const approver = PersonalDetailsUtils.getPersonalDetailByEmail(tagApprover); + const tagApprover = getTagApproverRule(policyID, route.params?.tagName)?.approver ?? ''; + const approver = getPersonalDetailByEmail(tagApprover); const approverText = approver?.displayName ?? tagApprover; const currentPolicyTag = policyTag.tags[tagName] ?? Object.values(policyTag.tags ?? {}).find((tag) => tag.previousTagName === tagName); @@ -60,7 +65,7 @@ function TagSettingsPage({route, navigation}: TagSettingsPageProps) { } const deleteTagAndHideModal = () => { - Tag.deletePolicyTags(policyID, [currentPolicyTag.name]); + deletePolicyTags(policyID, [currentPolicyTag.name]); setIsDeleteTagModalOpen(false); Navigation.goBack(isQuickSettingsFlow ? ROUTES.SETTINGS_TAGS_ROOT.getRoute(policyID, backTo) : undefined); }; @@ -78,14 +83,14 @@ function TagSettingsPage({route, navigation}: TagSettingsPageProps) { }; const navigateToEditGlCode = () => { - if (!PolicyUtils.isControlPolicy(policy)) { + if (!isControlPolicy(policy)) { Navigation.navigate( ROUTES.WORKSPACE_UPGRADE.getRoute( policyID, CONST.UPGRADE_FEATURE_INTRO_MAPPING.glCodes.alias, isQuickSettingsFlow - ? ROUTES.SETTINGS_TAG_GL_CODE.getRoute(policy?.id ?? '', orderWeight, tagName, backTo) - : ROUTES.WORKSPACE_TAG_GL_CODE.getRoute(policy?.id ?? '', orderWeight, tagName), + ? ROUTES.SETTINGS_TAG_GL_CODE.getRoute(policy?.id ?? `${CONST.DEFAULT_NUMBER_ID}`, orderWeight, tagName, backTo) + : ROUTES.WORKSPACE_TAG_GL_CODE.getRoute(policy?.id ?? `${CONST.DEFAULT_NUMBER_ID}`, orderWeight, tagName), ), ); return; @@ -106,10 +111,10 @@ function TagSettingsPage({route, navigation}: TagSettingsPageProps) { }; const isThereAnyAccountingConnection = Object.keys(policy?.connections ?? {}).length !== 0; - const isMultiLevelTags = PolicyUtils.isMultiLevelTags(policyTags); + const isMultiLevelTags = isMultiLevelTagsPolicyUtils(policyTags); const shouldShowDeleteMenuItem = !isThereAnyAccountingConnection && !isMultiLevelTags; - const workflowApprovalsUnavailable = PolicyUtils.getWorkflowApprovalsUnavailable(policy); + const workflowApprovalsUnavailable = getWorkflowApprovalsUnavailable(policy); const approverDisabled = !policy?.areWorkflowsEnabled || workflowApprovalsUnavailable; return ( @@ -124,7 +129,7 @@ function TagSettingsPage({route, navigation}: TagSettingsPageProps) { testID={TagSettingsPage.displayName} > Navigation.goBack(isQuickSettingsFlow ? ROUTES.SETTINGS_TAGS_ROOT.getRoute(policyID, backTo) : undefined)} /> @@ -141,10 +146,10 @@ function TagSettingsPage({route, navigation}: TagSettingsPageProps) { /> Tag.clearPolicyTagErrors(policyID, tagName, orderWeight)} + onClose={() => clearPolicyTagErrors(policyID, tagName, orderWeight)} > @@ -159,7 +164,7 @@ function TagSettingsPage({route, navigation}: TagSettingsPageProps) { - {!!policy?.areRulesEnabled && !!canUseCategoryAndTagApprovers && !isMultiLevelTags && ( + {!!policy?.areRulesEnabled && !isMultiLevelTags && ( <> {translate('workspace.tags.tagRules')}