diff --git a/assets/images/computer.svg b/assets/images/computer.svg new file mode 100644 index 000000000000..9c2628245eb1 --- /dev/null +++ b/assets/images/computer.svg @@ -0,0 +1,216 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/integrationicons/sage-intacct-icon-square.svg b/assets/images/integrationicons/sage-intacct-icon-square.svg new file mode 100644 index 000000000000..33d86259a2d1 --- /dev/null +++ b/assets/images/integrationicons/sage-intacct-icon-square.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/CONST.ts b/src/CONST.ts index fb481eb0724f..233b35e6ac4b 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -601,6 +601,9 @@ const CONST = { ONFIDO_TERMS_OF_SERVICE_URL: 'https://onfido.com/terms-of-service/', LIST_OF_RESTRICTED_BUSINESSES: 'https://community.expensify.com/discussion/6191/list-of-restricted-businesses', TRAVEL_TERMS_URL: `${USE_EXPENSIFY_URL}/travelterms`, + EXPENSIFY_PACKAGE_FOR_SAGE_INTACCT: 'https://www.expensify.com/tools/integrations/downloadPackage', + EXPENSIFY_PACKAGE_FOR_SAGE_INTACCT_FILE_NAME: 'ExpensifyPackageForSageIntacct', + HOW_TO_CONNECT_TO_SAGE_INTACCT: 'https://help.expensify.com/articles/expensify-classic/integrations/accounting-integrations/Sage-Intacct#how-to-connect-to-sage-intacct', PRICING: `https://www.expensify.com/pricing`, // Use Environment.getEnvironmentURL to get the complete URL with port number @@ -1793,11 +1796,13 @@ const CONST = { QBO: 'quickbooksOnline', XERO: 'xero', NETSUITE: 'netsuite', + SAGE_INTACCT: 'intacct', }, NAME_USER_FRIENDLY: { netsuite: 'NetSuite', quickbooksOnline: 'Quickbooks Online', xero: 'Xero', + intacct: 'Sage Intacct', }, SYNC_STAGE_NAME: { STARTING_IMPORT_QBO: 'startingImportQBO', @@ -1846,9 +1851,10 @@ const CONST = { NETSUITE_SYNC_NETSUITE_REIMBURSED_REPORTS: 'netSuiteSyncNetSuiteReimbursedReports', NETSUITE_SYNC_EXPENSIFY_REIMBURSED_REPORTS: 'netSuiteSyncExpensifyReimbursedReports', SAGE_INTACCT_SYNC_CHECK_CONNECTION: 'intacctCheckConnection', + SAGE_INTACCT_SYNC_IMPORT_TITLE: 'intacctImportTitle', SAGE_INTACCT_SYNC_IMPORT_DATA: 'intacctImportData', - SAGE_INTACCT_SYNC_IMPORT_DIMENSIONS: 'intacctImportDimensions', SAGE_INTACCT_SYNC_IMPORT_EMPLOYEES: 'intacctImportEmployees', + SAGE_INTACCT_SYNC_IMPORT_DIMENSIONS: 'intacctImportDimensions', SAGE_INTACCT_SYNC_IMPORT_SYNC_REIMBURSED_REPORTS: 'intacctImportSyncBillPayments', }, SYNC_STAGE_TIMEOUT_MINUTES: 20, diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index dac39249044e..6f94a23acad8 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -526,6 +526,8 @@ const ONYXKEYS = { SUBSCRIPTION_SIZE_FORM_DRAFT: 'subscriptionSizeFormDraft', ISSUE_NEW_EXPENSIFY_CARD_FORM: 'issueNewExpensifyCardForm', ISSUE_NEW_EXPENSIFY_CARD_FORM_DRAFT: 'issueNewExpensifyCardFormDraft', + SAGE_INTACCT_CREDENTIALS_FORM: 'sageIntacctCredentialsForm', + SAGE_INTACCT_CREDENTIALS_FORM_DRAFT: 'sageIntacctCredentialsFormDraft', }, } as const; @@ -587,6 +589,7 @@ type OnyxFormValuesMapping = { [ONYXKEYS.FORMS.NEW_CHAT_NAME_FORM]: FormTypes.NewChatNameForm; [ONYXKEYS.FORMS.SUBSCRIPTION_SIZE_FORM]: FormTypes.SubscriptionSizeForm; [ONYXKEYS.FORMS.ISSUE_NEW_EXPENSIFY_CARD_FORM]: FormTypes.IssueNewExpensifyCardForm; + [ONYXKEYS.FORMS.SAGE_INTACCT_CREDENTIALS_FORM]: FormTypes.SageIntactCredentialsForm; }; type OnyxFormDraftValuesMapping = { diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 85792fcff97f..33eb78dc300d 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -940,6 +940,18 @@ const ROUTES = { route: 'restricted-action/workspace/:policyID', getRoute: (policyID: string) => `restricted-action/workspace/${policyID}` as const, }, + POLICY_ACCOUNTING_SAGE_INTACCT_PREREQUISITES: { + route: 'settings/workspaces/:policyID/accounting/sage-intacct/prerequisites', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/sage-intacct/prerequisites` as const, + }, + POLICY_ACCOUNTING_SAGE_INTACCT_ENTER_CREDENTIALS: { + route: 'settings/workspaces/:policyID/accounting/sage-intacct/enter-credentials', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/sage-intacct/enter-credentials` as const, + }, + POLICY_ACCOUNTING_SAGE_INTACCT_EXISTING_CONNECTIONS: { + route: 'settings/workspaces/:policyID/accounting/sage-intacct/existing-connections', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/sage-intacct/existing-connections` as const, + }, } as const; /** diff --git a/src/SCREENS.ts b/src/SCREENS.ts index e277e88b338e..1807c9bb0bab 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -273,6 +273,9 @@ const SCREENS = { XERO_BILL_PAYMENT_ACCOUNT_SELECTOR: 'Policy_Accounting_Xero_Bill_Payment_Account_Selector', XERO_EXPORT_BANK_ACCOUNT_SELECT: 'Policy_Accounting_Xero_Export_Bank_Account_Select', NETSUITE_SUBSIDIARY_SELECTOR: 'Policy_Accounting_Net_Suite_Subsidiary_Selector', + SAGE_INTACCT_PREREQUISITES: 'Policy_Accounting_Sage_Intacct_Prerequisites', + ENTER_SAGE_INTACCT_CREDENTIALS: 'Policy_Enter_Sage_Intacct_Credentials', + EXISTING_SAGE_INTACCT_CONNECTIONS: 'Policy_Existing_Sage_Intacct_Connections', }, INITIAL: 'Workspace_Initial', PROFILE: 'Workspace_Profile', diff --git a/src/components/ConnectToSageIntacctButton/index.tsx b/src/components/ConnectToSageIntacctButton/index.tsx new file mode 100644 index 000000000000..460647838ec3 --- /dev/null +++ b/src/components/ConnectToSageIntacctButton/index.tsx @@ -0,0 +1,128 @@ +import React, {useRef, useState} from 'react'; +import type {View} from 'react-native'; +import AccountingConnectionConfirmationModal from '@components/AccountingConnectionConfirmationModal'; +import Button from '@components/Button'; +import * as Expensicons from '@components/Icon/Expensicons'; +import PopoverMenu from '@components/PopoverMenu'; +import useLocalize from '@hooks/useLocalize'; +import useNetwork from '@hooks/useNetwork'; +import useThemeStyles from '@hooks/useThemeStyles'; +import useWindowDimensions from '@hooks/useWindowDimensions'; +import {removePolicyConnection} from '@libs/actions/connections'; +import {getPoliciesConnectedToSageIntacct} from '@libs/actions/Policy/Policy'; +import Navigation from '@libs/Navigation/Navigation'; +import type {AnchorPosition} from '@styles/index'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; +import type {PolicyConnectionName} from '@src/types/onyx/Policy'; + +type ConnectToSageIntacctButtonProps = { + policyID: string; + shouldDisconnectIntegrationBeforeConnecting?: boolean; + integrationToDisconnect?: PolicyConnectionName; +}; + +function ConnectToSageIntacctButton({policyID, shouldDisconnectIntegrationBeforeConnecting, integrationToDisconnect}: ConnectToSageIntacctButtonProps) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + const {isOffline} = useNetwork(); + + const [isDisconnectModalOpen, setIsDisconnectModalOpen] = useState(false); + + const hasPoliciesConnectedToSageIntacct = !!getPoliciesConnectedToSageIntacct().length; + const {isSmallScreenWidth} = useWindowDimensions(); + const [isReuseConnectionsPopoverOpen, setIsReuseConnectionsPopoverOpen] = useState(false); + const [reuseConnectionPopoverPosition, setReuseConnectionPopoverPosition] = useState({horizontal: 0, vertical: 0}); + const threeDotsMenuContainerRef = useRef(null); + const connectionOptions = [ + { + icon: Expensicons.LinkCopy, + text: translate('workspace.intacct.createNewConnection'), + onSelected: () => { + Navigation.navigate(ROUTES.POLICY_ACCOUNTING_SAGE_INTACCT_PREREQUISITES.getRoute(policyID)); + setIsReuseConnectionsPopoverOpen(false); + }, + }, + { + icon: Expensicons.Copy, + text: translate('workspace.intacct.reuseExistingConnection'), + onSelected: () => { + Navigation.navigate(ROUTES.POLICY_ACCOUNTING_SAGE_INTACCT_EXISTING_CONNECTIONS.getRoute(policyID)); + setIsReuseConnectionsPopoverOpen(false); + }, + }, + ]; + + return ( + <> +