diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index d56f664119d6..5371997332ed 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -570,6 +570,9 @@ const ONYXKEYS = { /** Stores the information about duplicated workspace */ DUPLICATE_WORKSPACE: 'duplicateWorkspace', + /** Stores the state of the bulk Copy Policy Settings flow */ + COPY_POLICY_SETTINGS: 'copyPolicySettings', + /** Stores the information about currently edited advanced approval workflow */ APPROVAL_WORKFLOW: 'approvalWorkflow', @@ -1508,6 +1511,7 @@ type OnyxValuesMapping = { [ONYXKEYS.ASSIGN_CARD]: OnyxTypes.AssignCard; [ONYXKEYS.RAM_ONLY_MOBILE_SELECTION_MODE]: boolean; [ONYXKEYS.DUPLICATE_WORKSPACE]: OnyxTypes.DuplicateWorkspace; + [ONYXKEYS.COPY_POLICY_SETTINGS]: OnyxTypes.CopyPolicySettings; [ONYXKEYS.NVP_FIRST_DAY_FREE_TRIAL]: string; [ONYXKEYS.NVP_LAST_DAY_FREE_TRIAL]: string; [ONYXKEYS.NVP_BILLING_FUND_ID]: number; diff --git a/src/ROUTES.ts b/src/ROUTES.ts index e7e54762ce03..f36094cded50 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -2974,6 +2974,18 @@ const ROUTES = { route: 'workspace/:policyID/duplicate/select-features', getRoute: (policyID: string) => `workspace/${policyID}/duplicate/select-features` as const, }, + POLICY_COPY_SETTINGS: { + route: 'policy/:policyID/copy-settings', + getRoute: (policyID: string) => `policy/${policyID}/copy-settings` as const, + }, + POLICY_COPY_SETTINGS_SELECT_FEATURES: { + route: 'policy/:policyID/copy-settings/select-features', + getRoute: (policyID: string) => `policy/${policyID}/copy-settings/select-features` as const, + }, + POLICY_COPY_SETTINGS_CONFIRM: { + route: 'policy/:policyID/copy-settings/confirm', + getRoute: (policyID: string) => `policy/${policyID}/copy-settings/confirm` as const, + }, WORKSPACE_RECEIPT_PARTNERS: { route: 'workspaces/:policyID/receipt-partners', getRoute: (policyID: string | undefined, backTo?: string) => { diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 4cd8277f5626..751404e74e75 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -300,6 +300,7 @@ const SCREENS = { REPORT_CHANGE_WORKSPACE: 'ReportChangeWorkspace', WORKSPACE_CONFIRMATION: 'Workspace_Confirmation', WORKSPACE_DUPLICATE: 'Workspace_Duplicate', + POLICY_COPY_SETTINGS: 'Policy_Copy_Settings', REPORT_SETTINGS: 'Report_Settings', REPORT_DESCRIPTION: 'Report_Description', PARTICIPANTS: 'Participants', @@ -526,6 +527,11 @@ const SCREENS = { WORKSPACE_CONFIRMATION: {ROOT: 'Workspace_Confirmation_Root', OWNER_SELECTOR: 'Workspace_Confirmation_Owner_Selector', SUCCESS: 'Workspace_Confirmation_Success'}, WORKSPACE_DUPLICATE: {ROOT: 'Workspace_Duplicate_Root', SELECT_FEATURES: 'Workspace_Duplicate_Select_Features'}, + POLICY_COPY_SETTINGS: { + ROOT: 'Policy_Copy_Settings_Root', + SELECT_FEATURES: 'Policy_Copy_Settings_Select_Features', + CONFIRM: 'Policy_Copy_Settings_Confirm', + }, WORKSPACES_LIST: 'Workspaces_List', diff --git a/src/libs/API/parameters/CopyPolicySettingsParams.ts b/src/libs/API/parameters/CopyPolicySettingsParams.ts new file mode 100644 index 000000000000..8df8a34eca7b --- /dev/null +++ b/src/libs/API/parameters/CopyPolicySettingsParams.ts @@ -0,0 +1,11 @@ +type CopyPolicySettingsParams = { + sourcePolicyID: string; + + /** CSV list of target policy IDs to copy settings into */ + policyIDList: string; + + /** CSV list of feature keys to copy */ + parts: string; +}; + +export default CopyPolicySettingsParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 8ca61538fafe..77157dd625d7 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -96,6 +96,7 @@ export type {default as UnlinkLoginParams} from './UnlinkLoginParams'; export type {default as UpdateAutomaticTimezoneParams} from './UpdateAutomaticTimezoneParams'; export type {default as UpdateChatPriorityModeParams} from './UpdateChatPriorityModeParams'; export type {default as DuplicateWorkspaceParams} from './DuplicateWorkspaceParams'; +export type {default as CopyPolicySettingsParams} from './CopyPolicySettingsParams'; export type {default as UpdateDateOfBirthParams} from './UpdateDateOfBirthParams'; export type {default as UpdateDisplayNameParams} from './UpdateDisplayNameParams'; export type {default as UpdateChatNameParams} from './UpdateChatNameParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 0db112b564fe..22c3b4e83584 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -161,6 +161,8 @@ const WRITE_COMMANDS = { UPDATE_WORKSPACE_MEMBERS_ROLE: 'UpdateWorkspaceMembersRole', CREATE_WORKSPACE: 'CreateWorkspace', DUPLICATE_POLICY: 'DuplicatePolicy', + COPY_POLICY_SETTINGS: 'CopyPolicySettings', + COPY_POLICY_SETTINGS_NOTIFY: 'CopyPolicySettings_Notify', CREATE_WORKSPACE_FROM_IOU_PAYMENT: 'CreateWorkspaceFromIOUPayment', UPDATE_POLICY_MEMBERS_CUSTOM_FIELDS: 'UpdatePolicyMembersCustomFields', SET_WORKSPACE_CATEGORIES_ENABLED: 'SetWorkspaceCategoriesEnabled', @@ -970,6 +972,8 @@ type WriteCommandParameters = { [WRITE_COMMANDS.PAY_INVOICE]: Parameters.PayInvoiceParams; [WRITE_COMMANDS.MARK_AS_CASH]: Parameters.MarkAsCashParams; [WRITE_COMMANDS.DUPLICATE_POLICY]: Parameters.DuplicateWorkspaceParams; + [WRITE_COMMANDS.COPY_POLICY_SETTINGS]: Parameters.CopyPolicySettingsParams; + [WRITE_COMMANDS.COPY_POLICY_SETTINGS_NOTIFY]: EmptyObject; [WRITE_COMMANDS.MERGE_DUPLICATES]: Parameters.MergeDuplicatesParams; [WRITE_COMMANDS.RESOLVE_DUPLICATES]: Parameters.ResolveDuplicatesParams; [WRITE_COMMANDS.MERGE_TRANSACTION]: Parameters.MergeTransactionParams; diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 5dd5650a4943..3f293ccf720d 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -23,6 +23,7 @@ import type { NewReportWorkspaceSelectionNavigatorParamList, NewTaskNavigatorParamList, ParticipantsNavigatorParamList, + PolicyCopySettingsNavigatorParamList, PrivateNotesNavigatorParamList, ProfileNavigatorParamList, ReferralDetailsNavigatorParamList, @@ -307,6 +308,12 @@ const WorkspaceDuplicateModalStackNavigator = createModalStackNavigator require('../../../../pages/workspace/duplicate/WorkspaceDuplicateSelectFeaturesPage').default, }); +const PolicyCopySettingsModalStackNavigator = createModalStackNavigator({ + [SCREENS.POLICY_COPY_SETTINGS.ROOT]: () => require('../../../../pages/workspace/copyPolicySettings/CopyPolicySettingsSelectWorkspacesPage').default, + [SCREENS.POLICY_COPY_SETTINGS.SELECT_FEATURES]: () => require('../../../../pages/workspace/copyPolicySettings/CopyPolicySettingsSelectFeaturesPage').default, + [SCREENS.POLICY_COPY_SETTINGS.CONFIRM]: () => require('../../../../pages/workspace/copyPolicySettings/CopyPolicySettingsConfirmPage').default, +}); + const TaskModalStackNavigator = createModalStackNavigator({ [SCREENS.TASK.TITLE]: () => require('../../../../pages/tasks/TaskTitlePage').default, [SCREENS.TASK.ASSIGNEE]: () => require('../../../../pages/tasks/TaskAssigneeSelectorModal').default, @@ -1240,6 +1247,7 @@ export { WalletStatementStackNavigator, WorkspaceConfirmationModalStackNavigator, WorkspaceDuplicateModalStackNavigator, + PolicyCopySettingsModalStackNavigator, WorkspacesDomainModalStackNavigator, MultifactorAuthenticationStackNavigator, }; diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx index d85f3fabf03b..de165e8af48f 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx @@ -330,6 +330,10 @@ function RightModalNavigator({navigation, route}: RightModalNavigatorProps) { name={SCREENS.RIGHT_MODAL.WORKSPACE_DUPLICATE} component={ModalStackNavigators.WorkspaceDuplicateModalStackNavigator} /> + = [SCREENS.WORKSPACES_LIST]: [ SCREENS.WORKSPACE_DUPLICATE.SELECT_FEATURES, SCREENS.WORKSPACE_DUPLICATE.ROOT, + SCREENS.POLICY_COPY_SETTINGS.ROOT, + SCREENS.POLICY_COPY_SETTINGS.SELECT_FEATURES, + SCREENS.POLICY_COPY_SETTINGS.CONFIRM, SCREENS.WORKSPACES_VERIFY_DOMAIN, SCREENS.WORKSPACES_DOMAIN_VERIFIED, SCREENS.WORKSPACES_ADD_DOMAIN, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index fa161f0064fd..48604e12d3ff 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -1615,6 +1615,13 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE_DUPLICATE.SELECT_FEATURES]: ROUTES.WORKSPACE_DUPLICATE_SELECT_FEATURES.route, }, }, + [SCREENS.RIGHT_MODAL.POLICY_COPY_SETTINGS]: { + screens: { + [SCREENS.POLICY_COPY_SETTINGS.ROOT]: ROUTES.POLICY_COPY_SETTINGS.route, + [SCREENS.POLICY_COPY_SETTINGS.SELECT_FEATURES]: ROUTES.POLICY_COPY_SETTINGS_SELECT_FEATURES.route, + [SCREENS.POLICY_COPY_SETTINGS.CONFIRM]: ROUTES.POLICY_COPY_SETTINGS_CONFIRM.route, + }, + }, [SCREENS.RIGHT_MODAL.NEW_TASK]: { screens: { [SCREENS.NEW_TASK.ROOT]: ROUTES.NEW_TASK.route, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 78f60d770dee..f107da38d49a 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -2233,6 +2233,18 @@ type WorkspaceDuplicateNavigatorParamList = { }; }; +type PolicyCopySettingsNavigatorParamList = { + [SCREENS.POLICY_COPY_SETTINGS.ROOT]: { + policyID: string; + }; + [SCREENS.POLICY_COPY_SETTINGS.SELECT_FEATURES]: { + policyID: string; + }; + [SCREENS.POLICY_COPY_SETTINGS.CONFIRM]: { + policyID: string; + }; +}; + type NewTaskNavigatorParamList = { [SCREENS.NEW_TASK.ROOT]: { // eslint-disable-next-line no-restricted-syntax -- `backTo` usages in this file are legacy. Do not add new `backTo` params to screens. See contributingGuides/NAVIGATION.md @@ -2517,6 +2529,7 @@ type RightModalNavigatorParamList = { [SCREENS.RIGHT_MODAL.MONEY_REQUEST]: NavigatorScreenParams; [SCREENS.RIGHT_MODAL.WORKSPACE_CONFIRMATION]: NavigatorScreenParams; [SCREENS.RIGHT_MODAL.WORKSPACE_DUPLICATE]: NavigatorScreenParams; + [SCREENS.RIGHT_MODAL.POLICY_COPY_SETTINGS]: NavigatorScreenParams; [SCREENS.RIGHT_MODAL.NEW_TASK]: NavigatorScreenParams; [SCREENS.RIGHT_MODAL.TEACHERS_UNITE]: NavigatorScreenParams; [SCREENS.RIGHT_MODAL.TASK_DETAILS]: NavigatorScreenParams; @@ -3376,6 +3389,7 @@ export type { MigratedUserModalNavigatorParamList, WorkspaceConfirmationNavigatorParamList, WorkspaceDuplicateNavigatorParamList, + PolicyCopySettingsNavigatorParamList, TwoFactorAuthNavigatorParamList, ScheduleCallParamList, TestDriveModalNavigatorParamList, diff --git a/src/pages/workspace/copyPolicySettings/CopyPolicySettingsConfirmPage.tsx b/src/pages/workspace/copyPolicySettings/CopyPolicySettingsConfirmPage.tsx new file mode 100644 index 000000000000..68ba8a92a7d0 --- /dev/null +++ b/src/pages/workspace/copyPolicySettings/CopyPolicySettingsConfirmPage.tsx @@ -0,0 +1,7 @@ +function CopyPolicySettingsConfirmPage() { + return null; +} + +CopyPolicySettingsConfirmPage.displayName = 'CopyPolicySettingsConfirmPage'; + +export default CopyPolicySettingsConfirmPage; diff --git a/src/pages/workspace/copyPolicySettings/CopyPolicySettingsSelectFeaturesPage.tsx b/src/pages/workspace/copyPolicySettings/CopyPolicySettingsSelectFeaturesPage.tsx new file mode 100644 index 000000000000..51ea6c767056 --- /dev/null +++ b/src/pages/workspace/copyPolicySettings/CopyPolicySettingsSelectFeaturesPage.tsx @@ -0,0 +1,7 @@ +function CopyPolicySettingsSelectFeaturesPage() { + return null; +} + +CopyPolicySettingsSelectFeaturesPage.displayName = 'CopyPolicySettingsSelectFeaturesPage'; + +export default CopyPolicySettingsSelectFeaturesPage; diff --git a/src/pages/workspace/copyPolicySettings/CopyPolicySettingsSelectWorkspacesPage.tsx b/src/pages/workspace/copyPolicySettings/CopyPolicySettingsSelectWorkspacesPage.tsx new file mode 100644 index 000000000000..419265f184b1 --- /dev/null +++ b/src/pages/workspace/copyPolicySettings/CopyPolicySettingsSelectWorkspacesPage.tsx @@ -0,0 +1,7 @@ +function CopyPolicySettingsSelectWorkspacesPage() { + return null; +} + +CopyPolicySettingsSelectWorkspacesPage.displayName = 'CopyPolicySettingsSelectWorkspacesPage'; + +export default CopyPolicySettingsSelectWorkspacesPage; diff --git a/src/types/onyx/CopyPolicySettings.ts b/src/types/onyx/CopyPolicySettings.ts new file mode 100644 index 000000000000..4507c6aa9181 --- /dev/null +++ b/src/types/onyx/CopyPolicySettings.ts @@ -0,0 +1,26 @@ +import type {Errors} from './OnyxCommon'; + +/** Onyx state of the Copy Policy Settings (bulk workspace edits) flow */ +type CopyPolicySettings = { + /** The source policy ID we're copying settings FROM */ + sourcePolicyID?: string; + + /** The list of target policy IDs we're copying settings TO */ + targetPolicyIDs?: string[]; + + /** Which feature parts are selected for copying */ + parts?: string[]; + + /** + * Which step of the copy is happening in the backend + * - `loading`: copy in progress + * - `complete`: backend finished + * - undefined: copy hasn't started yet (e.g. user is still selecting features) + */ + currentStep?: 'loading' | 'complete' | undefined; + + /** Error state */ + errors?: Errors; +}; + +export default CopyPolicySettings; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 919a718afcf5..4b63957536dd 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -37,6 +37,7 @@ import type { } from './CardFeeds'; import type CardOnWaitlist from './CardOnWaitlist'; import type CodingRuleMatchingTransaction from './CodingRuleMatchingTransaction'; +import type CopyPolicySettings from './CopyPolicySettings'; import type {CorpayFields, CorpayFormField} from './CorpayFields'; import type {CorpayOnboardingFields} from './CorpayOnboardingFields'; import type Credentials from './Credentials'; @@ -219,6 +220,7 @@ export type { Domain, Download, DuplicateWorkspace, + CopyPolicySettings, WorkspaceCardsList, ExpenseRule, ExpensifyCardSettings,