diff --git a/src/CONST.ts b/src/CONST.ts index 0297f7bc0d5a..fb1c2a385d89 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1794,6 +1794,11 @@ const CONST = { XERO: 'xero', NETSUITE: 'netsuite', }, + NAME_USER_FRIENDLY: { + netsuite: 'NetSuite', + quickbooksOnline: 'Quickbooks Online', + xero: 'Xero', + }, SYNC_STAGE_NAME: { STARTING_IMPORT_QBO: 'startingImportQBO', STARTING_IMPORT_XERO: 'startingImportXero', diff --git a/src/components/AccountingConnectionConfirmationModal.tsx b/src/components/AccountingConnectionConfirmationModal.tsx new file mode 100644 index 000000000000..c472f215b6df --- /dev/null +++ b/src/components/AccountingConnectionConfirmationModal.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import useLocalize from '@hooks/useLocalize'; +import type {ConnectionName} from '@src/types/onyx/Policy'; +import ConfirmModal from './ConfirmModal'; + +type AccountingConnectionConfirmationModalProps = { + integrationToConnect: ConnectionName; + onConfirm: () => void; + onCancel: () => void; +}; + +function AccountingConnectionConfirmationModal({integrationToConnect, onCancel, onConfirm}: AccountingConnectionConfirmationModalProps) { + const {translate} = useLocalize(); + + return ( + <ConfirmModal + title={translate('workspace.accounting.connectTitle', integrationToConnect)} + isVisible + onConfirm={onConfirm} + onCancel={onCancel} + prompt={translate('workspace.accounting.connectPrompt', integrationToConnect)} + confirmText={translate('workspace.accounting.setup')} + cancelText={translate('common.cancel')} + success + /> + ); +} + +AccountingConnectionConfirmationModal.displayName = 'AccountingConnectionConfirmationModal'; +export default AccountingConnectionConfirmationModal; diff --git a/src/components/ConnectToNetSuiteButton/index.tsx b/src/components/ConnectToNetSuiteButton/index.tsx new file mode 100644 index 000000000000..fc948503a127 --- /dev/null +++ b/src/components/ConnectToNetSuiteButton/index.tsx @@ -0,0 +1,54 @@ +import React, {useState} from 'react'; +import AccountingConnectionConfirmationModal from '@components/AccountingConnectionConfirmationModal'; +import Button from '@components/Button'; +import useLocalize from '@hooks/useLocalize'; +import useNetwork from '@hooks/useNetwork'; +import useThemeStyles from '@hooks/useThemeStyles'; +import {removePolicyConnection} from '@libs/actions/connections'; +import Navigation from '@libs/Navigation/Navigation'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; +import type {ConnectToNetSuiteButtonProps} from './types'; + +function ConnectToNetSuiteButton({policyID, shouldDisconnectIntegrationBeforeConnecting, integrationToDisconnect}: ConnectToNetSuiteButtonProps) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + const {isOffline} = useNetwork(); + + const [isDisconnectModalOpen, setIsDisconnectModalOpen] = useState(false); + + return ( + <> + <Button + onPress={() => { + if (shouldDisconnectIntegrationBeforeConnecting && integrationToDisconnect) { + setIsDisconnectModalOpen(true); + return; + } + + // TODO: Will be updated to new token input page + Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_SUBSIDIARY_SELECTOR.getRoute(policyID)); + }} + text={translate('workspace.accounting.setup')} + style={styles.justifyContentCenter} + small + isDisabled={isOffline} + /> + {shouldDisconnectIntegrationBeforeConnecting && isDisconnectModalOpen && integrationToDisconnect && ( + <AccountingConnectionConfirmationModal + onConfirm={() => { + removePolicyConnection(policyID, integrationToDisconnect); + + // TODO: Will be updated to new token input page + Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_SUBSIDIARY_SELECTOR.getRoute(policyID)); + setIsDisconnectModalOpen(false); + }} + integrationToConnect={CONST.POLICY.CONNECTIONS.NAME.NETSUITE} + onCancel={() => setIsDisconnectModalOpen(false)} + /> + )} + </> + ); +} + +export default ConnectToNetSuiteButton; diff --git a/src/components/ConnectToNetSuiteButton/types.ts b/src/components/ConnectToNetSuiteButton/types.ts new file mode 100644 index 000000000000..0e66b7b15eb6 --- /dev/null +++ b/src/components/ConnectToNetSuiteButton/types.ts @@ -0,0 +1,10 @@ +import type {PolicyConnectionName} from '@src/types/onyx/Policy'; + +type ConnectToNetSuiteButtonProps = { + policyID: string; + shouldDisconnectIntegrationBeforeConnecting?: boolean; + integrationToDisconnect?: PolicyConnectionName; +}; + +// eslint-disable-next-line import/prefer-default-export +export type {ConnectToNetSuiteButtonProps}; diff --git a/src/components/ConnectToQuickbooksOnlineButton/index.native.tsx b/src/components/ConnectToQuickbooksOnlineButton/index.native.tsx index fbca4fbb5dae..bd9b623bcfb4 100644 --- a/src/components/ConnectToQuickbooksOnlineButton/index.native.tsx +++ b/src/components/ConnectToQuickbooksOnlineButton/index.native.tsx @@ -2,9 +2,9 @@ import React, {useRef, useState} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import {WebView} from 'react-native-webview'; +import AccountingConnectionConfirmationModal from '@components/AccountingConnectionConfirmationModal'; import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; import Button from '@components/Button'; -import ConfirmModal from '@components/ConfirmModal'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Modal from '@components/Modal'; @@ -57,19 +57,14 @@ function ConnectToQuickbooksOnlineButton({ isDisabled={isOffline} /> {shouldDisconnectIntegrationBeforeConnecting && integrationToDisconnect && isDisconnectModalOpen && ( - <ConfirmModal - title={translate('workspace.accounting.disconnectTitle', CONST.POLICY.CONNECTIONS.NAME.XERO)} + <AccountingConnectionConfirmationModal onConfirm={() => { removePolicyConnection(policyID, integrationToDisconnect); setIsDisconnectModalOpen(false); setWebViewOpen(true); }} - isVisible + integrationToConnect={CONST.POLICY.CONNECTIONS.NAME.QBO} onCancel={() => setIsDisconnectModalOpen(false)} - prompt={translate('workspace.accounting.disconnectPrompt', CONST.POLICY.CONNECTIONS.NAME.QBO)} - confirmText={translate('workspace.accounting.disconnect')} - cancelText={translate('common.cancel')} - danger /> )} {isWebViewOpen && ( diff --git a/src/components/ConnectToQuickbooksOnlineButton/index.tsx b/src/components/ConnectToQuickbooksOnlineButton/index.tsx index 10c358ad79c0..71f1fba91187 100644 --- a/src/components/ConnectToQuickbooksOnlineButton/index.tsx +++ b/src/components/ConnectToQuickbooksOnlineButton/index.tsx @@ -1,6 +1,6 @@ import React, {useState} from 'react'; +import AccountingConnectionConfirmationModal from '@components/AccountingConnectionConfirmationModal'; import Button from '@components/Button'; -import ConfirmModal from '@components/ConfirmModal'; import useEnvironment from '@hooks/useEnvironment'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; @@ -38,19 +38,14 @@ function ConnectToQuickbooksOnlineButton({policyID, shouldDisconnectIntegrationB small /> {shouldDisconnectIntegrationBeforeConnecting && integrationToDisconnect && isDisconnectModalOpen && ( - <ConfirmModal - title={translate('workspace.accounting.disconnectTitle', CONST.POLICY.CONNECTIONS.NAME.XERO)} - isVisible={isDisconnectModalOpen} + <AccountingConnectionConfirmationModal onConfirm={() => { removePolicyConnection(policyID, integrationToDisconnect); Link.openLink(getQuickBooksOnlineSetupLink(policyID), environmentURL); setIsDisconnectModalOpen(false); }} + integrationToConnect={CONST.POLICY.CONNECTIONS.NAME.QBO} onCancel={() => setIsDisconnectModalOpen(false)} - prompt={translate('workspace.accounting.disconnectPrompt', CONST.POLICY.CONNECTIONS.NAME.QBO)} - confirmText={translate('workspace.accounting.disconnect')} - cancelText={translate('common.cancel')} - danger /> )} </> diff --git a/src/components/ConnectToXeroButton/index.native.tsx b/src/components/ConnectToXeroButton/index.native.tsx index 11cafe2bdfbc..15fe201f2ac9 100644 --- a/src/components/ConnectToXeroButton/index.native.tsx +++ b/src/components/ConnectToXeroButton/index.native.tsx @@ -2,9 +2,9 @@ import React, {useRef, useState} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import {WebView} from 'react-native-webview'; +import AccountingConnectionConfirmationModal from '@components/AccountingConnectionConfirmationModal'; import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; import Button from '@components/Button'; -import ConfirmModal from '@components/ConfirmModal'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Modal from '@components/Modal'; @@ -52,19 +52,14 @@ function ConnectToXeroButton({policyID, session, shouldDisconnectIntegrationBefo isDisabled={isOffline} /> {shouldDisconnectIntegrationBeforeConnecting && isDisconnectModalOpen && integrationToDisconnect && ( - <ConfirmModal - title={translate('workspace.accounting.disconnectTitle', CONST.POLICY.CONNECTIONS.NAME.QBO)} + <AccountingConnectionConfirmationModal onConfirm={() => { removePolicyConnection(policyID, integrationToDisconnect); setIsDisconnectModalOpen(false); setWebViewOpen(true); }} - isVisible + integrationToConnect={CONST.POLICY.CONNECTIONS.NAME.XERO} onCancel={() => setIsDisconnectModalOpen(false)} - prompt={translate('workspace.accounting.disconnectPrompt', CONST.POLICY.CONNECTIONS.NAME.XERO)} - confirmText={translate('workspace.accounting.disconnect')} - cancelText={translate('common.cancel')} - danger /> )} <Modal diff --git a/src/components/ConnectToXeroButton/index.tsx b/src/components/ConnectToXeroButton/index.tsx index 5dd5541dd438..fd8e7919bcb1 100644 --- a/src/components/ConnectToXeroButton/index.tsx +++ b/src/components/ConnectToXeroButton/index.tsx @@ -1,6 +1,6 @@ import React, {useState} from 'react'; +import AccountingConnectionConfirmationModal from '@components/AccountingConnectionConfirmationModal'; import Button from '@components/Button'; -import ConfirmModal from '@components/ConfirmModal'; import useEnvironment from '@hooks/useEnvironment'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; @@ -35,19 +35,14 @@ function ConnectToXeroButton({policyID, shouldDisconnectIntegrationBeforeConnect isDisabled={isOffline} /> {shouldDisconnectIntegrationBeforeConnecting && isDisconnectModalOpen && integrationToDisconnect && ( - <ConfirmModal - title={translate('workspace.accounting.disconnectTitle', CONST.POLICY.CONNECTIONS.NAME.QBO)} - isVisible + <AccountingConnectionConfirmationModal onConfirm={() => { removePolicyConnection(policyID, integrationToDisconnect); Link.openLink(getXeroSetupLink(policyID), environmentURL); setIsDisconnectModalOpen(false); }} + integrationToConnect={CONST.POLICY.CONNECTIONS.NAME.XERO} onCancel={() => setIsDisconnectModalOpen(false)} - prompt={translate('workspace.accounting.disconnectPrompt', CONST.POLICY.CONNECTIONS.NAME.XERO)} - confirmText={translate('workspace.accounting.disconnect')} - cancelText={translate('common.cancel')} - danger /> )} </> diff --git a/src/languages/en.ts b/src/languages/en.ts index a864e70b6189..18de34e385cb 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2435,22 +2435,19 @@ export default { syncNow: 'Sync now', disconnect: 'Disconnect', disconnectTitle: (integration?: ConnectionName): string => { - switch (integration) { - case CONST.POLICY.CONNECTIONS.NAME.QBO: - return 'Disconnect QuickBooks Online'; - case CONST.POLICY.CONNECTIONS.NAME.XERO: - return 'Disconnect Xero'; - default: { - return 'Disconnect integration'; - } - } + const integrationName = integration && CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[integration] ? CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[integration] : 'integration'; + return `Disconnect ${integrationName}`; }, + connectTitle: (integrationToConnect: ConnectionName): string => `Connect ${CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[integrationToConnect] ?? 'accounting integration'}`, + syncError: (integration?: ConnectionName): string => { switch (integration) { case CONST.POLICY.CONNECTIONS.NAME.QBO: return "Can't connect to QuickBooks Online."; case CONST.POLICY.CONNECTIONS.NAME.XERO: return "Can't connect to Xero."; + case CONST.POLICY.CONNECTIONS.NAME.NETSUITE: + return "Can't connect to NetSuite."; default: { return "Can't connect to integration."; } @@ -2469,25 +2466,17 @@ export default { [CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE]: 'Not imported', [CONST.INTEGRATION_ENTITY_MAP_TYPES.REPORT_FIELD]: 'Imported as report fields', }, - disconnectPrompt: (integrationToConnect?: ConnectionName, currentIntegration?: ConnectionName): string => { - switch (integrationToConnect) { - case CONST.POLICY.CONNECTIONS.NAME.QBO: - return 'Are you sure you want to disconnect Xero to set up QuickBooks Online?'; - case CONST.POLICY.CONNECTIONS.NAME.XERO: - return 'Are you sure you want to disconnect QuickBooks Online to set up Xero?'; - default: { - switch (currentIntegration) { - case CONST.POLICY.CONNECTIONS.NAME.QBO: - return 'Are you sure you want to disconnect QuickBooks Online?'; - case CONST.POLICY.CONNECTIONS.NAME.XERO: - return 'Are you sure you want to disconnect Xero?'; - default: { - return 'Are you sure you want to disconnect this integration?'; - } - } - } - } + disconnectPrompt: (currentIntegration?: ConnectionName): string => { + const integrationName = + currentIntegration && CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[currentIntegration] + ? CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[currentIntegration] + : 'this integration'; + return `Are you sure you want to disconnect ${integrationName}?`; }, + connectPrompt: (integrationToConnect: ConnectionName): string => + `Are you sure you want to connect ${ + CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[integrationToConnect] ?? 'this accounting integration' + }? This will remove any existing acounting connections.`, enterCredentials: 'Enter your credentials', connections: { syncStageName: (stage: PolicyConnectionSyncStage) => { diff --git a/src/languages/es.ts b/src/languages/es.ts index 2a11549e7355..43c3ab6b591e 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2437,23 +2437,19 @@ export default { other: 'Otras integraciones', syncNow: 'Sincronizar ahora', disconnect: 'Desconectar', - disconnectTitle: (currentIntegration?: ConnectionName): string => { - switch (currentIntegration) { - case CONST.POLICY.CONNECTIONS.NAME.QBO: - return 'Desconectar QuickBooks Online'; - case CONST.POLICY.CONNECTIONS.NAME.XERO: - return 'Desconectar Xero'; - default: { - return 'Desconectar integración'; - } - } + disconnectTitle: (integration?: ConnectionName): string => { + const integrationName = integration && CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[integration] ? CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[integration] : 'integración'; + return `Desconectar ${integrationName}`; }, + connectTitle: (integrationToConnect: ConnectionName): string => `Conectar ${CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[integrationToConnect] ?? 'accounting integration'}`, syncError: (integration?: ConnectionName): string => { switch (integration) { case CONST.POLICY.CONNECTIONS.NAME.QBO: return 'No se puede conectar a QuickBooks Online.'; case CONST.POLICY.CONNECTIONS.NAME.XERO: - return 'No se puede conectar a Xero'; + return 'No se puede conectar a Xero.'; + case CONST.POLICY.CONNECTIONS.NAME.NETSUITE: + return 'No se puede conectar a NetSuite.'; default: { return 'No se ha podido conectar a la integración.'; } @@ -2472,25 +2468,15 @@ export default { [CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE]: 'No importado', [CONST.INTEGRATION_ENTITY_MAP_TYPES.REPORT_FIELD]: 'Importado como campos de informe', }, - disconnectPrompt: (integrationToConnect?: ConnectionName, currentIntegration?: ConnectionName): string => { - switch (integrationToConnect) { - case CONST.POLICY.CONNECTIONS.NAME.QBO: - return '¿Estás seguro de que quieres desconectar Xero para configurar QuickBooks Online?'; - case CONST.POLICY.CONNECTIONS.NAME.XERO: - return '¿Estás seguro de que quieres desconectar QuickBooks Online para configurar Xero?'; - default: { - switch (currentIntegration) { - case CONST.POLICY.CONNECTIONS.NAME.QBO: - return '¿Estás seguro de que quieres desconectar QuickBooks Online?'; - case CONST.POLICY.CONNECTIONS.NAME.XERO: - return '¿Estás seguro de que quieres desconectar Xero?'; - default: { - return '¿Estás seguro de que quieres desconectar integración?'; - } - } - } - } + disconnectPrompt: (currentIntegration?: ConnectionName): string => { + const integrationName = + currentIntegration && CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[currentIntegration] ? CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[currentIntegration] : 'integración'; + return `¿Estás seguro de que quieres desconectar ${integrationName}?`; }, + connectPrompt: (integrationToConnect: ConnectionName): string => + `¿Estás seguro de que quieres conectar a ${ + CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[integrationToConnect] ?? 'esta integración contable' + }? Esto eliminará cualquier conexión contable existente.`, enterCredentials: 'Ingresa tus credenciales', connections: { syncStageName: (stage: PolicyConnectionSyncStage) => { diff --git a/src/pages/workspace/accounting/PolicyAccountingPage.tsx b/src/pages/workspace/accounting/PolicyAccountingPage.tsx index 3bb63dadaadc..1854003e014d 100644 --- a/src/pages/workspace/accounting/PolicyAccountingPage.tsx +++ b/src/pages/workspace/accounting/PolicyAccountingPage.tsx @@ -5,6 +5,7 @@ import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import CollapsibleSection from '@components/CollapsibleSection'; import ConfirmModal from '@components/ConfirmModal'; +import ConnectToNetSuiteButton from '@components/ConnectToNetSuiteButton'; import ConnectToQuickbooksOnlineButton from '@components/ConnectToQuickbooksOnlineButton'; import ConnectToXeroButton from '@components/ConnectToXeroButton'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; @@ -105,8 +106,7 @@ function accountingIntegrationData( title: translate('workspace.accounting.netsuite'), icon: Expensicons.NetSuiteSquare, setupConnectionButton: ( - // TODO: Will be updated in the Token Input PR - <ConnectToXeroButton + <ConnectToNetSuiteButton policyID={policyID} shouldDisconnectIntegrationBeforeConnecting={isConnectedToIntegration} integrationToDisconnect={integrationToDisconnect} @@ -423,7 +423,7 @@ function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccounting setIsDisconnectModalOpen(false); }} onCancel={() => setIsDisconnectModalOpen(false)} - prompt={translate('workspace.accounting.disconnectPrompt', undefined, connectedIntegration)} + prompt={translate('workspace.accounting.disconnectPrompt', connectedIntegration)} confirmText={translate('workspace.accounting.disconnect')} cancelText={translate('common.cancel')} danger