diff --git a/src/CONST.ts b/src/CONST.ts index 4a0b3e2b18e4..e4ef7fdd4791 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1360,21 +1360,25 @@ const CONST = { }, QUICKBOOKS_ONLINE: 'quickbooksOnline', - QUICK_BOOKS_CONFIG: { - SYNC_CLASSES: 'syncClasses', + QUICKBOOKS_CONFIG: { ENABLE_NEW_CATEGORIES: 'enableNewCategories', + SYNC_CLASSES: 'syncClasses', SYNC_CUSTOMERS: 'syncCustomers', SYNC_LOCATIONS: 'syncLocations', SYNC_TAX: 'syncTax', EXPORT: 'export', + EXPORTER: 'exporter', EXPORT_DATE: 'exportDate', NON_REIMBURSABLE_EXPENSES_ACCOUNT: 'nonReimbursableExpensesAccount', NON_REIMBURSABLE_EXPENSES_EXPORT_DESTINATION: 'nonReimbursableExpensesExportDestination', REIMBURSABLE_EXPENSES_ACCOUNT: 'reimbursableExpensesAccount', REIMBURSABLE_EXPENSES_EXPORT_DESTINATION: 'reimbursableExpensesExportDestination', NON_REIMBURSABLE_BILL_DEFAULT_VENDOR: 'nonReimbursableBillDefaultVendor', + NON_REIMBURSABLE_EXPENSE_EXPORT_DESTINATION: 'nonReimbursableExpensesExportDestination', + NON_REIMBURSABLE_EXPENSE_ACCOUNT: 'nonReimbursableExpensesAccount', RECEIVABLE_ACCOUNT: 'receivableAccount', AUTO_SYNC: 'autoSync', + ENABLED: 'enabled', SYNC_PEOPLE: 'syncPeople', AUTO_CREATE_VENDOR: 'autoCreateVendor', REIMBURSEMENT_ACCOUNT_ID: 'reimbursementAccountID', diff --git a/src/components/SelectionScreen.tsx b/src/components/SelectionScreen.tsx index 8f6ccbf64c81..b86084421fac 100644 --- a/src/components/SelectionScreen.tsx +++ b/src/components/SelectionScreen.tsx @@ -145,6 +145,7 @@ function SelectionScreen({ pendingAction={pendingAction} style={[styles.flex1]} contentContainerStyle={[styles.flex1]} + shouldDisableOpacity={!sections.length} > ; +import type {Connections} from '@src/types/onyx/Policy'; function getQuickbooksOnlineSetupLink(policyID: string) { const params: ConnectPolicyToAccountingIntegrationParams = {policyID}; @@ -92,6 +90,7 @@ function buildOnyxDataForQuickbooksConfiguration, + oldSettingValue?: Partial, ) { const optimisticData: OnyxUpdate[] = [ { @@ -123,7 +122,7 @@ function buildOnyxDataForQuickbooksConfiguration(policyID: string, settingValue: TSettingValue) { + const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.ENABLE_NEW_CATEGORIES, settingValue, !settingValue); const parameters: UpdateQuickbooksOnlineGenericTypeParams = { policyID, settingValue: JSON.stringify(settingValue), - idempotencyKey: String(CONST.QUICK_BOOKS_CONFIG.ENABLE_NEW_CATEGORIES), + idempotencyKey: String(CONST.QUICKBOOKS_CONFIG.ENABLE_NEW_CATEGORIES), }; API.write(WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_ENABLE_NEW_CATEGORIES, parameters, onyxData); } @@ -187,76 +186,93 @@ function updateQuickbooksOnlineAutoCreateVendor( +function updateQuickbooksOnlineReimbursableExpensesAccount( policyID: string, - settingValue: Partial, + settingValue: TSettingValue, + oldSettingValue: TSettingValue, ) { - const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICK_BOOKS_CONFIG.REIMBURSABLE_EXPENSES_ACCOUNT, settingValue); + const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.REIMBURSABLE_EXPENSES_ACCOUNT, settingValue, oldSettingValue); const parameters: UpdateQuickbooksOnlineGenericTypeParams = { policyID, settingValue: JSON.stringify(settingValue), - idempotencyKey: String(CONST.QUICK_BOOKS_CONFIG.REIMBURSABLE_EXPENSES_ACCOUNT), + idempotencyKey: String(CONST.QUICKBOOKS_CONFIG.REIMBURSABLE_EXPENSES_ACCOUNT), }; API.write(WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_REIMBURSABLE_EXPENSES_ACCOUNT, parameters, onyxData); } -function updateQuickbooksOnlineSyncLocations(policyID: string, settingValue: IntegrationEntityMap) { - const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICK_BOOKS_CONFIG.SYNC_LOCATIONS, settingValue); +function updateQuickbooksOnlineSyncLocations( + policyID: string, + settingValue: TSettingValue, + oldSettingValue?: TSettingValue, +) { + const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.SYNC_LOCATIONS, settingValue, oldSettingValue); const parameters: UpdateQuickbooksOnlineGenericTypeParams = { policyID, settingValue: JSON.stringify(settingValue), - idempotencyKey: String(CONST.QUICK_BOOKS_CONFIG.SYNC_LOCATIONS), + idempotencyKey: String(CONST.QUICKBOOKS_CONFIG.SYNC_LOCATIONS), }; API.write(WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_SYNC_LOCATIONS, parameters, onyxData); } -function updateQuickbooksOnlineSyncCustomers(policyID: string, settingValue: IntegrationEntityMap) { - const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICK_BOOKS_CONFIG.SYNC_CUSTOMERS, settingValue); +function updateQuickbooksOnlineSyncCustomers( + policyID: string, + settingValue: TSettingValue, + oldSettingValue?: TSettingValue, +) { + const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.SYNC_CUSTOMERS, settingValue, oldSettingValue); const parameters: UpdateQuickbooksOnlineGenericTypeParams = { policyID, settingValue: JSON.stringify(settingValue), - idempotencyKey: String(CONST.QUICK_BOOKS_CONFIG.SYNC_CUSTOMERS), + idempotencyKey: String(CONST.QUICKBOOKS_CONFIG.SYNC_CUSTOMERS), }; API.write(WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_SYNC_CUSTOMERS, parameters, onyxData); } -function updateQuickbooksOnlineSyncClasses(policyID: string, settingValue: IntegrationEntityMap) { - const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICK_BOOKS_CONFIG.SYNC_CLASSES, settingValue); +function updateQuickbooksOnlineSyncClasses( + policyID: string, + settingValue: TSettingValue, + oldSettingValue?: TSettingValue, +) { + const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.SYNC_CLASSES, settingValue, oldSettingValue); const parameters: UpdateQuickbooksOnlineGenericTypeParams = { policyID, settingValue: JSON.stringify(settingValue), - idempotencyKey: String(CONST.QUICK_BOOKS_CONFIG.SYNC_CLASSES), + idempotencyKey: String(CONST.QUICKBOOKS_CONFIG.SYNC_CLASSES), }; API.write(WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_SYNC_CLASSES, parameters, onyxData); } -function updateQuickbooksOnlineNonReimbursableBillDefaultVendor(policyID: string, settingValue: string) { - const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICK_BOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR, settingValue); +function updateQuickbooksOnlineNonReimbursableBillDefaultVendor( + policyID: string, + settingValue: TSettingValue, + oldSettingValue?: TSettingValue, +) { + const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR, settingValue, oldSettingValue); const parameters: UpdateQuickbooksOnlineGenericTypeParams = { policyID, settingValue: JSON.stringify(settingValue), - idempotencyKey: String(CONST.QUICK_BOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR), + idempotencyKey: String(CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR), }; API.write(WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_NON_REIMBURSABLE_BILL_DEFAULT_VENDOR, parameters, onyxData); } -function updateQuickbooksOnlineSyncTax(policyID: string, settingValue: boolean) { - const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICK_BOOKS_CONFIG.SYNC_TAX, settingValue); +function updateQuickbooksOnlineSyncTax(policyID: string, settingValue: TSettingValue) { + const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.SYNC_TAX, settingValue, !settingValue); const parameters: UpdateQuickbooksOnlineGenericTypeParams = { policyID, settingValue: JSON.stringify(settingValue), - idempotencyKey: String(CONST.QUICK_BOOKS_CONFIG.SYNC_TAX), + idempotencyKey: String(CONST.QUICKBOOKS_CONFIG.SYNC_TAX), }; API.write(WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_SYNC_TAX, parameters, onyxData); } diff --git a/src/libs/actions/connections/index.ts b/src/libs/actions/connections/index.ts index 4c7ec69e6134..f7e74e62249b 100644 --- a/src/libs/actions/connections/index.ts +++ b/src/libs/actions/connections/index.ts @@ -75,7 +75,7 @@ function createErrorFields( +function updatePolicyConnectionConfig( policyID: string, connectionName: TConnectionName, settingName: TSettingName, @@ -144,89 +144,6 @@ function updatePolicyXeroConnectionConfig( - policyID: string, - connectionName: TConnectionName, - settingName: TSettingName, - settingValue: Partial, -) { - const optimisticData: OnyxUpdate[] = [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - value: { - connections: { - [connectionName]: { - config: { - [settingName]: settingValue ?? null, - pendingFields: { - [settingName]: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, - }, - errorFields: { - [settingName]: null, - }, - }, - }, - }, - }, - }, - ]; - - const failureData: OnyxUpdate[] = [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - value: { - connections: { - [connectionName]: { - config: { - [settingName]: settingValue ?? null, - pendingFields: { - [settingName]: null, - }, - errorFields: { - [settingName]: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage'), - }, - }, - }, - }, - }, - }, - ]; - - const successData: OnyxUpdate[] = [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - value: { - connections: { - [connectionName]: { - config: { - [settingName]: settingValue ?? null, - pendingFields: { - [settingName]: null, - }, - errorFields: { - [settingName]: null, - }, - }, - }, - }, - }, - }, - ]; - - const parameters: UpdatePolicyConnectionConfigParams = { - policyID, - connectionName, - settingName: String(settingName), - settingValue: JSON.stringify(settingValue), - idempotencyKey: String(settingName), - }; - API.write(WRITE_COMMANDS.UPDATE_POLICY_CONNECTION_CONFIG, parameters, {optimisticData, failureData, successData}); -} - /** * This method returns read command and stage in progres for a given accounting integration. * @@ -467,7 +384,6 @@ function isConnectionInProgress(connectionSyncProgress: OnyxEntry [...(bankAccounts ?? []), ...(creditCards ?? [])], [bankAccounts, creditCards]); const qboOnlineSelectorOptions = useMemo( @@ -38,9 +38,9 @@ function QuickbooksAccountSelectPage({policy}: WithPolicyConnectionsProps) { value: id, text: name, keyForList: id, - isSelected: reimbursementAccountID === id, + isSelected: qboConfig?.reimbursementAccountID === id, })), - [reimbursementAccountID, accountOptions], + [qboConfig?.reimbursementAccountID, accountOptions], ); const listHeaderComponent = useMemo( () => ( @@ -55,10 +55,10 @@ function QuickbooksAccountSelectPage({policy}: WithPolicyConnectionsProps) { const saveSelection = useCallback( ({value}: SelectorType) => { - Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, CONST.QUICK_BOOKS_CONFIG.REIMBURSEMENT_ACCOUNT_ID, value); + Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, CONST.QUICKBOOKS_CONFIG.REIMBURSEMENT_ACCOUNT_ID, value, qboConfig?.reimbursementAccountID); Navigation.goBack(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ADVANCED.getRoute(policyID)); }, - [policyID], + [policyID, qboConfig?.reimbursementAccountID], ); const listEmptyContent = useMemo( @@ -76,28 +76,26 @@ function QuickbooksAccountSelectPage({policy}: WithPolicyConnectionsProps) { ); return ( - - - - - - - + displayName={QuickbooksAccountSelectPage.displayName} + sections={qboOnlineSelectorOptions.length ? [{data: qboOnlineSelectorOptions}] : []} + listItem={RadioListItem} + headerContent={listHeaderComponent} + onSelectRow={saveSelection} + shouldSingleExecuteRowSelect + initiallyFocusedOptionKey={initiallyFocusedOptionKey} + listEmptyContent={listEmptyContent} + title="workspace.qbo.advancedConfig.qboBillPaymentAccount" + connectionName={CONST.POLICY.CONNECTIONS.NAME.QBO} + onBackButtonPress={() => Navigation.goBack(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ADVANCED.getRoute(policyID))} + pendingAction={settingsPendingAction([CONST.QUICKBOOKS_CONFIG.REIMBURSEMENT_ACCOUNT_ID], qboConfig?.pendingFields)} + errors={ErrorUtils.getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.REIMBURSEMENT_ACCOUNT_ID)} + errorRowStyles={[styles.ph5, styles.mv3]} + onClose={() => clearQBOErrorField(policyID, CONST.QUICKBOOKS_CONFIG.REIMBURSEMENT_ACCOUNT_ID)} + /> ); } diff --git a/src/pages/workspace/accounting/qbo/advanced/QuickbooksAdvancedPage.tsx b/src/pages/workspace/accounting/qbo/advanced/QuickbooksAdvancedPage.tsx index 385510cb7ff4..35cb2c36d915 100644 --- a/src/pages/workspace/accounting/qbo/advanced/QuickbooksAdvancedPage.tsx +++ b/src/pages/workspace/accounting/qbo/advanced/QuickbooksAdvancedPage.tsx @@ -1,10 +1,8 @@ import React, {useMemo} from 'react'; import {View} from 'react-native'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ConnectionLayout from '@components/ConnectionLayout'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; -import ScreenWrapper from '@components/ScreenWrapper'; -import ScrollView from '@components/ScrollView'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import useWaitForNavigation from '@hooks/useWaitForNavigation'; @@ -12,15 +10,18 @@ import * as Connections from '@libs/actions/connections'; import * as QuickbooksOnline from '@libs/actions/connections/QuickbooksOnline'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; -import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; +import * as PolicyUtils from '@libs/PolicyUtils'; +import {settingsPendingAction} from '@libs/PolicyUtils'; import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections'; import withPolicyConnections from '@pages/workspace/withPolicyConnections'; import ToggleSettingOptionRow from '@pages/workspace/workflows/ToggleSettingsOptionRow'; -import type {ToggleSettingOptionRowProps} from '@pages/workspace/workflows/ToggleSettingsOptionRow'; -import * as Policy from '@userActions/Policy/Policy'; +import {clearQBOErrorField} from '@userActions/Policy/Policy'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; +const reimbursementOrCollectionAccountIDs = [CONST.QUICKBOOKS_CONFIG.REIMBURSEMENT_ACCOUNT_ID, CONST.QUICKBOOKS_CONFIG.COLLECTION_ACCOUNT_ID]; +const collectionAccountIDs = [CONST.QUICKBOOKS_CONFIG.COLLECTION_ACCOUNT_ID]; + function QuickbooksAdvancedPage({policy}: WithPolicyConnectionsProps) { const styles = useThemeStyles(); const waitForNavigate = useWaitForNavigation(); @@ -28,80 +29,98 @@ function QuickbooksAdvancedPage({policy}: WithPolicyConnectionsProps) { const policyID = policy?.id ?? '-1'; const qboConfig = policy?.connections?.quickbooksOnline?.config; - const {autoSync, syncPeople, autoCreateVendor, pendingFields, collectionAccountID, reimbursementAccountID, errorFields} = qboConfig ?? {}; const {bankAccounts, creditCards, otherCurrentAssetAccounts, vendors} = policy?.connections?.quickbooksOnline?.data ?? {}; - const {nonReimbursableBillDefaultVendor} = policy?.connections?.quickbooksOnline?.config ?? {}; - const nonReimbursableBillDefaultVendorObject = vendors?.find((vendor) => vendor.id === nonReimbursableBillDefaultVendor); + const nonReimbursableBillDefaultVendorObject = vendors?.find((vendor) => vendor.id === qboConfig?.nonReimbursableBillDefaultVendor); + const qboAccountOptions = useMemo(() => [...(bankAccounts ?? []), ...(creditCards ?? [])], [bankAccounts, creditCards]); const invoiceAccountCollectionOptions = useMemo(() => [...(bankAccounts ?? []), ...(otherCurrentAssetAccounts ?? [])], [bankAccounts, otherCurrentAssetAccounts]); - const isSyncReimbursedSwitchOn = !!collectionAccountID; + const isSyncReimbursedSwitchOn = !!qboConfig?.collectionAccountID; + const reimbursementAccountID = qboConfig?.reimbursementAccountID; const selectedQboAccountName = useMemo(() => qboAccountOptions?.find(({id}) => id === reimbursementAccountID)?.name, [qboAccountOptions, reimbursementAccountID]); + const collectionAccountID = qboConfig?.collectionAccountID; + const selectedInvoiceCollectionAccountName = useMemo( () => invoiceAccountCollectionOptions?.find(({id}) => id === collectionAccountID)?.name, [invoiceAccountCollectionOptions, collectionAccountID], ); + const sectionMenuItems = [ + { + title: selectedQboAccountName, + description: translate('workspace.qbo.advancedConfig.qboBillPaymentAccount'), + onPress: waitForNavigate(() => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ACCOUNT_SELECTOR.getRoute(policyID))), + subscribedSettings: reimbursementOrCollectionAccountIDs, + brickRoadIndicator: PolicyUtils.areSettingsInErrorFields(reimbursementOrCollectionAccountIDs, qboConfig?.errorFields) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, + pendingAction: PolicyUtils.settingsPendingAction(reimbursementOrCollectionAccountIDs, qboConfig?.pendingFields), + }, + { + title: selectedInvoiceCollectionAccountName, + description: translate('workspace.qbo.advancedConfig.qboInvoiceCollectionAccount'), + onPress: waitForNavigate(() => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR.getRoute(policyID))), + subscribedSettings: collectionAccountIDs, + brickRoadIndicator: PolicyUtils.areSettingsInErrorFields(collectionAccountIDs, qboConfig?.errorFields) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, + pendingAction: PolicyUtils.settingsPendingAction(collectionAccountIDs, qboConfig?.pendingFields), + }, + ]; + const syncReimbursedSubMenuItems = () => ( - - Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ACCOUNT_SELECTOR.getRoute(policyID)))} - errorText={errorFields?.reimbursementAccountID ? translate('common.genericErrorMessage') : undefined} - brickRoadIndicator={errorFields?.reimbursementAccountID ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} - /> - - - Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR.getRoute(policyID)))} - errorText={errorFields?.collectionAccountID ? translate('common.genericErrorMessage') : undefined} - brickRoadIndicator={errorFields?.collectionAccountID ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} - /> - + {sectionMenuItems.map((item) => ( + + + + ))} ); - const qboToggleSettingItems: ToggleSettingOptionRowProps[] = [ + const qboToggleSettingItems = [ { title: translate('workspace.accounting.autoSync'), subtitle: translate('workspace.qbo.advancedConfig.autoSyncDescription'), switchAccessibilityLabel: translate('workspace.qbo.advancedConfig.autoSyncDescription'), - isActive: !!autoSync?.enabled, + isActive: !!qboConfig?.autoSync?.enabled, onToggle: () => - Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, CONST.QUICK_BOOKS_CONFIG.AUTO_SYNC, { - enabled: !autoSync?.enabled, - }), - pendingAction: pendingFields?.autoSync, - errors: ErrorUtils.getLatestErrorField(qboConfig ?? {}, CONST.QUICK_BOOKS_CONFIG.AUTO_SYNC), - onCloseError: () => Policy.clearQBOErrorField(policyID, CONST.QUICK_BOOKS_CONFIG.AUTO_SYNC), - wrapperStyle: styles.mv3, + Connections.updatePolicyConnectionConfig( + policyID, + CONST.POLICY.CONNECTIONS.NAME.QBO, + CONST.QUICKBOOKS_CONFIG.AUTO_SYNC, + { + enabled: !qboConfig?.autoSync?.enabled, + }, + { + enabled: qboConfig?.autoSync?.enabled, + }, + ), + subscribedSetting: CONST.QUICKBOOKS_CONFIG.ENABLED, + errors: ErrorUtils.getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.ENABLED), + pendingAction: settingsPendingAction([CONST.QUICKBOOKS_CONFIG.ENABLED], qboConfig?.pendingFields), }, { title: translate('workspace.qbo.advancedConfig.inviteEmployees'), subtitle: translate('workspace.qbo.advancedConfig.inviteEmployeesDescription'), switchAccessibilityLabel: translate('workspace.qbo.advancedConfig.inviteEmployeesDescription'), - isActive: !!syncPeople, - onToggle: () => Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, CONST.QUICK_BOOKS_CONFIG.SYNC_PEOPLE, !syncPeople), - pendingAction: pendingFields?.syncPeople, - errors: ErrorUtils.getLatestErrorField(qboConfig ?? {}, CONST.QUICK_BOOKS_CONFIG.SYNC_PEOPLE), - onCloseError: () => Policy.clearQBOErrorField(policyID, CONST.QUICK_BOOKS_CONFIG.SYNC_PEOPLE), - wrapperStyle: styles.mv3, + isActive: !!qboConfig?.syncPeople, + onToggle: () => + Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, CONST.QUICKBOOKS_CONFIG.SYNC_PEOPLE, !qboConfig?.syncPeople, qboConfig?.syncPeople), + subscribedSetting: CONST.QUICKBOOKS_CONFIG.SYNC_PEOPLE, + errors: ErrorUtils.getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.SYNC_PEOPLE), + pendingAction: settingsPendingAction([CONST.QUICKBOOKS_CONFIG.SYNC_PEOPLE], qboConfig?.pendingFields), }, { title: translate('workspace.qbo.advancedConfig.createEntities'), subtitle: translate('workspace.qbo.advancedConfig.createEntitiesDescription'), switchAccessibilityLabel: translate('workspace.qbo.advancedConfig.createEntitiesDescription'), - isActive: !!autoCreateVendor, - onToggle: (isOn) => { + isActive: !!qboConfig?.autoCreateVendor, + onToggle: (isOn: boolean) => { const nonReimbursableVendorUpdateValue = isOn ? policy?.connections?.quickbooksOnline?.data?.vendors?.[0]?.id ?? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE : CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE; @@ -110,19 +129,18 @@ function QuickbooksAdvancedPage({policy}: WithPolicyConnectionsProps) { QuickbooksOnline.updateQuickbooksOnlineAutoCreateVendor( policyID, { - [CONST.QUICK_BOOKS_CONFIG.AUTO_CREATE_VENDOR]: isOn, - [CONST.QUICK_BOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR]: nonReimbursableVendorUpdateValue, + [CONST.QUICKBOOKS_CONFIG.AUTO_CREATE_VENDOR]: isOn, + [CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR]: nonReimbursableVendorUpdateValue, }, { - [CONST.QUICK_BOOKS_CONFIG.AUTO_CREATE_VENDOR]: !!autoCreateVendor, - [CONST.QUICK_BOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR]: nonReimbursableVendorCurrentValue, + [CONST.QUICKBOOKS_CONFIG.AUTO_CREATE_VENDOR]: !!qboConfig?.autoCreateVendor, + [CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR]: nonReimbursableVendorCurrentValue, }, ); }, - pendingAction: pendingFields?.autoCreateVendor, - errors: ErrorUtils.getLatestErrorField(qboConfig ?? {}, CONST.QUICK_BOOKS_CONFIG.AUTO_CREATE_VENDOR), - onCloseError: () => Policy.clearQBOErrorField(policyID, CONST.QUICK_BOOKS_CONFIG.AUTO_CREATE_VENDOR), - wrapperStyle: styles.mv3, + subscribedSetting: CONST.QUICKBOOKS_CONFIG.AUTO_CREATE_VENDOR, + errors: ErrorUtils.getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.AUTO_CREATE_VENDOR), + pendingAction: settingsPendingAction([CONST.QUICKBOOKS_CONFIG.AUTO_CREATE_VENDOR], qboConfig?.pendingFields), }, { title: translate('workspace.accounting.reimbursedReports'), @@ -133,50 +151,44 @@ function QuickbooksAdvancedPage({policy}: WithPolicyConnectionsProps) { Connections.updatePolicyConnectionConfig( policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, - CONST.QUICK_BOOKS_CONFIG.COLLECTION_ACCOUNT_ID, + CONST.QUICKBOOKS_CONFIG.COLLECTION_ACCOUNT_ID, isSyncReimbursedSwitchOn ? '' : [...qboAccountOptions, ...invoiceAccountCollectionOptions][0].id, + qboConfig?.collectionAccountID, ), - pendingAction: pendingFields?.collectionAccountID, - errors: ErrorUtils.getLatestErrorField(qboConfig ?? {}, CONST.QUICK_BOOKS_CONFIG.COLLECTION_ACCOUNT_ID), - onCloseError: () => Policy.clearQBOErrorField(policyID, CONST.QUICK_BOOKS_CONFIG.COLLECTION_ACCOUNT_ID), - subMenuItems: syncReimbursedSubMenuItems(), - wrapperStyle: styles.mv3, + subscribedSetting: CONST.QUICKBOOKS_CONFIG.COLLECTION_ACCOUNT_ID, + errors: ErrorUtils.getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.COLLECTION_ACCOUNT_ID), + pendingAction: settingsPendingAction([CONST.QUICKBOOKS_CONFIG.COLLECTION_ACCOUNT_ID], qboConfig?.pendingFields), }, ]; return ( - Navigation.goBack(ROUTES.POLICY_ACCOUNTING.getRoute(policyID))} > - - - - - {qboToggleSettingItems.map((item) => ( - - ))} - - - + {qboToggleSettingItems.map((item) => ( + clearQBOErrorField(policyID, item.subscribedSetting)} + /> + ))} + {isSyncReimbursedSwitchOn && syncReimbursedSubMenuItems()} + ); } diff --git a/src/pages/workspace/accounting/qbo/advanced/QuickbooksInvoiceAccountSelectPage.tsx b/src/pages/workspace/accounting/qbo/advanced/QuickbooksInvoiceAccountSelectPage.tsx index 69acda4e1ba6..29741e93d97d 100644 --- a/src/pages/workspace/accounting/qbo/advanced/QuickbooksInvoiceAccountSelectPage.tsx +++ b/src/pages/workspace/accounting/qbo/advanced/QuickbooksInvoiceAccountSelectPage.tsx @@ -1,21 +1,21 @@ import React, {useCallback, useMemo} from 'react'; import {View} from 'react-native'; import BlockingView from '@components/BlockingViews/BlockingView'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Illustrations from '@components/Icon/Illustrations'; -import ScreenWrapper from '@components/ScreenWrapper'; -import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import type {ListItem} from '@components/SelectionList/types'; +import SelectionScreen from '@components/SelectionScreen'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as Connections from '@libs/actions/connections'; +import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; -import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; +import {settingsPendingAction} from '@libs/PolicyUtils'; import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections'; import withPolicyConnections from '@pages/workspace/withPolicyConnections'; import variables from '@styles/variables'; +import {clearQBOErrorField} from '@userActions/Policy/Policy'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; @@ -30,7 +30,7 @@ function QuickbooksInvoiceAccountSelectPage({policy}: WithPolicyConnectionsProps const policyID = policy?.id ?? '-1'; const {bankAccounts, otherCurrentAssetAccounts} = policy?.connections?.quickbooksOnline?.data ?? {}; const accountOptions = useMemo(() => [...(bankAccounts ?? []), ...(otherCurrentAssetAccounts ?? [])], [bankAccounts, otherCurrentAssetAccounts]); - const {collectionAccountID} = policy?.connections?.quickbooksOnline?.config ?? {}; + const qboConfig = policy?.connections?.quickbooksOnline?.config; const qboOnlineSelectorOptions = useMemo( () => @@ -38,9 +38,9 @@ function QuickbooksInvoiceAccountSelectPage({policy}: WithPolicyConnectionsProps value: id, text: name, keyForList: id, - isSelected: collectionAccountID === id, + isSelected: qboConfig?.collectionAccountID === id, })), - [collectionAccountID, accountOptions], + [qboConfig?.collectionAccountID, accountOptions], ); const listHeaderComponent = useMemo( @@ -56,10 +56,10 @@ function QuickbooksInvoiceAccountSelectPage({policy}: WithPolicyConnectionsProps const updateAccount = useCallback( ({value}: SelectorType) => { - Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, CONST.QUICK_BOOKS_CONFIG.COLLECTION_ACCOUNT_ID, value); + Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, CONST.QUICKBOOKS_CONFIG.COLLECTION_ACCOUNT_ID, value, qboConfig?.collectionAccountID); Navigation.goBack(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ADVANCED.getRoute(policyID)); }, - [policyID], + [policyID, qboConfig?.collectionAccountID], ); const listEmptyContent = useMemo( @@ -77,28 +77,26 @@ function QuickbooksInvoiceAccountSelectPage({policy}: WithPolicyConnectionsProps ); return ( - - - - - - - + displayName={QuickbooksInvoiceAccountSelectPage.displayName} + sections={qboOnlineSelectorOptions.length ? [{data: qboOnlineSelectorOptions}] : []} + listItem={RadioListItem} + headerContent={listHeaderComponent} + onSelectRow={updateAccount} + shouldSingleExecuteRowSelect + initiallyFocusedOptionKey={initiallyFocusedOptionKey} + listEmptyContent={listEmptyContent} + title="workspace.qbo.advancedConfig.qboInvoiceCollectionAccount" + connectionName={CONST.POLICY.CONNECTIONS.NAME.QBO} + onBackButtonPress={() => Navigation.goBack(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ADVANCED.getRoute(policyID))} + pendingAction={settingsPendingAction([CONST.QUICKBOOKS_CONFIG.COLLECTION_ACCOUNT_ID], qboConfig?.pendingFields)} + errors={ErrorUtils.getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.COLLECTION_ACCOUNT_ID)} + errorRowStyles={[styles.ph5, styles.mv3]} + onClose={() => clearQBOErrorField(policyID, CONST.QUICKBOOKS_CONFIG.COLLECTION_ACCOUNT_ID)} + /> ); } diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountPage.tsx index 01867a6c764d..8d59c13e528a 100644 --- a/src/pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountPage.tsx +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountPage.tsx @@ -1,19 +1,18 @@ import React from 'react'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ConnectionLayout from '@components/ConnectionLayout'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; -import ScreenWrapper from '@components/ScreenWrapper'; -import ScrollView from '@components/ScrollView'; -import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as Connections from '@libs/actions/connections'; import * as ConnectionUtils from '@libs/ConnectionUtils'; +import * as ErrorUtils from '@libs/ErrorUtils'; +import * as PolicyUtils from '@libs/PolicyUtils'; import Navigation from '@navigation/Navigation'; -import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections'; import withPolicyConnections from '@pages/workspace/withPolicyConnections'; import ToggleSettingOptionRow from '@pages/workspace/workflows/ToggleSettingsOptionRow'; +import {clearQBOErrorField} from '@userActions/Policy/Policy'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; @@ -21,90 +20,97 @@ function QuickbooksCompanyCardExpenseAccountPage({policy}: WithPolicyConnections const {translate} = useLocalize(); const styles = useThemeStyles(); const policyID = policy?.id ?? '-1'; - const {nonReimbursableBillDefaultVendor, autoCreateVendor, errorFields, pendingFields, nonReimbursableExpensesExportDestination, nonReimbursableExpensesAccount} = - policy?.connections?.quickbooksOnline?.config ?? {}; + const qboConfig = policy?.connections?.quickbooksOnline?.config; const {vendors} = policy?.connections?.quickbooksOnline?.data ?? {}; - const nonReimbursableBillDefaultVendorObject = vendors?.find((vendor) => vendor.id === nonReimbursableBillDefaultVendor); + const nonReimbursableBillDefaultVendorObject = vendors?.find((vendor) => vendor.id === qboConfig?.nonReimbursableBillDefaultVendor); + + const sections = [ + { + title: qboConfig?.nonReimbursableExpensesExportDestination ? translate(`workspace.qbo.accounts.${qboConfig?.nonReimbursableExpensesExportDestination}`) : undefined, + description: translate('workspace.accounting.exportAs'), + onPress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_SELECT.getRoute(policyID)), + hintText: qboConfig?.nonReimbursableExpensesExportDestination ? translate(`workspace.qbo.accounts.${qboConfig?.nonReimbursableExpensesExportDestination}Description`) : undefined, + subscribedSettings: [CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_EXPENSE_EXPORT_DESTINATION], + }, + { + title: qboConfig?.nonReimbursableExpensesAccount?.name ?? translate('workspace.qbo.notConfigured'), + description: ConnectionUtils.getQBONonReimbursableExportAccountType(qboConfig?.nonReimbursableExpensesExportDestination), + onPress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT.getRoute(policyID)), + subscribedSettings: [CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_EXPENSE_ACCOUNT], + }, + ]; + return ( - Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT.getRoute(policyID))} > - - - - {translate('workspace.qbo.exportCompanyCardsDescription')} - - Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_SELECT.getRoute(policyID))} - brickRoadIndicator={errorFields?.nonReimbursableExpensesExportDestination ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} - shouldShowRightIcon - hintText={nonReimbursableExpensesExportDestination ? translate(`workspace.qbo.accounts.${nonReimbursableExpensesExportDestination}Description`) : undefined} - /> - - - Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT.getRoute(policyID))} - brickRoadIndicator={errorFields?.nonReimbursableExpensesAccount ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} - shouldShowRightIcon - /> - - {nonReimbursableExpensesExportDestination === CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.VENDOR_BILL && ( - <> - - Connections.updateManyPolicyConnectionConfigs( - policyID, - CONST.POLICY.CONNECTIONS.NAME.QBO, - { - [CONST.QUICK_BOOKS_CONFIG.AUTO_CREATE_VENDOR]: isOn, - [CONST.QUICK_BOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR]: isOn - ? policy?.connections?.quickbooksOnline?.data?.vendors?.[0]?.id ?? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE - : CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE, - }, - { - [CONST.QUICK_BOOKS_CONFIG.AUTO_CREATE_VENDOR]: autoCreateVendor, - [CONST.QUICK_BOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR]: - nonReimbursableBillDefaultVendorObject?.id ?? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE, - }, - ) + {sections.map((section) => ( + + + + ))} + {qboConfig?.nonReimbursableExpensesExportDestination === CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.VENDOR_BILL && ( + <> + + Connections.updateManyPolicyConnectionConfigs( + policyID, + CONST.POLICY.CONNECTIONS.NAME.QBO, + { + [CONST.QUICKBOOKS_CONFIG.AUTO_CREATE_VENDOR]: isOn, + [CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR]: isOn + ? policy?.connections?.quickbooksOnline?.data?.vendors?.[0]?.id ?? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE + : CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE, + }, + { + [CONST.QUICKBOOKS_CONFIG.AUTO_CREATE_VENDOR]: qboConfig?.autoCreateVendor, + [CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR]: nonReimbursableBillDefaultVendorObject?.id ?? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE, + }, + ) + } + onCloseError={() => clearQBOErrorField(policyID, CONST.QUICKBOOKS_CONFIG.AUTO_CREATE_VENDOR)} + /> + {qboConfig?.autoCreateVendor && ( + + Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_NON_REIMBURSABLE_DEFAULT_VENDOR_SELECT.getRoute(policyID))} + brickRoadIndicator={ + PolicyUtils.areSettingsInErrorFields([CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR], qboConfig?.errorFields) + ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR + : undefined } - pendingAction={pendingFields?.autoCreateVendor} + shouldShowRightIcon /> - {autoCreateVendor && ( - - Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_NON_REIMBURSABLE_DEFAULT_VENDOR_SELECT.getRoute(policyID))} - brickRoadIndicator={errorFields?.nonReimbursableBillDefaultVendor ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} - shouldShowRightIcon - errorText={errorFields?.nonReimbursableBillDefaultVendor ? translate('common.genericErrorMessage') : undefined} - /> - - )} - + )} - - - + + )} + ); } diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountSelectCardPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountSelectCardPage.tsx index c36f7df6b245..24a16f15ce2f 100644 --- a/src/pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountSelectCardPage.tsx +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountSelectCardPage.tsx @@ -1,23 +1,23 @@ import React, {useCallback, useMemo} from 'react'; -import {View} from 'react-native'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import ScreenWrapper from '@components/ScreenWrapper'; -import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import type {ListItem} from '@components/SelectionList/types'; +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 * as Connections from '@libs/actions/connections'; +import * as ErrorUtils from '@libs/ErrorUtils'; +import * as PolicyUtils from '@libs/PolicyUtils'; import Navigation from '@navigation/Navigation'; -import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections'; import withPolicyConnections from '@pages/workspace/withPolicyConnections'; +import {clearQBOErrorField} from '@userActions/Policy/Policy'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type {Account, QBONonReimbursableExportAccountType} from '@src/types/onyx/Policy'; -type AccountListItem = ListItem & { +type MenuItem = ListItem & { value: QBONonReimbursableExportAccountType; accounts: Account[]; defaultVendor: string; @@ -27,17 +27,17 @@ function QuickbooksCompanyCardExpenseAccountSelectCardPage({policy}: WithPolicyC const {translate} = useLocalize(); const styles = useThemeStyles(); const policyID = policy?.id ?? '-1'; - const {nonReimbursableExpensesExportDestination, nonReimbursableExpensesAccount, syncLocations, nonReimbursableBillDefaultVendor} = policy?.connections?.quickbooksOnline?.config ?? {}; + const qboConfig = policy?.connections?.quickbooksOnline?.config; const {creditCards, bankAccounts, accountPayable, vendors} = policy?.connections?.quickbooksOnline?.data ?? {}; - const isLocationEnabled = !!(syncLocations && syncLocations !== CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE); + const isLocationEnabled = !!(qboConfig?.syncLocations && qboConfig?.syncLocations !== CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE); const sections = useMemo(() => { - const options: AccountListItem[] = [ + const options: MenuItem[] = [ { text: translate(`workspace.qbo.accounts.credit_card`), value: CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.CREDIT_CARD, keyForList: CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.CREDIT_CARD, - isSelected: CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.CREDIT_CARD === nonReimbursableExpensesExportDestination, + isSelected: CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.CREDIT_CARD === qboConfig?.nonReimbursableExpensesExportDestination, accounts: creditCards ?? [], defaultVendor: CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE, }, @@ -45,7 +45,7 @@ function QuickbooksCompanyCardExpenseAccountSelectCardPage({policy}: WithPolicyC text: translate(`workspace.qbo.accounts.debit_card`), value: CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.DEBIT_CARD, keyForList: CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.DEBIT_CARD, - isSelected: CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.DEBIT_CARD === nonReimbursableExpensesExportDestination, + isSelected: CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.DEBIT_CARD === qboConfig?.nonReimbursableExpensesExportDestination, accounts: bankAccounts ?? [], defaultVendor: CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE, }, @@ -55,60 +55,58 @@ function QuickbooksCompanyCardExpenseAccountSelectCardPage({policy}: WithPolicyC text: translate(`workspace.qbo.accounts.bill`), value: CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.VENDOR_BILL, keyForList: CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.VENDOR_BILL, - isSelected: CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.VENDOR_BILL === nonReimbursableExpensesExportDestination, + isSelected: CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.VENDOR_BILL === qboConfig?.nonReimbursableExpensesExportDestination, accounts: accountPayable ?? [], defaultVendor: vendors?.[0]?.id ?? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE, }); } return [{data: options}]; - }, [translate, nonReimbursableExpensesExportDestination, isLocationEnabled, accountPayable, bankAccounts, creditCards, vendors]); + }, [translate, qboConfig?.nonReimbursableExpensesExportDestination, isLocationEnabled, accountPayable, bankAccounts, creditCards, vendors]); const selectExportCompanyCard = useCallback( - (row: AccountListItem) => { - if (row.value !== nonReimbursableExpensesExportDestination) { + (row: MenuItem) => { + if (row.value !== qboConfig?.nonReimbursableExpensesExportDestination) { Connections.updateManyPolicyConnectionConfigs( policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, { - [CONST.QUICK_BOOKS_CONFIG.NON_REIMBURSABLE_EXPENSES_EXPORT_DESTINATION]: row.value, - [CONST.QUICK_BOOKS_CONFIG.NON_REIMBURSABLE_EXPENSES_ACCOUNT]: row.accounts[0], - [CONST.QUICK_BOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR]: row.defaultVendor, + [CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_EXPENSES_EXPORT_DESTINATION]: row.value, + [CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_EXPENSES_ACCOUNT]: row.accounts[0], + [CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR]: row.defaultVendor, }, { - [CONST.QUICK_BOOKS_CONFIG.NON_REIMBURSABLE_EXPENSES_EXPORT_DESTINATION]: nonReimbursableExpensesExportDestination, - [CONST.QUICK_BOOKS_CONFIG.NON_REIMBURSABLE_EXPENSES_ACCOUNT]: nonReimbursableExpensesAccount, - [CONST.QUICK_BOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR]: nonReimbursableBillDefaultVendor, + [CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_EXPENSES_EXPORT_DESTINATION]: qboConfig?.nonReimbursableExpensesExportDestination, + [CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_EXPENSES_ACCOUNT]: qboConfig?.nonReimbursableExpensesAccount, + [CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR]: qboConfig?.nonReimbursableBillDefaultVendor, }, ); } Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT.getRoute(policyID)); }, - [nonReimbursableExpensesExportDestination, policyID, nonReimbursableExpensesAccount, nonReimbursableBillDefaultVendor], + [qboConfig?.nonReimbursableExpensesExportDestination, policyID, qboConfig?.nonReimbursableExpensesAccount, qboConfig?.nonReimbursableBillDefaultVendor], ); - return ( - - - - - option.isSelected)?.keyForList} - footerContent={ - isLocationEnabled && {translate('workspace.qbo.companyCardsLocationEnabledDescription')} - } - /> - - - + displayName={QuickbooksCompanyCardExpenseAccountSelectCardPage.displayName} + title="workspace.accounting.exportAs" + sections={sections} + listItem={RadioListItem} + onSelectRow={(selection: SelectorType) => selectExportCompanyCard(selection as MenuItem)} + shouldSingleExecuteRowSelect + initiallyFocusedOptionKey={sections[0]?.data.find((mode) => mode.isSelected)?.keyForList} + connectionName={CONST.POLICY.CONNECTIONS.NAME.QBO} + onBackButtonPress={() => Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT.getRoute(policyID))} + listFooterContent={ + isLocationEnabled ? {translate('workspace.qbo.companyCardsLocationEnabledDescription')} : undefined + } + errors={ErrorUtils.getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_EXPENSES_EXPORT_DESTINATION)} + errorRowStyles={[styles.ph5, styles.pv3]} + pendingAction={PolicyUtils.settingsPendingAction([CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_EXPENSES_EXPORT_DESTINATION], qboConfig?.pendingFields)} + onClose={() => clearQBOErrorField(policyID, CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_EXPENSES_EXPORT_DESTINATION)} + /> ); } diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountSelectPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountSelectPage.tsx index 8bee7d206180..5506be9c1ab0 100644 --- a/src/pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountSelectPage.tsx +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksCompanyCardExpenseAccountSelectPage.tsx @@ -1,21 +1,21 @@ import React, {useCallback, useMemo} from 'react'; import BlockingView from '@components/BlockingViews/BlockingView'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Illustrations from '@components/Icon/Illustrations'; -import ScreenWrapper from '@components/ScreenWrapper'; -import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import type {ListItem} from '@components/SelectionList/types'; +import SelectionScreen from '@components/SelectionScreen'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as Connections from '@libs/actions/connections'; import * as ConnectionUtils from '@libs/ConnectionUtils'; +import * as ErrorUtils from '@libs/ErrorUtils'; +import * as PolicyUtils from '@libs/PolicyUtils'; import Navigation from '@navigation/Navigation'; -import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections'; import withPolicyConnections from '@pages/workspace/withPolicyConnections'; import variables from '@styles/variables'; +import {clearQBOErrorField} from '@userActions/Policy/Policy'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type {Account} from '@src/types/onyx/Policy'; @@ -29,12 +29,11 @@ function QuickbooksCompanyCardExpenseAccountSelectPage({policy}: WithPolicyConne const styles = useThemeStyles(); const policyID = policy?.id ?? '-1'; const {creditCards, accountPayable, bankAccounts} = policy?.connections?.quickbooksOnline?.data ?? {}; - - const {nonReimbursableExpensesAccount, nonReimbursableExpensesExportDestination} = policy?.connections?.quickbooksOnline?.config ?? {}; + const qboConfig = policy?.connections?.quickbooksOnline?.config; const data: CardListItem[] = useMemo(() => { let accounts: Account[]; - switch (nonReimbursableExpensesExportDestination) { + switch (qboConfig?.nonReimbursableExpensesExportDestination) { case CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.CREDIT_CARD: accounts = creditCards ?? []; break; @@ -52,18 +51,24 @@ function QuickbooksCompanyCardExpenseAccountSelectPage({policy}: WithPolicyConne value: card, text: card.name, keyForList: card.name, - isSelected: card.name === nonReimbursableExpensesAccount?.name, + isSelected: card.name === qboConfig?.nonReimbursableExpensesAccount?.name, })); - }, [nonReimbursableExpensesAccount, creditCards, bankAccounts, nonReimbursableExpensesExportDestination, accountPayable]); + }, [qboConfig?.nonReimbursableExpensesAccount, creditCards, bankAccounts, qboConfig?.nonReimbursableExpensesExportDestination, accountPayable]); const selectExportAccount = useCallback( (row: CardListItem) => { - if (row.value.id !== nonReimbursableExpensesAccount?.id) { - Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, CONST.QUICK_BOOKS_CONFIG.NON_REIMBURSABLE_EXPENSES_ACCOUNT, row.value); + if (row.value.id !== qboConfig?.nonReimbursableExpensesAccount?.id) { + Connections.updatePolicyConnectionConfig( + policyID, + CONST.POLICY.CONNECTIONS.NAME.QBO, + CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_EXPENSES_ACCOUNT, + row.value, + qboConfig?.nonReimbursableExpensesAccount, + ); } Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT.getRoute(policyID)); }, - [nonReimbursableExpensesAccount, policyID], + [qboConfig?.nonReimbursableExpensesAccount, policyID], ); const listEmptyContent = useMemo( @@ -79,30 +84,31 @@ function QuickbooksCompanyCardExpenseAccountSelectPage({policy}: WithPolicyConne ), [translate, styles.pb10], ); - return ( - - - - {translate(`workspace.qbo.accounts.${nonReimbursableExpensesExportDestination}AccountDescription`)} - ) : null - } - sections={data.length ? [{data}] : []} - ListItem={RadioListItem} - onSelectRow={selectExportAccount} - shouldSingleExecuteRowSelect - initiallyFocusedOptionKey={data.find((mode) => mode.isSelected)?.keyForList} - listEmptyContent={listEmptyContent} - /> - - + displayName={QuickbooksCompanyCardExpenseAccountSelectPage.displayName} + headerTitleAlreadyTranslated={ConnectionUtils.getQBONonReimbursableExportAccountType(qboConfig?.nonReimbursableExpensesExportDestination)} + headerContent={ + qboConfig?.nonReimbursableExpensesExportDestination ? ( + {translate(`workspace.qbo.accounts.${qboConfig?.nonReimbursableExpensesExportDestination}AccountDescription`)} + ) : null + } + sections={data.length ? [{data}] : []} + listItem={RadioListItem} + onSelectRow={selectExportAccount} + shouldSingleExecuteRowSelect + initiallyFocusedOptionKey={data.find((mode) => mode.isSelected)?.keyForList} + listEmptyContent={listEmptyContent} + connectionName={CONST.POLICY.CONNECTIONS.NAME.QBO} + onBackButtonPress={() => Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT.getRoute(policyID))} + errors={ErrorUtils.getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_EXPENSES_ACCOUNT)} + errorRowStyles={[styles.ph5, styles.pv3]} + pendingAction={PolicyUtils.settingsPendingAction([CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_EXPENSES_ACCOUNT], qboConfig?.pendingFields)} + onClose={() => clearQBOErrorField(policyID, CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_EXPENSES_ACCOUNT)} + /> ); } diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksExportConfigurationPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksExportConfigurationPage.tsx index b60431661f34..318582519604 100644 --- a/src/pages/workspace/accounting/qbo/export/QuickbooksExportConfigurationPage.tsx +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksExportConfigurationPage.tsx @@ -1,79 +1,67 @@ -import React from 'react'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import type {MenuItemProps} from '@components/MenuItem'; +import React, {useMemo} from 'react'; +import ConnectionLayout from '@components/ConnectionLayout'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; -import type {OfflineWithFeedbackProps} from '@components/OfflineWithFeedback'; -import ScreenWrapper from '@components/ScreenWrapper'; -import ScrollView from '@components/ScrollView'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; +import * as PolicyUtils from '@libs/PolicyUtils'; import Navigation from '@navigation/Navigation'; -import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections'; import withPolicyConnections from '@pages/workspace/withPolicyConnections'; import * as Link from '@userActions/Link'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; -type MenuItem = MenuItemProps & {pendingAction?: OfflineWithFeedbackProps['pendingAction']}; - function QuickbooksExportConfigurationPage({policy}: WithPolicyConnectionsProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const policyID = policy?.id ?? '-1'; const policyOwner = policy?.owner ?? ''; - const { - export: exportConfiguration, - exportDate, - reimbursableExpensesExportDestination, - receivableAccount, - nonReimbursableExpensesExportDestination, - errorFields, - pendingFields, - } = policy?.connections?.quickbooksOnline?.config ?? {}; - const menuItems: MenuItem[] = [ + const qboConfig = policy?.connections?.quickbooksOnline?.config; + const errorFields = qboConfig?.errorFields; + + const shouldShowVendorMenuItems = useMemo( + () => qboConfig?.nonReimbursableExpensesExportDestination === CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.VENDOR_BILL, + [qboConfig?.nonReimbursableExpensesExportDestination], + ); + const menuItems = [ { description: translate('workspace.accounting.preferredExporter'), onPress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_PREFERRED_EXPORTER.getRoute(policyID)), - brickRoadIndicator: errorFields?.exporter ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, - title: exportConfiguration?.exporter ?? policyOwner, - pendingAction: pendingFields?.export, - errorText: errorFields?.exporter ? translate('common.genericErrorMessage') : undefined, + title: qboConfig?.export?.exporter ?? policyOwner, + subscribedSettings: [CONST.QUICKBOOKS_CONFIG.EXPORTER], }, { description: translate('workspace.qbo.date'), onPress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_DATE_SELECT.getRoute(policyID)), - brickRoadIndicator: errorFields?.exportDate ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, - title: exportDate ? translate(`workspace.qbo.exportDate.values.${exportDate}.label`) : undefined, - pendingAction: pendingFields?.exportDate, - errorText: errorFields?.exportDate ? translate('common.genericErrorMessage') : undefined, + title: qboConfig?.exportDate ? translate(`workspace.qbo.exportDate.values.${qboConfig?.exportDate}.label`) : undefined, + subscribedSettings: [CONST.QUICKBOOKS_CONFIG.EXPORT_DATE], }, { description: translate('workspace.accounting.exportOutOfPocket'), onPress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES.getRoute(policyID)), - brickRoadIndicator: !!errorFields?.exportEntity || !!errorFields?.reimbursableExpensesAccount ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, - title: reimbursableExpensesExportDestination ? translate(`workspace.qbo.accounts.${reimbursableExpensesExportDestination}`) : undefined, - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - pendingAction: pendingFields?.reimbursableExpensesExportDestination || pendingFields?.reimbursableExpensesAccount, + title: qboConfig?.reimbursableExpensesExportDestination ? translate(`workspace.qbo.accounts.${qboConfig?.reimbursableExpensesExportDestination}`) : undefined, + subscribedSettings: [CONST.QUICKBOOKS_CONFIG.REIMBURSABLE_EXPENSES_EXPORT_DESTINATION, CONST.QUICKBOOKS_CONFIG.REIMBURSABLE_EXPENSES_ACCOUNT], }, { description: translate('workspace.qbo.exportInvoices'), onPress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECT.getRoute(policyID)), - brickRoadIndicator: errorFields?.receivableAccount ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, - title: receivableAccount?.name, - pendingAction: pendingFields?.receivableAccount, - errorText: errorFields?.receivableAccount ? translate('common.genericErrorMessage') : undefined, + title: qboConfig?.receivableAccount?.name, + subscribedSettings: [CONST.QUICKBOOKS_CONFIG.RECEIVABLE_ACCOUNT], }, { description: translate('workspace.accounting.exportCompanyCard'), onPress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT.getRoute(policyID)), - brickRoadIndicator: errorFields?.exportCompanyCard ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, - title: nonReimbursableExpensesExportDestination ? translate(`workspace.qbo.accounts.${nonReimbursableExpensesExportDestination}`) : undefined, - pendingAction: pendingFields?.nonReimbursableExpensesExportDestination, - errorText: errorFields?.nonReimbursableExpensesExportDestination ? translate('common.genericErrorMessage') : undefined, + brickRoadIndicator: qboConfig?.errorFields?.exportCompanyCard ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, + title: qboConfig?.nonReimbursableExpensesExportDestination ? translate(`workspace.qbo.accounts.${qboConfig?.nonReimbursableExpensesExportDestination}`) : undefined, + subscribedSettings: [ + CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_EXPENSES_EXPORT_DESTINATION, + CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_EXPENSE_ACCOUNT, + ...(shouldShowVendorMenuItems ? [CONST.QUICKBOOKS_CONFIG.AUTO_CREATE_VENDOR] : []), + ...(shouldShowVendorMenuItems && qboConfig?.autoCreateVendor ? [CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR] : []), + ], }, { description: translate('workspace.qbo.exportExpensifyCard'), @@ -84,46 +72,43 @@ function QuickbooksExportConfigurationPage({policy}: WithPolicyConnectionsProps) ]; return ( - Navigation.goBack(ROUTES.POLICY_ACCOUNTING.getRoute(policyID))} > - - - - {translate('workspace.qbo.exportDescription')} - {menuItems.map((menuItem) => ( - - - - ))} - - {`${translate('workspace.qbo.deepDiveExpensifyCard')} `} - Link.openExternalLink(CONST.DEEP_DIVE_EXPENSIFY_CARD)} - style={[styles.mutedNormalTextLabel, styles.link]} - > - {translate('workspace.qbo.deepDiveExpensifyCardIntegration')} - - - - - + {menuItems.map((menuItem) => ( + + + + ))} + + {`${translate('workspace.qbo.deepDiveExpensifyCard')} `} + Link.openExternalLink(CONST.DEEP_DIVE_EXPENSIFY_CARD)} + style={[styles.mutedNormalTextLabel, styles.link]} + > + {translate('workspace.qbo.deepDiveExpensifyCardIntegration')} + + + ); } diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksExportDateSelectPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksExportDateSelectPage.tsx index 89fbd6a96b33..a48a56b7710b 100644 --- a/src/pages/workspace/accounting/qbo/export/QuickbooksExportDateSelectPage.tsx +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksExportDateSelectPage.tsx @@ -1,18 +1,18 @@ -import React, {useCallback} from 'react'; +import React, {useCallback, useMemo} from 'react'; import type {ValueOf} from 'type-fest'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import ScreenWrapper from '@components/ScreenWrapper'; -import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import type {ListItem} from '@components/SelectionList/types'; +import SelectionScreen from '@components/SelectionScreen'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as Connections from '@libs/actions/connections'; +import * as ErrorUtils from '@libs/ErrorUtils'; +import * as PolicyUtils from '@libs/PolicyUtils'; import Navigation from '@navigation/Navigation'; -import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections'; import withPolicyConnections from '@pages/workspace/withPolicyConnections'; +import {clearQBOErrorField} from '@userActions/Policy/Policy'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; @@ -23,46 +23,47 @@ function QuickbooksExportDateSelectPage({policy}: WithPolicyConnectionsProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const policyID = policy?.id ?? '-1'; - const {exportDate} = policy?.connections?.quickbooksOnline?.config ?? {}; + const qboConfig = policy?.connections?.quickbooksOnline?.config; const data: CardListItem[] = Object.values(CONST.QUICKBOOKS_EXPORT_DATE).map((dateType) => ({ value: dateType, text: translate(`workspace.qbo.exportDate.values.${dateType}.label`), alternateText: translate(`workspace.qbo.exportDate.values.${dateType}.description`), keyForList: dateType, - isSelected: exportDate === dateType, + isSelected: qboConfig?.exportDate === dateType, })); + const exportDate = useMemo(() => qboConfig?.exportDate, [qboConfig]); + const selectExportDate = useCallback( (row: CardListItem) => { if (row.value !== exportDate) { - Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, CONST.QUICK_BOOKS_CONFIG.EXPORT_DATE, row.value); + Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, CONST.QUICKBOOKS_CONFIG.EXPORT_DATE, row.value, exportDate); } Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_DATE_SELECT.getRoute(policyID)); }, - [exportDate, policyID], + [policyID, exportDate], ); return ( - - - - {translate('workspace.qbo.exportDate.description')}} - sections={[{data}]} - ListItem={RadioListItem} - onSelectRow={selectExportDate} - shouldSingleExecuteRowSelect - initiallyFocusedOptionKey={data.find((mode) => mode.isSelected)?.keyForList} - /> - - + displayName={QuickbooksExportDateSelectPage.displayName} + sections={[{data}]} + listItem={RadioListItem} + headerContent={{translate('workspace.qbo.exportDate.description')}} + onBackButtonPress={() => Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT.getRoute(policyID))} + onSelectRow={selectExportDate} + initiallyFocusedOptionKey={data.find((mode) => mode.isSelected)?.keyForList} + title="workspace.qbo.exportDate.label" + connectionName={CONST.POLICY.CONNECTIONS.NAME.QBO} + pendingAction={PolicyUtils.settingsPendingAction([CONST.QUICKBOOKS_CONFIG.EXPORT_DATE], qboConfig?.pendingFields)} + errors={ErrorUtils.getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.EXPORT_DATE)} + errorRowStyles={[styles.ph5, styles.pv3]} + onClose={() => clearQBOErrorField(policyID, CONST.QUICKBOOKS_CONFIG.EXPORT_DATE)} + shouldSingleExecuteRowSelect + /> ); } diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksExportInvoiceAccountSelectPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksExportInvoiceAccountSelectPage.tsx index e2b285fe3d41..69efae3e558b 100644 --- a/src/pages/workspace/accounting/qbo/export/QuickbooksExportInvoiceAccountSelectPage.tsx +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksExportInvoiceAccountSelectPage.tsx @@ -1,20 +1,20 @@ import React, {useCallback, useMemo} from 'react'; import BlockingView from '@components/BlockingViews/BlockingView'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Illustrations from '@components/Icon/Illustrations'; -import ScreenWrapper from '@components/ScreenWrapper'; -import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import type {ListItem} from '@components/SelectionList/types'; +import SelectionScreen from '@components/SelectionScreen'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as Connections from '@libs/actions/connections'; +import * as ErrorUtils from '@libs/ErrorUtils'; +import * as PolicyUtils from '@libs/PolicyUtils'; import Navigation from '@navigation/Navigation'; -import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections'; import withPolicyConnections from '@pages/workspace/withPolicyConnections'; import variables from '@styles/variables'; +import {clearQBOErrorField} from '@userActions/Policy/Policy'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type {Account} from '@src/types/onyx/Policy'; @@ -27,7 +27,7 @@ function QuickbooksExportInvoiceAccountSelectPage({policy}: WithPolicyConnection const {translate} = useLocalize(); const styles = useThemeStyles(); const {accountsReceivable} = policy?.connections?.quickbooksOnline?.data ?? {}; - const {receivableAccount} = policy?.connections?.quickbooksOnline?.config ?? {}; + const qboConfig = policy?.connections?.quickbooksOnline?.config; const policyID = policy?.id ?? '-1'; const data: CardListItem[] = useMemo( @@ -36,19 +36,19 @@ function QuickbooksExportInvoiceAccountSelectPage({policy}: WithPolicyConnection value: account, text: account.name, keyForList: account.name, - isSelected: account.id === receivableAccount?.id, + isSelected: account.id === qboConfig?.receivableAccount?.id, })) ?? [], - [receivableAccount, accountsReceivable], + [qboConfig?.receivableAccount, accountsReceivable], ); const selectExportInvoice = useCallback( (row: CardListItem) => { - if (row.value.id !== receivableAccount?.id) { - Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, CONST.QUICK_BOOKS_CONFIG.RECEIVABLE_ACCOUNT, row.value); + if (row.value.id !== qboConfig?.receivableAccount?.id) { + Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, CONST.QUICKBOOKS_CONFIG.RECEIVABLE_ACCOUNT, row.value, qboConfig?.receivableAccount); } Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECT.getRoute(policyID)); }, - [receivableAccount, policyID], + [qboConfig?.receivableAccount, policyID], ); const listEmptyContent = useMemo( @@ -66,24 +66,26 @@ function QuickbooksExportInvoiceAccountSelectPage({policy}: WithPolicyConnection ); return ( - - - - {translate('workspace.qbo.exportInvoicesDescription')}} - sections={data.length ? [{data}] : []} - ListItem={RadioListItem} - onSelectRow={selectExportInvoice} - shouldSingleExecuteRowSelect - initiallyFocusedOptionKey={data.find((mode) => mode.isSelected)?.keyForList} - listEmptyContent={listEmptyContent} - /> - - + displayName={QuickbooksExportInvoiceAccountSelectPage.displayName} + sections={data.length ? [{data}] : []} + listItem={RadioListItem} + headerContent={{translate('workspace.qbo.exportInvoicesDescription')}} + onBackButtonPress={() => Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT.getRoute(policyID))} + onSelectRow={selectExportInvoice} + initiallyFocusedOptionKey={data.find((mode) => mode.isSelected)?.keyForList} + title="workspace.qbo.exportInvoices" + connectionName={CONST.POLICY.CONNECTIONS.NAME.QBO} + pendingAction={PolicyUtils.settingsPendingAction([CONST.QUICKBOOKS_CONFIG.RECEIVABLE_ACCOUNT], qboConfig?.pendingFields)} + errors={ErrorUtils.getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.RECEIVABLE_ACCOUNT)} + errorRowStyles={[styles.ph5, styles.pv3]} + onClose={() => clearQBOErrorField(policyID, CONST.QUICKBOOKS_CONFIG.RECEIVABLE_ACCOUNT)} + listEmptyContent={listEmptyContent} + shouldSingleExecuteRowSelect + /> ); } diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksNonReimbursableDefaultVendorSelectPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksNonReimbursableDefaultVendorSelectPage.tsx index 368cecc5de3b..95fe2793af2b 100644 --- a/src/pages/workspace/accounting/qbo/export/QuickbooksNonReimbursableDefaultVendorSelectPage.tsx +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksNonReimbursableDefaultVendorSelectPage.tsx @@ -1,19 +1,19 @@ import React, {useCallback, useMemo} from 'react'; import BlockingView from '@components/BlockingViews/BlockingView'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Illustrations from '@components/Icon/Illustrations'; -import ScreenWrapper from '@components/ScreenWrapper'; -import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import type {ListItem} from '@components/SelectionList/types'; +import SelectionScreen from '@components/SelectionScreen'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as QuickbooksOnline from '@libs/actions/connections/QuickbooksOnline'; +import * as ErrorUtils from '@libs/ErrorUtils'; +import * as PolicyUtils from '@libs/PolicyUtils'; import Navigation from '@navigation/Navigation'; -import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections'; import withPolicyConnections from '@pages/workspace/withPolicyConnections'; import variables from '@styles/variables'; +import {clearQBOErrorField} from '@userActions/Policy/Policy'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; @@ -25,7 +25,7 @@ function QuickbooksNonReimbursableDefaultVendorSelectPage({policy}: WithPolicyCo const {translate} = useLocalize(); const styles = useThemeStyles(); const {vendors} = policy?.connections?.quickbooksOnline?.data ?? {}; - const {nonReimbursableBillDefaultVendor} = policy?.connections?.quickbooksOnline?.config ?? {}; + const qboConfig = policy?.connections?.quickbooksOnline?.config; const policyID = policy?.id ?? '-1'; const sections = useMemo(() => { @@ -34,19 +34,19 @@ function QuickbooksNonReimbursableDefaultVendorSelectPage({policy}: WithPolicyCo value: vendor.id, text: vendor.name, keyForList: vendor.name, - isSelected: vendor.id === nonReimbursableBillDefaultVendor, + isSelected: vendor.id === qboConfig?.nonReimbursableBillDefaultVendor, })) ?? []; return data.length ? [{data}] : []; - }, [nonReimbursableBillDefaultVendor, vendors]); + }, [qboConfig?.nonReimbursableBillDefaultVendor, vendors]); const selectVendor = useCallback( (row: CardListItem) => { - if (row.value !== nonReimbursableBillDefaultVendor) { - QuickbooksOnline.updateQuickbooksOnlineNonReimbursableBillDefaultVendor(policyID, row.value); + if (row.value !== qboConfig?.nonReimbursableBillDefaultVendor) { + QuickbooksOnline.updateQuickbooksOnlineNonReimbursableBillDefaultVendor(policyID, row.value, qboConfig?.nonReimbursableBillDefaultVendor); } Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT.getRoute(policyID)); }, - [nonReimbursableBillDefaultVendor, policyID], + [qboConfig?.nonReimbursableBillDefaultVendor, policyID], ); const listEmptyContent = useMemo( @@ -64,23 +64,25 @@ function QuickbooksNonReimbursableDefaultVendorSelectPage({policy}: WithPolicyCo ); return ( - - - - mode.isSelected)?.keyForList} - listEmptyContent={listEmptyContent} - /> - - + displayName={QuickbooksNonReimbursableDefaultVendorSelectPage.displayName} + title="workspace.accounting.defaultVendor" + sections={sections} + listItem={RadioListItem} + onSelectRow={selectVendor} + shouldSingleExecuteRowSelect + initiallyFocusedOptionKey={sections[0]?.data.find((mode) => mode.isSelected)?.keyForList} + listEmptyContent={listEmptyContent} + connectionName={CONST.POLICY.CONNECTIONS.NAME.QBO} + onBackButtonPress={() => Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT.getRoute(policyID))} + pendingAction={PolicyUtils.settingsPendingAction([CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR], qboConfig?.pendingFields)} + errors={ErrorUtils.getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR)} + errorRowStyles={[styles.ph5, styles.pv3]} + onClose={() => clearQBOErrorField(policyID, CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR)} + /> ); } diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseAccountSelectPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseAccountSelectPage.tsx index 1e50464d3b06..6ca3b2c114b5 100644 --- a/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseAccountSelectPage.tsx +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseAccountSelectPage.tsx @@ -1,49 +1,48 @@ import React, {useCallback, useMemo} from 'react'; import BlockingView from '@components/BlockingViews/BlockingView'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Illustrations from '@components/Icon/Illustrations'; -import ScreenWrapper from '@components/ScreenWrapper'; -import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import type {ListItem} from '@components/SelectionList/types'; +import SelectionScreen from '@components/SelectionScreen'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as QuickbooksOnline from '@libs/actions/connections/QuickbooksOnline'; +import * as ErrorUtils from '@libs/ErrorUtils'; +import * as PolicyUtils from '@libs/PolicyUtils'; import Navigation from '@navigation/Navigation'; -import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections'; import withPolicyConnections from '@pages/workspace/withPolicyConnections'; import variables from '@styles/variables'; +import {clearQBOErrorField} from '@userActions/Policy/Policy'; import CONST from '@src/CONST'; +import type {TranslationPaths} from '@src/languages/types'; import ROUTES from '@src/ROUTES'; import type {Account} from '@src/types/onyx/Policy'; type CardListItem = ListItem & { value: Account; }; - function QuickbooksOutOfPocketExpenseAccountSelectPage({policy}: WithPolicyConnectionsProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const {bankAccounts, journalEntryAccounts, accountPayable} = policy?.connections?.quickbooksOnline?.data ?? {}; - - const {reimbursableExpensesExportDestination, reimbursableExpensesAccount} = policy?.connections?.quickbooksOnline?.config ?? {}; + const qboConfig = policy?.connections?.quickbooksOnline?.config; const [title, description] = useMemo(() => { - let titleText: string | undefined; + let titleText: TranslationPaths | undefined; let descriptionText: string | undefined; - switch (reimbursableExpensesExportDestination) { + switch (qboConfig?.reimbursableExpensesExportDestination) { case CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.CHECK: - titleText = translate('workspace.qbo.bankAccount'); + titleText = 'workspace.qbo.bankAccount'; descriptionText = translate('workspace.qbo.bankAccountDescription'); break; case CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.JOURNAL_ENTRY: - titleText = translate('workspace.qbo.account'); + titleText = 'workspace.qbo.account'; descriptionText = translate('workspace.qbo.accountDescription'); break; case CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.VENDOR_BILL: - titleText = translate('workspace.qbo.accountsPayable'); + titleText = 'workspace.qbo.accountsPayable'; descriptionText = translate('workspace.qbo.accountsPayableDescription'); break; default: @@ -51,11 +50,11 @@ function QuickbooksOutOfPocketExpenseAccountSelectPage({policy}: WithPolicyConne } return [titleText, descriptionText]; - }, [translate, reimbursableExpensesExportDestination]); + }, [qboConfig?.reimbursableExpensesExportDestination, translate]); const data: CardListItem[] = useMemo(() => { let accounts: Account[]; - switch (reimbursableExpensesExportDestination) { + switch (qboConfig?.reimbursableExpensesExportDestination) { case CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.CHECK: accounts = bankAccounts ?? []; break; @@ -73,20 +72,20 @@ function QuickbooksOutOfPocketExpenseAccountSelectPage({policy}: WithPolicyConne value: account, text: account.name, keyForList: account.name, - isSelected: account.id === reimbursableExpensesAccount?.id, + isSelected: account.id === qboConfig?.reimbursableExpensesAccount?.id, })); - }, [accountPayable, bankAccounts, reimbursableExpensesExportDestination, reimbursableExpensesAccount, journalEntryAccounts]); + }, [qboConfig?.reimbursableExpensesExportDestination, qboConfig?.reimbursableExpensesAccount?.id, bankAccounts, journalEntryAccounts, accountPayable]); const policyID = policy?.id ?? '-1'; const selectExportAccount = useCallback( (row: CardListItem) => { - if (row.value.id !== reimbursableExpensesAccount?.id) { - QuickbooksOnline.updateQuickbooksOnlineReimbursableExpensesAccount(policyID, row.value); + if (row.value.id !== qboConfig?.reimbursableExpensesAccount?.id) { + QuickbooksOnline.updateQuickbooksOnlineReimbursableExpensesAccount(policyID, row.value, qboConfig?.reimbursableExpensesAccount); } Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES.getRoute(policyID)); }, - [reimbursableExpensesAccount, policyID], + [qboConfig?.reimbursableExpensesAccount, policyID], ); const listEmptyContent = useMemo( @@ -104,24 +103,26 @@ function QuickbooksOutOfPocketExpenseAccountSelectPage({policy}: WithPolicyConne ); return ( - - - - {description}} - sections={data.length ? [{data}] : []} - ListItem={RadioListItem} - onSelectRow={selectExportAccount} - shouldSingleExecuteRowSelect - initiallyFocusedOptionKey={data.find((mode) => mode.isSelected)?.keyForList} - listEmptyContent={listEmptyContent} - /> - - + displayName={QuickbooksOutOfPocketExpenseAccountSelectPage.displayName} + sections={data.length ? [{data}] : []} + listItem={RadioListItem} + headerContent={{description}} + onBackButtonPress={() => Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES.getRoute(policyID))} + onSelectRow={selectExportAccount} + initiallyFocusedOptionKey={data.find((mode) => mode.isSelected)?.keyForList} + title={title} + connectionName={CONST.POLICY.CONNECTIONS.NAME.QBO} + pendingAction={PolicyUtils.settingsPendingAction([CONST.QUICKBOOKS_CONFIG.REIMBURSABLE_EXPENSES_ACCOUNT], qboConfig?.pendingFields)} + errors={ErrorUtils.getLatestErrorField(qboConfig, CONST.QUICKBOOKS_CONFIG.REIMBURSABLE_EXPENSES_ACCOUNT)} + errorRowStyles={[styles.ph5, styles.pv3]} + onClose={() => clearQBOErrorField(policyID, CONST.QUICKBOOKS_CONFIG.REIMBURSABLE_EXPENSES_ACCOUNT)} + listEmptyContent={listEmptyContent} + shouldSingleExecuteRowSelect + /> ); } diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseConfigurationPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseConfigurationPage.tsx index 679f021e60fa..772b33bb8872 100644 --- a/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseConfigurationPage.tsx +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseConfigurationPage.tsx @@ -1,33 +1,42 @@ import React, {useMemo} from 'react'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import type {ValueOf} from 'type-fest'; +import ConnectionLayout from '@components/ConnectionLayout'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; -import ScreenWrapper from '@components/ScreenWrapper'; -import ScrollView from '@components/ScrollView'; -import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; +import * as PolicyUtils from '@libs/PolicyUtils'; import Navigation from '@navigation/Navigation'; -import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections'; import withPolicyConnections from '@pages/workspace/withPolicyConnections'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; +import type {PendingAction} from '@src/types/onyx/OnyxCommon'; + +type QBOSectionType = { + title?: string; + description?: string; + onPress: () => void; + errorText?: string; + hintText?: string; + subscribedSettings: string[]; + pendingAction?: PendingAction; + brickRoadIndicator?: ValueOf; +}; +const account = [CONST.QUICKBOOKS_CONFIG.REIMBURSABLE_EXPENSES_ACCOUNT]; +const accountOrExportDestination = [CONST.QUICKBOOKS_CONFIG.REIMBURSABLE_EXPENSES_EXPORT_DESTINATION, CONST.QUICKBOOKS_CONFIG.REIMBURSABLE_EXPENSES_ACCOUNT]; function QuickbooksOutOfPocketExpenseConfigurationPage({policy}: WithPolicyConnectionsProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const policyID = policy?.id ?? '-1'; - const {syncLocations, syncTax, reimbursableExpensesAccount, reimbursableExpensesExportDestination, errorFields, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; - const isLocationEnabled = !!(syncLocations && syncLocations !== CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE); - const isTaxesEnabled = !!syncTax; - const shouldShowTaxError = isTaxesEnabled && reimbursableExpensesExportDestination === CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.JOURNAL_ENTRY; - const shouldShowLocationError = isLocationEnabled && reimbursableExpensesExportDestination !== CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.JOURNAL_ENTRY; - const hasErrors = !!errorFields?.reimbursableExpensesExportDestination || shouldShowTaxError || shouldShowLocationError; + const qboConfig = policy?.connections?.quickbooksOnline?.config; + const isLocationEnabled = !!(qboConfig?.syncLocations && qboConfig?.syncLocations !== CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE); + const isTaxesEnabled = !!qboConfig?.syncTax; const [exportHintText, accountDescription] = useMemo(() => { let hintText: string | undefined; let description: string | undefined; - switch (reimbursableExpensesExportDestination) { + switch (qboConfig?.reimbursableExpensesExportDestination) { case CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.CHECK: hintText = isLocationEnabled ? undefined : translate('workspace.qbo.exportCheckDescription'); description = translate('workspace.qbo.bankAccount'); @@ -45,45 +54,58 @@ function QuickbooksOutOfPocketExpenseConfigurationPage({policy}: WithPolicyConne } return [hintText, description]; - }, [translate, reimbursableExpensesExportDestination, isLocationEnabled, isTaxesEnabled]); + }, [translate, qboConfig?.reimbursableExpensesExportDestination, isLocationEnabled, isTaxesEnabled]); + + const sections: QBOSectionType[] = [ + { + title: qboConfig?.reimbursableExpensesExportDestination ? translate(`workspace.qbo.accounts.${qboConfig?.reimbursableExpensesExportDestination}`) : undefined, + description: translate('workspace.accounting.exportAs'), + onPress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_SELECT.getRoute(policyID)), + hintText: exportHintText, + subscribedSettings: accountOrExportDestination, + pendingAction: PolicyUtils.settingsPendingAction(accountOrExportDestination, qboConfig?.pendingFields), + brickRoadIndicator: PolicyUtils.areSettingsInErrorFields(accountOrExportDestination, qboConfig?.errorFields) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, + }, + { + title: qboConfig?.reimbursableExpensesAccount?.name ?? translate('workspace.qbo.notConfigured'), + description: accountDescription, + onPress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_ACCOUNT_SELECT.getRoute(policyID)), + subscribedSettings: account, + pendingAction: PolicyUtils.settingsPendingAction(account, qboConfig?.pendingFields), + brickRoadIndicator: PolicyUtils.areSettingsInErrorFields(account, qboConfig?.errorFields) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, + }, + ]; return ( - Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT.getRoute(policyID))} > - - - - {translate('workspace.qbo.exportOutOfPocketExpensesDescription')} - - Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_SELECT.getRoute(policyID))} - brickRoadIndicator={hasErrors ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} - shouldShowRightIcon - hintText={exportHintText} - /> - - - Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_ACCOUNT_SELECT.getRoute(policyID))} - brickRoadIndicator={errorFields?.exportAccount ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} - shouldShowRightIcon - errorText={errorFields?.exportAccount ? translate('common.genericErrorMessage') : undefined} - /> - - - - + {sections.map((section, index) => ( + + + + ))} + ); } diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseEntitySelectPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseEntitySelectPage.tsx index b0d8afa6d53b..51dee308fb75 100644 --- a/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseEntitySelectPage.tsx +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksOutOfPocketExpenseEntitySelectPage.tsx @@ -1,19 +1,19 @@ import React, {useCallback, useMemo} from 'react'; import {View} from 'react-native'; -import type {SectionListData} from 'react-native'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import ScreenWrapper from '@components/ScreenWrapper'; -import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; -import type {ListItem, Section} from '@components/SelectionList/types'; +import type {ListItem} from '@components/SelectionList/types'; +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 * as Connections from '@libs/actions/connections'; +import * as ErrorUtils from '@libs/ErrorUtils'; +import * as PolicyUtils from '@libs/PolicyUtils'; import Navigation from '@navigation/Navigation'; -import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections'; import withPolicyConnections from '@pages/workspace/withPolicyConnections'; +import {clearQBOErrorField} from '@userActions/Policy/Policy'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type {Account, QBOReimbursableExportAccountType} from '@src/types/onyx/Policy'; @@ -27,36 +27,36 @@ function Footer({isTaxEnabled, isLocationsEnabled}: {isTaxEnabled: boolean; isLo } return ( - + {isTaxEnabled && {translate('workspace.qbo.outOfPocketTaxEnabledDescription')}} {isLocationsEnabled && {translate('workspace.qbo.outOfPocketLocationEnabledDescription')}} ); } - -type CardListItem = ListItem & { +type MenuItem = ListItem & { value: QBOReimbursableExportAccountType; isShown: boolean; accounts: Account[]; }; -type CardsSection = SectionListData>; - function QuickbooksOutOfPocketExpenseEntitySelectPage({policy}: WithPolicyConnectionsProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); - const {reimbursableExpensesExportDestination, reimbursableExpensesAccount, syncTax, syncLocations} = policy?.connections?.quickbooksOnline?.config ?? {}; + const qboConfig = policy?.connections?.quickbooksOnline?.config; const {bankAccounts, accountPayable, journalEntryAccounts} = policy?.connections?.quickbooksOnline?.data ?? {}; - const isLocationsEnabled = !!(syncLocations && syncLocations !== CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE); - const isTaxesEnabled = !!syncTax; + const isLocationsEnabled = !!(qboConfig?.syncLocations && qboConfig?.syncLocations !== CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE); + const isTaxesEnabled = !!qboConfig?.syncTax; + const shouldShowTaxError = isTaxesEnabled && qboConfig?.reimbursableExpensesExportDestination === CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.JOURNAL_ENTRY; + const shouldShowLocationError = isLocationsEnabled && qboConfig?.reimbursableExpensesExportDestination !== CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.JOURNAL_ENTRY; + const hasErrors = !!qboConfig?.errorFields?.reimbursableExpensesExportDestination && (shouldShowTaxError || shouldShowLocationError); const policyID = policy?.id ?? '-1'; - const data: CardListItem[] = useMemo( + const data: MenuItem[] = useMemo( () => [ { value: CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.CHECK, text: translate(`workspace.qbo.accounts.check`), keyForList: CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.CHECK, - isSelected: reimbursableExpensesExportDestination === CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.CHECK, + isSelected: qboConfig?.reimbursableExpensesExportDestination === CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.CHECK, isShown: !isLocationsEnabled, accounts: bankAccounts ?? [], }, @@ -64,7 +64,7 @@ function QuickbooksOutOfPocketExpenseEntitySelectPage({policy}: WithPolicyConnec value: CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.JOURNAL_ENTRY, text: translate(`workspace.qbo.accounts.journal_entry`), keyForList: CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.JOURNAL_ENTRY, - isSelected: reimbursableExpensesExportDestination === CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.JOURNAL_ENTRY, + isSelected: qboConfig?.reimbursableExpensesExportDestination === CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.JOURNAL_ENTRY, isShown: !isTaxesEnabled, accounts: journalEntryAccounts ?? [], }, @@ -72,66 +72,69 @@ function QuickbooksOutOfPocketExpenseEntitySelectPage({policy}: WithPolicyConnec value: CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.VENDOR_BILL, text: translate(`workspace.qbo.accounts.bill`), keyForList: CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.VENDOR_BILL, - isSelected: reimbursableExpensesExportDestination === CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.VENDOR_BILL, + isSelected: qboConfig?.reimbursableExpensesExportDestination === CONST.QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE.VENDOR_BILL, isShown: !isLocationsEnabled, accounts: accountPayable ?? [], }, ], - [reimbursableExpensesExportDestination, isTaxesEnabled, translate, isLocationsEnabled, bankAccounts, accountPayable, journalEntryAccounts], + [qboConfig?.reimbursableExpensesExportDestination, isTaxesEnabled, translate, isLocationsEnabled, bankAccounts, accountPayable, journalEntryAccounts], ); - const sections: CardsSection[] = useMemo(() => [{data: data.filter((item) => item.isShown)}], [data]); + const sections = useMemo(() => [{data: data.filter((item) => item.isShown)}], [data]); const selectExportEntity = useCallback( - (row: CardListItem) => { - if (row.value !== reimbursableExpensesExportDestination) { + (row: MenuItem) => { + if (row.value !== qboConfig?.reimbursableExpensesExportDestination) { Connections.updateManyPolicyConnectionConfigs( policyID, CONST.POLICY.CONNECTIONS.NAME.QBO, { - [CONST.QUICK_BOOKS_CONFIG.REIMBURSABLE_EXPENSES_EXPORT_DESTINATION]: row.value, - [CONST.QUICK_BOOKS_CONFIG.REIMBURSABLE_EXPENSES_ACCOUNT]: row.accounts[0], + [CONST.QUICKBOOKS_CONFIG.REIMBURSABLE_EXPENSES_EXPORT_DESTINATION]: row.value, + [CONST.QUICKBOOKS_CONFIG.REIMBURSABLE_EXPENSES_ACCOUNT]: row.accounts[0], }, { - [CONST.QUICK_BOOKS_CONFIG.REIMBURSABLE_EXPENSES_EXPORT_DESTINATION]: reimbursableExpensesExportDestination, - [CONST.QUICK_BOOKS_CONFIG.REIMBURSABLE_EXPENSES_ACCOUNT]: reimbursableExpensesAccount, + [CONST.QUICKBOOKS_CONFIG.REIMBURSABLE_EXPENSES_EXPORT_DESTINATION]: qboConfig?.reimbursableExpensesExportDestination, + [CONST.QUICKBOOKS_CONFIG.REIMBURSABLE_EXPENSES_ACCOUNT]: qboConfig?.reimbursableExpensesAccount, }, ); } Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES.getRoute(policyID)); }, - [reimbursableExpensesExportDestination, policyID, reimbursableExpensesAccount], + [qboConfig?.reimbursableExpensesExportDestination, policyID, qboConfig?.reimbursableExpensesAccount], ); return ( - - - - - mode.isSelected)?.keyForList} - footerContent={ -