Skip to content

Commit f96628b

Browse files
authored
Merge pull request Expensify#87273 from mananjadhav/mj-83832-migrate-workspace-categories-import
2 parents 1c4b3e5 + 578419d commit f96628b

12 files changed

Lines changed: 88 additions & 48 deletions

File tree

src/ROUTES.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,14 @@ const DYNAMIC_ROUTES = {
236236
path: 'workspace-address',
237237
entryScreens: [SCREENS.WORKSPACE.PROFILE],
238238
},
239+
WORKSPACE_CATEGORIES_IMPORT: {
240+
path: 'import',
241+
entryScreens: [SCREENS.WORKSPACE.CATEGORIES],
242+
},
243+
WORKSPACE_CATEGORIES_IMPORTED: {
244+
path: 'imported',
245+
entryScreens: [SCREENS.WORKSPACE.CATEGORIES],
246+
},
239247
WORKSPACE_INVITE: {
240248
path: 'invite',
241249
entryScreens: [SCREENS.WORKSPACE.PROFILE, SCREENS.WORKSPACE.MEMBERS],
@@ -2272,14 +2280,6 @@ const ROUTES = {
22722280
route: 'workspaces/:policyID/categories/settings',
22732281
getRoute: (policyID: string) => `workspaces/${policyID}/categories/settings` as const,
22742282
},
2275-
WORKSPACE_CATEGORIES_IMPORT: {
2276-
route: 'workspaces/:policyID/categories/import',
2277-
getRoute: (policyID: string) => `workspaces/${policyID}/categories/import` as const,
2278-
},
2279-
WORKSPACE_CATEGORIES_IMPORTED: {
2280-
route: 'workspaces/:policyID/categories/imported',
2281-
getRoute: (policyID: string) => `workspaces/${policyID}/categories/imported` as const,
2282-
},
22832283
WORKSPACE_CATEGORY_CREATE: {
22842284
route: 'workspaces/:policyID/categories/new',
22852285
getRoute: (policyID: string) => `workspaces/${policyID}/categories/new` as const,

src/SCREENS.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -778,8 +778,8 @@ const SCREENS = {
778778
CATEGORY_REQUIRE_ITEMIZED_RECEIPTS_OVER: 'Category_Require_Itemized_Receipts_Over',
779779
CATEGORY_REQUIRED_FIELDS: 'Category_Required_Fields',
780780
CATEGORIES_SETTINGS: 'Categories_Settings',
781-
CATEGORIES_IMPORT: 'Categories_Import',
782-
CATEGORIES_IMPORTED: 'Categories_Imported',
781+
DYNAMIC_CATEGORIES_IMPORT: 'Dynamic_Categories_Import',
782+
DYNAMIC_CATEGORIES_IMPORTED: 'Dynamic_Categories_Imported',
783783
MORE_FEATURES: 'Workspace_More_Features',
784784
MEMBER_DETAILS: 'Workspace_Member_Details',
785785
MEMBER_DETAILS_ROLE: 'Workspace_Member_Details_Role',

src/components/ImportSpreadsheet.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,14 @@ type ImportSpreadsheetProps = {
3535
// The route to navigate to after the file import is completed.
3636
goTo: Routes;
3737

38+
// If true, replace the current route after import instead of pushing on top.
39+
shouldForceReplaceNavigation?: boolean;
40+
3841
/** Whether the spreadsheet is importing multi-level tags */
3942
isImportingMultiLevelTags?: boolean;
4043
};
4144

42-
function ImportSpreadsheet({backTo, goTo, isImportingMultiLevelTags}: ImportSpreadsheetProps) {
45+
function ImportSpreadsheet({backTo, goTo, shouldForceReplaceNavigation = false, isImportingMultiLevelTags}: ImportSpreadsheetProps) {
4346
const [importedSpreadsheet] = useOnyx(ONYXKEYS.IMPORTED_SPREADSHEET);
4447
const icons = useMemoizedLazyExpensifyIcons(['SpreadsheetComputer']);
4548
const styles = useThemeStyles();
@@ -145,7 +148,7 @@ function ImportSpreadsheet({backTo, goTo, isImportingMultiLevelTags}: ImportSpre
145148
);
146149
})
147150
.then(() => {
148-
Navigation.navigate(goTo);
151+
Navigation.navigate(goTo, {forceReplace: shouldForceReplaceNavigation});
149152
})
150153
.catch(() => {
151154
showUploadFileError('spreadsheet.importFailedTitle', 'spreadsheet.invalidFileMessage');

src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ const OPTIONS_PER_SCREEN: Partial<Record<Screen, PlatformStackNavigationOptions>
110110
[SCREENS.MULTIFACTOR_AUTHENTICATION.NOT_FOUND]: {
111111
animationTypeForReplace: 'push',
112112
},
113+
[SCREENS.WORKSPACE.DYNAMIC_CATEGORIES_IMPORTED]: {
114+
animationTypeForReplace: 'push',
115+
},
113116
};
114117

115118
/**
@@ -518,8 +521,8 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
518521
[SCREENS.WORKSPACE.DYNAMIC_WORKSPACE_OVERVIEW_ADDRESS]: () => require<ReactComponentModule>('../../../../pages/workspace/WorkspaceOverviewAddressPage').default,
519522
[SCREENS.WORKSPACE.DYNAMIC_WORKSPACE_OVERVIEW_PLAN]: () => require<ReactComponentModule>('../../../../pages/workspace/DynamicWorkspaceOverviewPlanTypePage').default,
520523
[SCREENS.WORKSPACE.CATEGORIES_SETTINGS]: () => require<ReactComponentModule>('../../../../pages/workspace/categories/WorkspaceCategoriesSettingsPage').default,
521-
[SCREENS.WORKSPACE.CATEGORIES_IMPORT]: () => require<ReactComponentModule>('../../../../pages/workspace/categories/ImportCategoriesPage').default,
522-
[SCREENS.WORKSPACE.CATEGORIES_IMPORTED]: () => require<ReactComponentModule>('../../../../pages/workspace/categories/ImportedCategoriesPage').default,
524+
[SCREENS.WORKSPACE.DYNAMIC_CATEGORIES_IMPORT]: () => require<ReactComponentModule>('../../../../pages/workspace/categories/ImportCategoriesPage').default,
525+
[SCREENS.WORKSPACE.DYNAMIC_CATEGORIES_IMPORTED]: () => require<ReactComponentModule>('../../../../pages/workspace/categories/ImportedCategoriesPage').default,
523526
[SCREENS.WORKSPACE.UPGRADE]: () => require<ReactComponentModule>('../../../../pages/workspace/upgrade/WorkspaceUpgradePage').default,
524527
[SCREENS.WORKSPACE.DOWNGRADE]: () => require<ReactComponentModule>('../../../../pages/workspace/downgrade/WorkspaceDowngradePage').default,
525528
[SCREENS.WORKSPACE.PAY_AND_DOWNGRADE]: () => require<ReactComponentModule>('../../../../pages/workspace/downgrade/PayAndDowngradePage').default,

src/libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,22 @@ const combinePathAndSuffix = (basePath: string, suffixWithQuery: string): Route
5454
return `${combinedPath}${mergedQuery}` as Route;
5555
};
5656

57-
/** Adds dynamic route name (with optional query params) to the current URL and returns it */
58-
const createDynamicRoute = (dynamicRouteSuffixWithParams: string): Route => {
57+
/** Adds dynamic route name (with optional query params) to the current URL and returns it
58+
*
59+
* @param dynamicRouteSuffixWithParams - The dynamic route suffix with optional query params
60+
* @param basePath - The base path to use for the dynamic route
61+
*
62+
* @returns The combined dynamic route path and query string
63+
*/
64+
const createDynamicRoute = (dynamicRouteSuffixWithParams: string, basePath?: string): Route => {
5965
const [suffixPath] = splitPathAndQuery(dynamicRouteSuffixWithParams);
6066

6167
if (!suffixPath || !isDynamicRouteSuffix(suffixPath)) {
6268
throw new Error(`The route name ${suffixPath} is not supported in createDynamicRoute`);
6369
}
6470

65-
const activeRoute = Navigation.getActiveRoute();
66-
return combinePathAndSuffix(activeRoute, dynamicRouteSuffixWithParams);
71+
const routePath = basePath ?? Navigation.getActiveRoute();
72+
return combinePathAndSuffix(routePath, dynamicRouteSuffixWithParams);
6773
};
6874

6975
export default createDynamicRoute;

src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,8 @@ const WORKSPACE_TO_RHP: Partial<Record<keyof WorkspaceSplitNavigatorParamList, s
196196
[SCREENS.WORKSPACE.CATEGORIES]: [
197197
SCREENS.WORKSPACE.CATEGORY_CREATE,
198198
SCREENS.WORKSPACE.CATEGORY_SETTINGS,
199-
SCREENS.WORKSPACE.CATEGORIES_IMPORT,
200-
SCREENS.WORKSPACE.CATEGORIES_IMPORTED,
199+
SCREENS.WORKSPACE.DYNAMIC_CATEGORIES_IMPORT,
200+
SCREENS.WORKSPACE.DYNAMIC_CATEGORIES_IMPORTED,
201201
SCREENS.WORKSPACE.CATEGORIES_SETTINGS,
202202
SCREENS.WORKSPACE.CATEGORY_EDIT,
203203
SCREENS.WORKSPACE.CATEGORY_GL_CODE,

src/libs/Navigation/linkingConfig/config.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -994,12 +994,8 @@ const config: LinkingOptions<RootNavigatorParamList>['config'] = {
994994
[SCREENS.WORKSPACE.CATEGORIES_SETTINGS]: {
995995
path: ROUTES.WORKSPACE_CATEGORIES_SETTINGS.route,
996996
},
997-
[SCREENS.WORKSPACE.CATEGORIES_IMPORT]: {
998-
path: ROUTES.WORKSPACE_CATEGORIES_IMPORT.route,
999-
},
1000-
[SCREENS.WORKSPACE.CATEGORIES_IMPORTED]: {
1001-
path: ROUTES.WORKSPACE_CATEGORIES_IMPORTED.route,
1002-
},
997+
[SCREENS.WORKSPACE.DYNAMIC_CATEGORIES_IMPORT]: DYNAMIC_ROUTES.WORKSPACE_CATEGORIES_IMPORT.path,
998+
[SCREENS.WORKSPACE.DYNAMIC_CATEGORIES_IMPORTED]: DYNAMIC_ROUTES.WORKSPACE_CATEGORIES_IMPORTED.path,
1003999
[SCREENS.WORKSPACE.WORKFLOWS_PAYER]: {
10041000
path: ROUTES.WORKSPACE_WORKFLOWS_PAYER.route,
10051001
},

src/libs/Navigation/types.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -434,20 +434,16 @@ type SettingsNavigatorParamList = {
434434
// 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
435435
backTo?: Routes;
436436
};
437-
[SCREENS.WORKSPACE.CATEGORIES_IMPORT]: {
437+
[SCREENS.WORKSPACE.DYNAMIC_CATEGORIES_IMPORT]: {
438438
policyID: string;
439-
// 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
440-
backTo?: Routes;
441439
};
442440
[SCREENS.SETTINGS_CATEGORIES.SETTINGS_CATEGORIES_IMPORT]: {
443441
policyID: string;
444442
// 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
445443
backTo?: Routes;
446444
};
447-
[SCREENS.WORKSPACE.CATEGORIES_IMPORTED]: {
445+
[SCREENS.WORKSPACE.DYNAMIC_CATEGORIES_IMPORTED]: {
448446
policyID: string;
449-
// 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
450-
backTo?: Routes;
451447
};
452448
[SCREENS.SETTINGS_CATEGORIES.SETTINGS_CATEGORIES_IMPORTED]: {
453449
policyID: string;

src/pages/workspace/categories/ImportCategoriesPage.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,31 @@
11
import React from 'react';
22
import ImportSpreadsheet from '@components/ImportSpreadsheet';
3+
import useDynamicBackPath from '@hooks/useDynamicBackPath';
34
import usePolicy from '@hooks/usePolicy';
5+
import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute';
46
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
57
import type {SettingsNavigatorParamList} from '@libs/Navigation/types';
68
import {goBackFromInvalidPolicy, hasAccountingConnections as hasAccountingConnectionsUtil} from '@libs/PolicyUtils';
79
import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
810
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
911
import CONST from '@src/CONST';
10-
import ROUTES from '@src/ROUTES';
12+
import ROUTES, {DYNAMIC_ROUTES} from '@src/ROUTES';
1113
import SCREENS from '@src/SCREENS';
1214
import {isEmptyObject} from '@src/types/utils/EmptyObject';
1315

1416
type ImportCategoriesPageProps =
15-
| PlatformStackScreenProps<SettingsNavigatorParamList, typeof SCREENS.WORKSPACE.CATEGORIES_IMPORT>
17+
| PlatformStackScreenProps<SettingsNavigatorParamList, typeof SCREENS.WORKSPACE.DYNAMIC_CATEGORIES_IMPORT>
1618
| PlatformStackScreenProps<SettingsNavigatorParamList, typeof SCREENS.SETTINGS_CATEGORIES.SETTINGS_CATEGORIES_IMPORT>;
1719

1820
function ImportCategoriesPage({route}: ImportCategoriesPageProps) {
1921
const policyID = route.params.policyID;
20-
const backTo = route.params.backTo;
2122
const policy = usePolicy(policyID);
2223
const hasAccountingConnections = hasAccountingConnectionsUtil(policy);
2324
const isQuickSettingsFlow = route.name === SCREENS.SETTINGS_CATEGORIES.SETTINGS_CATEGORIES_IMPORT;
25+
const backTo = isQuickSettingsFlow && 'backTo' in route.params ? route.params.backTo : undefined;
26+
27+
const workspaceCategoriesListBackPath = useDynamicBackPath(DYNAMIC_ROUTES.WORKSPACE_CATEGORIES_IMPORT.path);
28+
const workspaceGoToImportedPath = createDynamicRoute(DYNAMIC_ROUTES.WORKSPACE_CATEGORIES_IMPORTED.path, ROUTES.WORKSPACE_CATEGORIES.getRoute(policyID));
2429

2530
if (hasAccountingConnections) {
2631
return <NotFoundPage />;
@@ -34,8 +39,9 @@ function ImportCategoriesPage({route}: ImportCategoriesPageProps) {
3439
fullPageNotFoundViewProps={{subtitleKey: isEmptyObject(policy) ? undefined : 'workspace.common.notAuthorized', onLinkPress: goBackFromInvalidPolicy}}
3540
>
3641
<ImportSpreadsheet
37-
backTo={backTo}
38-
goTo={isQuickSettingsFlow ? ROUTES.SETTINGS_CATEGORIES_IMPORTED.getRoute(policyID, backTo) : ROUTES.WORKSPACE_CATEGORIES_IMPORTED.getRoute(policyID)}
42+
backTo={isQuickSettingsFlow ? backTo : workspaceCategoriesListBackPath}
43+
goTo={isQuickSettingsFlow ? ROUTES.SETTINGS_CATEGORIES_IMPORTED.getRoute(policyID, backTo) : workspaceGoToImportedPath}
44+
shouldForceReplaceNavigation={!isQuickSettingsFlow}
3945
/>
4046
</AccessOrNotFoundWrapper>
4147
);

src/pages/workspace/categories/ImportedCategoriesPage.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type {RouteProp} from '@react-navigation/native';
12
import React, {useCallback, useState} from 'react';
23
import HeaderWithBackButton from '@components/HeaderWithBackButton';
34
import type {ColumnRole} from '@components/ImportColumn';
@@ -10,36 +11,37 @@ import useOnyx from '@hooks/useOnyx';
1011
import usePolicy from '@hooks/usePolicy';
1112
import {importPolicyCategories} from '@libs/actions/Policy/Category';
1213
import {findDuplicate, generateColumnNames} from '@libs/importSpreadsheetUtils';
14+
import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute';
1315
import Navigation from '@libs/Navigation/Navigation';
14-
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
1516
import type {SettingsNavigatorParamList} from '@libs/Navigation/types';
1617
import {hasAccountingConnections as hasAccountingConnectionsPolicyUtils, isControlPolicy} from '@libs/PolicyUtils';
1718
import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
1819
import CONST from '@src/CONST';
1920
import ONYXKEYS from '@src/ONYXKEYS';
20-
import ROUTES from '@src/ROUTES';
21+
import ROUTES, {DYNAMIC_ROUTES} from '@src/ROUTES';
2122
import SCREENS from '@src/SCREENS';
2223
import type {Errors} from '@src/types/onyx/OnyxCommon';
2324
import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue';
2425

25-
type ImportedCategoriesPageProps =
26-
| PlatformStackScreenProps<SettingsNavigatorParamList, typeof SCREENS.WORKSPACE.CATEGORIES_IMPORTED>
27-
| PlatformStackScreenProps<SettingsNavigatorParamList, typeof SCREENS.SETTINGS_CATEGORIES.SETTINGS_CATEGORIES_IMPORTED>;
26+
type ImportedCategoriesPageProps = {
27+
route: RouteProp<SettingsNavigatorParamList, typeof SCREENS.WORKSPACE.DYNAMIC_CATEGORIES_IMPORTED | typeof SCREENS.SETTINGS_CATEGORIES.SETTINGS_CATEGORIES_IMPORTED>;
28+
};
2829
function ImportedCategoriesPage({route}: ImportedCategoriesPageProps) {
2930
const {translate} = useLocalize();
3031
const [spreadsheet, spreadsheetMetadata] = useOnyx(ONYXKEYS.IMPORTED_SPREADSHEET);
3132
const [isImportingCategories, setIsImportingCategories] = useState(false);
3233
const {containsHeader = true} = spreadsheet ?? {};
3334
const [isValidationEnabled, setIsValidationEnabled] = useState(false);
3435
const policyID = route.params.policyID;
35-
const backTo = route.params.backTo;
3636
const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`);
3737

3838
const {setIsClosing} = useCloseImportPage();
3939

4040
const policy = usePolicy(policyID);
4141
const columnNames = generateColumnNames(spreadsheet?.data?.length ?? 0);
4242
const isQuickSettingsFlow = route.name === SCREENS.SETTINGS_CATEGORIES.SETTINGS_CATEGORIES_IMPORTED;
43+
const backTo = isQuickSettingsFlow && 'backTo' in route.params ? route.params.backTo : undefined;
44+
const workspaceImportPath = createDynamicRoute(DYNAMIC_ROUTES.WORKSPACE_CATEGORIES_IMPORT.path, ROUTES.WORKSPACE_CATEGORIES.getRoute(policyID));
4345

4446
const getColumnRoles = (): ColumnRole[] => {
4547
const roles = [];
@@ -142,9 +144,7 @@ function ImportedCategoriesPage({route}: ImportedCategoriesPageProps) {
142144
>
143145
<HeaderWithBackButton
144146
title={translate('workspace.categories.importCategories')}
145-
onBackButtonPress={() =>
146-
Navigation.goBack(isQuickSettingsFlow ? ROUTES.SETTINGS_CATEGORIES_IMPORT.getRoute(policyID, backTo) : ROUTES.WORKSPACE_CATEGORIES_IMPORT.getRoute(policyID))
147-
}
147+
onBackButtonPress={() => Navigation.goBack(isQuickSettingsFlow ? ROUTES.SETTINGS_CATEGORIES_IMPORT.getRoute(policyID, backTo) : workspaceImportPath)}
148148
/>
149149
<ImportSpreadsheetColumns
150150
spreadsheetColumns={spreadsheetColumns}

0 commit comments

Comments
 (0)