diff --git a/assets/images/integrationicons/netsuite-icon-square.svg b/assets/images/integrationicons/netsuite-icon-square.svg new file mode 100644 index 000000000000..d4f19f4f44c0 --- /dev/null +++ b/assets/images/integrationicons/netsuite-icon-square.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + diff --git a/src/CONST.ts b/src/CONST.ts index f8ce1a574d49..e71ad55a452c 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1333,6 +1333,10 @@ const CONST = { }, }, + NETSUITE_CONFIG: { + SUBSIDIARY: 'subsidiary', + }, + QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE: { VENDOR_BILL: 'bill', CHECK: 'check', diff --git a/src/ROUTES.ts b/src/ROUTES.ts index db40c142a22d..c38ec192127e 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -917,6 +917,10 @@ const ROUTES = { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/taxes', getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import/taxes` as const, }, + POLICY_ACCOUNTING_NETSUITE_SUBSIDIARY_SELECTOR: { + route: 'settings/workspaces/:policyID/accounting/net-suite/subsidiary-selector', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/net-suite/subsidiary-selector` as const, + }, RESTRICTED_ACTION: { route: 'restricted-action/workspace/:policyID', getRoute: (policyID: string) => `restricted-action/workspace/${policyID}` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index d8a2d166099e..6e3d1f3276e9 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -269,6 +269,7 @@ const SCREENS = { XERO_EXPORT_PREFERRED_EXPORTER_SELECT: 'Workspace_Accounting_Xero_Export_Preferred_Exporter_Select', 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', }, INITIAL: 'Workspace_Initial', PROFILE: 'Workspace_Profile', diff --git a/src/components/Icon/Expensicons.ts b/src/components/Icon/Expensicons.ts index c3e50cff3178..3b6d51e786a3 100644 --- a/src/components/Icon/Expensicons.ts +++ b/src/components/Icon/Expensicons.ts @@ -98,6 +98,7 @@ import ImageCropCircleMask from '@assets/images/image-crop-circle-mask.svg'; import ImageCropSquareMask from '@assets/images/image-crop-square-mask.svg'; import Inbox from '@assets/images/inbox.svg'; import Info from '@assets/images/info.svg'; +import NetSuiteSquare from '@assets/images/integrationicons/netsuite-icon-square.svg'; import QBOSquare from '@assets/images/integrationicons/qbo-icon-square.svg'; import XeroSquare from '@assets/images/integrationicons/xero-icon-square.svg'; import InvoiceGeneric from '@assets/images/invoice-generic.svg'; @@ -366,4 +367,5 @@ export { Clear, CheckCircle, CheckmarkCircle, + NetSuiteSquare, }; diff --git a/src/languages/en.ts b/src/languages/en.ts index b8c248704b62..2475bd2dd56e 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2182,6 +2182,12 @@ export default { noAccountsFound: 'No accounts found', noAccountsFoundDescription: 'Add the account in Xero and sync the connection again.', }, + netsuite: { + subsidiary: 'Subsidiary', + subsidiarySelectDescription: "Choose the subsidiary in NetSuite that you'd like to import data from.", + noSubsidiariesFound: 'No subsidiaries found', + noSubsidiariesFoundDescription: 'Add the subsidiary in NetSuite and sync the connection again.', + }, type: { free: 'Free', control: 'Control', @@ -2410,6 +2416,7 @@ export default { subtitle: 'Connect to your accounting system to code transactions with your chart of accounts, auto-match payments, and keep your finances in sync.', qbo: 'Quickbooks Online', xero: 'Xero', + netsuite: 'NetSuite', setup: 'Connect', lastSync: 'Last synced just now', import: 'Import', diff --git a/src/languages/es.ts b/src/languages/es.ts index ecd96d8ca582..72876757c8aa 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2218,6 +2218,12 @@ export default { noAccountsFound: 'No se ha encontrado ninguna cuenta', noAccountsFoundDescription: 'Añade la cuenta en Xero y sincroniza de nuevo la conexión.', }, + netsuite: { + subsidiary: 'Subsidiaria', + subsidiarySelectDescription: 'Elige la subsidiaria de NetSuite de la que deseas importar datos.', + noSubsidiariesFound: 'No se ha encontrado subsidiarias', + noSubsidiariesFoundDescription: 'Añade la subsidiaria en NetSuite y sincroniza de nuevo la conexión.', + }, type: { free: 'Gratis', control: 'Control', @@ -2414,6 +2420,7 @@ export default { subtitle: 'Conecta a tu sistema de contabilidad para codificar transacciones con tu plan de cuentas, auto-cotejar pagos, y mantener tus finanzas sincronizadas.', qbo: 'Quickbooks Online', xero: 'Xero', + netsuite: 'NetSuite', setup: 'Configurar', lastSync: 'Recién sincronizado', import: 'Importar', diff --git a/src/libs/API/parameters/UpdateNetSuiteSubsidiaryParams.ts b/src/libs/API/parameters/UpdateNetSuiteSubsidiaryParams.ts new file mode 100644 index 000000000000..15353589663a --- /dev/null +++ b/src/libs/API/parameters/UpdateNetSuiteSubsidiaryParams.ts @@ -0,0 +1,7 @@ +type UpdateNetSuiteSubsidiaryParams = { + policyID: string; + subsidiary: string; + subsidiaryID: string; +}; + +export default UpdateNetSuiteSubsidiaryParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 269821318889..c43ab514b251 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -233,3 +233,4 @@ export type {default as UpdateSubscriptionAutoRenewParams} from './UpdateSubscri export type {default as UpdateSubscriptionAddNewUsersAutomaticallyParams} from './UpdateSubscriptionAddNewUsersAutomaticallyParams'; export type {default as GenerateSpotnanaTokenParams} from './GenerateSpotnanaTokenParams'; export type {default as UpdateSubscriptionSizeParams} from './UpdateSubscriptionSizeParams'; +export type {default as UpdateNetSuiteSubsidiaryParams} from './UpdateNetSuiteSubsidiaryParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 63473a4b2c68..1ab68bf16ad0 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -227,6 +227,7 @@ const WRITE_COMMANDS = { UPDATE_SUBSCRIPTION_AUTO_RENEW: 'UpdateSubscriptionAutoRenew', UPDATE_SUBSCRIPTION_ADD_NEW_USERS_AUTOMATICALLY: 'UpdateSubscriptionAddNewUsersAutomatically', UPDATE_SUBSCRIPTION_SIZE: 'UpdateSubscriptionSize', + UPDATE_NETSUITE_SUBSIDIARY: 'UpdateNetSuiteSubsidiary', } as const; type WriteCommand = ValueOf; @@ -455,6 +456,9 @@ type WriteCommandParameters = { [WRITE_COMMANDS.UPDATE_SUBSCRIPTION_AUTO_RENEW]: Parameters.UpdateSubscriptionAutoRenewParams; [WRITE_COMMANDS.UPDATE_SUBSCRIPTION_ADD_NEW_USERS_AUTOMATICALLY]: Parameters.UpdateSubscriptionAddNewUsersAutomaticallyParams; [WRITE_COMMANDS.UPDATE_SUBSCRIPTION_SIZE]: Parameters.UpdateSubscriptionSizeParams; + + // Netsuite parameters + [WRITE_COMMANDS.UPDATE_NETSUITE_SUBSIDIARY]: Parameters.UpdateNetSuiteSubsidiaryParams; }; const READ_COMMANDS = { diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 64f253f7aeea..cb13c347d8aa 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -318,6 +318,7 @@ const SettingsModalStackNavigator = createModalStackNavigator('../../../../pages/workspace/accounting/xero/export/XeroPreferredExporterSelectPage').default, [SCREENS.WORKSPACE.ACCOUNTING.XERO_BILL_PAYMENT_ACCOUNT_SELECTOR]: () => require('../../../../pages/workspace/accounting/xero/advanced/XeroBillPaymentAccountSelectorPage').default, + [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_SUBSIDIARY_SELECTOR]: () => require('../../../../pages/workspace/accounting/netsuite/NetSuiteSubsidiarySelector').default, [SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_FREQUENCY]: () => require('../../../../pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage').default, [SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_MONTHLY_OFFSET]: () => require('../../../../pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage').default, [SCREENS.WORKSPACE.TAX_EDIT]: () => require('../../../../pages/workspace/taxes/WorkspaceEditTaxPage').default, diff --git a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts index f2897587a043..5defdd9d2e08 100755 --- a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts @@ -54,6 +54,7 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial> = { SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT_PREFERRED_EXPORTER_SELECT, SCREENS.WORKSPACE.ACCOUNTING.XERO_BILL_PAYMENT_ACCOUNT_SELECTOR, SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT_BANK_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_SUBSIDIARY_SELECTOR, ], [SCREENS.WORKSPACE.TAXES]: [ SCREENS.WORKSPACE.TAXES_SETTINGS, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 3ba386d63670..bba611136450 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -333,6 +333,7 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE.ACCOUNTING.XERO_INVOICE_ACCOUNT_SELECTOR]: {path: ROUTES.POLICY_ACCOUNTING_XERO_INVOICE_SELECTOR.route}, [SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT_PREFERRED_EXPORTER_SELECT]: {path: ROUTES.POLICY_ACCOUNTING_XERO_PREFERRED_EXPORTER_SELECT.route}, [SCREENS.WORKSPACE.ACCOUNTING.XERO_BILL_PAYMENT_ACCOUNT_SELECTOR]: {path: ROUTES.POLICY_ACCOUNTING_XERO_BILL_PAYMENT_ACCOUNT_SELECTOR.route}, + [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_SUBSIDIARY_SELECTOR]: {path: ROUTES.POLICY_ACCOUNTING_NETSUITE_SUBSIDIARY_SELECTOR.route}, [SCREENS.WORKSPACE.DESCRIPTION]: { path: ROUTES.WORKSPACE_PROFILE_DESCRIPTION.route, }, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index a6840b523967..4f09e3a42d58 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -385,6 +385,9 @@ type SettingsNavigatorParamList = { [SCREENS.WORKSPACE.ACCOUNTING.XERO_BILL_PAYMENT_ACCOUNT_SELECTOR]: { policyID: string; }; + [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_SUBSIDIARY_SELECTOR]: { + policyID: string; + }; [SCREENS.GET_ASSISTANCE]: { backTo: Routes; }; diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index a81dc08ba587..88aae0dcb149 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -528,6 +528,10 @@ function clearXeroErrorField(policyID: string, fieldName: string) { Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {connections: {xero: {config: {errorFields: {[fieldName]: null}}}}}); } +function clearNetSuiteErrorField(policyID: string, fieldName: string) { + Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {connections: {netsuite: {options: {config: {errorFields: {[fieldName]: null}}}}}}); +} + function setWorkspaceReimbursement(policyID: string, reimbursementChoice: ValueOf, reimburserEmail: string) { const policy = getPolicy(policyID); @@ -3002,6 +3006,7 @@ export { createDraftWorkspace, buildPolicyData, createPolicyExpenseChats, + clearNetSuiteErrorField, }; export type {NewCustomUnit}; diff --git a/src/libs/actions/connections/NetSuiteCommands.ts b/src/libs/actions/connections/NetSuiteCommands.ts new file mode 100644 index 000000000000..49c42a95542e --- /dev/null +++ b/src/libs/actions/connections/NetSuiteCommands.ts @@ -0,0 +1,99 @@ +import Onyx from 'react-native-onyx'; +import * as API from '@libs/API'; +import {WRITE_COMMANDS} from '@libs/API/types'; +import * as ErrorUtils from '@libs/ErrorUtils'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {OnyxData} from '@src/types/onyx/Request'; + +type SubsidiaryParam = { + subsidiaryID: string; + subsidiary: string; +}; + +function updateNetSuiteSubsidiary(policyID: string, newSubsidiary: SubsidiaryParam, oldSubsidiary: SubsidiaryParam) { + const onyxData: OnyxData = { + optimisticData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: { + connections: { + netsuite: { + options: { + config: { + subsidiary: newSubsidiary.subsidiary, + subsidiaryID: newSubsidiary.subsidiaryID, + pendingFields: { + subsidiary: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, + errorFields: { + subsidiary: null, + }, + }, + }, + }, + }, + }, + }, + ], + successData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: { + connections: { + netsuite: { + options: { + config: { + subsidiary: newSubsidiary.subsidiary, + subsidiaryID: newSubsidiary.subsidiaryID, + errorFields: { + subsidiary: null, + }, + pendingFields: { + subsidiary: null, + }, + }, + }, + }, + }, + }, + }, + ], + failureData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: { + connections: { + netsuite: { + options: { + config: { + subsidiary: oldSubsidiary.subsidiary, + subsidiaryID: oldSubsidiary.subsidiaryID, + errorFields: { + subsidiary: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage'), + }, + pendingFields: { + subsidiary: null, + }, + }, + }, + }, + }, + }, + }, + ], + }; + + const params = { + policyID, + ...newSubsidiary, + }; + API.write(WRITE_COMMANDS.UPDATE_NETSUITE_SUBSIDIARY, params, onyxData); +} + +// We'll have more API calls in upcoming PRs +// eslint-disable-next-line import/prefer-default-export +export {updateNetSuiteSubsidiary}; diff --git a/src/pages/workspace/accounting/PolicyAccountingPage.tsx b/src/pages/workspace/accounting/PolicyAccountingPage.tsx index c8d0eac3ca44..3bb63dadaadc 100644 --- a/src/pages/workspace/accounting/PolicyAccountingPage.tsx +++ b/src/pages/workspace/accounting/PolicyAccountingPage.tsx @@ -100,6 +100,22 @@ function accountingIntegrationData( onExportPagePress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_XERO_EXPORT.getRoute(policyID)), onAdvancedPagePress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_XERO_ADVANCED.getRoute(policyID)), }; + case CONST.POLICY.CONNECTIONS.NAME.NETSUITE: + return { + title: translate('workspace.accounting.netsuite'), + icon: Expensicons.NetSuiteSquare, + setupConnectionButton: ( + // TODO: Will be updated in the Token Input PR + + ), + onImportPagePress: () => {}, + onExportPagePress: () => {}, + onAdvancedPagePress: () => {}, + }; default: return undefined; } @@ -131,11 +147,15 @@ function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccounting const formattedDate = useMemo(() => (successfulDate ? new Date(successfulDate) : new Date()), [successfulDate]); const policyConnectedToXero = connectedIntegration === CONST.POLICY.CONNECTIONS.NAME.XERO; + const policyConnectedToNetSuite = connectedIntegration === CONST.POLICY.CONNECTIONS.NAME.NETSUITE; const tenants = useMemo(() => getXeroTenants(policy), [policy]); const currentXeroOrganization = findCurrentXeroOrganization(tenants, policy?.connections?.xero?.config?.tenantID); const currentXeroOrganizationName = useMemo(() => getCurrentXeroOrganizationName(policy), [policy]); + const netSuiteSubsidiaryList = policy?.connections?.netsuite?.options?.data?.subsidiaryList ?? []; + const netSuiteSelectedSubsidiary = policy?.connections?.netsuite?.options?.config?.subsidiary ?? ''; + const overflowMenu: ThreeDotsMenuProps['menuItems'] = useMemo( () => [ { @@ -234,6 +254,27 @@ function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccounting }, ] : []), + ...(policyConnectedToNetSuite && !shouldShowSynchronizationError + ? [ + { + description: translate('workspace.netsuite.subsidiary'), + iconRight: Expensicons.ArrowRight, + title: netSuiteSelectedSubsidiary, + wrapperStyle: [styles.sectionMenuItemTopDescription], + titleStyle: styles.fontWeightNormal, + shouldShowRightIcon: netSuiteSubsidiaryList.length > 1, + shouldShowDescriptionOnTop: true, + pendingAction: policy?.connections?.netsuite?.options?.config?.pendingFields?.subsidiary, + brickRoadIndicator: policy?.connections?.netsuite?.options?.config?.errorFields?.subsidiary ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, + onPress: () => { + if (!(netSuiteSubsidiaryList.length > 1)) { + return; + } + Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_SUBSIDIARY_SELECTOR.getRoute(policyID)); + }, + }, + ] + : []), ...(isEmptyObject(policy?.connections) || shouldShowSynchronizationError ? [] : [ @@ -275,13 +316,16 @@ function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccounting styles.popoverMenuIcon, styles.fontWeightNormal, connectionSyncProgress?.stageInProgress, + datetimeToRelative, theme.spinner, overflowMenu, threeDotsMenuPosition, policyConnectedToXero, currentXeroOrganizationName, tenants.length, - datetimeToRelative, + policyConnectedToNetSuite, + netSuiteSelectedSubsidiary, + netSuiteSubsidiaryList.length, accountingIntegrations, currentXeroOrganization?.id, ]); diff --git a/src/pages/workspace/accounting/netsuite/NetSuiteSubsidiarySelector.tsx b/src/pages/workspace/accounting/netsuite/NetSuiteSubsidiarySelector.tsx new file mode 100644 index 000000000000..3e5546eceb66 --- /dev/null +++ b/src/pages/workspace/accounting/netsuite/NetSuiteSubsidiarySelector.tsx @@ -0,0 +1,105 @@ +import React, {useMemo} from 'react'; +import BlockingView from '@components/BlockingViews/BlockingView'; +import * as Illustrations from '@components/Icon/Illustrations'; +import OfflineWithFeedback from '@components/OfflineWithFeedback'; +import RadioListItem from '@components/SelectionList/RadioListItem'; +import SelectionScreen from '@components/SelectionScreen'; +import type {SelectorType} from '@components/SelectionScreen'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import {updateNetSuiteSubsidiary} from '@libs/actions/connections/NetSuiteCommands'; +import * as ErrorUtils from '@libs/ErrorUtils'; +import Navigation from '@libs/Navigation/Navigation'; +import withPolicyConnections from '@pages/workspace/withPolicyConnections'; +import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections'; +import variables from '@styles/variables'; +import * as Policy from '@userActions/Policy/Policy'; +import CONST from '@src/CONST'; +import type {NetSuiteSubsidiary} from '@src/types/onyx/Policy'; + +function NetSuiteSubsidiarySelector({policy}: WithPolicyConnectionsProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const subsidiaryList = policy?.connections?.netsuite?.options?.data?.subsidiaryList ?? []; + const netsuiteConfig = policy?.connections?.netsuite?.options?.config; + const currentSubsidiaryName = netsuiteConfig?.subsidiary ?? ''; + const currentSubsidiaryID = netsuiteConfig?.subsidiaryID ?? ''; + const policyID = policy?.id ?? '-1'; + + const subsidiaryListSections = + subsidiaryList.map((subsidiary: NetSuiteSubsidiary) => ({ + text: subsidiary.name, + keyForList: subsidiary.internalID, + isSelected: subsidiary.name === currentSubsidiaryName, + value: subsidiary.name, + })) ?? []; + + const updateSubsidiary = ({keyForList, value}: SelectorType) => { + if (!keyForList || keyForList === currentSubsidiaryID) { + return; + } + + updateNetSuiteSubsidiary( + policyID, + { + subsidiary: value, + subsidiaryID: keyForList, + }, + { + subsidiary: currentSubsidiaryName, + subsidiaryID: currentSubsidiaryID, + }, + ); + Navigation.goBack(); + }; + + const listEmptyContent = useMemo( + () => ( + + ), + [translate, styles.pb10], + ); + + const listHeaderComponent = useMemo( + () => ( + Policy.clearNetSuiteErrorField(policyID, CONST.NETSUITE_CONFIG.SUBSIDIARY)} + > + {translate('workspace.netsuite.subsidiarySelectDescription')} + + ), + [netsuiteConfig, styles.ph5, styles.mt2, styles.pb5, styles.mb4, translate, policyID], + ); + + return ( + 0 ? [{data: subsidiaryListSections}] : []} + listItem={RadioListItem} + connectionName={CONST.POLICY.CONNECTIONS.NAME.NETSUITE} + onSelectRow={updateSubsidiary} + initiallyFocusedOptionKey={netsuiteConfig?.subsidiaryID ?? subsidiaryListSections?.[0]?.keyForList} + headerContent={listHeaderComponent} + onBackButtonPress={() => Navigation.goBack()} + title="workspace.netsuite.subsidiary" + listEmptyContent={listEmptyContent} + /> + ); +} + +NetSuiteSubsidiarySelector.displayName = 'NetSuiteSubsidiarySelector'; + +export default withPolicyConnections(NetSuiteSubsidiarySelector); diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index bd8f5e7d33d9..bc10ba51e3c9 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -595,7 +595,7 @@ type XeroConnectionConfig = OnyxCommon.OnyxValueWithOfflineFeedback<{ }>; /** Data stored about subsidiaries from NetSuite */ -type Subsidiary = { +type NetSuiteSubsidiary = { /** ID of the subsidiary */ internalID: string; @@ -664,7 +664,7 @@ type InvoiceItem = { /** Data from the NetSuite accounting integration. */ type NetSuiteConnectionData = { /** Collection of the subsidiaries present in the NetSuite account */ - subsidiaryList: Subsidiary[]; + subsidiaryList: NetSuiteSubsidiary[]; /** Collection of receivable accounts */ receivableList: NetSuiteAccount[]; @@ -1314,4 +1314,5 @@ export type { QBOReimbursableExportAccountType, QBOConnectionConfig, XeroTrackingCategory, + NetSuiteSubsidiary, };