Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2617,13 +2617,23 @@ const CONST = {
AUTO_CREATE_ENTITIES: 'autoCreateEntities',
APPROVAL_ACCOUNT: 'approvalAccount',
CUSTOM_FORM_ID_OPTIONS: 'customFormIDOptions',
TOKEN_INPUT_STEP_NAMES: ['1', '2', '3', '4', '5'],
TOKEN_INPUT_STEP_KEYS: {
0: 'installBundle',
1: 'enableTokenAuthentication',
2: 'enableSoapServices',
3: 'createAccessToken',
4: 'enterCredentials',
TOKEN_INPUT: {
STEP_INDEX_LIST: ['1', '2', '3', '4'],
PAGE_NAME: {
INSTALL: 'install',
AUTHENTICATION: 'authentication',
SOAP: 'soap',
ACCESS_TOKEN: 'access-token',
CREDENTIALS: 'credentials',
},
CREDENTIALS_PAGE_INDEX: 4,
STEP_KEYS: {
install: 'installBundle',
authentication: 'enableTokenAuthentication',
soap: 'enableSoapServices',
'access-token': 'createAccessToken',
credentials: 'enterCredentials',
},
},
IMPORT_CUSTOM_FIELDS: {
CUSTOM_SEGMENTS: 'customSegments',
Expand Down
9 changes: 7 additions & 2 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3368,8 +3368,13 @@ const ROUTES = {
getRoute: (policyID: string) => `workspaces/${policyID}/accounting/netsuite/existing-connections` as const,
},
POLICY_ACCOUNTING_NETSUITE_TOKEN_INPUT: {
route: 'workspaces/:policyID/accounting/netsuite/token-input',
getRoute: (policyID: string) => `workspaces/${policyID}/accounting/netsuite/token-input` as const,
route: 'workspaces/:policyID/accounting/netsuite/token-input/:subPage',
getRoute: (policyID: string | undefined, subPage: string) => {
if (!policyID) {
Log.warn('Invalid policyID is used to build the POLICY_ACCOUNTING_NETSUITE_TOKEN_INPUT route');
}
return `workspaces/${policyID}/accounting/netsuite/token-input/${subPage}` as const;
},
},
POLICY_ACCOUNTING_NETSUITE_IMPORT: {
route: 'workspaces/:policyID/accounting/netsuite/import',
Expand Down
5 changes: 3 additions & 2 deletions src/components/ConnectToNetSuiteFlow/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type {AnchorPosition} from '@styles/index';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import {getInitialSubPageForNetsuiteTokenInput} from '@pages/workspace/accounting/netsuite/utils';
import type {ConnectToNetSuiteFlowProps} from './types';

function ConnectToNetSuiteFlow({policyID}: ConnectToNetSuiteFlowProps) {
Expand All @@ -37,7 +38,7 @@ function ConnectToNetSuiteFlow({policyID}: ConnectToNetSuiteFlowProps) {
icon: Expensicons.LinkCopy,
text: translate('workspace.common.createNewConnection'),
onSelected: () => {
Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_TOKEN_INPUT.getRoute(policyID));
Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_TOKEN_INPUT.getRoute(policyID, getInitialSubPageForNetsuiteTokenInput(policy)));
setIsReuseConnectionsPopoverOpen(false);
},
},
Expand All @@ -53,7 +54,7 @@ function ConnectToNetSuiteFlow({policyID}: ConnectToNetSuiteFlowProps) {

useEffect(() => {
if (shouldGoToCredentialsPage || !hasPoliciesConnectedToNetSuite) {
Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_TOKEN_INPUT.getRoute(policyID));
Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_TOKEN_INPUT.getRoute(policyID, getInitialSubPageForNetsuiteTokenInput(policy)));
return;
}
setIsReuseConnectionsPopoverOpen(true);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,56 +1,50 @@
import React, {useRef} from 'react';
import type {ComponentType, ForwardedRef} from 'react';
import React from 'react';
import {View} from 'react-native';
import ConnectionLayout from '@components/ConnectionLayout';
import InteractiveStepSubHeader from '@components/InteractiveStepSubHeader';
import type {InteractiveStepSubHeaderHandle} from '@components/InteractiveStepSubHeader';
import useSubStep from '@hooks/useSubStep';
import InteractiveStepSubPageHeader from '@components/InteractiveStepSubPageHeader';
import useSubPage from '@hooks/useSubPage';
import useThemeStyles from '@hooks/useThemeStyles';
import {isAuthenticationError} from '@libs/actions/connections';
import Navigation from '@libs/Navigation/Navigation';
import type {SubStepWithPolicy} from '@pages/workspace/accounting/netsuite/types';
import type {CustomSubPageTokenInputProps} from '@pages/workspace/accounting/netsuite/types';
import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections';
import withPolicyConnections from '@pages/workspace/withPolicyConnections';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import NetSuiteTokenInputForm from './substeps/NetSuiteTokenInputForm';
import NetSuiteTokenSetupContent from './substeps/NetSuiteTokenSetupContent';
import NetSuiteTokenInputForm from './subPages/NetSuiteTokenInputForm';
import NetSuiteTokenSetupContent from './subPages/NetSuiteTokenSetupContent';

const staticContentSteps = Array<ComponentType<SubStepWithPolicy>>(4).fill(NetSuiteTokenSetupContent);
const tokenInputSteps: Array<ComponentType<SubStepWithPolicy>> = [...staticContentSteps, NetSuiteTokenInputForm];
const pages = [
{pageName: CONST.NETSUITE_CONFIG.TOKEN_INPUT.PAGE_NAME.INSTALL, component: NetSuiteTokenSetupContent},
{pageName: CONST.NETSUITE_CONFIG.TOKEN_INPUT.PAGE_NAME.AUTHENTICATION, component: NetSuiteTokenSetupContent},
{pageName: CONST.NETSUITE_CONFIG.TOKEN_INPUT.PAGE_NAME.SOAP, component: NetSuiteTokenSetupContent},
{pageName: CONST.NETSUITE_CONFIG.TOKEN_INPUT.PAGE_NAME.ACCESS_TOKEN, component: NetSuiteTokenSetupContent},
{pageName: CONST.NETSUITE_CONFIG.TOKEN_INPUT.PAGE_NAME.CREDENTIALS, component: NetSuiteTokenInputForm},
];

function NetSuiteTokenInputPage({policy}: WithPolicyConnectionsProps) {
function NetSuiteTokenInputPage({policy, route}: WithPolicyConnectionsProps) {
const policyID = policy?.id;
const styles = useThemeStyles();
const ref: ForwardedRef<InteractiveStepSubHeaderHandle> = useRef(null);

const hasAuthError = isAuthenticationError(policy, CONST.POLICY.CONNECTIONS.NAME.NETSUITE);

const submit = () => {
Navigation.dismissModal();
};

const {
componentToRender: SubStep,
isEditing,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed isEditing because both NetSuiteTokenSetupContent and NetSuiteTokenInputForm don't use it.

nextScreen,
prevScreen,
screenIndex,
moveTo,
} = useSubStep<SubStepWithPolicy>({bodyContent: tokenInputSteps, startFrom: hasAuthError ? 4 : 0, onFinished: submit});
const {CurrentPage, nextPage, prevPage, pageIndex, moveTo, currentPageName} = useSubPage<CustomSubPageTokenInputProps>({
pages,
onFinished: submit,
Comment thread
bernhardoj marked this conversation as resolved.
buildRoute: (pageName) => ROUTES.POLICY_ACCOUNTING_NETSUITE_TOKEN_INPUT.getRoute(route.params.policyID, pageName),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use policy?.id instead of route.params.policyID?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

policy?.id can be undefined when the onyx is loading.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If so I think we should pass policyID to NetSuiteTokenInputPage instead of the whole route data

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All react-navigation page/screen have route props

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay I got it. I was mistaken for your other PR.

});

const handleBackButtonPress = () => {
if (screenIndex === 0) {
if (pageIndex === 0) {
Navigation.goBack();
return;
}
ref.current?.movePrevious();
prevScreen();
};

const handleNextScreen = () => {
ref.current?.moveNext();
nextScreen();
prevPage();
};

const shouldPageBeBlocked = !isEmptyObject(policy?.connections?.[CONST.POLICY.CONNECTIONS.NAME.NETSUITE]) && !hasAuthError;
Expand All @@ -68,20 +62,20 @@ function NetSuiteTokenInputPage({policy}: WithPolicyConnectionsProps) {
onBackButtonPress={handleBackButtonPress}
shouldLoadForEmptyConnection={isEmptyObject(policy?.connections?.[CONST.POLICY.CONNECTIONS.NAME.NETSUITE])}
shouldBeBlocked={shouldPageBeBlocked}
shouldUseScrollView={SubStep !== NetSuiteTokenInputForm}
shouldUseScrollView={CurrentPage !== NetSuiteTokenInputForm}
>
<View style={[styles.ph5, styles.mb3, styles.mt3, {height: CONST.BANK_ACCOUNT.STEPS_HEADER_HEIGHT}]}>
<InteractiveStepSubHeader
ref={ref}
startStepIndex={screenIndex}
stepNames={CONST.NETSUITE_CONFIG.TOKEN_INPUT_STEP_NAMES}
<InteractiveStepSubPageHeader
currentStepIndex={pageIndex}
stepNames={CONST.NETSUITE_CONFIG.TOKEN_INPUT.STEP_INDEX_LIST}
onStepSelected={moveTo}
/>
</View>
<SubStep
isEditing={isEditing}
onNext={handleNextScreen}
<CurrentPage
isEditing={false}
onNext={nextPage}
onMove={moveTo}
screenIndex={screenIndex}
currentPageName={currentPageName}
policyID={policyID}
/>
</ConnectionLayout>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ import {connectPolicyToNetSuite} from '@libs/actions/connections/NetSuiteCommand
import {isMobileSafari} from '@libs/Browser';
import {addErrorMessage} from '@libs/ErrorUtils';
import Parser from '@libs/Parser';
import type {SubStepWithPolicy} from '@pages/workspace/accounting/netsuite/types';
import type {CustomSubPageTokenInputProps} from '@pages/workspace/accounting/netsuite/types';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import INPUT_IDS from '@src/types/form/NetSuiteTokenInputForm';

function NetSuiteTokenInputForm({onNext, policyID}: SubStepWithPolicy) {
function NetSuiteTokenInputForm({onNext, policyID}: CustomSubPageTokenInputProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const {inputCallbackRef} = useAutoFocusInput();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Parser from '@libs/Parser';
import type {SubStepWithPolicy} from '@pages/workspace/accounting/netsuite/types';
import type {CustomSubPageTokenInputProps} from '@pages/workspace/accounting/netsuite/types';
import CONST from '@src/CONST';
import type {TranslationPaths} from '@src/languages/types';

function NetSuiteTokenSetupContent({onNext, screenIndex}: SubStepWithPolicy) {
function NetSuiteTokenSetupContent({onNext, currentPageName}: CustomSubPageTokenInputProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();

const stepKeys = CONST.NETSUITE_CONFIG.TOKEN_INPUT_STEP_KEYS;
const currentStepKey = stepKeys[(screenIndex ?? 0) as keyof typeof stepKeys];
const stepKeys = CONST.NETSUITE_CONFIG.TOKEN_INPUT.STEP_KEYS;
const currentStepKey = stepKeys[currentPageName as keyof typeof stepKeys];

const titleKey = `workspace.netsuite.tokenInput.formSteps.${currentStepKey}.title` as TranslationPaths;
const description = `workspace.netsuite.tokenInput.formSteps.${currentStepKey}.description` as TranslationPaths;
Expand Down
5 changes: 3 additions & 2 deletions src/pages/workspace/accounting/netsuite/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type {ValueOf} from 'type-fest';
import type {MenuItemProps} from '@components/MenuItem';
import type {OfflineWithFeedbackProps} from '@components/OfflineWithFeedback';
import type {SelectorType} from '@components/SelectionScreen';
import type {SubPageProps} from '@hooks/useSubPage/types';
import type {SubStepProps} from '@hooks/useSubStep/types';
import type {ToggleSettingOptionRowProps} from '@pages/workspace/workflows/ToggleSettingsOptionRow';
import type CONST from '@src/CONST';
Expand Down Expand Up @@ -106,7 +107,7 @@ type CustomListSelectorType = SelectorType & {
id: string;
};

type SubStepWithPolicy = SubStepProps & {policyID: string | undefined};
type CustomSubPageTokenInputProps = SubPageProps & {policyID: string | undefined};

export type {
MenuItem,
Expand All @@ -118,5 +119,5 @@ export type {
CustomFieldSubStepWithPolicy,
CustomListSelectorType,
ExtendedMenuItemWithSubscribedSettings,
SubStepWithPolicy,
CustomSubPageTokenInputProps,
};
9 changes: 9 additions & 0 deletions src/pages/workspace/accounting/netsuite/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import type {ValueOf} from 'type-fest';
import {canUseProvincialTaxNetSuite, canUseTaxNetSuite} from '@libs/PolicyUtils';
import CONST from '@src/CONST';
import type {NetSuiteConnectionConfig, NetSuiteSubsidiary} from '@src/types/onyx/Policy';
import {isAuthenticationError} from '@libs/actions/connections';
import type Policy from '@src/types/onyx/Policy';
import type {OnyxEntry} from 'react-native-onyx';

function shouldHideReimbursedReportsSection(config?: NetSuiteConnectionConfig) {
return config?.reimbursableExpensesExportDestination === CONST.NETSUITE_EXPORT_DESTINATION.JOURNAL_ENTRY;
Expand Down Expand Up @@ -73,6 +76,11 @@ function getImportCustomFieldsSettings(importField: ValueOf<typeof CONST.NETSUIT
return data.map((_, index) => `${importField}_${index}`);
}

function getInitialSubPageForNetsuiteTokenInput(policy: OnyxEntry<Policy>) {
const hasAuthError = isAuthenticationError(policy, CONST.POLICY.CONNECTIONS.NAME.NETSUITE);
return hasAuthError ? CONST.NETSUITE_CONFIG.TOKEN_INPUT.PAGE_NAME.CREDENTIALS : CONST.NETSUITE_CONFIG.TOKEN_INPUT.PAGE_NAME.INSTALL;
}

export {
shouldHideReimbursedReportsSection,
shouldHideReportsExportTo,
Expand All @@ -89,4 +97,5 @@ export {
shouldHideTaxPostingAccountSelect,
shouldHideExportForeignCurrencyAmount,
getImportCustomFieldsSettings,
getInitialSubPageForNetsuiteTokenInput,
};
3 changes: 2 additions & 1 deletion src/pages/workspace/accounting/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject';
import type IconAsset from '@src/types/utils/IconAsset';
import {
getImportCustomFieldsSettings,
getInitialSubPageForNetsuiteTokenInput,
shouldHideCustomFormIDOptions,
shouldHideExportForeignCurrencyAmount,
shouldHideExportJournalsTo,
Expand Down Expand Up @@ -221,7 +222,7 @@ function getAccountingIntegrationData(
integrationAlias: CONST.UPGRADE_FEATURE_INTRO_MAPPING.netsuite.alias,
backToAfterWorkspaceUpgradeRoute: integrationToDisconnect
? ROUTES.POLICY_ACCOUNTING.getRoute(policyID, connectionName, integrationToDisconnect, shouldDisconnectIntegrationBeforeConnecting)
: ROUTES.POLICY_ACCOUNTING_NETSUITE_TOKEN_INPUT.getRoute(policyID),
: ROUTES.POLICY_ACCOUNTING_NETSUITE_TOKEN_INPUT.getRoute(policyID, getInitialSubPageForNetsuiteTokenInput(policy)),
},
pendingFields: {...netsuiteConfig?.pendingFields, ...policy?.connections?.netsuite?.config?.pendingFields, ...policy?.connections?.netsuite?.options?.config?.pendingFields},
errorFields: {...netsuiteConfig?.errorFields, ...policy?.connections?.netsuite?.config?.errorFields, ...policy?.connections?.netsuite?.options?.config?.errorFields},
Expand Down
Loading