From 3ffaecec4d6b96e5fafac73f3692f31379fd57b6 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Thu, 7 May 2026 19:32:50 +0100 Subject: [PATCH 1/7] Add Copy Policy Settings routes and screen names Declares POLICY_COPY_SETTINGS, POLICY_COPY_SETTINGS_SELECT_FEATURES, POLICY_COPY_SETTINGS_CONFIRM routes plus the matching screen name constants and RIGHT_MODAL.POLICY_COPY_SETTINGS entry. First slice of scaffolding for the bulk workspace edits flow. --- src/ROUTES.ts | 12 ++++++++++++ src/SCREENS.ts | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 717ccc1bbe6d..18d7ff441f7d 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -2903,6 +2903,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 83801778f079..d6395eabd5f2 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -289,6 +289,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', @@ -514,6 +515,11 @@ const SCREENS = { WORKSPACE_CONFIRMATION: {ROOT: 'Workspace_Confirmation_Root', OWNER_SELECTOR: 'Workspace_Confirmation_Owner_Selector'}, 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', From a6a4e32a6ad87940f016e52fd14e4a8451014187 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Thu, 7 May 2026 19:33:09 +0100 Subject: [PATCH 2/7] Add PolicyCopySettingsNavigatorParamList nav type Defines the param list for the new RHP flow (ROOT, SELECT_FEATURES, CONFIRM) and registers it in RightModalNavigatorParamList. --- src/libs/Navigation/types.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 4de218abacf6..95dc94fbdde1 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -2207,6 +2207,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 @@ -2483,6 +2495,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; @@ -3333,6 +3346,7 @@ export type { MigratedUserModalNavigatorParamList, WorkspaceConfirmationNavigatorParamList, WorkspaceDuplicateNavigatorParamList, + PolicyCopySettingsNavigatorParamList, TwoFactorAuthNavigatorParamList, ScheduleCallParamList, TestDriveModalNavigatorParamList, From 1cf07a9f55ee5eda876db21e381891189c9e19c8 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Thu, 7 May 2026 19:33:43 +0100 Subject: [PATCH 3/7] Register PolicyCopySettings modal stack navigator Adds PolicyCopySettingsModalStackNavigator wired to three stub page components and registers it on RightModalNavigator under SCREENS.RIGHT_MODAL.POLICY_COPY_SETTINGS. Pages are intentionally empty and will be filled in by the follow-up issues. --- .../AppNavigator/ModalStackNavigators/index.tsx | 8 ++++++++ .../AppNavigator/Navigators/RightModalNavigator.tsx | 4 ++++ .../copyPolicySettings/CopyPolicySettingsConfirmPage.tsx | 7 +++++++ .../CopyPolicySettingsSelectFeaturesPage.tsx | 7 +++++++ .../CopyPolicySettingsSelectWorkspacesPage.tsx | 7 +++++++ 5 files changed, 33 insertions(+) create mode 100644 src/pages/workspace/copyPolicySettings/CopyPolicySettingsConfirmPage.tsx create mode 100644 src/pages/workspace/copyPolicySettings/CopyPolicySettingsSelectFeaturesPage.tsx create mode 100644 src/pages/workspace/copyPolicySettings/CopyPolicySettingsSelectWorkspacesPage.tsx diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index f5dcf67b4aa2..165640ef3cc1 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -22,6 +22,7 @@ import type { NewReportWorkspaceSelectionNavigatorParamList, NewTaskNavigatorParamList, ParticipantsNavigatorParamList, + PolicyCopySettingsNavigatorParamList, PrivateNotesNavigatorParamList, ProfileNavigatorParamList, ReferralDetailsNavigatorParamList, @@ -292,6 +293,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, @@ -1198,6 +1205,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 1f82e1378524..40b824167bd0 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx @@ -331,6 +331,10 @@ function RightModalNavigator({navigation, route}: RightModalNavigatorProps) { name={SCREENS.RIGHT_MODAL.WORKSPACE_DUPLICATE} component={ModalStackNavigators.WorkspaceDuplicateModalStackNavigator} /> + Date: Thu, 7 May 2026 19:33:59 +0100 Subject: [PATCH 4/7] Wire Copy Policy Settings into linking config and RHP relations Maps the three new routes to their screens in linkingConfig and adds them to WORKSPACES_LIST_TO_RHP so the RHP slides over the Workspaces list during in-app navigation, deep links, and refreshes. --- .../linkingConfig/RELATIONS/WORKSPACES_LIST_TO_RHP.ts | 3 +++ src/libs/Navigation/linkingConfig/config.ts | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACES_LIST_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACES_LIST_TO_RHP.ts index a40fab3fc819..6d580c0a6377 100644 --- a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACES_LIST_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACES_LIST_TO_RHP.ts @@ -4,6 +4,9 @@ const WORKSPACES_LIST_TO_RHP: Record = [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 1e1d3a40665f..dd45d1462158 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -1619,6 +1619,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, From 0f316f41e4e42c751c6c55bc273f7e8b40e59fbb Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Thu, 7 May 2026 19:34:15 +0100 Subject: [PATCH 5/7] Add COPY_POLICY_SETTINGS Onyx key and CopyPolicySettings type Adds the new Onyx key copyPolicySettings and its type definition, including currentStep ('loading' | 'complete' | undefined) which drives the progress modal state in later issues. --- src/ONYXKEYS.ts | 4 ++++ src/types/onyx/CopyPolicySettings.ts | 26 ++++++++++++++++++++++++++ src/types/onyx/index.ts | 2 ++ 3 files changed, 32 insertions(+) create mode 100644 src/types/onyx/CopyPolicySettings.ts diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index a80e8ccca749..ccec7e098abd 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -557,6 +557,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', @@ -1472,6 +1475,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/types/onyx/CopyPolicySettings.ts b/src/types/onyx/CopyPolicySettings.ts new file mode 100644 index 000000000000..b360b1f04a6f --- /dev/null +++ b/src/types/onyx/CopyPolicySettings.ts @@ -0,0 +1,26 @@ +import type * as OnyxCommon 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?: OnyxCommon.Errors; +}; + +export default CopyPolicySettings; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index adf447f942c3..e44d1bff5b92 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -36,6 +36,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'; @@ -213,6 +214,7 @@ export type { Domain, Download, DuplicateWorkspace, + CopyPolicySettings, WorkspaceCardsList, ExpenseRule, ExpensifyCardSettings, From 0ea35adfb14832184ab6f45808c351b43ce315dc Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Thu, 7 May 2026 19:34:35 +0100 Subject: [PATCH 6/7] Add CopyPolicySettings API params and write commands Defines CopyPolicySettingsParams (sourcePolicyID, policyIDList, parts) and registers COPY_POLICY_SETTINGS and COPY_POLICY_SETTINGS_NOTIFY in WRITE_COMMANDS so the action layer can call them in later issues. --- src/libs/API/parameters/CopyPolicySettingsParams.ts | 11 +++++++++++ src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 4 ++++ 3 files changed, 16 insertions(+) create mode 100644 src/libs/API/parameters/CopyPolicySettingsParams.ts 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 dfbde3571fcd..599d374ad574 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 0c6a1e5b6e52..c2274956c460 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -160,6 +160,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', @@ -960,6 +962,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; From 3dd7ce89c5ac4582a3e6edc19e832662f8ed39ba Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Thu, 7 May 2026 21:01:45 +0100 Subject: [PATCH 7/7] Use named type import in CopyPolicySettings Switches from `import type * as OnyxCommon` to `import type {Errors}` to satisfy the no-restricted-syntax rule that disallows namespace imports from sibling modules. --- src/types/onyx/CopyPolicySettings.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/onyx/CopyPolicySettings.ts b/src/types/onyx/CopyPolicySettings.ts index b360b1f04a6f..4507c6aa9181 100644 --- a/src/types/onyx/CopyPolicySettings.ts +++ b/src/types/onyx/CopyPolicySettings.ts @@ -1,4 +1,4 @@ -import type * as OnyxCommon from './OnyxCommon'; +import type {Errors} from './OnyxCommon'; /** Onyx state of the Copy Policy Settings (bulk workspace edits) flow */ type CopyPolicySettings = { @@ -20,7 +20,7 @@ type CopyPolicySettings = { currentStep?: 'loading' | 'complete' | undefined; /** Error state */ - errors?: OnyxCommon.Errors; + errors?: Errors; }; export default CopyPolicySettings;