From 53828c7b306c4fa136db7e270ee1890ba248127c Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 28 Aug 2024 14:00:45 +0200 Subject: [PATCH 01/30] Add WorkspaceMembersSelectionList --- .../WorkspaceMembersSelectionList.tsx | 115 ++++++++++++++++++ .../categories/CategoryApproverPage.tsx | 60 +++++++++ 2 files changed, 175 insertions(+) create mode 100644 src/components/WorkspaceMembersSelectionList.tsx create mode 100644 src/pages/workspace/categories/CategoryApproverPage.tsx diff --git a/src/components/WorkspaceMembersSelectionList.tsx b/src/components/WorkspaceMembersSelectionList.tsx new file mode 100644 index 00000000000..f2ce215fc50 --- /dev/null +++ b/src/components/WorkspaceMembersSelectionList.tsx @@ -0,0 +1,115 @@ +import React, {useMemo} from 'react'; +import type {SectionListData} from 'react-native'; +import useDebouncedState from '@hooks/useDebouncedState'; +import useLocalize from '@hooks/useLocalize'; +import usePolicy from '@hooks/usePolicy'; +import useScreenWrapperTranstionStatus from '@hooks/useScreenWrapperTransitionStatus'; +import * as DeviceCapabilities from '@libs/DeviceCapabilities'; +import * as OptionsListUtils from '@libs/OptionsListUtils'; +import * as PolicyUtils from '@libs/PolicyUtils'; +import CONST from '@src/CONST'; +import type {Icon} from '@src/types/onyx/OnyxCommon'; +import Badge from './Badge'; +import {FallbackAvatar} from './Icon/Expensicons'; +import {usePersonalDetails} from './OnyxProvider'; +import SelectionList from './SelectionList'; +import InviteMemberListItem from './SelectionList/InviteMemberListItem'; +import type {Section} from './SelectionList/types'; + +type WorkspaceMembersSelectionListProps = { + policyID: string; + selectedApprover: string; + setApprover: (email: string) => void; +}; + +type SelectionListApprover = { + text: string; + alternateText: string; + keyForList: string; + isSelected: boolean; + login: string; + rightElement?: React.ReactNode; + icons: Icon[]; +}; +type ApproverSection = SectionListData>; + +function WorkspaceMembersSelectionList({policyID, selectedApprover, setApprover}: WorkspaceMembersSelectionListProps) { + const {translate} = useLocalize(); + const {didScreenTransitionEnd} = useScreenWrapperTranstionStatus(); + const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState(''); + const personalDetails = usePersonalDetails(); + const policy = usePolicy(policyID); + + const sections: ApproverSection[] = useMemo(() => { + const approvers: SelectionListApprover[] = []; + + if (policy?.employeeList) { + const availableApprovers = Object.values(policy.employeeList) + .map((employee): SelectionListApprover | null => { + const isAdmin = employee?.role === CONST.REPORT.ROLE.ADMIN; + const email = employee.email; + + if (!email) { + return null; + } + + const policyMemberEmailsToAccountIDs = PolicyUtils.getMemberAccountIDsForWorkspace(policy?.employeeList); + const accountID = Number(policyMemberEmailsToAccountIDs[email] ?? ''); + const {avatar, displayName = email} = personalDetails?.[accountID] ?? {}; + + return { + text: displayName, + alternateText: email, + keyForList: email, + isSelected: selectedApprover === email, + login: email, + icons: [{source: avatar ?? FallbackAvatar, type: CONST.ICON_TYPE_AVATAR, name: displayName, id: accountID}], + rightElement: isAdmin ? : undefined, + }; + }) + .filter((approver): approver is SelectionListApprover => !!approver); + + approvers.push(...availableApprovers); + } + + const filteredApprovers = + debouncedSearchTerm !== '' + ? approvers.filter((option) => { + const searchValue = OptionsListUtils.getSearchValueForPhoneOrEmail(debouncedSearchTerm); + const isPartOfSearchTerm = !!option.text?.toLowerCase().includes(searchValue) || !!option.login?.toLowerCase().includes(searchValue); + return isPartOfSearchTerm; + }) + : approvers; + + return [ + { + title: undefined, + data: OptionsListUtils.sortAlphabetically(filteredApprovers, 'text'), + shouldShow: true, + }, + ]; + }, [debouncedSearchTerm, personalDetails, policy?.employeeList, selectedApprover, translate]); + + const handleOnSelectRow = (approver: SelectionListApprover) => { + setApprover(approver.login); + }; + + const headerMessage = useMemo(() => (searchTerm && !sections[0].data.length ? translate('common.noResultsFound') : ''), [searchTerm, sections, translate]); + + return ( + + ); +} + +export default WorkspaceMembersSelectionList; diff --git a/src/pages/workspace/categories/CategoryApproverPage.tsx b/src/pages/workspace/categories/CategoryApproverPage.tsx new file mode 100644 index 00000000000..ae882ceef14 --- /dev/null +++ b/src/pages/workspace/categories/CategoryApproverPage.tsx @@ -0,0 +1,60 @@ +import type {StackScreenProps} from '@react-navigation/stack'; +import React from 'react'; +import {useOnyx} from 'react-native-onyx'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import WorkspaceMembersSelectionList from '@components/WorkspaceMembersSelectionList'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import type {SettingsNavigatorParamList} from '@navigation/types'; +import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; +import * as Category from '@userActions/Policy/Category'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import type SCREENS from '@src/SCREENS'; + +type EditCategoryPageProps = StackScreenProps; + +function CategoryApproverPage({ + route: { + params: {policyID, categoryName}, + }, +}: EditCategoryPageProps) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`); + + return ( + + + Navigation.goBack(ROUTES.WORKSPACE_CATEGORY_SETTINGS.getRoute(policyID, categoryName))} + /> + { + Category.setPolicyCategoryApprover(policyID, categoryName, email); + Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.goBack(ROUTES.WORKSPACE_CATEGORY_SETTINGS.getRoute(policyID, categoryName))); + }} + /> + + + ); +} + +CategoryApproverPage.displayName = 'CategoryApproverPage'; + +export default CategoryApproverPage; From 374f29870cdc8c0ca00c6218b8ab8e161925cb07 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 28 Aug 2024 21:52:34 +0200 Subject: [PATCH 02/30] add interface for tag edit --- src/languages/en.ts | 2 + src/languages/es.ts | 130 ++---------------- .../categories/CategoryApproverPage.tsx | 110 +++++++-------- src/pages/workspace/tags/TagSettingsPage.tsx | 17 +++ 4 files changed, 82 insertions(+), 177 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index afa501c0b6b..fb496e870e4 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2999,6 +2999,8 @@ export default { importedFromAccountingSoftware: 'The tags below are imported from your', glCode: 'GL code', updateGLCodeFailureMessage: 'An error occurred while updating the GL code, please try again.', + tagRules: 'Tag rules', + approverDescription: 'Approver', }, taxes: { subtitle: 'Add tax names, rates, and set defaults.', diff --git a/src/languages/es.ts b/src/languages/es.ts index 941592276dd..062a57395c4 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1,125 +1,8 @@ -import {Str} from 'expensify-common'; +import { Str } from 'expensify-common'; import CONST from '@src/CONST'; -import type {ConnectionName, PolicyConnectionSyncStage, SageIntacctMappingName} from '@src/types/onyx/Policy'; -import type { - AddressLineParams, - AdminCanceledRequestParams, - AlreadySignedInParams, - ApprovalWorkflowErrorParams, - ApprovedAmountParams, - BeginningOfChatHistoryAdminRoomPartOneParams, - BeginningOfChatHistoryAnnounceRoomPartOneParams, - BeginningOfChatHistoryAnnounceRoomPartTwo, - BeginningOfChatHistoryDomainRoomPartOneParams, - CanceledRequestParams, - ChangeFieldParams, - ChangePolicyParams, - ChangeTypeParams, - CharacterLimitParams, - ConfirmHoldExpenseParams, - ConfirmThatParams, - DateShouldBeAfterParams, - DateShouldBeBeforeParams, - DelegateSubmitParams, - DeleteActionParams, - DeleteConfirmationParams, - DeleteExpenseTranslationParams, - DidSplitAmountMessageParams, - DistanceRateOperationsParams, - EditActionParams, - ElectronicFundsParams, - EnglishTranslation, - EnterMagicCodeParams, - ExportedToIntegrationParams, - FormattedMaxLengthParams, - ForwardedAmountParams, - GoBackMessageParams, - GoToRoomParams, - InstantSummaryParams, - IssueVirtualCardParams, - LocalTimeParams, - LoggedInAsParams, - LogSizeParams, - ManagerApprovedAmountParams, - ManagerApprovedParams, - MarkedReimbursedParams, - MarkReimbursedFromIntegrationParams, - NoLongerHaveAccessParams, - NotAllowedExtensionParams, - NotYouParams, - OOOEventSummaryFullDayParams, - OOOEventSummaryPartialDayParams, - OurEmailProviderParams, - PaidElsewhereWithAmountParams, - PaidWithExpensifyWithAmountParams, - ParentNavigationSummaryParams, - PayerOwesAmountParams, - PayerOwesParams, - PayerPaidAmountParams, - PayerPaidParams, - PayerSettledParams, - PaySomeoneParams, - ReimbursementRateParams, - RemovedTheRequestParams, - RemoveMembersWarningPrompt, - RenamedRoomActionParams, - ReportArchiveReasonsClosedParams, - ReportArchiveReasonsMergedParams, - ReportArchiveReasonsPolicyDeletedParams, - ReportArchiveReasonsRemovedFromPolicyParams, - RequestAmountParams, - RequestCountParams, - RequestedAmountMessageParams, - ResolutionConstraintsParams, - RoomNameReservedErrorParams, - RoomRenamedToParams, - SetTheDistanceParams, - SetTheRequestParams, - SettledAfterAddedBankAccountParams, - SettleExpensifyCardParams, - ShareParams, - SignUpNewFaceCodeParams, - SizeExceededParams, - SplitAmountParams, - StepCounterParams, - StripePaidParams, - TaskCreatedActionParams, - TermsParams, - ThreadRequestReportNameParams, - ThreadSentMoneyReportNameParams, - ToValidateLoginParams, - TransferParams, - UnapprovedParams, - UnshareParams, - UntilTimeParams, - UpdatedTheDistanceParams, - UpdatedTheRequestParams, - UsePlusButtonParams, - UserIsAlreadyMemberParams, - UserSplitParams, - ViolationsAutoReportedRejectedExpenseParams, - ViolationsCashExpenseWithNoReceiptParams, - ViolationsConversionSurchargeParams, - ViolationsInvoiceMarkupParams, - ViolationsMaxAgeParams, - ViolationsMissingTagParams, - ViolationsModifiedAmountParams, - ViolationsOverAutoApprovalLimitParams, - ViolationsOverCategoryLimitParams, - ViolationsOverLimitParams, - ViolationsPerDayLimitParams, - ViolationsReceiptRequiredParams, - ViolationsRterParams, - ViolationsTagOutOfPolicyParams, - ViolationsTaxOutOfPolicyParams, - WaitingOnBankAccountParams, - WalletProgramParams, - WelcomeEnterMagicCodeParams, - WelcomeNoteParams, - WelcomeToRoomParams, - WeSentYouMagicSignInLinkParams, - ZipCodeExampleFormatParams, -} from './types'; +import type { ConnectionName, PolicyConnectionSyncStage, SageIntacctMappingName } from '@src/types/onyx/Policy'; +import type { AddressLineParams, AdminCanceledRequestParams, AlreadySignedInParams, ApprovalWorkflowErrorParams, ApprovedAmountParams, BeginningOfChatHistoryAdminRoomPartOneParams, BeginningOfChatHistoryAnnounceRoomPartOneParams, BeginningOfChatHistoryAnnounceRoomPartTwo, BeginningOfChatHistoryDomainRoomPartOneParams, CanceledRequestParams, ChangeFieldParams, ChangePolicyParams, ChangeTypeParams, CharacterLimitParams, ConfirmHoldExpenseParams, ConfirmThatParams, DateShouldBeAfterParams, DateShouldBeBeforeParams, DelegateSubmitParams, DeleteActionParams, DeleteConfirmationParams, DeleteExpenseTranslationParams, DidSplitAmountMessageParams, DistanceRateOperationsParams, EditActionParams, ElectronicFundsParams, EnglishTranslation, EnterMagicCodeParams, ExportedToIntegrationParams, FormattedMaxLengthParams, ForwardedAmountParams, GoBackMessageParams, GoToRoomParams, InstantSummaryParams, IssueVirtualCardParams, LocalTimeParams, LoggedInAsParams, LogSizeParams, ManagerApprovedAmountParams, ManagerApprovedParams, MarkedReimbursedParams, MarkReimbursedFromIntegrationParams, NoLongerHaveAccessParams, NotAllowedExtensionParams, NotYouParams, OOOEventSummaryFullDayParams, OOOEventSummaryPartialDayParams, OurEmailProviderParams, PaidElsewhereWithAmountParams, PaidWithExpensifyWithAmountParams, ParentNavigationSummaryParams, PayerOwesAmountParams, PayerOwesParams, PayerPaidAmountParams, PayerPaidParams, PayerSettledParams, PaySomeoneParams, ReimbursementRateParams, RemovedTheRequestParams, RemoveMembersWarningPrompt, RenamedRoomActionParams, ReportArchiveReasonsClosedParams, ReportArchiveReasonsMergedParams, ReportArchiveReasonsPolicyDeletedParams, ReportArchiveReasonsRemovedFromPolicyParams, RequestAmountParams, RequestCountParams, RequestedAmountMessageParams, ResolutionConstraintsParams, RoomNameReservedErrorParams, RoomRenamedToParams, SetTheDistanceParams, SetTheRequestParams, SettledAfterAddedBankAccountParams, SettleExpensifyCardParams, ShareParams, SignUpNewFaceCodeParams, SizeExceededParams, SplitAmountParams, StepCounterParams, StripePaidParams, TaskCreatedActionParams, TermsParams, ThreadRequestReportNameParams, ThreadSentMoneyReportNameParams, ToValidateLoginParams, TransferParams, UnapprovedParams, UnshareParams, UntilTimeParams, UpdatedTheDistanceParams, UpdatedTheRequestParams, UsePlusButtonParams, UserIsAlreadyMemberParams, UserSplitParams, ViolationsAutoReportedRejectedExpenseParams, ViolationsCashExpenseWithNoReceiptParams, ViolationsConversionSurchargeParams, ViolationsInvoiceMarkupParams, ViolationsMaxAgeParams, ViolationsMissingTagParams, ViolationsModifiedAmountParams, ViolationsOverAutoApprovalLimitParams, ViolationsOverCategoryLimitParams, ViolationsOverLimitParams, ViolationsPerDayLimitParams, ViolationsReceiptRequiredParams, ViolationsRterParams, ViolationsTagOutOfPolicyParams, ViolationsTaxOutOfPolicyParams, WaitingOnBankAccountParams, WalletProgramParams, WelcomeEnterMagicCodeParams, WelcomeNoteParams, WelcomeToRoomParams, WeSentYouMagicSignInLinkParams, ZipCodeExampleFormatParams } from './types'; + /* eslint-disable max-len */ export default { @@ -3047,6 +2930,8 @@ export default { importedFromAccountingSoftware: 'Etiquetas importadas desde', glCode: 'Código de Libro Mayor', updateGLCodeFailureMessage: 'Se produjo un error al actualizar el código de Libro Mayor. Por favor, inténtelo nuevamente.', + tagRules: 'Tag rules', + approverDescription: 'Approver', }, taxes: { subtitle: 'Añade nombres, tasas y establezca valores por defecto para los impuestos.', @@ -3771,6 +3656,7 @@ export default { pleaseEnterTaskName: 'Por favor, introduce un título', pleaseEnterTaskDestination: 'Por favor, selecciona dónde deseas compartir esta tarea.', }, + task: { task: 'Tarea', title: 'Título', @@ -5010,4 +4896,4 @@ export default { updateRoomDescription: 'establece la descripción de la sala a:', clearRoomDescription: 'la descripción de la habitación ha sido borrada', }, -} satisfies EnglishTranslation; +} satisfies EnglishTranslation; \ No newline at end of file diff --git a/src/pages/workspace/categories/CategoryApproverPage.tsx b/src/pages/workspace/categories/CategoryApproverPage.tsx index ae882ceef14..b02abd7f852 100644 --- a/src/pages/workspace/categories/CategoryApproverPage.tsx +++ b/src/pages/workspace/categories/CategoryApproverPage.tsx @@ -1,60 +1,60 @@ -import type {StackScreenProps} from '@react-navigation/stack'; -import React from 'react'; -import {useOnyx} from 'react-native-onyx'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import ScreenWrapper from '@components/ScreenWrapper'; -import WorkspaceMembersSelectionList from '@components/WorkspaceMembersSelectionList'; -import useLocalize from '@hooks/useLocalize'; -import useThemeStyles from '@hooks/useThemeStyles'; -import Navigation from '@libs/Navigation/Navigation'; -import type {SettingsNavigatorParamList} from '@navigation/types'; -import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; -import * as Category from '@userActions/Policy/Category'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; -import type SCREENS from '@src/SCREENS'; +// import type {StackScreenProps} from '@react-navigation/stack'; +// import React from 'react'; +// import {useOnyx} from 'react-native-onyx'; +// import HeaderWithBackButton from '@components/HeaderWithBackButton'; +// import ScreenWrapper from '@components/ScreenWrapper'; +// import WorkspaceMembersSelectionList from '@components/WorkspaceMembersSelectionList'; +// import useLocalize from '@hooks/useLocalize'; +// import useThemeStyles from '@hooks/useThemeStyles'; +// import Navigation from '@libs/Navigation/Navigation'; +// import type {SettingsNavigatorParamList} from '@navigation/types'; +// import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; +// import * as Category from '@userActions/Policy/Category'; +// import CONST from '@src/CONST'; +// import ONYXKEYS from '@src/ONYXKEYS'; +// import ROUTES from '@src/ROUTES'; +// import type SCREENS from '@src/SCREENS'; -type EditCategoryPageProps = StackScreenProps; +// type EditCategoryPageProps = StackScreenProps; -function CategoryApproverPage({ - route: { - params: {policyID, categoryName}, - }, -}: EditCategoryPageProps) { - const styles = useThemeStyles(); - const {translate} = useLocalize(); - const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`); +// function CategoryApproverPage({ +// route: { +// params: {policyID, categoryName}, +// }, +// }: EditCategoryPageProps) { +// const styles = useThemeStyles(); +// const {translate} = useLocalize(); +// const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`); - return ( - - - Navigation.goBack(ROUTES.WORKSPACE_CATEGORY_SETTINGS.getRoute(policyID, categoryName))} - /> - { - Category.setPolicyCategoryApprover(policyID, categoryName, email); - Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.goBack(ROUTES.WORKSPACE_CATEGORY_SETTINGS.getRoute(policyID, categoryName))); - }} - /> - - - ); -} +// return ( +// +// +// Navigation.goBack(ROUTES.WORKSPACE_CATEGORY_SETTINGS.getRoute(policyID, categoryName))} +// /> +// { +// Category.setPolicyCategoryApprover(policyID, categoryName, email); +// Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.goBack(ROUTES.WORKSPACE_CATEGORY_SETTINGS.getRoute(policyID, categoryName))); +// }} +// /> +// +// +// ); +// } -CategoryApproverPage.displayName = 'CategoryApproverPage'; +// CategoryApproverPage.displayName = 'CategoryApproverPage'; -export default CategoryApproverPage; +// export default CategoryApproverPage; diff --git a/src/pages/workspace/tags/TagSettingsPage.tsx b/src/pages/workspace/tags/TagSettingsPage.tsx index a0f98ef699e..c4dbd85a082 100644 --- a/src/pages/workspace/tags/TagSettingsPage.tsx +++ b/src/pages/workspace/tags/TagSettingsPage.tsx @@ -85,6 +85,10 @@ function TagSettingsPage({route, policyTags, navigation}: TagSettingsPageProps) Navigation.navigate(ROUTES.WORKSPACE_TAG_GL_CODE.getRoute(route.params.policyID, route.params.orderWeight, currentPolicyTag.name)); }; + const navigateToEditTagApprover = () => { + Navigation.navigate(ROUTES.WORKSPACE_TAG_EDIT.getRoute(route.params.policyID, route.params.orderWeight, currentPolicyTag.name)); + }; + const isThereAnyAccountingConnection = Object.keys(policy?.connections ?? {}).length !== 0; const isMultiLevelTags = PolicyUtils.isMultiLevelTags(policyTags); @@ -150,6 +154,19 @@ function TagSettingsPage({route, policyTags, navigation}: TagSettingsPageProps) shouldShowRightIcon /> + + + {translate('workspace.tags.tagRules')} + + + + + {shouldShowDeleteMenuItem && ( Date: Thu, 29 Aug 2024 12:38:52 +0200 Subject: [PATCH 03/30] wire up the tags --- src/ROUTES.ts | 4 ++ src/SCREENS.ts | 1 + .../WorkspaceMembersSelectionList.tsx | 2 +- .../parameters/SetPolicyTagApproverParams.ts | 7 ++ src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 11 ++-- .../ModalStackNavigators/index.tsx | 1 + .../FULL_SCREEN_TO_RHP_MAPPING.ts | 1 + src/libs/Navigation/linkingConfig/config.ts | 7 ++ src/libs/Navigation/types.ts | 5 ++ src/libs/actions/Policy/Tag.ts | 12 ++++ src/pages/workspace/tags/TagApproverPage.tsx | 64 +++++++++++++++++++ src/pages/workspace/tags/TagSettingsPage.tsx | 28 ++++---- src/types/onyx/Policy.ts | 52 +++++++++++++++ 14 files changed, 179 insertions(+), 17 deletions(-) create mode 100644 src/libs/API/parameters/SetPolicyTagApproverParams.ts create mode 100644 src/pages/workspace/tags/TagApproverPage.tsx diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 6f9289e0b28..4fc164d9183 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -786,6 +786,10 @@ const ROUTES = { route: 'settings/workspaces/:policyID/tag/:orderWeight/:tagName', getRoute: (policyID: string, orderWeight: number, tagName: string) => `settings/workspaces/${policyID}/tag/${orderWeight}/${encodeURIComponent(tagName)}` as const, }, + WORKSPACE_TAG_APPROVER: { + route: 'settings/workspaces/:policyID/tag/:orderWeight/:tagName/approver', + getRoute: (policyID: string, orderWeight: number, tagName: string) => `settings/workspaces/${policyID}/tag/${orderWeight}/${tagName}/approver` as const, + }, WORKSPACE_TAG_LIST_VIEW: { route: 'settings/workspaces/:policyID/tag-list/:orderWeight', getRoute: (policyID: string, orderWeight: number) => `settings/workspaces/${policyID}/tag-list/${orderWeight}` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index e8c1f71b9db..d2ec2e6b249 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -408,6 +408,7 @@ const SCREENS = { TAX_CREATE: 'Workspace_Tax_Create', TAG_CREATE: 'Tag_Create', TAG_SETTINGS: 'Tag_Settings', + TAG_APPROVER: 'Tag_Approver', TAG_LIST_VIEW: 'Tag_List_View', TAG_GL_CODE: 'Tag_GL_Code', CURRENCY: 'Workspace_Profile_Currency', diff --git a/src/components/WorkspaceMembersSelectionList.tsx b/src/components/WorkspaceMembersSelectionList.tsx index f2ce215fc50..fb98fe9fb44 100644 --- a/src/components/WorkspaceMembersSelectionList.tsx +++ b/src/components/WorkspaceMembersSelectionList.tsx @@ -84,7 +84,7 @@ function WorkspaceMembersSelectionList({policyID, selectedApprover, setApprover} return [ { title: undefined, - data: OptionsListUtils.sortAlphabetically(filteredApprovers, 'text'), + data: filteredApprovers, shouldShow: true, }, ]; diff --git a/src/libs/API/parameters/SetPolicyTagApproverParams.ts b/src/libs/API/parameters/SetPolicyTagApproverParams.ts new file mode 100644 index 00000000000..fbd086dfebe --- /dev/null +++ b/src/libs/API/parameters/SetPolicyTagApproverParams.ts @@ -0,0 +1,7 @@ +type SetPolicyTagApproverParams = { + policyID: string; + tagName: string; + email: string; +}; + +export default SetPolicyTagApproverParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index fe2e89faa7f..537897514f8 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -289,3 +289,4 @@ export type {default as OpenCardDetailsPageParams} from './OpenCardDetailsPagePa export type {default as EnablePolicyCompanyCardsParams} from './EnablePolicyCompanyCardsParams'; export type {default as ToggleCardContinuousReconciliationParams} from './ToggleCardContinuousReconciliationParams'; export type {default as UpdateExpensifyCardLimitTypeParams} from './UpdateExpensifyCardLimitTypeParams'; +export type {default as SetPolicyTagApproverParams} from './SetPolicyTagApproverParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 5dad9820ea1..f892de8d3e8 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -1,11 +1,12 @@ -import type {ValueOf} from 'type-fest'; +import type { ValueOf } from 'type-fest'; import type CONST from '@src/CONST'; -import type {SageIntacctMappingValue} from '@src/types/onyx/Policy'; -import type {EmptyObject} from '@src/types/utils/EmptyObject'; +import type { SageIntacctMappingValue } from '@src/types/onyx/Policy'; +import type { EmptyObject } from '@src/types/utils/EmptyObject'; import type * as Parameters from './parameters'; import type SignInUserParams from './parameters/SignInUserParams'; import type UpdateBeneficialOwnersForBankAccountParams from './parameters/UpdateBeneficialOwnersForBankAccountParams'; + type ApiRequestType = ValueOf; const WRITE_COMMANDS = { @@ -345,6 +346,7 @@ const WRITE_COMMANDS = { CREATE_EXPENSIFY_CARD: 'CreateExpensifyCard', CREATE_ADMIN_ISSUED_VIRTUAL_CARD: 'CreateAdminIssuedVirtualCard', TOGGLE_CARD_CONTINUOUS_RECONCILIATION: 'ToggleCardContinuousReconciliation', + SET_POLICY_TAG_APPROVER: 'SetPolicyTagApprover', } as const; type WriteCommand = ValueOf; @@ -557,6 +559,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.DECLINE_JOIN_REQUEST]: Parameters.DeclineJoinRequestParams; [WRITE_COMMANDS.SET_POLICY_TAXES_CURRENCY_DEFAULT]: Parameters.SetPolicyCurrencyDefaultParams; [WRITE_COMMANDS.SET_POLICY_CUSTOM_TAX_NAME]: Parameters.SetPolicyCustomTaxNameParams; + [WRITE_COMMANDS.SET_POLICY_TAG_APPROVER]: Parameters.SetPolicyTagApproverParams; [WRITE_COMMANDS.SET_POLICY_TAXES_FOREIGN_CURRENCY_DEFAULT]: Parameters.SetPolicyForeignCurrencyDefaultParams; [WRITE_COMMANDS.CREATE_POLICY_TAX]: Parameters.CreatePolicyTaxParams; [WRITE_COMMANDS.SET_POLICY_TAXES_ENABLED]: Parameters.SetPolicyTaxesEnabledParams; @@ -854,4 +857,4 @@ type CommandOfType = TRequestType extends t ? ReadCommand : SideEffectRequestCommand; -export type {ApiCommand, ApiRequestType, ApiRequestCommandParameters, CommandOfType, WriteCommand, ReadCommand, SideEffectRequestCommand}; +export type {ApiCommand, ApiRequestType, ApiRequestCommandParameters, CommandOfType, WriteCommand, ReadCommand, SideEffectRequestCommand}; \ No newline at end of file diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 9c95edd8be9..3564c6fd677 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -260,6 +260,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/workspace/tags/WorkspaceEditTagsPage').default, [SCREENS.WORKSPACE.TAG_CREATE]: () => require('../../../../pages/workspace/tags/WorkspaceCreateTagPage').default, [SCREENS.WORKSPACE.TAG_EDIT]: () => require('../../../../pages/workspace/tags/EditTagPage').default, + [SCREENS.WORKSPACE.TAG_APPROVER]: () => require('../../../../pages/workspace/tags/TagApproverPage').default, [SCREENS.WORKSPACE.TAG_GL_CODE]: () => require('../../../../pages/workspace/tags/TagGLCodePage').default, [SCREENS.WORKSPACE.TAXES_SETTINGS]: () => require('../../../../pages/workspace/taxes/WorkspaceTaxesSettingsPage').default, [SCREENS.WORKSPACE.TAXES_SETTINGS_CUSTOM_TAX_NAME]: () => require('../../../../pages/workspace/taxes/WorkspaceTaxesSettingsCustomTaxName').default, diff --git a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts index 72ce7d6d105..156db729fb8 100755 --- a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts @@ -133,6 +133,7 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial> = { SCREENS.WORKSPACE.TAG_EDIT, SCREENS.WORKSPACE.TAG_LIST_VIEW, SCREENS.WORKSPACE.TAG_GL_CODE, + SCREENS.WORKSPACE.TAG_APPROVER, ], [SCREENS.WORKSPACE.CATEGORIES]: [ SCREENS.WORKSPACE.CATEGORY_CREATE, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 0db9c5833fd..67b588c4314 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -626,6 +626,13 @@ const config: LinkingOptions['config'] = { tagName: (tagName: string) => decodeURIComponent(tagName), }, }, + [SCREENS.WORKSPACE.TAG_APPROVER]: { + path: ROUTES.WORKSPACE_TAG_APPROVER.route, + parse: { + orderWeight: Number, + tagName: (tagName: string) => decodeURIComponent(tagName), + }, + }, [SCREENS.WORKSPACE.TAG_GL_CODE]: { path: ROUTES.WORKSPACE_TAG_GL_CODE.route, parse: { diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index c856e7d8942..e55875c89b2 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -274,6 +274,11 @@ type SettingsNavigatorParamList = { orderWeight: number; tagName: string; }; + [SCREENS.WORKSPACE.TAG_APPROVER]: { + policyID: string; + orderWeight: number; + tagName: string; + }; [SCREENS.WORKSPACE.TAG_GL_CODE]: { policyID: string; orderWeight: number; diff --git a/src/libs/actions/Policy/Tag.ts b/src/libs/actions/Policy/Tag.ts index 49a285c12bb..f6ab37dd1b9 100644 --- a/src/libs/actions/Policy/Tag.ts +++ b/src/libs/actions/Policy/Tag.ts @@ -6,6 +6,7 @@ import type { OpenPolicyTagsPageParams, RenamePolicyTaglistParams, RenamePolicyTagsParams, + SetPolicyTagApproverParams, SetPolicyTagsEnabled, SetPolicyTagsRequired, UpdatePolicyTagGLCodeParams, @@ -846,6 +847,16 @@ function setPolicyTagGLCode(policyID: string, tagName: string, tagListIndex: num API.write(WRITE_COMMANDS.UPDATE_POLICY_TAG_GL_CODE, parameters, onyxData); } +function setPolicyTagApprover(policyID: string, tag: string, approver: string) { + const parameters: SetPolicyTagApproverParams = { + policyID, + tagName: tag, + email: approver, + }; + + API.write(WRITE_COMMANDS.SET_POLICY_TAG_APPROVER, parameters); +} + export { buildOptimisticPolicyRecentlyUsedTags, setPolicyRequiresTag, @@ -861,6 +872,7 @@ export { renamePolicyTaglist, setWorkspaceTagEnabled, setPolicyTagGLCode, + setPolicyTagApprover, }; export type {NewCustomUnit}; diff --git a/src/pages/workspace/tags/TagApproverPage.tsx b/src/pages/workspace/tags/TagApproverPage.tsx new file mode 100644 index 00000000000..5f2f0a50fdc --- /dev/null +++ b/src/pages/workspace/tags/TagApproverPage.tsx @@ -0,0 +1,64 @@ +import type {StackScreenProps} from '@react-navigation/stack'; +import React from 'react'; +import {useOnyx} from 'react-native-onyx'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import WorkspaceMembersSelectionList from '@components/WorkspaceMembersSelectionList'; +import useLocalize from '@hooks/useLocalize'; +import usePolicy from '@hooks/usePolicy'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import type {SettingsNavigatorParamList} from '@navigation/types'; +import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; +import * as Tag from '@userActions/Policy/Tag'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type SCREENS from '@src/SCREENS'; + +type TagApproverPageProps = StackScreenProps; + +function TagApproverPage({route}: TagApproverPageProps) { + const {policyID, orderWeight, tagName} = route.params; + + const policy = usePolicy(policyID); + const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`); + + const styles = useThemeStyles(); + const {translate} = useLocalize(); + + const policyExpenseRules = policy?.rules?.expenseRules; + // const tagExpenseRule = policyExpenseRules?.find(({applyWhen}) => applyWhen.some(({condition, field, value}) => condition === 'matches' && field === 'tag' && value === tagName)); + + console.log('POLICY EXPENSE RULES ', policyTags); + return ( + + + Navigation.goBack()} + /> + { + Tag.setPolicyTagApprover(policyID, tagName, email); + Navigation.setNavigationActionToMicrotaskQueue(Navigation.goBack); + }} + /> + + + ); +} + +TagApproverPage.displayName = 'TagApproverPage'; + +export default TagApproverPage; diff --git a/src/pages/workspace/tags/TagSettingsPage.tsx b/src/pages/workspace/tags/TagSettingsPage.tsx index c4dbd85a082..103b7e65968 100644 --- a/src/pages/workspace/tags/TagSettingsPage.tsx +++ b/src/pages/workspace/tags/TagSettingsPage.tsx @@ -86,7 +86,7 @@ function TagSettingsPage({route, policyTags, navigation}: TagSettingsPageProps) }; const navigateToEditTagApprover = () => { - Navigation.navigate(ROUTES.WORKSPACE_TAG_EDIT.getRoute(route.params.policyID, route.params.orderWeight, currentPolicyTag.name)); + Navigation.navigate(ROUTES.WORKSPACE_TAG_APPROVER.getRoute(route.params.policyID, route.params.orderWeight, currentPolicyTag.name)); }; const isThereAnyAccountingConnection = Object.keys(policy?.connections ?? {}).length !== 0; @@ -155,17 +155,21 @@ function TagSettingsPage({route, policyTags, navigation}: TagSettingsPageProps) /> - - {translate('workspace.tags.tagRules')} - - - - + {policy?.areRulesEnabled && ( + <> + + {translate('workspace.tags.tagRules')} + + + + + + )} {shouldShowDeleteMenuItem && ( ; }; +/** + * + */ +type ExpenseRule = { + /** Set of conditions under which the expense rule should be applied */ + applyWhen: ApplyRulesWhen[]; + + /** Policy tag approver */ + approver: string; + + /** An id of the rule */ + id: string; +}; + +/** Data informing when a given rule should be applied */ +type ApplyRulesWhen = { + /** The condition for applying the rule to the workspace */ + condition: 'matches'; + + /** The target field to which the rule is applied */ + field: 'category' | 'tag'; + + /** The value of the target field */ + value: string; +}; + +/** Approval rule data model */ +type ApprovalRule = { + /** The approver's email */ + approver: string; + + /** Set of conditions under which the approval rule should be applied */ + applyWhen: ApplyRulesWhen[]; + + /** An id of the rule */ + id: string; +}; + /** Model of policy data */ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback< { @@ -1510,6 +1548,20 @@ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback< /** Collection of tax rates attached to a policy */ taxRates?: TaxRatesWithDefault; + /** A set of rules related to the workpsace */ + rules?: { + /** A set of rules related to the workpsace approvals */ + approvalRules?: ApprovalRule[]; + + /** A set of rules related to the workpsace expenses */ + expenseRules?: ExpenseRule[]; + }; + + /** + * + */ + expenseRules?: ExpenseRule[]; + /** ReportID of the admins room for this workspace */ chatReportIDAdmins?: number; From 4a3bfcc806c3d3f0bf52e5c59e71ad4a0c323bf2 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Fri, 30 Aug 2024 13:20:16 +0200 Subject: [PATCH 04/30] wire up action --- .../parameters/SetPolicyTagApproverParams.ts | 2 +- src/libs/PolicyUtils.ts | 10 +++ src/libs/actions/Policy/Tag.ts | 65 ++++++++++++++++++- src/pages/workspace/tags/TagApproverPage.tsx | 8 +-- src/pages/workspace/tags/TagSettingsPage.tsx | 5 +- src/types/onyx/Policy.ts | 4 +- 6 files changed, 83 insertions(+), 11 deletions(-) diff --git a/src/libs/API/parameters/SetPolicyTagApproverParams.ts b/src/libs/API/parameters/SetPolicyTagApproverParams.ts index fbd086dfebe..0e9b286ba81 100644 --- a/src/libs/API/parameters/SetPolicyTagApproverParams.ts +++ b/src/libs/API/parameters/SetPolicyTagApproverParams.ts @@ -1,7 +1,7 @@ type SetPolicyTagApproverParams = { policyID: string; tagName: string; - email: string; + approver: string; }; export default SetPolicyTagApproverParams; diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 3f3a2a96a1e..b914f3d7816 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -969,6 +969,15 @@ function getWorkspaceAccountID(policyID: string) { return policy.workspaceAccountID ?? 0; } +function getTagExpenseRule(policyID: string, tagName: string) { + const policy = getPolicy(policyID); + + const expenseRules = policy?.rules?.expenseRules ?? []; + const expenseRule = expenseRules.find((rule) => rule.applyWhen.find(({condition, field, value}) => condition === 'matches' && field === 'tag' && value === tagName)); + + return expenseRule; +} + export { canEditTaxRate, extractPolicyIDFromPath, @@ -1074,6 +1083,7 @@ export { getWorkspaceAccountID, getAllTaxRatesNamesAndKeys as getAllTaxRates, getTagNamesFromTagsLists, + getTagExpenseRule, }; export type {MemberEmailsToAccountIDs}; diff --git a/src/libs/actions/Policy/Tag.ts b/src/libs/actions/Policy/Tag.ts index f6ab37dd1b9..d02a42cccd9 100644 --- a/src/libs/actions/Policy/Tag.ts +++ b/src/libs/actions/Policy/Tag.ts @@ -848,13 +848,74 @@ function setPolicyTagGLCode(policyID: string, tagName: string, tagListIndex: num } function setPolicyTagApprover(policyID: string, tag: string, approver: string) { + const policy = PolicyUtils.getPolicy(policyID); + const prevExpenseRules = policy?.rules?.approvalRules ?? []; + const expenseRuleToUpdate = PolicyUtils.getTagExpenseRule(policyID, tag); + const filteredExpenseRules = expenseRuleToUpdate ? prevExpenseRules.filter((rule) => rule.id === expenseRuleToUpdate.id) : prevExpenseRules; + + const updatedExpenseRule = expenseRuleToUpdate + ? {...expenseRuleToUpdate, approver} + : { + applyWhen: [ + { + condition: 'matches', + field: 'tag', + value: tag, + }, + ], + approver, + id: '-1', + }; + + const onyxData: OnyxData = { + optimisticData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: { + rules: { + expenseRules: [...filteredExpenseRules, updatedExpenseRule], + }, + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + pendingFields: {rules: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}, + }, + }, + ], + successData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: { + rules: { + expenseRules: [...filteredExpenseRules, updatedExpenseRule], + }, + pendingAction: null, + pendingFields: {rules: null}, + }, + }, + ], + failureData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: { + rules: { + expenseRules: prevExpenseRules, + }, + pendingAction: null, + pendingFields: {rules: null}, + }, + }, + ], + }; + const parameters: SetPolicyTagApproverParams = { policyID, tagName: tag, - email: approver, + approver, }; - API.write(WRITE_COMMANDS.SET_POLICY_TAG_APPROVER, parameters); + API.write(WRITE_COMMANDS.SET_POLICY_TAG_APPROVER, parameters, onyxData); } export { diff --git a/src/pages/workspace/tags/TagApproverPage.tsx b/src/pages/workspace/tags/TagApproverPage.tsx index 5f2f0a50fdc..ce3fa822e76 100644 --- a/src/pages/workspace/tags/TagApproverPage.tsx +++ b/src/pages/workspace/tags/TagApproverPage.tsx @@ -8,6 +8,7 @@ import useLocalize from '@hooks/useLocalize'; import usePolicy from '@hooks/usePolicy'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; +import * as PolicyUtils from '@libs/PolicyUtils'; import type {SettingsNavigatorParamList} from '@navigation/types'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import * as Tag from '@userActions/Policy/Tag'; @@ -26,10 +27,9 @@ function TagApproverPage({route}: TagApproverPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const policyExpenseRules = policy?.rules?.expenseRules; - // const tagExpenseRule = policyExpenseRules?.find(({applyWhen}) => applyWhen.some(({condition, field, value}) => condition === 'matches' && field === 'tag' && value === tagName)); + const tagApprover = PolicyUtils.getTagExpenseRule(policyID, tagName)?.approver; - console.log('POLICY EXPENSE RULES ', policyTags); + console.log('POLICY ', policy); return ( { Tag.setPolicyTagApprover(policyID, tagName, email); Navigation.setNavigationActionToMicrotaskQueue(Navigation.goBack); diff --git a/src/pages/workspace/tags/TagSettingsPage.tsx b/src/pages/workspace/tags/TagSettingsPage.tsx index 103b7e65968..92166504dd7 100644 --- a/src/pages/workspace/tags/TagSettingsPage.tsx +++ b/src/pages/workspace/tags/TagSettingsPage.tsx @@ -91,6 +91,7 @@ function TagSettingsPage({route, policyTags, navigation}: TagSettingsPageProps) const isThereAnyAccountingConnection = Object.keys(policy?.connections ?? {}).length !== 0; const isMultiLevelTags = PolicyUtils.isMultiLevelTags(policyTags); + const tagApprover = PolicyUtils.getTagExpenseRule(route.params.policyID, currentPolicyTag.name)?.approver; const shouldShowDeleteMenuItem = !isThereAnyAccountingConnection && !isMultiLevelTags; @@ -160,9 +161,9 @@ function TagSettingsPage({route, policyTags, navigation}: TagSettingsPageProps) {translate('workspace.tags.tagRules')} - + Date: Mon, 9 Sep 2024 11:19:14 +0200 Subject: [PATCH 05/30] cleanup, modify action --- src/libs/PolicyUtils.ts | 10 ++-- src/libs/actions/Policy/Tag.ts | 16 ++--- .../categories/CategoryApproverPage.tsx | 60 ------------------- src/pages/workspace/tags/TagApproverPage.tsx | 11 +--- src/pages/workspace/tags/TagSettingsPage.tsx | 2 +- src/types/onyx/Policy.ts | 22 ------- 6 files changed, 16 insertions(+), 105 deletions(-) delete mode 100644 src/pages/workspace/categories/CategoryApproverPage.tsx diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 37e204ef356..688813d4363 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -978,13 +978,13 @@ function getWorkspaceAccountID(policyID: string) { return policy.workspaceAccountID ?? 0; } -function getTagExpenseRule(policyID: string, tagName: string) { +function getTagApproverRule(policyID: string, tagName: string) { const policy = getPolicy(policyID); - const expenseRules = policy?.rules?.expenseRules ?? []; - const expenseRule = expenseRules.find((rule) => rule.applyWhen.find(({condition, field, value}) => condition === 'matches' && field === 'tag' && value === tagName)); + const approvalRules = policy?.rules?.approvalRules ?? []; + const approverRule = approvalRules.find((rule) => rule.applyWhen.find(({condition, field, value}) => condition === 'matches' && field === 'tag' && value === tagName)); - return expenseRule; + return approverRule; } function getDomainNameForPolicy(policyID?: string): string { @@ -1105,7 +1105,7 @@ export { getWorkspaceAccountID, getAllTaxRatesNamesAndKeys as getAllTaxRates, getTagNamesFromTagsLists, - getTagExpenseRule, + getTagApproverRule, getDomainNameForPolicy, getWorkflowApprovalsUnavailable, }; diff --git a/src/libs/actions/Policy/Tag.ts b/src/libs/actions/Policy/Tag.ts index d02a42cccd9..8166d594aaa 100644 --- a/src/libs/actions/Policy/Tag.ts +++ b/src/libs/actions/Policy/Tag.ts @@ -849,12 +849,12 @@ function setPolicyTagGLCode(policyID: string, tagName: string, tagListIndex: num function setPolicyTagApprover(policyID: string, tag: string, approver: string) { const policy = PolicyUtils.getPolicy(policyID); - const prevExpenseRules = policy?.rules?.approvalRules ?? []; - const expenseRuleToUpdate = PolicyUtils.getTagExpenseRule(policyID, tag); - const filteredExpenseRules = expenseRuleToUpdate ? prevExpenseRules.filter((rule) => rule.id === expenseRuleToUpdate.id) : prevExpenseRules; + const prevApprovalRules = policy?.rules?.approvalRules ?? []; + const approverRuleToUpdate = PolicyUtils.getTagApproverRule(policyID, tag); + const filteredApprovalRules = approverRuleToUpdate ? prevApprovalRules.filter((rule) => rule.id !== approverRuleToUpdate.id) : prevApprovalRules; - const updatedExpenseRule = expenseRuleToUpdate - ? {...expenseRuleToUpdate, approver} + const updatedApproverRule = approverRuleToUpdate + ? {...approverRuleToUpdate, approver} : { applyWhen: [ { @@ -874,7 +874,7 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { rules: { - expenseRules: [...filteredExpenseRules, updatedExpenseRule], + approvalRules: [...filteredApprovalRules, updatedApproverRule], }, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, pendingFields: {rules: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}, @@ -887,7 +887,7 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { rules: { - expenseRules: [...filteredExpenseRules, updatedExpenseRule], + approvalRules: [...filteredApprovalRules, updatedApproverRule], }, pendingAction: null, pendingFields: {rules: null}, @@ -900,7 +900,7 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { rules: { - expenseRules: prevExpenseRules, + approvalRules: prevApprovalRules, }, pendingAction: null, pendingFields: {rules: null}, diff --git a/src/pages/workspace/categories/CategoryApproverPage.tsx b/src/pages/workspace/categories/CategoryApproverPage.tsx deleted file mode 100644 index b02abd7f852..00000000000 --- a/src/pages/workspace/categories/CategoryApproverPage.tsx +++ /dev/null @@ -1,60 +0,0 @@ -// import type {StackScreenProps} from '@react-navigation/stack'; -// import React from 'react'; -// import {useOnyx} from 'react-native-onyx'; -// import HeaderWithBackButton from '@components/HeaderWithBackButton'; -// import ScreenWrapper from '@components/ScreenWrapper'; -// import WorkspaceMembersSelectionList from '@components/WorkspaceMembersSelectionList'; -// import useLocalize from '@hooks/useLocalize'; -// import useThemeStyles from '@hooks/useThemeStyles'; -// import Navigation from '@libs/Navigation/Navigation'; -// import type {SettingsNavigatorParamList} from '@navigation/types'; -// import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; -// import * as Category from '@userActions/Policy/Category'; -// import CONST from '@src/CONST'; -// import ONYXKEYS from '@src/ONYXKEYS'; -// import ROUTES from '@src/ROUTES'; -// import type SCREENS from '@src/SCREENS'; - -// type EditCategoryPageProps = StackScreenProps; - -// function CategoryApproverPage({ -// route: { -// params: {policyID, categoryName}, -// }, -// }: EditCategoryPageProps) { -// const styles = useThemeStyles(); -// const {translate} = useLocalize(); -// const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`); - -// return ( -// -// -// Navigation.goBack(ROUTES.WORKSPACE_CATEGORY_SETTINGS.getRoute(policyID, categoryName))} -// /> -// { -// Category.setPolicyCategoryApprover(policyID, categoryName, email); -// Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.goBack(ROUTES.WORKSPACE_CATEGORY_SETTINGS.getRoute(policyID, categoryName))); -// }} -// /> -// -// -// ); -// } - -// CategoryApproverPage.displayName = 'CategoryApproverPage'; - -// export default CategoryApproverPage; diff --git a/src/pages/workspace/tags/TagApproverPage.tsx b/src/pages/workspace/tags/TagApproverPage.tsx index ce3fa822e76..874754b2cf4 100644 --- a/src/pages/workspace/tags/TagApproverPage.tsx +++ b/src/pages/workspace/tags/TagApproverPage.tsx @@ -1,11 +1,9 @@ import type {StackScreenProps} from '@react-navigation/stack'; import React from 'react'; -import {useOnyx} from 'react-native-onyx'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import WorkspaceMembersSelectionList from '@components/WorkspaceMembersSelectionList'; import useLocalize from '@hooks/useLocalize'; -import usePolicy from '@hooks/usePolicy'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; @@ -13,23 +11,18 @@ import type {SettingsNavigatorParamList} from '@navigation/types'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import * as Tag from '@userActions/Policy/Tag'; import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; type TagApproverPageProps = StackScreenProps; function TagApproverPage({route}: TagApproverPageProps) { - const {policyID, orderWeight, tagName} = route.params; - - const policy = usePolicy(policyID); - const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`); + const {policyID, tagName} = route.params; const styles = useThemeStyles(); const {translate} = useLocalize(); - const tagApprover = PolicyUtils.getTagExpenseRule(policyID, tagName)?.approver; + const tagApprover = PolicyUtils.getTagApproverRule(policyID, tagName)?.approver; - console.log('POLICY ', policy); return ( ; }; -/** - * - */ -type ExpenseRule = { - /** Set of conditions under which the expense rule should be applied */ - applyWhen: ApplyRulesWhen[]; - - /** Policy tag approver */ - approver: string; - - /** An id of the rule */ - id: string; -}; - /** Data informing when a given rule should be applied */ type ApplyRulesWhen = { /** The condition for applying the rule to the workspace */ @@ -1585,16 +1571,8 @@ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback< rules?: { /** A set of rules related to the workpsace approvals */ approvalRules?: ApprovalRule[]; - - /** A set of rules related to the workpsace expenses */ - expenseRules?: ExpenseRule[]; }; - /** - * - */ - expenseRules?: ExpenseRule[]; - /** ReportID of the admins room for this workspace */ chatReportIDAdmins?: number; From e9dbc5ce87b30459839b82a65d68d703c64b3a16 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Mon, 9 Sep 2024 11:24:01 +0200 Subject: [PATCH 06/30] change translations --- src/languages/es.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/languages/es.ts b/src/languages/es.ts index cc0fb7bee6d..07ef49748ba 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -3159,8 +3159,8 @@ export default { importedFromAccountingSoftware: 'Etiquetas importadas desde', glCode: 'Código de Libro Mayor', updateGLCodeFailureMessage: 'Se produjo un error al actualizar el código de Libro Mayor. Por favor, inténtelo nuevamente.', - tagRules: 'Tag rules', - approverDescription: 'Approver', + tagRules: 'Reglas de etiquetas', + approverDescription: 'Aprobador', }, taxes: { subtitle: 'Añade nombres, tasas y establezca valores por defecto para los impuestos.', @@ -3899,7 +3899,6 @@ export default { pleaseEnterTaskName: 'Por favor, introduce un título', pleaseEnterTaskDestination: 'Por favor, selecciona dónde deseas compartir esta tarea.', }, - task: { task: 'Tarea', title: 'Título', From 78df9712c9fceb5d5e2e291ee4ce8b4cfba52c04 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Tue, 10 Sep 2024 10:18:47 +0200 Subject: [PATCH 07/30] add remove approver option --- src/libs/API/parameters/SetPolicyTagApproverParams.ts | 2 +- src/libs/actions/Policy/Tag.ts | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/libs/API/parameters/SetPolicyTagApproverParams.ts b/src/libs/API/parameters/SetPolicyTagApproverParams.ts index 0e9b286ba81..48112b323fa 100644 --- a/src/libs/API/parameters/SetPolicyTagApproverParams.ts +++ b/src/libs/API/parameters/SetPolicyTagApproverParams.ts @@ -1,7 +1,7 @@ type SetPolicyTagApproverParams = { policyID: string; tagName: string; - approver: string; + approver: string | null; }; export default SetPolicyTagApproverParams; diff --git a/src/libs/actions/Policy/Tag.ts b/src/libs/actions/Policy/Tag.ts index 8166d594aaa..3e7a1cc998d 100644 --- a/src/libs/actions/Policy/Tag.ts +++ b/src/libs/actions/Policy/Tag.ts @@ -852,6 +852,7 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { const prevApprovalRules = policy?.rules?.approvalRules ?? []; const approverRuleToUpdate = PolicyUtils.getTagApproverRule(policyID, tag); const filteredApprovalRules = approverRuleToUpdate ? prevApprovalRules.filter((rule) => rule.id !== approverRuleToUpdate.id) : prevApprovalRules; + const toBeUnselected = approverRuleToUpdate?.approver === approver; const updatedApproverRule = approverRuleToUpdate ? {...approverRuleToUpdate, approver} @@ -867,6 +868,8 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { id: '-1', }; + const updatedApprovalRules = toBeUnselected ? filteredApprovalRules : [...filteredApprovalRules, updatedApproverRule]; + const onyxData: OnyxData = { optimisticData: [ { @@ -874,7 +877,7 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { rules: { - approvalRules: [...filteredApprovalRules, updatedApproverRule], + approvalRules: updatedApprovalRules, }, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, pendingFields: {rules: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}, @@ -887,7 +890,7 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { rules: { - approvalRules: [...filteredApprovalRules, updatedApproverRule], + approvalRules: updatedApprovalRules, }, pendingAction: null, pendingFields: {rules: null}, @@ -912,7 +915,7 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { const parameters: SetPolicyTagApproverParams = { policyID, tagName: tag, - approver, + approver: toBeUnselected ? null : approver, }; API.write(WRITE_COMMANDS.SET_POLICY_TAG_APPROVER, parameters, onyxData); From 7f792c8a737096fa6e2f461bd631faefd7c1255c Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Tue, 10 Sep 2024 22:46:34 +0200 Subject: [PATCH 08/30] disable when workflows are disabled --- src/pages/workspace/tags/TagSettingsPage.tsx | 49 ++++++++++++-------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/src/pages/workspace/tags/TagSettingsPage.tsx b/src/pages/workspace/tags/TagSettingsPage.tsx index 296e26e170a..97e2456734a 100644 --- a/src/pages/workspace/tags/TagSettingsPage.tsx +++ b/src/pages/workspace/tags/TagSettingsPage.tsx @@ -12,6 +12,7 @@ import OfflineWithFeedback from '@components/OfflineWithFeedback'; import ScreenWrapper from '@components/ScreenWrapper'; import Switch from '@components/Switch'; import Text from '@components/Text'; +import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; import usePolicy from '@hooks/usePolicy'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -37,68 +38,65 @@ type TagSettingsPageOnyxProps = { type TagSettingsPageProps = TagSettingsPageOnyxProps & StackScreenProps; function TagSettingsPage({route, policyTags, navigation}: TagSettingsPageProps) { + const {orderWeight, policyID, tagName} = route.params; const styles = useThemeStyles(); const {translate} = useLocalize(); - const policyTag = useMemo(() => PolicyUtils.getTagList(policyTags, route.params.orderWeight), [policyTags, route.params.orderWeight]); - const policy = usePolicy(route.params.policyID); + const policyTag = useMemo(() => PolicyUtils.getTagList(policyTags, orderWeight), [policyTags, orderWeight]); + const policy = usePolicy(policyID); const [isDeleteTagModalOpen, setIsDeleteTagModalOpen] = React.useState(false); - const currentPolicyTag = policyTag.tags[route.params.tagName] ?? Object.values(policyTag.tags ?? {}).find((tag) => tag.previousTagName === route.params.tagName); + const currentPolicyTag = policyTag.tags[tagName] ?? Object.values(policyTag.tags ?? {}).find((tag) => tag.previousTagName === tagName); useEffect(() => { - if (currentPolicyTag?.name === route.params.tagName || !currentPolicyTag) { + if (currentPolicyTag?.name === tagName || !currentPolicyTag) { return; } navigation.setParams({tagName: currentPolicyTag?.name}); - }, [route.params.tagName, currentPolicyTag, navigation]); + }, [tagName, currentPolicyTag, navigation]); if (!currentPolicyTag) { return ; } const deleteTagAndHideModal = () => { - Tag.deletePolicyTags(route.params.policyID, [currentPolicyTag.name]); + Tag.deletePolicyTags(policyID, [currentPolicyTag.name]); setIsDeleteTagModalOpen(false); Navigation.goBack(); }; const updateWorkspaceTagEnabled = (value: boolean) => { - setWorkspaceTagEnabled(route.params.policyID, {[currentPolicyTag.name]: {name: currentPolicyTag.name, enabled: value}}, policyTag.orderWeight); + setWorkspaceTagEnabled(policyID, {[currentPolicyTag.name]: {name: currentPolicyTag.name, enabled: value}}, policyTag.orderWeight); }; const navigateToEditTag = () => { - Navigation.navigate(ROUTES.WORKSPACE_TAG_EDIT.getRoute(route.params.policyID, route.params.orderWeight, currentPolicyTag.name)); + Navigation.navigate(ROUTES.WORKSPACE_TAG_EDIT.getRoute(policyID, orderWeight, currentPolicyTag.name)); }; const navigateToEditGlCode = () => { if (!PolicyUtils.isControlPolicy(policy)) { Navigation.navigate( - ROUTES.WORKSPACE_UPGRADE.getRoute( - route.params.policyID, - CONST.UPGRADE_FEATURE_INTRO_MAPPING.glCodes.alias, - ROUTES.WORKSPACE_TAG_GL_CODE.getRoute(policy?.id ?? '', route.params.orderWeight, route.params.tagName), - ), + ROUTES.WORKSPACE_UPGRADE.getRoute(policyID, CONST.UPGRADE_FEATURE_INTRO_MAPPING.glCodes.alias, ROUTES.WORKSPACE_TAG_GL_CODE.getRoute(policy?.id ?? '', orderWeight, tagName)), ); return; } - Navigation.navigate(ROUTES.WORKSPACE_TAG_GL_CODE.getRoute(route.params.policyID, route.params.orderWeight, currentPolicyTag.name)); + Navigation.navigate(ROUTES.WORKSPACE_TAG_GL_CODE.getRoute(policyID, orderWeight, currentPolicyTag.name)); }; const navigateToEditTagApprover = () => { - Navigation.navigate(ROUTES.WORKSPACE_TAG_APPROVER.getRoute(route.params.policyID, route.params.orderWeight, currentPolicyTag.name)); + Navigation.navigate(ROUTES.WORKSPACE_TAG_APPROVER.getRoute(policyID, orderWeight, currentPolicyTag.name)); }; const isThereAnyAccountingConnection = Object.keys(policy?.connections ?? {}).length !== 0; const isMultiLevelTags = PolicyUtils.isMultiLevelTags(policyTags); - const tagApprover = PolicyUtils.getTagApproverRule(route.params.policyID, currentPolicyTag.name)?.approver; + const tagApprover = PolicyUtils.getTagApproverRule(policyID, currentPolicyTag.name)?.approver; const shouldShowDeleteMenuItem = !isThereAnyAccountingConnection && !isMultiLevelTags; return ( Tag.clearPolicyTagErrors(route.params.policyID, route.params.tagName, route.params.orderWeight)} + onClose={() => Tag.clearPolicyTagErrors(policyID, tagName, orderWeight)} > @@ -167,8 +165,21 @@ function TagSettingsPage({route, policyTags, navigation}: TagSettingsPageProps) description={translate(`workspace.tags.approverDescription`)} onPress={navigateToEditTagApprover} shouldShowRightIcon + disabled={!policy?.areWorkflowsEnabled} /> + {!policy?.areWorkflowsEnabled && ( + + {translate('workspace.rules.categoryRules.goTo')}{' '} + Navigation.navigate(ROUTES.WORKSPACE_MORE_FEATURES.getRoute(policyID))} + > + {translate('workspace.common.moreFeatures')} + {' '} + {translate('workspace.rules.categoryRules.andEnableWorkflows')} + + )} )} From 6163fe5edcd843349fabad96f27e0d7b71a0c93e Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Tue, 10 Sep 2024 22:49:46 +0200 Subject: [PATCH 09/30] add approver conditon --- src/pages/workspace/tags/TagSettingsPage.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/tags/TagSettingsPage.tsx b/src/pages/workspace/tags/TagSettingsPage.tsx index 97e2456734a..6ff81af80ed 100644 --- a/src/pages/workspace/tags/TagSettingsPage.tsx +++ b/src/pages/workspace/tags/TagSettingsPage.tsx @@ -92,6 +92,8 @@ function TagSettingsPage({route, policyTags, navigation}: TagSettingsPageProps) const tagApprover = PolicyUtils.getTagApproverRule(policyID, currentPolicyTag.name)?.approver; const shouldShowDeleteMenuItem = !isThereAnyAccountingConnection && !isMultiLevelTags; + const workflowApprovalsUnavailable = PolicyUtils.getWorkflowApprovalsUnavailable(policy); + const approverDisabled = !policy?.areWorkflowsEnabled || workflowApprovalsUnavailable; return ( - {!policy?.areWorkflowsEnabled && ( + {approverDisabled && ( {translate('workspace.rules.categoryRules.goTo')}{' '} Date: Tue, 10 Sep 2024 22:55:53 +0200 Subject: [PATCH 10/30] add approver conditon to category settings --- src/pages/workspace/categories/CategorySettingsPage.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/categories/CategorySettingsPage.tsx b/src/pages/workspace/categories/CategorySettingsPage.tsx index 0cac6b8a7bd..7c7ed08b911 100644 --- a/src/pages/workspace/categories/CategorySettingsPage.tsx +++ b/src/pages/workspace/categories/CategorySettingsPage.tsx @@ -22,6 +22,7 @@ import * as CurrencyUtils from '@libs/CurrencyUtils'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import {isControlPolicy} from '@libs/PolicyUtils'; +import * as PolicyUtils from '@libs/PolicyUtils'; import type {SettingsNavigatorParamList} from '@navigation/types'; import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; @@ -133,6 +134,8 @@ function CategorySettingsPage({ }; const isThereAnyAccountingConnection = Object.keys(policy?.connections ?? {}).length !== 0; + const workflowApprovalsUnavailable = PolicyUtils.getWorkflowApprovalsUnavailable(policy); + const approverDisabled = !policy?.areWorkflowsEnabled || workflowApprovalsUnavailable; return ( - {!policy?.areWorkflowsEnabled && ( + {approverDisabled && ( {translate('workspace.rules.categoryRules.goTo')}{' '} Date: Wed, 11 Sep 2024 12:41:11 +0200 Subject: [PATCH 11/30] replace values with const --- src/CONST.ts | 8 +++++- src/libs/PolicyUtils.ts | 4 ++- src/libs/actions/Policy/Category.ts | 4 +-- src/libs/actions/Policy/Policy.ts | 26 +++++++++---------- src/libs/actions/Policy/Tag.ts | 4 +-- .../rules/ExpenseReportRulesSection.tsx | 12 ++++----- .../workspace/rules/RulesCustomNamePage.tsx | 2 +- 7 files changed, 34 insertions(+), 26 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index cf3facb0d1d..95f2b97e297 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -2143,7 +2143,13 @@ const CONST = { // Often referred to as "collect" workspaces TEAM: 'team', }, - FIELD_LIST_TITLE_FIELD_ID: 'text_title', + RULE_CONDITIONS: { + MATCHES: 'matches', + }, + FIELDS: { + TAG: 'tag', + TITLE: 'text_title', + }, DEFAULT_REPORT_NAME_PATTERN: '{report:type} {report:startdate}', ROLE: { ADMIN: 'admin', diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 688813d4363..46914be44f3 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -982,7 +982,9 @@ function getTagApproverRule(policyID: string, tagName: string) { const policy = getPolicy(policyID); const approvalRules = policy?.rules?.approvalRules ?? []; - const approverRule = approvalRules.find((rule) => rule.applyWhen.find(({condition, field, value}) => condition === 'matches' && field === 'tag' && value === tagName)); + const approverRule = approvalRules.find((rule) => + rule.applyWhen.find(({condition, field, value}) => condition === CONST.POLICY.RULE_CONDITIONS.MATCHES && field === CONST.POLICY.FIELDS.TAG && value === tagName), + ); return approverRule; } diff --git a/src/libs/actions/Policy/Category.ts b/src/libs/actions/Policy/Category.ts index 501b7cbbe1e..1d331d84119 100644 --- a/src/libs/actions/Policy/Category.ts +++ b/src/libs/actions/Policy/Category.ts @@ -1158,7 +1158,7 @@ function setPolicyCategoryApprover(policyID: string, categoryName: string, appro approver, applyWhen: [ { - condition: 'matches', + condition: CONST.POLICY.RULE_CONDITIONS.MATCHES, field: 'category', value: categoryName, }, @@ -1241,7 +1241,7 @@ function setPolicyCategoryTax(policyID: string, categoryName: string, taxID: str }, applyWhen: [ { - condition: 'matches', + condition: CONST.POLICY.RULE_CONDITIONS.MATCHES, field: 'category', value: categoryName, }, diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 7bb66d02d79..eca47005857 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -3891,8 +3891,8 @@ function enablePolicyDefaultReportTitle(policyID: string, enabled: boolean) { return; } - const previousReportTitleField = policy?.fieldList?.[CONST.POLICY.FIELD_LIST_TITLE_FIELD_ID] ?? {}; - const titleFieldValues = enabled ? {} : {fieldList: {[CONST.POLICY.FIELD_LIST_TITLE_FIELD_ID]: {...previousReportTitleField, defaultValue: CONST.POLICY.DEFAULT_REPORT_NAME_PATTERN}}}; + const previousReportTitleField = policy?.fieldList?.[CONST.POLICY.FIELDS.TITLE] ?? {}; + const titleFieldValues = enabled ? {} : {fieldList: {[CONST.POLICY.FIELDS.TITLE]: {...previousReportTitleField, defaultValue: CONST.POLICY.DEFAULT_REPORT_NAME_PATTERN}}}; const optimisticData: OnyxUpdate[] = [ { @@ -3928,7 +3928,7 @@ function enablePolicyDefaultReportTitle(policyID: string, enabled: boolean) { value: { shouldShowCustomReportTitleOption: !!policy?.shouldShowCustomReportTitleOption, fieldList: { - [CONST.POLICY.FIELD_LIST_TITLE_FIELD_ID]: previousReportTitleField, + [CONST.POLICY.FIELDS.TITLE]: previousReportTitleField, }, pendingFields: { shouldShowCustomReportTitleOption: null, @@ -3960,11 +3960,11 @@ function enablePolicyDefaultReportTitle(policyID: string, enabled: boolean) { function setPolicyDefaultReportTitle(policyID: string, customName: string) { const policy = getPolicy(policyID); - if (customName === policy?.fieldList?.[CONST.POLICY.FIELD_LIST_TITLE_FIELD_ID]?.defaultValue) { + if (customName === policy?.fieldList?.[CONST.POLICY.FIELDS.TITLE]?.defaultValue) { return; } - const previousReportTitleField = policy?.fieldList?.[CONST.POLICY.FIELD_LIST_TITLE_FIELD_ID] ?? {}; + const previousReportTitleField = policy?.fieldList?.[CONST.POLICY.FIELDS.TITLE] ?? {}; const optimisticData: OnyxUpdate[] = [ { @@ -3972,7 +3972,7 @@ function setPolicyDefaultReportTitle(policyID: string, customName: string) { key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { fieldList: { - [CONST.POLICY.FIELD_LIST_TITLE_FIELD_ID]: { + [CONST.POLICY.FIELDS.TITLE]: { defaultValue: customName, pendingFields: {defaultValue: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}, }, @@ -3987,7 +3987,7 @@ function setPolicyDefaultReportTitle(policyID: string, customName: string) { key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { fieldList: { - [CONST.POLICY.FIELD_LIST_TITLE_FIELD_ID]: {pendingFields: {defaultValue: null}}, + [CONST.POLICY.FIELDS.TITLE]: {pendingFields: {defaultValue: null}}, }, errorFields: null, }, @@ -4000,7 +4000,7 @@ function setPolicyDefaultReportTitle(policyID: string, customName: string) { key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { fieldList: { - [CONST.POLICY.FIELD_LIST_TITLE_FIELD_ID]: {...previousReportTitleField, pendingFields: {defaultValue: null}}, + [CONST.POLICY.FIELDS.TITLE]: {...previousReportTitleField, pendingFields: {defaultValue: null}}, }, errorFields: { fieldList: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage'), @@ -4029,11 +4029,11 @@ function setPolicyDefaultReportTitle(policyID: string, customName: string) { function setPolicyPreventMemberCreatedTitle(policyID: string, enforced: boolean) { const policy = getPolicy(policyID); - if (!enforced === policy?.fieldList?.[CONST.POLICY.FIELD_LIST_TITLE_FIELD_ID].deletable) { + if (!enforced === policy?.fieldList?.[CONST.POLICY.FIELDS.TITLE].deletable) { return; } - const previousReportTitleField = policy?.fieldList?.[CONST.POLICY.FIELD_LIST_TITLE_FIELD_ID] ?? {}; + const previousReportTitleField = policy?.fieldList?.[CONST.POLICY.FIELDS.TITLE] ?? {}; const optimisticData: OnyxUpdate[] = [ { @@ -4041,7 +4041,7 @@ function setPolicyPreventMemberCreatedTitle(policyID: string, enforced: boolean) key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { fieldList: { - [CONST.POLICY.FIELD_LIST_TITLE_FIELD_ID]: {...previousReportTitleField, deletable: !enforced, pendingFields: {deletable: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}}, + [CONST.POLICY.FIELDS.TITLE]: {...previousReportTitleField, deletable: !enforced, pendingFields: {deletable: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}}, }, }, }, @@ -4053,7 +4053,7 @@ function setPolicyPreventMemberCreatedTitle(policyID: string, enforced: boolean) key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { fieldList: { - [CONST.POLICY.FIELD_LIST_TITLE_FIELD_ID]: {pendingFields: {deletable: null}}, + [CONST.POLICY.FIELDS.TITLE]: {pendingFields: {deletable: null}}, }, errorFields: null, }, @@ -4066,7 +4066,7 @@ function setPolicyPreventMemberCreatedTitle(policyID: string, enforced: boolean) key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { fieldList: { - [CONST.POLICY.FIELD_LIST_TITLE_FIELD_ID]: {...previousReportTitleField, pendingFields: {deletable: null}}, + [CONST.POLICY.FIELDS.TITLE]: {...previousReportTitleField, pendingFields: {deletable: null}}, }, errorFields: { fieldList: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage'), diff --git a/src/libs/actions/Policy/Tag.ts b/src/libs/actions/Policy/Tag.ts index 3e7a1cc998d..2853f1b9627 100644 --- a/src/libs/actions/Policy/Tag.ts +++ b/src/libs/actions/Policy/Tag.ts @@ -859,8 +859,8 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { : { applyWhen: [ { - condition: 'matches', - field: 'tag', + condition: CONST.POLICY.RULE_CONDITIONS.MATCHES, + field: CONST.POLICY.FIELDS.TAG, value: tag, }, ], diff --git a/src/pages/workspace/rules/ExpenseReportRulesSection.tsx b/src/pages/workspace/rules/ExpenseReportRulesSection.tsx index 71fdc0a29ee..e18f155b77a 100644 --- a/src/pages/workspace/rules/ExpenseReportRulesSection.tsx +++ b/src/pages/workspace/rules/ExpenseReportRulesSection.tsx @@ -54,15 +54,15 @@ function ExpenseReportRulesSection({policyID}: ExpenseReportRulesSectionProps) { subMenuItems: [ Navigation.navigate(ROUTES.RULES_CUSTOM_NAME.getRoute(policyID))} @@ -70,8 +70,8 @@ function ExpenseReportRulesSection({policyID}: ExpenseReportRulesSectionProps) { , PolicyActions.setPolicyPreventMemberCreatedTitle(policyID, isEnabled)} />, ], diff --git a/src/pages/workspace/rules/RulesCustomNamePage.tsx b/src/pages/workspace/rules/RulesCustomNamePage.tsx index afd8f455fee..42b9cfe9648 100644 --- a/src/pages/workspace/rules/RulesCustomNamePage.tsx +++ b/src/pages/workspace/rules/RulesCustomNamePage.tsx @@ -39,7 +39,7 @@ function RulesCustomNamePage({route}: RulesCustomNamePageProps) { translate('workspace.rules.expenseReportRules.customNameTotalExample'), ] as const satisfies string[]; - const customNameDefaultValue = policy?.fieldList?.[CONST.POLICY.FIELD_LIST_TITLE_FIELD_ID].defaultValue; + const customNameDefaultValue = policy?.fieldList?.[CONST.POLICY.FIELDS_TITLE].defaultValue; const validateCustomName = ({customName}: FormOnyxValues) => { const errors: FormInputErrors = {}; From d7cb9646c5008b4836ecb5fce341d50eb64b7124 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 11 Sep 2024 13:17:42 +0200 Subject: [PATCH 12/30] change conditon for find category approver --- src/CONST.ts | 1 + src/libs/CategoryUtils.ts | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index 95f2b97e297..2e91ec48901 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -2148,6 +2148,7 @@ const CONST = { }, FIELDS: { TAG: 'tag', + CATEGORY: 'category', TITLE: 'text_title', }, DEFAULT_REPORT_NAME_PATTERN: '{report:type} {report:startdate}', diff --git a/src/libs/CategoryUtils.ts b/src/libs/CategoryUtils.ts index 7f971f37d3f..6ca4d0ae39b 100644 --- a/src/libs/CategoryUtils.ts +++ b/src/libs/CategoryUtils.ts @@ -45,7 +45,10 @@ function formatRequireReceiptsOverText(translate: LocaleContextProps['translate' } function getCategoryApprover(approvalRules: ApprovalRule[], categoryName: string) { - return approvalRules?.find((rule) => rule.applyWhen.some((when) => when.value === categoryName))?.approver; + const approverRule = approvalRules?.find((rule) => + rule.applyWhen.find(({condition, field, value}) => condition === CONST.POLICY.RULE_CONDITIONS.MATCHES && field === CONST.POLICY.FIELDS.CATEGORY && value === categoryName), + ); + return approverRule?.approver; } function getCategoryDefaultTaxRate(expenseRules: ExpenseRule[], categoryName: string, defaultTaxRate?: string) { From 5c0b778b0e755fe1b2010580dc3bce94aa9ba092 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 11 Sep 2024 13:24:54 +0200 Subject: [PATCH 13/30] ts fix --- src/pages/workspace/rules/RulesCustomNamePage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/rules/RulesCustomNamePage.tsx b/src/pages/workspace/rules/RulesCustomNamePage.tsx index 42b9cfe9648..738ac2e0cf3 100644 --- a/src/pages/workspace/rules/RulesCustomNamePage.tsx +++ b/src/pages/workspace/rules/RulesCustomNamePage.tsx @@ -39,7 +39,7 @@ function RulesCustomNamePage({route}: RulesCustomNamePageProps) { translate('workspace.rules.expenseReportRules.customNameTotalExample'), ] as const satisfies string[]; - const customNameDefaultValue = policy?.fieldList?.[CONST.POLICY.FIELDS_TITLE].defaultValue; + const customNameDefaultValue = policy?.fieldList?.[CONST.POLICY.FIELDS.TITLE].defaultValue; const validateCustomName = ({customName}: FormOnyxValues) => { const errors: FormInputErrors = {}; From 804c601bb8f39e282ecf17bf27dd5a5d3212e537 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Thu, 12 Sep 2024 11:47:37 +0200 Subject: [PATCH 14/30] use getCategoryApproverRule in the actions --- src/libs/CategoryUtils.ts | 6 +++--- src/libs/actions/Policy/Category.ts | 4 +++- src/pages/workspace/categories/CategoryApproverPage.tsx | 2 +- src/pages/workspace/categories/CategorySettingsPage.tsx | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/libs/CategoryUtils.ts b/src/libs/CategoryUtils.ts index 6ca4d0ae39b..7b2f71dbd10 100644 --- a/src/libs/CategoryUtils.ts +++ b/src/libs/CategoryUtils.ts @@ -44,11 +44,11 @@ function formatRequireReceiptsOverText(translate: LocaleContextProps['translate' ); } -function getCategoryApprover(approvalRules: ApprovalRule[], categoryName: string) { +function getCategoryApproverRule(approvalRules: ApprovalRule[], categoryName: string) { const approverRule = approvalRules?.find((rule) => rule.applyWhen.find(({condition, field, value}) => condition === CONST.POLICY.RULE_CONDITIONS.MATCHES && field === CONST.POLICY.FIELDS.CATEGORY && value === categoryName), ); - return approverRule?.approver; + return approverRule; } function getCategoryDefaultTaxRate(expenseRules: ExpenseRule[], categoryName: string, defaultTaxRate?: string) { @@ -62,4 +62,4 @@ function getCategoryDefaultTaxRate(expenseRules: ExpenseRule[], categoryName: st return categoryDefaultTaxRate; } -export {formatDefaultTaxRateText, formatRequireReceiptsOverText, getCategoryApprover, getCategoryDefaultTaxRate}; +export {formatDefaultTaxRateText, formatRequireReceiptsOverText, getCategoryApproverRule, getCategoryDefaultTaxRate}; diff --git a/src/libs/actions/Policy/Category.ts b/src/libs/actions/Policy/Category.ts index 1d331d84119..ec9457e3607 100644 --- a/src/libs/actions/Policy/Category.ts +++ b/src/libs/actions/Policy/Category.ts @@ -18,6 +18,7 @@ import type { } from '@libs/API/parameters'; import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; import * as ApiUtils from '@libs/ApiUtils'; +import * as CategoryUtils from '@libs/CategoryUtils'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import * as ErrorUtils from '@libs/ErrorUtils'; import fileDownload from '@libs/fileDownload'; @@ -1150,7 +1151,8 @@ function setPolicyCategoryApprover(policyID: string, categoryName: string, appro const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]; const approvalRules = policy?.rules?.approvalRules ?? []; let updatedApprovalRules: ApprovalRule[] = lodashCloneDeep(approvalRules); - const existingCategoryApproverRule = updatedApprovalRules.find((rule) => rule.applyWhen.some((when) => when.value === categoryName)); + const existingCategoryApproverRule = CategoryUtils.getCategoryApproverRule(updatedApprovalRules, categoryName); + let newApprover = approver; if (!existingCategoryApproverRule) { diff --git a/src/pages/workspace/categories/CategoryApproverPage.tsx b/src/pages/workspace/categories/CategoryApproverPage.tsx index 390a577d9cf..649681db615 100644 --- a/src/pages/workspace/categories/CategoryApproverPage.tsx +++ b/src/pages/workspace/categories/CategoryApproverPage.tsx @@ -26,7 +26,7 @@ function CategoryApproverPage({ const {translate} = useLocalize(); const policy = usePolicy(policyID); - const selectedApprover = CategoryUtils.getCategoryApprover(policy?.rules?.approvalRules ?? [], categoryName) ?? ''; + const selectedApprover = CategoryUtils.getCategoryApproverRule(policy?.rules?.approvalRules ?? [], categoryName)?.approver ?? ''; return ( { - const categoryApprover = CategoryUtils.getCategoryApprover(policy?.rules?.approvalRules ?? [], categoryName); + const categoryApprover = CategoryUtils.getCategoryApproverRule(policy?.rules?.approvalRules ?? [], categoryName)?.approver; return categoryApprover ?? ''; }, [categoryName, policy?.rules?.approvalRules]); From c43913b251cf7fd98212184235c08cdbbae1dfa8 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Thu, 12 Sep 2024 12:14:57 +0200 Subject: [PATCH 15/30] change offline pattern for tags --- src/libs/actions/Policy/Category.ts | 36 +++++++++++-------- src/libs/actions/Policy/Tag.ts | 21 +++++++---- .../categories/CategorySettingsPage.tsx | 4 +-- src/pages/workspace/tags/TagSettingsPage.tsx | 2 +- src/types/onyx/Policy.ts | 19 ++++++++-- 5 files changed, 57 insertions(+), 25 deletions(-) diff --git a/src/libs/actions/Policy/Category.ts b/src/libs/actions/Policy/Category.ts index ec9457e3607..1b571e4d6bd 100644 --- a/src/libs/actions/Policy/Category.ts +++ b/src/libs/actions/Policy/Category.ts @@ -1182,8 +1182,10 @@ function setPolicyCategoryApprover(policyID: string, categoryName: string, appro value: { rules: { approvalRules: updatedApprovalRules, - pendingFields: { - approvalRules: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, + pendingRulesUpdates: { + [categoryName]: { + approvalRule: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, }, }, @@ -1194,9 +1196,9 @@ function setPolicyCategoryApprover(policyID: string, categoryName: string, appro onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { - rules: { - pendingFields: { - approvalRules: null, + pendingRulesUpdates: { + [categoryName]: { + approvalRule: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, }, }, @@ -1209,8 +1211,10 @@ function setPolicyCategoryApprover(policyID: string, categoryName: string, appro value: { rules: { approvalRules, - pendingFields: { - approvalRules: null, + }, + pendingRulesUpdates: { + [categoryName]: { + approvalRule: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, }, }, @@ -1262,8 +1266,10 @@ function setPolicyCategoryTax(policyID: string, categoryName: string, taxID: str value: { rules: { expenseRules: updatedExpenseRules, - pendingFields: { - expenseRules: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, + pendingRulesUpdates: { + [categoryName]: { + expenseRule: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, }, }, @@ -1274,9 +1280,9 @@ function setPolicyCategoryTax(policyID: string, categoryName: string, taxID: str onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { - rules: { - pendingFields: { - expenseRules: null, + pendingRulesUpdates: { + [categoryName]: { + expenseRule: null, }, }, }, @@ -1289,8 +1295,10 @@ function setPolicyCategoryTax(policyID: string, categoryName: string, taxID: str value: { rules: { expenseRules, - pendingFields: { - expenseRules: null, + }, + pendingRulesUpdates: { + [categoryName]: { + expenseRule: null, }, }, }, diff --git a/src/libs/actions/Policy/Tag.ts b/src/libs/actions/Policy/Tag.ts index 2853f1b9627..d126cf9e58e 100644 --- a/src/libs/actions/Policy/Tag.ts +++ b/src/libs/actions/Policy/Tag.ts @@ -879,8 +879,11 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { rules: { approvalRules: updatedApprovalRules, }, - pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, - pendingFields: {rules: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}, + pendingRulesUpdates: { + [tag]: { + approvalRule: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, + }, }, }, ], @@ -892,8 +895,11 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { rules: { approvalRules: updatedApprovalRules, }, - pendingAction: null, - pendingFields: {rules: null}, + pendingRulesUpdates: { + [tag]: { + approvalRule: null, + }, + }, }, }, ], @@ -905,8 +911,11 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { rules: { approvalRules: prevApprovalRules, }, - pendingAction: null, - pendingFields: {rules: null}, + pendingRulesUpdates: { + [tag]: { + approvalRule: null, + }, + }, }, }, ], diff --git a/src/pages/workspace/categories/CategorySettingsPage.tsx b/src/pages/workspace/categories/CategorySettingsPage.tsx index 180941329a8..cd8a462f7bb 100644 --- a/src/pages/workspace/categories/CategorySettingsPage.tsx +++ b/src/pages/workspace/categories/CategorySettingsPage.tsx @@ -260,7 +260,7 @@ function CategorySettingsPage({ /> )} - + )} {policy?.tax?.trackingEnabled && ( - + {translate('workspace.tags.tagRules')} - + ; + }; /** ReportID of the admins room for this workspace */ chatReportIDAdmins?: number; @@ -1683,6 +1686,18 @@ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback< /** Workspace account ID configured for Expensify Card */ workspaceAccountID?: number; + + /** Information about rules being updated */ + pendingRulesUpdates: Record< + CategoryOrTagName, + { + /** Indicates whether the approval rule is updated for the given category or tag */ + approvalRule: OnyxCommon.PendingAction; + + /** Indicates whether the expense rule is updated for the given category or tag */ + expenseRule: OnyxCommon.PendingAction; + } + >; } & Partial, 'addWorkspaceRoom' | keyof ACHAccount | keyof Attributes >; From 477079229b38bab88ba19090d11128c803d5c873 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Thu, 12 Sep 2024 12:23:31 +0200 Subject: [PATCH 16/30] ts fix --- src/types/onyx/Policy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 41a8b0cb8b0..006a4a42cf0 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -1688,7 +1688,7 @@ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback< workspaceAccountID?: number; /** Information about rules being updated */ - pendingRulesUpdates: Record< + pendingRulesUpdates?: Record< CategoryOrTagName, { /** Indicates whether the approval rule is updated for the given category or tag */ From e0e1d5bff44f677d7f9fae8af8c3bb6646da3552 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Thu, 12 Sep 2024 17:02:18 +0200 Subject: [PATCH 17/30] make pending keys unique --- src/CONST.ts | 1 + src/libs/PolicyUtils.ts | 7 +++++++ src/libs/actions/Policy/Category.ts | 19 +++++++++++-------- src/libs/actions/Policy/Tag.ts | 7 ++++--- .../categories/CategorySettingsPage.tsx | 8 ++++++-- src/pages/workspace/tags/TagSettingsPage.tsx | 2 +- 6 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 2e91ec48901..5a6a7ba3056 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -2150,6 +2150,7 @@ const CONST = { TAG: 'tag', CATEGORY: 'category', TITLE: 'text_title', + TAX: 'tax', }, DEFAULT_REPORT_NAME_PATTERN: '{report:type} {report:startdate}', ROLE: { diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 46914be44f3..9c322a62b78 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -989,6 +989,12 @@ function getTagApproverRule(policyID: string, tagName: string) { return approverRule; } +type PolicyFieldUpdateKeyField = ValueOf; + +function getPolicyFieldUpdateKey(fieldValue: string, fieldName: PolicyFieldUpdateKeyField) { + return `${fieldName}_${fieldValue}`; +} + function getDomainNameForPolicy(policyID?: string): string { if (!policyID) { return ''; @@ -1110,6 +1116,7 @@ export { getTagApproverRule, getDomainNameForPolicy, getWorkflowApprovalsUnavailable, + getPolicyFieldUpdateKey, }; export type {MemberEmailsToAccountIDs}; diff --git a/src/libs/actions/Policy/Category.ts b/src/libs/actions/Policy/Category.ts index 1b571e4d6bd..f34cdf5b57d 100644 --- a/src/libs/actions/Policy/Category.ts +++ b/src/libs/actions/Policy/Category.ts @@ -28,6 +28,7 @@ import Log from '@libs/Log'; import enhanceParameters from '@libs/Network/enhanceParameters'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import {navigateWhenEnableFeature, removePendingFieldsFromCustomUnit} from '@libs/PolicyUtils'; +import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -1152,6 +1153,7 @@ function setPolicyCategoryApprover(policyID: string, categoryName: string, appro const approvalRules = policy?.rules?.approvalRules ?? []; let updatedApprovalRules: ApprovalRule[] = lodashCloneDeep(approvalRules); const existingCategoryApproverRule = CategoryUtils.getCategoryApproverRule(updatedApprovalRules, categoryName); + const categoryRuleUpdateKey = PolicyUtils.getPolicyFieldUpdateKey(categoryName, CONST.POLICY.FIELDS.CATEGORY); let newApprover = approver; @@ -1184,7 +1186,7 @@ function setPolicyCategoryApprover(policyID: string, categoryName: string, appro approvalRules: updatedApprovalRules, }, pendingRulesUpdates: { - [categoryName]: { + [categoryRuleUpdateKey]: { approvalRule: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, }, @@ -1197,8 +1199,8 @@ function setPolicyCategoryApprover(policyID: string, categoryName: string, appro key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { pendingRulesUpdates: { - [categoryName]: { - approvalRule: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + [categoryRuleUpdateKey]: { + approvalRule: null, }, }, }, @@ -1213,8 +1215,8 @@ function setPolicyCategoryApprover(policyID: string, categoryName: string, appro approvalRules, }, pendingRulesUpdates: { - [categoryName]: { - approvalRule: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + [categoryRuleUpdateKey]: { + approvalRule: null, }, }, }, @@ -1236,6 +1238,7 @@ function setPolicyCategoryTax(policyID: string, categoryName: string, taxID: str const expenseRules = policy?.rules?.expenseRules ?? []; const updatedExpenseRules: ExpenseRule[] = lodashCloneDeep(expenseRules); const existingCategoryExpenseRule = updatedExpenseRules.find((rule) => rule.applyWhen.some((when) => when.value === categoryName)); + const categoryRuleUpdateKey = PolicyUtils.getPolicyFieldUpdateKey(categoryName, CONST.POLICY.FIELDS.TAX); if (!existingCategoryExpenseRule) { updatedExpenseRules.push({ @@ -1268,7 +1271,7 @@ function setPolicyCategoryTax(policyID: string, categoryName: string, taxID: str expenseRules: updatedExpenseRules, }, pendingRulesUpdates: { - [categoryName]: { + [categoryRuleUpdateKey]: { expenseRule: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, }, @@ -1281,7 +1284,7 @@ function setPolicyCategoryTax(policyID: string, categoryName: string, taxID: str key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { pendingRulesUpdates: { - [categoryName]: { + [categoryRuleUpdateKey]: { expenseRule: null, }, }, @@ -1297,7 +1300,7 @@ function setPolicyCategoryTax(policyID: string, categoryName: string, taxID: str expenseRules, }, pendingRulesUpdates: { - [categoryName]: { + [categoryRuleUpdateKey]: { expenseRule: null, }, }, diff --git a/src/libs/actions/Policy/Tag.ts b/src/libs/actions/Policy/Tag.ts index d126cf9e58e..f6ed865d169 100644 --- a/src/libs/actions/Policy/Tag.ts +++ b/src/libs/actions/Policy/Tag.ts @@ -853,6 +853,7 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { const approverRuleToUpdate = PolicyUtils.getTagApproverRule(policyID, tag); const filteredApprovalRules = approverRuleToUpdate ? prevApprovalRules.filter((rule) => rule.id !== approverRuleToUpdate.id) : prevApprovalRules; const toBeUnselected = approverRuleToUpdate?.approver === approver; + const tagRuleUpdateKey = PolicyUtils.getPolicyFieldUpdateKey(tag, CONST.POLICY.FIELDS.TAG); const updatedApproverRule = approverRuleToUpdate ? {...approverRuleToUpdate, approver} @@ -880,7 +881,7 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { approvalRules: updatedApprovalRules, }, pendingRulesUpdates: { - [tag]: { + [tagRuleUpdateKey]: { approvalRule: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, }, @@ -896,7 +897,7 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { approvalRules: updatedApprovalRules, }, pendingRulesUpdates: { - [tag]: { + [tagRuleUpdateKey]: { approvalRule: null, }, }, @@ -912,7 +913,7 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { approvalRules: prevApprovalRules, }, pendingRulesUpdates: { - [tag]: { + [tagRuleUpdateKey]: { approvalRule: null, }, }, diff --git a/src/pages/workspace/categories/CategorySettingsPage.tsx b/src/pages/workspace/categories/CategorySettingsPage.tsx index cd8a462f7bb..6e939dc1835 100644 --- a/src/pages/workspace/categories/CategorySettingsPage.tsx +++ b/src/pages/workspace/categories/CategorySettingsPage.tsx @@ -260,7 +260,9 @@ function CategorySettingsPage({ /> )} - + )} {policy?.tax?.trackingEnabled && ( - + {translate('workspace.tags.tagRules')} - + Date: Fri, 13 Sep 2024 12:55:59 +0200 Subject: [PATCH 18/30] review fixes --- src/CONST.ts | 2 +- src/libs/PolicyUtils.ts | 7 +++-- src/libs/actions/Policy/Category.ts | 4 +-- src/libs/actions/Policy/Policy.ts | 26 +++++++++---------- src/libs/actions/Policy/Tag.ts | 2 +- .../categories/CategorySettingsPage.tsx | 4 +-- .../rules/ExpenseReportRulesSection.tsx | 12 ++++----- .../workspace/rules/RulesCustomNamePage.tsx | 2 +- src/pages/workspace/tags/TagSettingsPage.tsx | 2 +- 9 files changed, 32 insertions(+), 29 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 5a6a7ba3056..91b9b7579c9 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -2149,7 +2149,7 @@ const CONST = { FIELDS: { TAG: 'tag', CATEGORY: 'category', - TITLE: 'text_title', + FIELD_LIST_TITLE: 'text_title', TAX: 'tax', }, DEFAULT_REPORT_NAME_PATTERN: '{report:type} {report:startdate}', diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 9c322a62b78..4b18fd8a593 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -991,7 +991,10 @@ function getTagApproverRule(policyID: string, tagName: string) { type PolicyFieldUpdateKeyField = ValueOf; -function getPolicyFieldUpdateKey(fieldValue: string, fieldName: PolicyFieldUpdateKeyField) { +/** + * Get a key for a pending rule field update - we want to differentiate specific field updates to gray out only desired sections + */ +function getKeyForPendingRuleUpdate(fieldValue: string, fieldName: PolicyFieldUpdateKeyField) { return `${fieldName}_${fieldValue}`; } @@ -1116,7 +1119,7 @@ export { getTagApproverRule, getDomainNameForPolicy, getWorkflowApprovalsUnavailable, - getPolicyFieldUpdateKey, + getKeyForPendingRuleUpdate, }; export type {MemberEmailsToAccountIDs}; diff --git a/src/libs/actions/Policy/Category.ts b/src/libs/actions/Policy/Category.ts index f34cdf5b57d..695a2c9b9f8 100644 --- a/src/libs/actions/Policy/Category.ts +++ b/src/libs/actions/Policy/Category.ts @@ -1153,7 +1153,7 @@ function setPolicyCategoryApprover(policyID: string, categoryName: string, appro const approvalRules = policy?.rules?.approvalRules ?? []; let updatedApprovalRules: ApprovalRule[] = lodashCloneDeep(approvalRules); const existingCategoryApproverRule = CategoryUtils.getCategoryApproverRule(updatedApprovalRules, categoryName); - const categoryRuleUpdateKey = PolicyUtils.getPolicyFieldUpdateKey(categoryName, CONST.POLICY.FIELDS.CATEGORY); + const categoryRuleUpdateKey = PolicyUtils.getKeyForPendingRuleUpdate(categoryName, CONST.POLICY.FIELDS.CATEGORY); let newApprover = approver; @@ -1238,7 +1238,7 @@ function setPolicyCategoryTax(policyID: string, categoryName: string, taxID: str const expenseRules = policy?.rules?.expenseRules ?? []; const updatedExpenseRules: ExpenseRule[] = lodashCloneDeep(expenseRules); const existingCategoryExpenseRule = updatedExpenseRules.find((rule) => rule.applyWhen.some((when) => when.value === categoryName)); - const categoryRuleUpdateKey = PolicyUtils.getPolicyFieldUpdateKey(categoryName, CONST.POLICY.FIELDS.TAX); + const categoryRuleUpdateKey = PolicyUtils.getKeyForPendingRuleUpdate(categoryName, CONST.POLICY.FIELDS.TAX); if (!existingCategoryExpenseRule) { updatedExpenseRules.push({ diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index eca47005857..f99d37b4394 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -3891,8 +3891,8 @@ function enablePolicyDefaultReportTitle(policyID: string, enabled: boolean) { return; } - const previousReportTitleField = policy?.fieldList?.[CONST.POLICY.FIELDS.TITLE] ?? {}; - const titleFieldValues = enabled ? {} : {fieldList: {[CONST.POLICY.FIELDS.TITLE]: {...previousReportTitleField, defaultValue: CONST.POLICY.DEFAULT_REPORT_NAME_PATTERN}}}; + const previousReportTitleField = policy?.fieldList?.[CONST.POLICY.FIELDS.FIELD_LIST_TITLE] ?? {}; + const titleFieldValues = enabled ? {} : {fieldList: {[CONST.POLICY.FIELDS.FIELD_LIST_TITLE]: {...previousReportTitleField, defaultValue: CONST.POLICY.DEFAULT_REPORT_NAME_PATTERN}}}; const optimisticData: OnyxUpdate[] = [ { @@ -3928,7 +3928,7 @@ function enablePolicyDefaultReportTitle(policyID: string, enabled: boolean) { value: { shouldShowCustomReportTitleOption: !!policy?.shouldShowCustomReportTitleOption, fieldList: { - [CONST.POLICY.FIELDS.TITLE]: previousReportTitleField, + [CONST.POLICY.FIELDS.FIELD_LIST_TITLE]: previousReportTitleField, }, pendingFields: { shouldShowCustomReportTitleOption: null, @@ -3960,11 +3960,11 @@ function enablePolicyDefaultReportTitle(policyID: string, enabled: boolean) { function setPolicyDefaultReportTitle(policyID: string, customName: string) { const policy = getPolicy(policyID); - if (customName === policy?.fieldList?.[CONST.POLICY.FIELDS.TITLE]?.defaultValue) { + if (customName === policy?.fieldList?.[CONST.POLICY.FIELDS.FIELD_LIST_TITLE]?.defaultValue) { return; } - const previousReportTitleField = policy?.fieldList?.[CONST.POLICY.FIELDS.TITLE] ?? {}; + const previousReportTitleField = policy?.fieldList?.[CONST.POLICY.FIELDS.FIELD_LIST_TITLE] ?? {}; const optimisticData: OnyxUpdate[] = [ { @@ -3972,7 +3972,7 @@ function setPolicyDefaultReportTitle(policyID: string, customName: string) { key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { fieldList: { - [CONST.POLICY.FIELDS.TITLE]: { + [CONST.POLICY.FIELDS.FIELD_LIST_TITLE]: { defaultValue: customName, pendingFields: {defaultValue: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}, }, @@ -3987,7 +3987,7 @@ function setPolicyDefaultReportTitle(policyID: string, customName: string) { key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { fieldList: { - [CONST.POLICY.FIELDS.TITLE]: {pendingFields: {defaultValue: null}}, + [CONST.POLICY.FIELDS.FIELD_LIST_TITLE]: {pendingFields: {defaultValue: null}}, }, errorFields: null, }, @@ -4000,7 +4000,7 @@ function setPolicyDefaultReportTitle(policyID: string, customName: string) { key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { fieldList: { - [CONST.POLICY.FIELDS.TITLE]: {...previousReportTitleField, pendingFields: {defaultValue: null}}, + [CONST.POLICY.FIELDS.FIELD_LIST_TITLE]: {...previousReportTitleField, pendingFields: {defaultValue: null}}, }, errorFields: { fieldList: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage'), @@ -4029,11 +4029,11 @@ function setPolicyDefaultReportTitle(policyID: string, customName: string) { function setPolicyPreventMemberCreatedTitle(policyID: string, enforced: boolean) { const policy = getPolicy(policyID); - if (!enforced === policy?.fieldList?.[CONST.POLICY.FIELDS.TITLE].deletable) { + if (!enforced === policy?.fieldList?.[CONST.POLICY.FIELDS.FIELD_LIST_TITLE].deletable) { return; } - const previousReportTitleField = policy?.fieldList?.[CONST.POLICY.FIELDS.TITLE] ?? {}; + const previousReportTitleField = policy?.fieldList?.[CONST.POLICY.FIELDS.FIELD_LIST_TITLE] ?? {}; const optimisticData: OnyxUpdate[] = [ { @@ -4041,7 +4041,7 @@ function setPolicyPreventMemberCreatedTitle(policyID: string, enforced: boolean) key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { fieldList: { - [CONST.POLICY.FIELDS.TITLE]: {...previousReportTitleField, deletable: !enforced, pendingFields: {deletable: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}}, + [CONST.POLICY.FIELDS.FIELD_LIST_TITLE]: {...previousReportTitleField, deletable: !enforced, pendingFields: {deletable: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}}, }, }, }, @@ -4053,7 +4053,7 @@ function setPolicyPreventMemberCreatedTitle(policyID: string, enforced: boolean) key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { fieldList: { - [CONST.POLICY.FIELDS.TITLE]: {pendingFields: {deletable: null}}, + [CONST.POLICY.FIELDS.FIELD_LIST_TITLE]: {pendingFields: {deletable: null}}, }, errorFields: null, }, @@ -4066,7 +4066,7 @@ function setPolicyPreventMemberCreatedTitle(policyID: string, enforced: boolean) key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { fieldList: { - [CONST.POLICY.FIELDS.TITLE]: {...previousReportTitleField, pendingFields: {deletable: null}}, + [CONST.POLICY.FIELDS.FIELD_LIST_TITLE]: {...previousReportTitleField, pendingFields: {deletable: null}}, }, errorFields: { fieldList: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage'), diff --git a/src/libs/actions/Policy/Tag.ts b/src/libs/actions/Policy/Tag.ts index f6ed865d169..8f4db840476 100644 --- a/src/libs/actions/Policy/Tag.ts +++ b/src/libs/actions/Policy/Tag.ts @@ -853,7 +853,7 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { const approverRuleToUpdate = PolicyUtils.getTagApproverRule(policyID, tag); const filteredApprovalRules = approverRuleToUpdate ? prevApprovalRules.filter((rule) => rule.id !== approverRuleToUpdate.id) : prevApprovalRules; const toBeUnselected = approverRuleToUpdate?.approver === approver; - const tagRuleUpdateKey = PolicyUtils.getPolicyFieldUpdateKey(tag, CONST.POLICY.FIELDS.TAG); + const tagRuleUpdateKey = PolicyUtils.getKeyForPendingRuleUpdate(tag, CONST.POLICY.FIELDS.TAG); const updatedApproverRule = approverRuleToUpdate ? {...approverRuleToUpdate, approver} diff --git a/src/pages/workspace/categories/CategorySettingsPage.tsx b/src/pages/workspace/categories/CategorySettingsPage.tsx index 6e939dc1835..02115c47d8b 100644 --- a/src/pages/workspace/categories/CategorySettingsPage.tsx +++ b/src/pages/workspace/categories/CategorySettingsPage.tsx @@ -261,7 +261,7 @@ function CategorySettingsPage({ )} Navigation.navigate(ROUTES.RULES_CUSTOM_NAME.getRoute(policyID))} @@ -70,8 +70,8 @@ function ExpenseReportRulesSection({policyID}: ExpenseReportRulesSectionProps) { , PolicyActions.setPolicyPreventMemberCreatedTitle(policyID, isEnabled)} />, ], diff --git a/src/pages/workspace/rules/RulesCustomNamePage.tsx b/src/pages/workspace/rules/RulesCustomNamePage.tsx index 738ac2e0cf3..42f0ab1e504 100644 --- a/src/pages/workspace/rules/RulesCustomNamePage.tsx +++ b/src/pages/workspace/rules/RulesCustomNamePage.tsx @@ -39,7 +39,7 @@ function RulesCustomNamePage({route}: RulesCustomNamePageProps) { translate('workspace.rules.expenseReportRules.customNameTotalExample'), ] as const satisfies string[]; - const customNameDefaultValue = policy?.fieldList?.[CONST.POLICY.FIELDS.TITLE].defaultValue; + const customNameDefaultValue = policy?.fieldList?.[CONST.POLICY.FIELDS.FIELD_LIST_TITLE].defaultValue; const validateCustomName = ({customName}: FormOnyxValues) => { const errors: FormInputErrors = {}; diff --git a/src/pages/workspace/tags/TagSettingsPage.tsx b/src/pages/workspace/tags/TagSettingsPage.tsx index fd4c20e8437..fd2b39b14f9 100644 --- a/src/pages/workspace/tags/TagSettingsPage.tsx +++ b/src/pages/workspace/tags/TagSettingsPage.tsx @@ -161,7 +161,7 @@ function TagSettingsPage({route, policyTags, navigation}: TagSettingsPageProps) {translate('workspace.tags.tagRules')} - + Date: Wed, 18 Sep 2024 00:50:01 +0200 Subject: [PATCH 19/30] update category rule when renaming category --- src/libs/actions/Policy/Category.ts | 38 +++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/libs/actions/Policy/Category.ts b/src/libs/actions/Policy/Category.ts index 695a2c9b9f8..b0b2c10b37e 100644 --- a/src/libs/actions/Policy/Category.ts +++ b/src/libs/actions/Policy/Category.ts @@ -521,8 +521,28 @@ function importPolicyCategories(policyID: string, categories: PolicyCategory[]) } function renamePolicyCategory(policyID: string, policyCategory: {oldName: string; newName: string}) { + const policy = PolicyUtils.getPolicy(policyID); const policyCategoryToUpdate = allPolicyCategories?.[`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`]?.[policyCategory.oldName]; + const policyCategoryRule = CategoryUtils.getCategoryApproverRule(policy?.rules?.approvalRules ?? [], policyCategory.oldName); + const approvalRules = policy?.rules?.approvalRules ?? []; + const updatedApprovalRules: ApprovalRule[] = lodashCloneDeep(approvalRules); + + // Its related by name, so the corresponding rule has to be updated to handle offline scenario + if (policyCategoryRule) { + const indexToUpdate = updatedApprovalRules.findIndex((rule) => rule.id === policyCategoryRule.id); + policyCategoryRule.applyWhen = policyCategoryRule.applyWhen.map((ruleCondition) => { + const {value, field, condition} = ruleCondition; + + if (value === policyCategory.oldName && field === CONST.POLICY.FIELDS.CATEGORY && condition === CONST.POLICY.RULE_CONDITIONS.MATCHES) { + return {...ruleCondition, value: policyCategory.newName}; + } + + return ruleCondition; + }); + updatedApprovalRules[indexToUpdate] = policyCategoryRule; + } + const onyxData: OnyxData = { optimisticData: [ { @@ -542,6 +562,15 @@ function renamePolicyCategory(policyID: string, policyCategory: {oldName: string }, }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: { + rules: { + approvalRules: updatedApprovalRules, + }, + }, + }, ], successData: [ { @@ -576,6 +605,15 @@ function renamePolicyCategory(policyID: string, policyCategory: {oldName: string }, }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: { + rules: { + approvalRules, + }, + }, + }, ], }; From bc4eed8fe3ee3cddddfc772e45d48768e0898f2a Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 18 Sep 2024 01:19:20 +0200 Subject: [PATCH 20/30] update tag rule when renaming tag --- src/libs/actions/Policy/Tag.ts | 43 +++++++++++++++----- src/pages/workspace/tags/TagSettingsPage.tsx | 2 +- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/libs/actions/Policy/Tag.ts b/src/libs/actions/Policy/Tag.ts index 8f4db840476..ba2a06d450b 100644 --- a/src/libs/actions/Policy/Tag.ts +++ b/src/libs/actions/Policy/Tag.ts @@ -1,3 +1,4 @@ +import lodashCloneDeep from 'lodash/cloneDeep'; import type {NullishDeep, OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import * as API from '@libs/API'; @@ -24,7 +25,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Policy, PolicyTag, PolicyTagLists, PolicyTags, RecentlyUsedTags, Report} from '@src/types/onyx'; import type {OnyxValueWithOfflineFeedback} from '@src/types/onyx/OnyxCommon'; -import type {Attributes, Rate} from '@src/types/onyx/Policy'; +import type {ApprovalRule, Attributes, Rate} from '@src/types/onyx/Policy'; import type {OnyxData} from '@src/types/onyx/Request'; type NewCustomUnit = { @@ -410,10 +411,31 @@ function clearPolicyTagListErrors(policyID: string, tagListIndex: number) { } function renamePolicyTag(policyID: string, policyTag: {oldName: string; newName: string}, tagListIndex: number) { + const policy = PolicyUtils.getPolicy(policyID); const tagList = PolicyUtils.getTagLists(allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`] ?? {})?.[tagListIndex] ?? {}; const tag = tagList.tags?.[policyTag.oldName]; const oldTagName = policyTag.oldName; const newTagName = PolicyUtils.escapeTagName(policyTag.newName); + + const policyTagRule = PolicyUtils.getTagApproverRule(policyID, oldTagName); + const approvalRules = policy?.rules?.approvalRules ?? []; + const updatedApprovalRules: ApprovalRule[] = lodashCloneDeep(approvalRules); + + // Its related by name, so the corresponding rule has to be updated to handle offline scenario + if (policyTagRule) { + const indexToUpdate = updatedApprovalRules.findIndex((rule) => rule.id === policyTagRule.id); + policyTagRule.applyWhen = policyTagRule.applyWhen.map((ruleCondition) => { + const {value, field, condition} = ruleCondition; + + if (value === policyTag.oldName && field === CONST.POLICY.FIELDS.TAG && condition === CONST.POLICY.RULE_CONDITIONS.MATCHES) { + return {...ruleCondition, value: policyTag.newName}; + } + + return ruleCondition; + }); + updatedApprovalRules[indexToUpdate] = policyTagRule; + } + const onyxData: OnyxData = { optimisticData: [ { @@ -438,6 +460,15 @@ function renamePolicyTag(policyID: string, policyTag: {oldName: string; newName: }, }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: { + rules: { + approvalRules: updatedApprovalRules, + }, + }, + }, ], successData: [ { @@ -896,11 +927,6 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { rules: { approvalRules: updatedApprovalRules, }, - pendingRulesUpdates: { - [tagRuleUpdateKey]: { - approvalRule: null, - }, - }, }, }, ], @@ -912,11 +938,6 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { rules: { approvalRules: prevApprovalRules, }, - pendingRulesUpdates: { - [tagRuleUpdateKey]: { - approvalRule: null, - }, - }, }, }, ], diff --git a/src/pages/workspace/tags/TagSettingsPage.tsx b/src/pages/workspace/tags/TagSettingsPage.tsx index fd2b39b14f9..3240758f12b 100644 --- a/src/pages/workspace/tags/TagSettingsPage.tsx +++ b/src/pages/workspace/tags/TagSettingsPage.tsx @@ -89,7 +89,7 @@ function TagSettingsPage({route, policyTags, navigation}: TagSettingsPageProps) const isThereAnyAccountingConnection = Object.keys(policy?.connections ?? {}).length !== 0; const isMultiLevelTags = PolicyUtils.isMultiLevelTags(policyTags); - const tagApprover = PolicyUtils.getTagApproverRule(policyID, currentPolicyTag.name)?.approver; + const tagApprover = PolicyUtils.getTagApproverRule(policyID, route.params.tagName)?.approver; const shouldShowDeleteMenuItem = !isThereAnyAccountingConnection && !isMultiLevelTags; const workflowApprovalsUnavailable = PolicyUtils.getWorkflowApprovalsUnavailable(policy); From 6fc0879a41aa1526b5122b60f84d521b81125e9d Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 18 Sep 2024 01:29:27 +0200 Subject: [PATCH 21/30] remove pending action pattern for rules --- src/libs/PolicyUtils.ts | 10 ---- src/libs/actions/Policy/Category.ts | 51 +------------------ src/libs/actions/Policy/Tag.ts | 6 --- .../categories/CategorySettingsPage.tsx | 42 +++++++-------- src/pages/workspace/tags/TagSettingsPage.tsx | 16 +++--- 5 files changed, 26 insertions(+), 99 deletions(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index e5852f44a1c..0eb656d3663 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -995,15 +995,6 @@ function getTagApproverRule(policyID: string, tagName: string) { return approverRule; } -type PolicyFieldUpdateKeyField = ValueOf; - -/** - * Get a key for a pending rule field update - we want to differentiate specific field updates to gray out only desired sections - */ -function getKeyForPendingRuleUpdate(fieldValue: string, fieldName: PolicyFieldUpdateKeyField) { - return `${fieldName}_${fieldValue}`; -} - function getDomainNameForPolicy(policyID?: string): string { if (!policyID) { return ''; @@ -1126,7 +1117,6 @@ export { getTagApproverRule, getDomainNameForPolicy, getWorkflowApprovalsUnavailable, - getKeyForPendingRuleUpdate, }; export type {MemberEmailsToAccountIDs}; diff --git a/src/libs/actions/Policy/Category.ts b/src/libs/actions/Policy/Category.ts index b0b2c10b37e..95f2e8efe11 100644 --- a/src/libs/actions/Policy/Category.ts +++ b/src/libs/actions/Policy/Category.ts @@ -1191,7 +1191,6 @@ function setPolicyCategoryApprover(policyID: string, categoryName: string, appro const approvalRules = policy?.rules?.approvalRules ?? []; let updatedApprovalRules: ApprovalRule[] = lodashCloneDeep(approvalRules); const existingCategoryApproverRule = CategoryUtils.getCategoryApproverRule(updatedApprovalRules, categoryName); - const categoryRuleUpdateKey = PolicyUtils.getKeyForPendingRuleUpdate(categoryName, CONST.POLICY.FIELDS.CATEGORY); let newApprover = approver; @@ -1223,27 +1222,10 @@ function setPolicyCategoryApprover(policyID: string, categoryName: string, appro rules: { approvalRules: updatedApprovalRules, }, - pendingRulesUpdates: { - [categoryRuleUpdateKey]: { - approvalRule: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, - }, - }, - }, - }, - ], - successData: [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - value: { - pendingRulesUpdates: { - [categoryRuleUpdateKey]: { - approvalRule: null, - }, - }, }, }, ], + failureData: [ { onyxMethod: Onyx.METHOD.MERGE, @@ -1252,11 +1234,6 @@ function setPolicyCategoryApprover(policyID: string, categoryName: string, appro rules: { approvalRules, }, - pendingRulesUpdates: { - [categoryRuleUpdateKey]: { - approvalRule: null, - }, - }, }, }, ], @@ -1272,11 +1249,10 @@ function setPolicyCategoryApprover(policyID: string, categoryName: string, appro } function setPolicyCategoryTax(policyID: string, categoryName: string, taxID: string) { - const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]; + const policy = PolicyUtils.getPolicy(policyID); const expenseRules = policy?.rules?.expenseRules ?? []; const updatedExpenseRules: ExpenseRule[] = lodashCloneDeep(expenseRules); const existingCategoryExpenseRule = updatedExpenseRules.find((rule) => rule.applyWhen.some((when) => when.value === categoryName)); - const categoryRuleUpdateKey = PolicyUtils.getKeyForPendingRuleUpdate(categoryName, CONST.POLICY.FIELDS.TAX); if (!existingCategoryExpenseRule) { updatedExpenseRules.push({ @@ -1308,24 +1284,6 @@ function setPolicyCategoryTax(policyID: string, categoryName: string, taxID: str rules: { expenseRules: updatedExpenseRules, }, - pendingRulesUpdates: { - [categoryRuleUpdateKey]: { - expenseRule: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, - }, - }, - }, - }, - ], - successData: [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - value: { - pendingRulesUpdates: { - [categoryRuleUpdateKey]: { - expenseRule: null, - }, - }, }, }, ], @@ -1337,11 +1295,6 @@ function setPolicyCategoryTax(policyID: string, categoryName: string, taxID: str rules: { expenseRules, }, - pendingRulesUpdates: { - [categoryRuleUpdateKey]: { - expenseRule: null, - }, - }, }, }, ], diff --git a/src/libs/actions/Policy/Tag.ts b/src/libs/actions/Policy/Tag.ts index ba2a06d450b..f3be5d64b83 100644 --- a/src/libs/actions/Policy/Tag.ts +++ b/src/libs/actions/Policy/Tag.ts @@ -884,7 +884,6 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { const approverRuleToUpdate = PolicyUtils.getTagApproverRule(policyID, tag); const filteredApprovalRules = approverRuleToUpdate ? prevApprovalRules.filter((rule) => rule.id !== approverRuleToUpdate.id) : prevApprovalRules; const toBeUnselected = approverRuleToUpdate?.approver === approver; - const tagRuleUpdateKey = PolicyUtils.getKeyForPendingRuleUpdate(tag, CONST.POLICY.FIELDS.TAG); const updatedApproverRule = approverRuleToUpdate ? {...approverRuleToUpdate, approver} @@ -911,11 +910,6 @@ function setPolicyTagApprover(policyID: string, tag: string, approver: string) { rules: { approvalRules: updatedApprovalRules, }, - pendingRulesUpdates: { - [tagRuleUpdateKey]: { - approvalRule: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, - }, - }, }, }, ], diff --git a/src/pages/workspace/categories/CategorySettingsPage.tsx b/src/pages/workspace/categories/CategorySettingsPage.tsx index 02115c47d8b..17c1a69ac66 100644 --- a/src/pages/workspace/categories/CategorySettingsPage.tsx +++ b/src/pages/workspace/categories/CategorySettingsPage.tsx @@ -260,19 +260,15 @@ function CategorySettingsPage({ /> )} - - { - Navigation.navigate(ROUTES.WORSKPACE_CATEGORY_APPROVER.getRoute(policyID, policyCategory.name)); - }} - shouldShowRightIcon - disabled={approverDisabled} - /> - + { + Navigation.navigate(ROUTES.WORSKPACE_CATEGORY_APPROVER.getRoute(policyID, policyCategory.name)); + }} + shouldShowRightIcon + disabled={approverDisabled} + /> {approverDisabled && ( {translate('workspace.rules.categoryRules.goTo')}{' '} @@ -286,18 +282,14 @@ function CategorySettingsPage({ )} {policy?.tax?.trackingEnabled && ( - - { - Navigation.navigate(ROUTES.WORSKPACE_CATEGORY_DEFAULT_TAX_RATE.getRoute(policyID, policyCategory.name)); - }} - shouldShowRightIcon - /> - + { + Navigation.navigate(ROUTES.WORSKPACE_CATEGORY_DEFAULT_TAX_RATE.getRoute(policyID, policyCategory.name)); + }} + shouldShowRightIcon + /> )} diff --git a/src/pages/workspace/tags/TagSettingsPage.tsx b/src/pages/workspace/tags/TagSettingsPage.tsx index 3240758f12b..c96632ddf87 100644 --- a/src/pages/workspace/tags/TagSettingsPage.tsx +++ b/src/pages/workspace/tags/TagSettingsPage.tsx @@ -161,15 +161,13 @@ function TagSettingsPage({route, policyTags, navigation}: TagSettingsPageProps) {translate('workspace.tags.tagRules')} - - - + {approverDisabled && ( {translate('workspace.rules.categoryRules.goTo')}{' '} From 08cf2a2c52d327460facc2acbb9bb59c37ac06be Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 18 Sep 2024 02:26:58 +0200 Subject: [PATCH 22/30] fix onyx check --- package-lock.json | 16 ---------------- src/libs/ReportActionsConnection.ts | 24 ++++++++++++++++++++++++ src/libs/actions/Policy/Policy.ts | 7 +++++-- 3 files changed, 29 insertions(+), 18 deletions(-) create mode 100644 src/libs/ReportActionsConnection.ts diff --git a/package-lock.json b/package-lock.json index d21d8035308..fd4217d640e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27979,22 +27979,6 @@ "jest": "bin/jest.js" } }, - "node_modules/jest-expo/node_modules/@babel/code-frame": { - "version": "7.10.4", - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/jest-expo/node_modules/@expo/json-file": { - "version": "8.3.1", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "~7.10.4", - "json5": "^2.2.2", - "write-file-atomic": "^2.3.0" - } - }, "node_modules/jest-expo/node_modules/json5": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz", diff --git a/src/libs/ReportActionsConnection.ts b/src/libs/ReportActionsConnection.ts new file mode 100644 index 00000000000..b512aeb42c9 --- /dev/null +++ b/src/libs/ReportActionsConnection.ts @@ -0,0 +1,24 @@ +import type {OnyxCollection} from 'react-native-onyx'; +import Onyx from 'react-native-onyx'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {Message, OldDotReportAction, OriginalMessage, ReportActions} from '@src/types/onyx/ReportAction'; + +let allReportActions: OnyxCollection; +Onyx.connect({ + key: ONYXKEYS.COLLECTION.REPORT_ACTIONS, + waitForCollectionCallback: true, + callback: (actions) => { + if (!actions) { + return; + } + + allReportActions = actions; + }, +}); + +// This function is used to get all reports +function getAllReportActions() { + return allReportActions; +} + +export {getAllReportActions}; diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index ae12b3747ba..6dda2a45711 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -71,8 +71,8 @@ import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as PhoneNumber from '@libs/PhoneNumber'; import * as PolicyUtils from '@libs/PolicyUtils'; import {navigateWhenEnableFeature} from '@libs/PolicyUtils'; -import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportConnection from '@libs/ReportConnection'; +import * as ReportAcionsConnection from '@libs/ReportActionsConnection' import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import type {PolicySelector} from '@pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover'; @@ -2578,7 +2578,10 @@ function createWorkspaceFromIOUPayment(iouReport: OnyxEntry): WorkspaceF }); // We need to move the report preview action from the DM to the workspace chat. - const reportPreview = ReportActionsUtils.getParentReportAction(iouReport); + const parentReport = ReportAcionsConnection.getAllReportActions()?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.parentReportID}`] + const parentReportActionID = iouReport.parentReportActionID + const reportPreview = parentReportActionID ? parentReport?.[parentReportActionID] : undefined; + optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oldChatReportID}`, From b32ed64cc822f7e7803e522ba400c9d5becefdf5 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 18 Sep 2024 02:28:08 +0200 Subject: [PATCH 23/30] remove pending pattern from type --- src/types/onyx/Policy.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 006a4a42cf0..6b8817ff558 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -1686,18 +1686,6 @@ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback< /** Workspace account ID configured for Expensify Card */ workspaceAccountID?: number; - - /** Information about rules being updated */ - pendingRulesUpdates?: Record< - CategoryOrTagName, - { - /** Indicates whether the approval rule is updated for the given category or tag */ - approvalRule: OnyxCommon.PendingAction; - - /** Indicates whether the expense rule is updated for the given category or tag */ - expenseRule: OnyxCommon.PendingAction; - } - >; } & Partial, 'addWorkspaceRoom' | keyof ACHAccount | keyof Attributes >; From 71c8ef800f284f085fcbb6e408293cca9b358624 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 18 Sep 2024 02:37:42 +0200 Subject: [PATCH 24/30] run prettier --- src/libs/actions/Policy/Policy.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 6dda2a45711..b202ac96175 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -71,8 +71,8 @@ import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as PhoneNumber from '@libs/PhoneNumber'; import * as PolicyUtils from '@libs/PolicyUtils'; import {navigateWhenEnableFeature} from '@libs/PolicyUtils'; +import * as ReportAcionsConnection from '@libs/ReportActionsConnection'; import * as ReportConnection from '@libs/ReportConnection'; -import * as ReportAcionsConnection from '@libs/ReportActionsConnection' import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import type {PolicySelector} from '@pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover'; @@ -2578,10 +2578,10 @@ function createWorkspaceFromIOUPayment(iouReport: OnyxEntry): WorkspaceF }); // We need to move the report preview action from the DM to the workspace chat. - const parentReport = ReportAcionsConnection.getAllReportActions()?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.parentReportID}`] - const parentReportActionID = iouReport.parentReportActionID - const reportPreview = parentReportActionID ? parentReport?.[parentReportActionID] : undefined; - + const parentReport = ReportAcionsConnection.getAllReportActions()?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.parentReportID}`]; + const parentReportActionID = iouReport.parentReportActionID; + const reportPreview = parentReportActionID ? parentReport?.[parentReportActionID] : undefined; + optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oldChatReportID}`, From 669e6924b64b47030a0156e5c8e4d929358dfcb2 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 18 Sep 2024 02:38:30 +0200 Subject: [PATCH 25/30] cleanup --- src/types/onyx/Policy.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 6b8817ff558..1f1be7e89c2 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -1412,9 +1412,6 @@ type ExpenseRule = { id?: string; }; -/** The name of the category or tag */ -type CategoryOrTagName = string; - /** Model of policy data */ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback< { From 4fccbb14cb2472960cfff8bdaac78be84dc88592 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 18 Sep 2024 02:44:02 +0200 Subject: [PATCH 26/30] cleanup --- src/libs/ReportActionsConnection.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportActionsConnection.ts b/src/libs/ReportActionsConnection.ts index b512aeb42c9..e3c8a4c3cf6 100644 --- a/src/libs/ReportActionsConnection.ts +++ b/src/libs/ReportActionsConnection.ts @@ -1,7 +1,7 @@ import type {OnyxCollection} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Message, OldDotReportAction, OriginalMessage, ReportActions} from '@src/types/onyx/ReportAction'; +import type {ReportActions} from '@src/types/onyx/ReportAction'; let allReportActions: OnyxCollection; Onyx.connect({ @@ -21,4 +21,5 @@ function getAllReportActions() { return allReportActions; } +// eslint-disable-next-line import/prefer-default-export export {getAllReportActions}; From 2fdea8246269e9c1cc6b9ccf2a349fc6aa31d83e Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 18 Sep 2024 02:46:58 +0200 Subject: [PATCH 27/30] remove withOnyx --- .../categories/CategorySettingsPage.tsx | 19 ++++-------------- src/pages/workspace/tags/TagSettingsPage.tsx | 20 +++++-------------- 2 files changed, 9 insertions(+), 30 deletions(-) diff --git a/src/pages/workspace/categories/CategorySettingsPage.tsx b/src/pages/workspace/categories/CategorySettingsPage.tsx index 17c1a69ac66..05111864f61 100644 --- a/src/pages/workspace/categories/CategorySettingsPage.tsx +++ b/src/pages/workspace/categories/CategorySettingsPage.tsx @@ -1,8 +1,7 @@ import type {StackScreenProps} from '@react-navigation/stack'; import React, {useEffect, useMemo, useState} from 'react'; import {View} from 'react-native'; -import type {OnyxEntry} from 'react-native-onyx'; -import {withOnyx} from 'react-native-onyx'; +import {useOnyx} from 'react-native-onyx'; import ConfirmModal from '@components/ConfirmModal'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; @@ -31,22 +30,16 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -import type * as OnyxTypes from '@src/types/onyx'; -type CategorySettingsPageOnyxProps = { - /** Collection of categories attached to a policy */ - policyCategories: OnyxEntry; -}; - -type CategorySettingsPageProps = CategorySettingsPageOnyxProps & StackScreenProps; +type CategorySettingsPageProps = StackScreenProps; function CategorySettingsPage({ route: { params: {backTo, policyID, categoryName}, }, - policyCategories, navigation, }: CategorySettingsPageProps) { + const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`); const styles = useThemeStyles(); const {translate} = useLocalize(); const [deleteCategoryConfirmModalVisible, setDeleteCategoryConfirmModalVisible] = useState(false); @@ -332,8 +325,4 @@ function CategorySettingsPage({ CategorySettingsPage.displayName = 'CategorySettingsPage'; -export default withOnyx({ - policyCategories: { - key: ({route}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${route.params.policyID}`, - }, -})(CategorySettingsPage); +export default CategorySettingsPage; diff --git a/src/pages/workspace/tags/TagSettingsPage.tsx b/src/pages/workspace/tags/TagSettingsPage.tsx index c96632ddf87..6b70b6f636f 100644 --- a/src/pages/workspace/tags/TagSettingsPage.tsx +++ b/src/pages/workspace/tags/TagSettingsPage.tsx @@ -1,8 +1,7 @@ import type {StackScreenProps} from '@react-navigation/stack'; import React, {useEffect, useMemo} from 'react'; import {View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; -import type {OnyxEntry} from 'react-native-onyx'; +import {useOnyx} from 'react-native-onyx'; import ConfirmModal from '@components/ConfirmModal'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; @@ -28,16 +27,11 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -import type {PolicyTagLists} from '@src/types/onyx'; -type TagSettingsPageOnyxProps = { - /** All policy tags */ - policyTags: OnyxEntry; -}; +type TagSettingsPageProps = StackScreenProps; -type TagSettingsPageProps = TagSettingsPageOnyxProps & StackScreenProps; - -function TagSettingsPage({route, policyTags, navigation}: TagSettingsPageProps) { +function TagSettingsPage({route, navigation}: TagSettingsPageProps) { + const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${route.params.policyID}`); const {orderWeight, policyID, tagName} = route.params; const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -198,8 +192,4 @@ function TagSettingsPage({route, policyTags, navigation}: TagSettingsPageProps) TagSettingsPage.displayName = 'TagSettingsPage'; -export default withOnyx({ - policyTags: { - key: ({route}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${route.params.policyID}`, - }, -})(TagSettingsPage); +export default TagSettingsPage; From 4810e33e8d836cdcde4b00ac404cd6a8f3a59fac Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 18 Sep 2024 16:53:38 +0200 Subject: [PATCH 28/30] run prettier --- src/libs/actions/Policy/Policy.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index eb75338d0ca..97edc635e8e 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -166,8 +166,6 @@ Onyx.connect({ }, }); - - let lastAccessedWorkspacePolicyID: OnyxEntry; Onyx.connect({ key: ONYXKEYS.LAST_ACCESSED_WORKSPACE_POLICY_ID, From 2ba31913da3662e45dc3da9a86a8a8871a30a821 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 18 Sep 2024 16:56:31 +0200 Subject: [PATCH 29/30] cleanup --- src/libs/actions/Policy/Policy.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 97edc635e8e..79ae9a63687 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -93,7 +93,6 @@ import type { } from '@src/types/onyx'; import type {Errors} from '@src/types/onyx/OnyxCommon'; import type {Attributes, CompanyAddress, CustomUnit, NetSuiteCustomList, NetSuiteCustomSegment, Rate, TaxRate, Unit} from '@src/types/onyx/Policy'; -import type {ReportActions} from '@src/types/onyx/ReportAction'; import type {OnyxData} from '@src/types/onyx/Request'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import {buildOptimisticPolicyCategories} from './Category'; From e06551c1b6bd081bf675e5b52e246027d5ec131c Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Thu, 19 Sep 2024 10:42:54 +0200 Subject: [PATCH 30/30] rename connection --- src/libs/actions/Policy/Policy.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 79ae9a63687..50db00cc64d 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -71,7 +71,7 @@ import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as PhoneNumber from '@libs/PhoneNumber'; import * as PolicyUtils from '@libs/PolicyUtils'; import {navigateWhenEnableFeature} from '@libs/PolicyUtils'; -import * as ReportAcionsConnection from '@libs/ReportActionsConnection'; +import * as ReportActionsConnection from '@libs/ReportActionsConnection'; import * as ReportConnection from '@libs/ReportConnection'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; @@ -2619,7 +2619,7 @@ function createWorkspaceFromIOUPayment(iouReport: OnyxEntry): WorkspaceF }); // We need to move the report preview action from the DM to the workspace chat. - const parentReport = ReportAcionsConnection.getAllReportActions()?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.parentReportID}`]; + const parentReport = ReportActionsConnection.getAllReportActions()?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.parentReportID}`]; const parentReportActionID = iouReport.parentReportActionID; const reportPreview = iouReport?.parentReportID && parentReportActionID ? parentReport?.[parentReportActionID] : undefined;