From a148a37e894e99d195889b2da06c080e82c7465b Mon Sep 17 00:00:00 2001 From: Filip Solecki Date: Wed, 24 Apr 2024 11:03:51 +0200 Subject: [PATCH 1/8] Basic import and organization pages --- src/ROUTES.ts | 8 ++ src/SCREENS.ts | 2 + src/languages/en.ts | 15 +++ .../ModalStackNavigators/index.tsx | 3 + .../FULL_SCREEN_TO_RHP_MAPPING.ts | 2 + src/libs/Navigation/linkingConfig/config.ts | 2 + src/libs/Navigation/types.ts | 6 ++ src/libs/Permissions.ts | 4 +- .../workspace/WorkspaceMoreFeaturesPage.tsx | 2 +- .../accounting/PolicyAccountingPage.tsx | 34 ++++++- .../accounting/xero/XeroImportPage.tsx | 97 +++++++++++++++++++ .../XeroOrganizationConfigurationPage.tsx | 70 +++++++++++++ src/types/onyx/Policy.ts | 62 +++++++++++- 13 files changed, 302 insertions(+), 5 deletions(-) create mode 100644 src/pages/workspace/accounting/xero/XeroImportPage.tsx create mode 100644 src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx diff --git a/src/ROUTES.ts b/src/ROUTES.ts index a8cb1847ccc1..e6e802be7bd3 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -749,6 +749,14 @@ const ROUTES = { route: 'r/:reportID/transaction/:transactionID/receipt', getRoute: (reportID: string, transactionID: string) => `r/${reportID}/transaction/${transactionID}/receipt` as const, }, + POLICY_ACCOUNTING_XERO_IMPORT: { + route: 'settings/workspaces/:policyID/accounting/xero/import', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/import` as const, + }, + POLICY_ACCOUNTING_XERO_ORGANIZATION: { + route: 'settings/workspaces/:policyID/accounting/xero/organization/:currentOrganizationID', + getRoute: (policyID: string, currentOrganizationID: string) => `settings/workspaces/${policyID}/accounting/xero/organization/${currentOrganizationID}` as const, + }, POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_IMPORT: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import', getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index c6658c2f6578..b9a05aa6b159 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -226,6 +226,8 @@ const SCREENS = { QUICKBOOKS_ONLINE_ADVANCED: 'Policy_Accounting_Quickbooks_Online_Advanced', QUICKBOOKS_ONLINE_ACCOUNT_SELECTOR: 'Policy_Accounting_Quickbooks_Online_Account_Selector', QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR: 'Policy_Accounting_Quickbooks_Online_Invoice_Account_Selector', + XERO_IMPORT: 'Policy_Accounting_Xero_Import', + XERO_ORGANIZATION: 'Policy_Accounting_Xero_Customers', }, INITIAL: 'Workspace_Initial', PROFILE: 'Workspace_Profile', diff --git a/src/languages/en.ts b/src/languages/en.ts index fea08f2d6b82..0e095744a45a 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1935,6 +1935,21 @@ export default { 'If you are exporting invoices from Expensify to Quickbooks Online, this is the account the invoice will appear against once marked as paid.', }, }, + xero: { + organization: 'Xero organization', + organizationDescription: 'Select the organization in Xero you are importing data from.', + import: 'Import', + importDescription: 'Choose which coding configurations are imported from Xero to Expensify.', + accounts: 'Chart of accounts', + trackingCategories: 'Tracking categories', + taxes: 'Taxes', + customers: 'Re-bill customers', + imported: 'Imported', + displayedAs: 'Displayed as', + importedAsCategories: 'Imported, displayed as categories', + importedAsTags: 'Imported, displayed as tags', + importedAsReportFields: 'Imported, displayed as report fields', + }, type: { free: 'Free', control: 'Control', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index bc6d9decf6ec..2802b03181ca 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -291,6 +291,9 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/workspace/accounting/qbo/advanced/QuickbooksInvoiceAccountSelectPage').default as React.ComponentType, + + [SCREENS.WORKSPACE.ACCOUNTING.XERO_IMPORT]: () => require('../../../../pages/workspace/accounting/xero/XeroImportPage').default as React.ComponentType, + [SCREENS.WORKSPACE.ACCOUNTING.XERO_ORGANIZATION]: () => require('../../../../pages/workspace/accounting/xero/XeroOrganizationConfigurationPage').default as React.ComponentType, [SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_FREQUENCY]: () => require('../../../../pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage').default as React.ComponentType, [SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_MONTHLY_OFFSET]: () => require('../../../../pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage').default as React.ComponentType, 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 5225408a3677..f032e5a233bc 100755 --- a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts @@ -36,6 +36,8 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial> = { SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_ADVANCED, SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_ACCOUNT_SELECTOR, SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR, + SCREENS.WORKSPACE.ACCOUNTING.XERO_IMPORT, + SCREENS.WORKSPACE.ACCOUNTING.XERO_ORGANIZATION, ], [SCREENS.WORKSPACE.TAXES]: [ SCREENS.WORKSPACE.TAXES_SETTINGS, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index ca6264e00917..7ca56839a71c 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -299,6 +299,8 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR]: { path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR.route, }, + [SCREENS.WORKSPACE.ACCOUNTING.XERO_IMPORT]: {path: ROUTES.POLICY_ACCOUNTING_XERO_IMPORT.route}, + [SCREENS.WORKSPACE.ACCOUNTING.XERO_ORGANIZATION]: {path: ROUTES.POLICY_ACCOUNTING_XERO_ORGANIZATION.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 de26a81276ef..cc2be13f45c9 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -289,6 +289,12 @@ type SettingsNavigatorParamList = { [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_PREFERRED_EXPORTER]: { policyID: string; }; + [SCREENS.WORKSPACE.ACCOUNTING.XERO_IMPORT]: { + policyID: string; + }; + [SCREENS.WORKSPACE.ACCOUNTING.XERO_ORGANIZATION]: { + policyID: string; + }; [SCREENS.GET_ASSISTANCE]: { backTo: Routes; }; diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts index c79e9011386f..3c452ad4fde6 100644 --- a/src/libs/Permissions.ts +++ b/src/libs/Permissions.ts @@ -4,7 +4,7 @@ import type {IOUType} from '@src/CONST'; import type Beta from '@src/types/onyx/Beta'; function canUseAllBetas(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.ALL); + return true; } function canUseChronos(betas: OnyxEntry): boolean { @@ -37,7 +37,7 @@ function canUseWorkflowsDelayedSubmission(betas: OnyxEntry): boolean { } function canUseAccountingIntegrations(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.ACCOUNTING_ON_NEW_EXPENSIFY) || canUseAllBetas(betas); + return true; } /** diff --git a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx index 66e6b87d79d3..ad770bdb02af 100644 --- a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx +++ b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx @@ -48,7 +48,7 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro const {translate} = useLocalize(); const {canUseAccountingIntegrations} = usePermissions(); const hasAccountingConnection = !!policy?.areConnectionsEnabled && !!policy?.connections; - const isSyncTaxEnabled = !!policy?.connections?.quickbooksOnline?.config?.syncTax; + const isSyncTaxEnabled = !!policy?.connections?.quickbooksOnline?.config.syncTax || !!policy?.connections?.xero?.config.importTaxRates; const spendItems: Item[] = [ { diff --git a/src/pages/workspace/accounting/PolicyAccountingPage.tsx b/src/pages/workspace/accounting/PolicyAccountingPage.tsx index a1e6364ca239..7dda3b865d20 100644 --- a/src/pages/workspace/accounting/PolicyAccountingPage.tsx +++ b/src/pages/workspace/accounting/PolicyAccountingPage.tsx @@ -89,7 +89,7 @@ function accountingIntegrationData( integrationToDisconnect={integrationToDisconnect} /> ), - onImportPagePress: () => {}, + onImportPagePress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_XERO_IMPORT.getRoute(policyID)), }; } } @@ -107,6 +107,20 @@ function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccounting const connectedIntegration = accountingIntegrations.find((integration) => !!policy?.connections?.[integration]) ?? connectionSyncProgress?.connectionName; const policyID = policy?.id ?? ''; + const policyConnectedToXero = connectedIntegration === CONST.POLICY.CONNECTIONS.NAME.XERO; + + const tenants = policy?.connections?.xero?.data?.tenants ?? []; + console.log('Testy4', policy.connections?.xero); + console.log('Testy', tenants, policy.connections?.xero); + const currentXeroOrganization = + tenants?.length === 1 + ? tenants[0] + : tenants.find((tenant) => { + console.log('testy3', tenant.id, policy.connections?.xero.config?.tenantID); + return tenant.id === policy?.connections?.xero.config.tenantID; + }); + console.log('testy2', currentXeroOrganization); + const overflowMenu: ThreeDotsMenuProps['menuItems'] = useMemo( () => [ { @@ -177,6 +191,21 @@ function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccounting ), }, + ...(policyConnectedToXero + ? [ + { + description: translate('workspace.xero.organization'), + iconRight: Expensicons.ArrowRight, + shouldShowRightIcon: true, + title: currentXeroOrganization?.name, + wrapperStyle: [styles.sectionMenuItemTopDescription], + shouldShowDescriptionOnTop: true, + onPress: () => { + Navigation.navigate(ROUTES.POLICY_ACCOUNTING_XERO_ORGANIZATION.getRoute(policyID, currentXeroOrganization?.id ?? '')); + }, + }, + ] + : []), ...(isEmptyObject(policy?.connections) ? [] : [ @@ -209,9 +238,12 @@ function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccounting }, [ connectedIntegration, connectionSyncProgress?.stageInProgress, + currentXeroOrganization?.id, + currentXeroOrganization?.name, isSyncInProgress, overflowMenu, policy?.connections, + policyConnectedToXero, policyID, styles, theme.spinner, diff --git a/src/pages/workspace/accounting/xero/XeroImportPage.tsx b/src/pages/workspace/accounting/xero/XeroImportPage.tsx new file mode 100644 index 000000000000..909d15d13575 --- /dev/null +++ b/src/pages/workspace/accounting/xero/XeroImportPage.tsx @@ -0,0 +1,97 @@ +import React from 'react'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +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 AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; +import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; +import withPolicy from '@pages/workspace/withPolicy'; +import type {WithPolicyProps} from '@pages/workspace/withPolicy'; +import CONST from '@src/CONST'; + +function XeroImportPage({policy}: WithPolicyProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + + const policyID = policy?.id ?? ''; + const {importCustomers, importTaxRates, importTrackingCategories, pendingFields} = policy?.connections?.xero?.config ?? {}; + + const tenants = policy?.connections?.xero?.data?.tenants ?? []; + console.log('Testy', tenants, policy?.connections?.xero); + const currentXeroOrganization = tenants?.length === 1 ? tenants[0] : tenants.find((tenant) => tenant.id === policy?.connections?.xero.config.tenantID); + + const sections = [ + { + description: translate('workspace.xero.accounts'), + action: () => {}, + hasError: !!policy?.errors?.enableNewCategories, + title: translate('workspace.xero.imported'), + pendingAction: pendingFields?.enableNewCategories, + }, + { + description: translate('workspace.xero.trackingCategories'), + action: () => {}, + hasError: !!policy?.errors?.importTrackingCategories, + title: importTrackingCategories ? translate('workspace.xero.importedAsTags') : '', + pendingAction: pendingFields?.importTrackingCategories, + }, + { + description: translate('workspace.xero.customers'), + action: () => {}, + hasError: !!policy?.errors?.importCustomers, + title: importCustomers ? translate('workspace.xero.importedAsTags') : '', + pendingAction: pendingFields?.importCustomers, + }, + { + description: translate('workspace.xero.taxes'), + action: () => {}, + title: importTaxRates ? translate('workspace.xero.imported') : '', + pendingAction: pendingFields?.importTaxRates, + }, + ]; + + return ( + + + + + + {translate('workspace.xero.importDescription')} + {sections.map((section) => ( + + + + ))} + + + + + ); +} + +XeroImportPage.displayName = 'PolicyXeroImportPage'; + +export default withPolicy(XeroImportPage); diff --git a/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx b/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx new file mode 100644 index 000000000000..5df8e2bfcf2b --- /dev/null +++ b/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx @@ -0,0 +1,70 @@ +import React from 'react'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import ScrollView from '@components/ScrollView'; +import SelectionList from '@components/SelectionList'; +import RadioListItem from '@components/SelectionList/RadioListItem'; +import type {ListItem} from '@components/SelectionList/types'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import {updatePolicyConnectionConfig} from '@libs/actions/connections'; +import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; +import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; +import withPolicy from '@pages/workspace/withPolicy'; +import type {WithPolicyProps} from '@pages/workspace/withPolicy'; +import CONST from '@src/CONST'; + +type XeroOrganizationConfigurationPageProps = WithPolicyProps; +function XeroOrganizationConfigurationPage({policy}: XeroOrganizationConfigurationPageProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + + const policyID = policy?.id ?? ''; + const currentOrganizationID = policy?.connections?.xero.config.tenantID ?? ''; + + const sections = + policy?.connections?.xero.data.tenants.map((tenant) => ({ + text: tenant.name, + keyForList: tenant.id, + isSelected: tenant.id === currentOrganizationID, + })) ?? []; + + const saveSelection = ({keyForList}: ListItem) => { + if (!keyForList) { + return; + } + + updatePolicyConnectionConfig(policyID, 'xero', 'tenantID', keyForList); + }; + + return ( + + + + + + {translate('workspace.xero.organizationDescription')} + + + + + + ); +} + +XeroOrganizationConfigurationPage.displayName = 'PolicyXeroOrganizationConfigurationPage'; + +export default withPolicy(XeroOrganizationConfigurationPage); diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 87b94780332d..8c53e319847e 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -183,6 +183,65 @@ type QBOConnectionConfig = OnyxCommon.OnyxValueWithOfflineFeedback<{ exportCompanyCard: string; errorFields?: OnyxCommon.ErrorFields; }>; + +type Tenant = { + id: string; + name: string; + value: string; +}; + +type XeroConnectionData = { + bankAccounts: unknown[]; + countryCode: string; + organisationID: string; + revenueAccounts: Array<{ + id: string; + name: string; + }>; + tenants: Tenant[]; + trackingCategories: unknown[]; +}; + +/** + * User configuration for the Xero accounting integration. + */ +type XeroConnectionConfig = OnyxCommon.OnyxValueWithOfflineFeedback<{ + autoSync: { + enabled: boolean; + jobID: string; + }; + enableNewCategories: boolean; + export: { + billDate: string; + billStatus: { + purchase: string; + sales: string; + }; + billable: string; + exporter: string; + nonReimbursable: string; + nonReimbursableAccount: string; + reimbursable: string; + }; + importCustomers: boolean; + importTaxRates: boolean; + importTrackingCategories: boolean; + isConfigured: boolean; + mappings: { + customer: string; + }; + sync: { + hasChosenAutoSyncOption: boolean; + hasChosenSyncReimbursedReportsOption: boolean; + invoiceCollectionsAccountID: string; + reimbursementAccountID: string; + syncReimbursedReports: boolean; + }; + tenantID: string; + errors?: OnyxCommon.Errors; + errorFields?: OnyxCommon.ErrorFields; +}>; + type Connection = { lastSync?: ConnectionLastSync; data: ConnectionData; @@ -191,7 +250,7 @@ type Connection = { type Connections = { quickbooksOnline: Connection; - xero: Connection; + xero: Connection; }; type ConnectionName = keyof Connections; @@ -476,4 +535,5 @@ export type { PolicyConnectionSyncProgress, Connections, ConnectionName, + Tenant, }; From 5056a34d665c013fbb77d45d06341bdc5be3f6f9 Mon Sep 17 00:00:00 2001 From: Filip Solecki Date: Wed, 24 Apr 2024 18:03:01 +0200 Subject: [PATCH 2/8] Small fixes --- .../workspace/WorkspaceMoreFeaturesPage.tsx | 5 +++-- .../accounting/PolicyAccountingPage.tsx | 17 ++++------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx index ad770bdb02af..b50f85424469 100644 --- a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx +++ b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx @@ -17,6 +17,7 @@ import * as Policy from '@userActions/Policy'; import type {TranslationPaths} from '@src/languages/types'; import type SCREENS from '@src/SCREENS'; import type {PendingAction} from '@src/types/onyx/OnyxCommon'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type IconAsset from '@src/types/utils/IconAsset'; import AdminPolicyAccessOrNotFoundWrapper from './AdminPolicyAccessOrNotFoundWrapper'; import PaidPolicyAccessOrNotFoundWrapper from './PaidPolicyAccessOrNotFoundWrapper'; @@ -47,7 +48,7 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro const {isSmallScreenWidth} = useWindowDimensions(); const {translate} = useLocalize(); const {canUseAccountingIntegrations} = usePermissions(); - const hasAccountingConnection = !!policy?.areConnectionsEnabled && !!policy?.connections; + const hasAccountingConnection = !!policy?.areConnectionsEnabled && !isEmptyObject(policy?.connections); const isSyncTaxEnabled = !!policy?.connections?.quickbooksOnline?.config.syncTax || !!policy?.connections?.xero?.config.importTaxRates; const spendItems: Item[] = [ @@ -90,7 +91,7 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro titleTranslationKey: 'workspace.moreFeatures.tags.title', subtitleTranslationKey: 'workspace.moreFeatures.tags.subtitle', isActive: policy?.areTagsEnabled ?? false, - disabled: hasAccountingConnection, + // disabled: hasAccountingConnection, pendingAction: policy?.pendingFields?.areTagsEnabled, action: (isEnabled: boolean) => { Policy.enablePolicyTags(policy?.id ?? '', isEnabled); diff --git a/src/pages/workspace/accounting/PolicyAccountingPage.tsx b/src/pages/workspace/accounting/PolicyAccountingPage.tsx index 7dda3b865d20..b69423cd72dc 100644 --- a/src/pages/workspace/accounting/PolicyAccountingPage.tsx +++ b/src/pages/workspace/accounting/PolicyAccountingPage.tsx @@ -110,16 +110,7 @@ function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccounting const policyConnectedToXero = connectedIntegration === CONST.POLICY.CONNECTIONS.NAME.XERO; const tenants = policy?.connections?.xero?.data?.tenants ?? []; - console.log('Testy4', policy.connections?.xero); - console.log('Testy', tenants, policy.connections?.xero); - const currentXeroOrganization = - tenants?.length === 1 - ? tenants[0] - : tenants.find((tenant) => { - console.log('testy3', tenant.id, policy.connections?.xero.config?.tenantID); - return tenant.id === policy?.connections?.xero.config.tenantID; - }); - console.log('testy2', currentXeroOrganization); + const currentXeroOrganization = tenants?.length === 1 ? tenants[0] : tenants.find((tenant) => tenant.id === policy?.connections?.xero.config.tenantID); const overflowMenu: ThreeDotsMenuProps['menuItems'] = useMemo( () => [ @@ -196,9 +187,9 @@ function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccounting { description: translate('workspace.xero.organization'), iconRight: Expensicons.ArrowRight, - shouldShowRightIcon: true, title: currentXeroOrganization?.name, wrapperStyle: [styles.sectionMenuItemTopDescription], + shouldShowRightIcon: tenants.length > 1, shouldShowDescriptionOnTop: true, onPress: () => { Navigation.navigate(ROUTES.POLICY_ACCOUNTING_XERO_ORGANIZATION.getRoute(policyID, currentXeroOrganization?.id ?? '')); @@ -238,8 +229,8 @@ function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccounting }, [ connectedIntegration, connectionSyncProgress?.stageInProgress, - currentXeroOrganization?.id, - currentXeroOrganization?.name, + currentXeroOrganization, + tenants, isSyncInProgress, overflowMenu, policy?.connections, From fd73fd6488e6381ef0c661b9381b3a1b1cd5af18 Mon Sep 17 00:00:00 2001 From: Filip Solecki Date: Thu, 25 Apr 2024 15:57:50 +0200 Subject: [PATCH 3/8] clean up --- src/libs/Navigation/types.ts | 1 + src/libs/Permissions.ts | 4 +- .../workspace/WorkspaceMoreFeaturesPage.tsx | 2 +- .../accounting/PolicyAccountingPage.tsx | 9 +- .../accounting/xero/XeroImportPage.tsx | 83 +++++++++++-------- .../XeroOrganizationConfigurationPage.tsx | 19 +++-- src/types/onyx/Policy.ts | 18 ++-- 7 files changed, 85 insertions(+), 51 deletions(-) diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index cc2be13f45c9..5d595f57ec83 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -294,6 +294,7 @@ type SettingsNavigatorParamList = { }; [SCREENS.WORKSPACE.ACCOUNTING.XERO_ORGANIZATION]: { policyID: string; + organizationID: string; }; [SCREENS.GET_ASSISTANCE]: { backTo: Routes; diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts index 3c452ad4fde6..c79e9011386f 100644 --- a/src/libs/Permissions.ts +++ b/src/libs/Permissions.ts @@ -4,7 +4,7 @@ import type {IOUType} from '@src/CONST'; import type Beta from '@src/types/onyx/Beta'; function canUseAllBetas(betas: OnyxEntry): boolean { - return true; + return !!betas?.includes(CONST.BETAS.ALL); } function canUseChronos(betas: OnyxEntry): boolean { @@ -37,7 +37,7 @@ function canUseWorkflowsDelayedSubmission(betas: OnyxEntry): boolean { } function canUseAccountingIntegrations(betas: OnyxEntry): boolean { - return true; + return !!betas?.includes(CONST.BETAS.ACCOUNTING_ON_NEW_EXPENSIFY) || canUseAllBetas(betas); } /** diff --git a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx index b50f85424469..4c38c1e1c597 100644 --- a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx +++ b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx @@ -91,7 +91,7 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro titleTranslationKey: 'workspace.moreFeatures.tags.title', subtitleTranslationKey: 'workspace.moreFeatures.tags.subtitle', isActive: policy?.areTagsEnabled ?? false, - // disabled: hasAccountingConnection, + disabled: hasAccountingConnection, pendingAction: policy?.pendingFields?.areTagsEnabled, action: (isEnabled: boolean) => { Policy.enablePolicyTags(policy?.id ?? '', isEnabled); diff --git a/src/pages/workspace/accounting/PolicyAccountingPage.tsx b/src/pages/workspace/accounting/PolicyAccountingPage.tsx index b69423cd72dc..19fe2db91f71 100644 --- a/src/pages/workspace/accounting/PolicyAccountingPage.tsx +++ b/src/pages/workspace/accounting/PolicyAccountingPage.tsx @@ -34,7 +34,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Policy, PolicyConnectionSyncProgress} from '@src/types/onyx'; -import type {PolicyConnectionName} from '@src/types/onyx/Policy'; +import type {PolicyConnectionName, Tenant} from '@src/types/onyx/Policy'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type IconAsset from '@src/types/utils/IconAsset'; @@ -109,8 +109,8 @@ function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccounting const policyConnectedToXero = connectedIntegration === CONST.POLICY.CONNECTIONS.NAME.XERO; - const tenants = policy?.connections?.xero?.data?.tenants ?? []; - const currentXeroOrganization = tenants?.length === 1 ? tenants[0] : tenants.find((tenant) => tenant.id === policy?.connections?.xero.config.tenantID); + const tenants = useMemo(() => policy?.connections?.xero?.data?.tenants ?? [], [policy?.connections?.xero.data.tenants]); + const currentXeroOrganization = tenants.find((tenant) => tenant.id === policy?.connections?.xero.config.tenantID); const overflowMenu: ThreeDotsMenuProps['menuItems'] = useMemo( () => [ @@ -192,6 +192,9 @@ function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccounting shouldShowRightIcon: tenants.length > 1, shouldShowDescriptionOnTop: true, onPress: () => { + if (!(tenants.length > 1)) { + return; + } Navigation.navigate(ROUTES.POLICY_ACCOUNTING_XERO_ORGANIZATION.getRoute(policyID, currentXeroOrganization?.id ?? '')); }, }, diff --git a/src/pages/workspace/accounting/xero/XeroImportPage.tsx b/src/pages/workspace/accounting/xero/XeroImportPage.tsx index 909d15d13575..fac598cc8068 100644 --- a/src/pages/workspace/accounting/xero/XeroImportPage.tsx +++ b/src/pages/workspace/accounting/xero/XeroImportPage.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useMemo} from 'react'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -12,6 +12,7 @@ import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabl import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import CONST from '@src/CONST'; +import type {Tenant} from '@src/types/onyx/Policy'; function XeroImportPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); @@ -20,39 +21,55 @@ function XeroImportPage({policy}: WithPolicyProps) { const policyID = policy?.id ?? ''; const {importCustomers, importTaxRates, importTrackingCategories, pendingFields} = policy?.connections?.xero?.config ?? {}; - const tenants = policy?.connections?.xero?.data?.tenants ?? []; - console.log('Testy', tenants, policy?.connections?.xero); - const currentXeroOrganization = tenants?.length === 1 ? tenants[0] : tenants.find((tenant) => tenant.id === policy?.connections?.xero.config.tenantID); + const tenants = useMemo(() => policy?.connections?.xero?.data?.tenants ?? [], [policy?.connections?.xero.data.tenants]); + const currentXeroOrganization = tenants.find((tenant) => tenant.id === policy?.connections?.xero.config.tenantID); - const sections = [ - { - description: translate('workspace.xero.accounts'), - action: () => {}, - hasError: !!policy?.errors?.enableNewCategories, - title: translate('workspace.xero.imported'), - pendingAction: pendingFields?.enableNewCategories, - }, - { - description: translate('workspace.xero.trackingCategories'), - action: () => {}, - hasError: !!policy?.errors?.importTrackingCategories, - title: importTrackingCategories ? translate('workspace.xero.importedAsTags') : '', - pendingAction: pendingFields?.importTrackingCategories, - }, - { - description: translate('workspace.xero.customers'), - action: () => {}, - hasError: !!policy?.errors?.importCustomers, - title: importCustomers ? translate('workspace.xero.importedAsTags') : '', - pendingAction: pendingFields?.importCustomers, - }, - { - description: translate('workspace.xero.taxes'), - action: () => {}, - title: importTaxRates ? translate('workspace.xero.imported') : '', - pendingAction: pendingFields?.importTaxRates, - }, - ]; + const sections = useMemo( + () => [ + { + description: translate('workspace.xero.accounts'), + action: () => {}, + hasError: !!policy?.errors?.enableNewCategories, + title: translate('workspace.xero.imported'), + pendingAction: pendingFields?.enableNewCategories, + }, + { + description: translate('workspace.xero.trackingCategories'), + action: () => {}, + hasError: !!policy?.errors?.importTrackingCategories, + title: importTrackingCategories ? translate('workspace.xero.importedAsTags') : '', + pendingAction: pendingFields?.importTrackingCategories, + }, + { + description: translate('workspace.xero.customers'), + action: () => {}, + hasError: !!policy?.errors?.importCustomers, + title: importCustomers ? translate('workspace.xero.importedAsTags') : '', + pendingAction: pendingFields?.importCustomers, + }, + { + description: translate('workspace.xero.taxes'), + action: () => {}, + hasError: !!policy?.errors?.importTaxes, + title: importTaxRates ? translate('workspace.xero.imported') : '', + pendingAction: pendingFields?.importTaxRates, + }, + ], + [ + importCustomers, + importTaxRates, + importTrackingCategories, + pendingFields?.enableNewCategories, + pendingFields?.importTaxRates, + pendingFields?.importCustomers, + pendingFields?.importTrackingCategories, + policy?.errors?.importTrackingCategories, + policy?.errors?.enableNewCategories, + policy?.errors?.importCustomers, + policy?.errors?.importTaxes, + translate, + ], + ); return ( diff --git a/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx b/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx index 5df8e2bfcf2b..9944e2307214 100644 --- a/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx +++ b/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx @@ -1,3 +1,4 @@ +import type {StackScreenProps} from '@react-navigation/stack'; import React from 'react'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; @@ -9,25 +10,31 @@ import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import {updatePolicyConnectionConfig} from '@libs/actions/connections'; +import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import CONST from '@src/CONST'; +import type SCREENS from '@src/SCREENS'; -type XeroOrganizationConfigurationPageProps = WithPolicyProps; -function XeroOrganizationConfigurationPage({policy}: XeroOrganizationConfigurationPageProps) { +type XeroOrganizationConfigurationPageProps = WithPolicyProps & StackScreenProps; +function XeroOrganizationConfigurationPage({ + policy, + route: { + params: {organizationID}, + }, +}: XeroOrganizationConfigurationPageProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const policyID = policy?.id ?? ''; - const currentOrganizationID = policy?.connections?.xero.config.tenantID ?? ''; const sections = policy?.connections?.xero.data.tenants.map((tenant) => ({ text: tenant.name, keyForList: tenant.id, - isSelected: tenant.id === currentOrganizationID, + isSelected: tenant.id === organizationID, })) ?? []; const saveSelection = ({keyForList}: ListItem) => { @@ -35,7 +42,7 @@ function XeroOrganizationConfigurationPage({policy}: XeroOrganizationConfigurati return; } - updatePolicyConnectionConfig(policyID, 'xero', 'tenantID', keyForList); + updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.XERO, 'tenantID', keyForList); }; return ( @@ -56,7 +63,7 @@ function XeroOrganizationConfigurationPage({policy}: XeroOrganizationConfigurati ListItem={RadioListItem} onSelectRow={saveSelection} sections={[{data: sections}]} - initiallyFocusedOptionKey={currentOrganizationID} + initiallyFocusedOptionKey={organizationID} /> diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 8c53e319847e..592b96c46a74 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -184,6 +184,12 @@ type QBOConnectionConfig = OnyxCommon.OnyxValueWithOfflineFeedback<{ errorFields?: OnyxCommon.ErrorFields; }>; +type BillStatusValues = 'DRAFT' | 'AWT_APPROVAL' | 'AWT_PAYMENT'; + +type ExpenseTypesValues = 'BILL' | 'BANK_TRANSACTION' | 'SALES_INVOICE' | 'NOTHING'; + +type BillDateValues = 'REPORT_SUBMITTED' | 'REPORT_EXPORTED' | 'LAST_EXPENSE'; + type Tenant = { id: string; name: string; @@ -212,16 +218,16 @@ type XeroConnectionConfig = OnyxCommon.OnyxValueWithOfflineFeedback<{ }; enableNewCategories: boolean; export: { - billDate: string; + billDate: BillDateValues; billStatus: { - purchase: string; - sales: string; + purchase: BillStatusValues; + sales: BillStatusValues; }; - billable: string; + billable: ExpenseTypesValues; exporter: string; - nonReimbursable: string; + nonReimbursable: ExpenseTypesValues; nonReimbursableAccount: string; - reimbursable: string; + reimbursable: ExpenseTypesValues; }; importCustomers: boolean; importTaxRates: boolean; From db60b0f537d2316d209354df32c89f605c4e4815 Mon Sep 17 00:00:00 2001 From: Filip Solecki Date: Fri, 26 Apr 2024 07:18:42 +0200 Subject: [PATCH 4/8] Add translations --- src/languages/en.ts | 3 --- src/languages/es.ts | 12 ++++++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 7e85ac89d8f2..ae25964ce5f2 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1963,10 +1963,7 @@ export default { taxes: 'Taxes', customers: 'Re-bill customers', imported: 'Imported', - displayedAs: 'Displayed as', - importedAsCategories: 'Imported, displayed as categories', importedAsTags: 'Imported, displayed as tags', - importedAsReportFields: 'Imported, displayed as report fields', }, type: { free: 'Free', diff --git a/src/languages/es.ts b/src/languages/es.ts index 849aef9ef968..827f6c537fd0 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1980,6 +1980,18 @@ export default { 'Si está exportando facturas de Expensify a Quickbooks Online, ésta es la cuenta en la que aparecerá la factura una vez marcada como pagada.', }, }, + xero: { + organization: 'Organización Xero', + organizationDescription: 'Seleccione la organización en Xero desde la que está importando los datos.', + import: 'Importación', + importDescription: 'Elija qué configuraciones de codificación se importan de Xero a Expensify.', + accounts: 'Plan de cuentas', + trackingCategories: 'Categorías de seguimiento', + taxes: 'Impuestos', + customers: 'Volver a facturar a los clientes', + imported: 'Importado', + importedAsTags: 'Importado, mostrado como etiqueta', + }, type: { free: 'Gratis', control: 'Control', From 088aeb74f0fabe21b1b00f1b2fdec9c485b59c06 Mon Sep 17 00:00:00 2001 From: Filip Solecki Date: Fri, 26 Apr 2024 07:25:29 +0200 Subject: [PATCH 5/8] Unify translations between accounting tools --- src/languages/en.ts | 14 ++++---------- src/languages/es.ts | 14 ++++---------- .../qbo/import/QuickbooksChartOfAccountsPage.tsx | 4 ++-- .../qbo/import/QuickbooksClassesPage.tsx | 2 +- .../qbo/import/QuickbooksCustomersPage.tsx | 2 +- .../accounting/qbo/import/QuickbooksImportPage.tsx | 12 ++++++------ .../qbo/import/QuickbooksLocationsPage.tsx | 2 +- .../accounting/qbo/import/QuickbooksTaxesPage.tsx | 6 +++--- .../workspace/accounting/xero/XeroImportPage.tsx | 14 +++++++------- 9 files changed, 29 insertions(+), 41 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index ae25964ce5f2..296ad30f6f98 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1856,17 +1856,12 @@ export default { `You have been invited to ${workspaceName || 'a workspace'}! Download the Expensify mobile app at use.expensify.com/download to start tracking your expenses.`, }, qbo: { - import: 'Import', importDescription: 'Choose which coding configurations are imported from QuickBooks Online to Expensify.', classes: 'Classes', - accounts: 'Chart of accounts', locations: 'Locations', - taxes: 'Taxes', customers: 'Customers/Projects', - imported: 'Imported', displayedAs: 'Displayed as', notImported: 'Not imported', - importedAsTags: 'Imported, displayed as tags', importedAsReportFields: 'Imported, displayed as report fields', accountsDescription: 'Chart of Accounts import as categories when connected to an accounting integration, this cannot be disabled.', accountsSwitchTitle: 'Enable newly imported Chart of Accounts.', @@ -1956,14 +1951,9 @@ export default { xero: { organization: 'Xero organization', organizationDescription: 'Select the organization in Xero you are importing data from.', - import: 'Import', importDescription: 'Choose which coding configurations are imported from Xero to Expensify.', - accounts: 'Chart of accounts', trackingCategories: 'Tracking categories', - taxes: 'Taxes', customers: 'Re-bill customers', - imported: 'Imported', - importedAsTags: 'Imported, displayed as tags', }, type: { free: 'Free', @@ -2181,6 +2171,10 @@ export default { syncNow: 'Sync now', disconnect: 'Disconnect', disconnectTitle: 'Disconnect integration', + accounts: 'Chart of accounts', + taxes: 'Taxes', + imported: 'Imported', + importedAsTags: 'Imported, displayed as tags', disconnectPrompt: (integrationToConnect?: ConnectionName): string => { switch (integrationToConnect) { case CONST.POLICY.CONNECTIONS.NAME.QBO: diff --git a/src/languages/es.ts b/src/languages/es.ts index 827f6c537fd0..1098cbe5db1b 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1880,17 +1880,12 @@ export default { `¡Has sido invitado a ${workspaceName}! Descargue la aplicación móvil Expensify en use.expensify.com/download para comenzar a rastrear sus gastos.`, }, qbo: { - import: 'Importación', importDescription: 'Elige que configuraciónes de codificación son importadas desde QuickBooks Online a Expensify.', classes: 'Clases', - accounts: 'Plan de cuentas', locations: 'Lugares', - taxes: 'Impuestos', customers: 'Clientes/Proyectos', - imported: 'Importado', displayedAs: 'Mostrado como', notImported: 'No importado', - importedAsTags: 'Importado, mostrado como etiqueta', importedAsReportFields: 'Importado, mostrado como campo de informe', accountsDescription: 'Los planes de cuentas se importan como categorías cuando está conectado con una integración de contaduría, esto no se puede desactivar.', accountsSwitchTitle: 'Habilita el plan de cuentas recien importado', @@ -1983,14 +1978,9 @@ export default { xero: { organization: 'Organización Xero', organizationDescription: 'Seleccione la organización en Xero desde la que está importando los datos.', - import: 'Importación', importDescription: 'Elija qué configuraciones de codificación se importan de Xero a Expensify.', - accounts: 'Plan de cuentas', trackingCategories: 'Categorías de seguimiento', - taxes: 'Impuestos', customers: 'Volver a facturar a los clientes', - imported: 'Importado', - importedAsTags: 'Importado, mostrado como etiqueta', }, type: { free: 'Gratis', @@ -2176,6 +2166,10 @@ export default { syncNow: 'Sincronizar ahora', disconnect: 'Desconectar', disconnectTitle: 'Desconectar integración', + accounts: 'Plan de cuentas', + taxes: 'Impuestos', + imported: 'Importado', + importedAsTags: 'Importado, mostrado como etiqueta', disconnectPrompt: (integrationToConnect?: ConnectionName): string => { switch (integrationToConnect) { case CONST.POLICY.CONNECTIONS.NAME.QBO: diff --git a/src/pages/workspace/accounting/qbo/import/QuickbooksChartOfAccountsPage.tsx b/src/pages/workspace/accounting/qbo/import/QuickbooksChartOfAccountsPage.tsx index 0a59d258ab0c..2735c8199aee 100644 --- a/src/pages/workspace/accounting/qbo/import/QuickbooksChartOfAccountsPage.tsx +++ b/src/pages/workspace/accounting/qbo/import/QuickbooksChartOfAccountsPage.tsx @@ -34,7 +34,7 @@ function QuickbooksChartOfAccountsPage({policy}: WithPolicyProps) { shouldEnableMaxHeight testID={QuickbooksChartOfAccountsPage.displayName} > - + {translate('workspace.qbo.accountsDescription')} @@ -44,7 +44,7 @@ function QuickbooksChartOfAccountsPage({policy}: WithPolicyProps) { Connections.updatePolicyConnectionConfig( diff --git a/src/pages/workspace/accounting/qbo/import/QuickbooksClassesPage.tsx b/src/pages/workspace/accounting/qbo/import/QuickbooksClassesPage.tsx index 3f547fa9c6de..57251bdb6193 100644 --- a/src/pages/workspace/accounting/qbo/import/QuickbooksClassesPage.tsx +++ b/src/pages/workspace/accounting/qbo/import/QuickbooksClassesPage.tsx @@ -41,7 +41,7 @@ function QuickbooksClassesPage({policy}: WithPolicyProps) { {translate('workspace.qbo.classesDescription')} - {translate('workspace.qbo.import')} + {translate('workspace.accounting.import')} diff --git a/src/pages/workspace/accounting/qbo/import/QuickbooksCustomersPage.tsx b/src/pages/workspace/accounting/qbo/import/QuickbooksCustomersPage.tsx index 14fe0ba07bc4..556e30c10cb8 100644 --- a/src/pages/workspace/accounting/qbo/import/QuickbooksCustomersPage.tsx +++ b/src/pages/workspace/accounting/qbo/import/QuickbooksCustomersPage.tsx @@ -40,7 +40,7 @@ function QuickbooksCustomersPage({policy}: WithPolicyProps) { {translate('workspace.qbo.customersDescription')} - {translate('workspace.qbo.import')} + {translate('workspace.accounting.import')} diff --git a/src/pages/workspace/accounting/qbo/import/QuickbooksImportPage.tsx b/src/pages/workspace/accounting/qbo/import/QuickbooksImportPage.tsx index d9457a2f5670..2e2d7e51286f 100644 --- a/src/pages/workspace/accounting/qbo/import/QuickbooksImportPage.tsx +++ b/src/pages/workspace/accounting/qbo/import/QuickbooksImportPage.tsx @@ -19,11 +19,11 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const quickbooksOnlineConfigTitles = { - [CONST.INTEGRATION_ENTITY_MAP_TYPES.DEFAULT]: translate('workspace.qbo.imported'), - [CONST.INTEGRATION_ENTITY_MAP_TYPES.IMPORTED]: translate('workspace.qbo.imported'), + [CONST.INTEGRATION_ENTITY_MAP_TYPES.DEFAULT]: translate('workspace.accounting.imported'), + [CONST.INTEGRATION_ENTITY_MAP_TYPES.IMPORTED]: translate('workspace.accounting.imported'), [CONST.INTEGRATION_ENTITY_MAP_TYPES.NOT_IMPORTED]: translate('workspace.qbo.notImported'), [CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE]: translate('workspace.qbo.notImported'), - [CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG]: translate('workspace.qbo.importedAsTags'), + [CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG]: translate('workspace.accounting.importedAsTags'), [CONST.INTEGRATION_ENTITY_MAP_TYPES.REPORT_FIELD]: translate('workspace.qbo.importedAsReportFields'), }; const policyID = policy?.id ?? ''; @@ -31,7 +31,7 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { const sections = [ { - description: translate('workspace.qbo.accounts'), + description: translate('workspace.accounting.accounts'), action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_CHART_OF_ACCOUNTS.getRoute(policyID)), hasError: Boolean(policy?.errors?.enableNewCategories), title: enableNewCategories, @@ -62,7 +62,7 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { if (policy?.connections?.quickbooksOnline.data.country !== CONST.COUNTRY.US) { sections.push({ - description: translate('workspace.qbo.taxes'), + description: translate('workspace.accounting.taxes'), action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_TAXES.getRoute(policyID)), hasError: Boolean(policy?.errors?.syncTaxes), title: syncTaxes, @@ -81,7 +81,7 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { shouldEnableMaxHeight testID={QuickbooksImportPage.displayName} > - + {translate('workspace.qbo.importDescription')} {sections.map((section) => ( diff --git a/src/pages/workspace/accounting/qbo/import/QuickbooksLocationsPage.tsx b/src/pages/workspace/accounting/qbo/import/QuickbooksLocationsPage.tsx index b7e9724bb8a0..840132801be2 100644 --- a/src/pages/workspace/accounting/qbo/import/QuickbooksLocationsPage.tsx +++ b/src/pages/workspace/accounting/qbo/import/QuickbooksLocationsPage.tsx @@ -41,7 +41,7 @@ function QuickbooksLocationsPage({policy}: WithPolicyProps) { {translate('workspace.qbo.locationsDescription')} - {translate('workspace.qbo.import')} + {translate('workspace.accounting.import')} diff --git a/src/pages/workspace/accounting/qbo/import/QuickbooksTaxesPage.tsx b/src/pages/workspace/accounting/qbo/import/QuickbooksTaxesPage.tsx index 98b4f5d8c6f7..c013d12cfce9 100644 --- a/src/pages/workspace/accounting/qbo/import/QuickbooksTaxesPage.tsx +++ b/src/pages/workspace/accounting/qbo/import/QuickbooksTaxesPage.tsx @@ -33,17 +33,17 @@ function QuickbooksTaxesPage({policy}: WithPolicyProps) { shouldEnableMaxHeight testID={QuickbooksTaxesPage.displayName} > - + {translate('workspace.qbo.taxesDescription')} - {translate('workspace.qbo.import')} + {translate('workspace.accounting.import')} Connections.updatePolicyConnectionConfig( diff --git a/src/pages/workspace/accounting/xero/XeroImportPage.tsx b/src/pages/workspace/accounting/xero/XeroImportPage.tsx index fac598cc8068..56716631a400 100644 --- a/src/pages/workspace/accounting/xero/XeroImportPage.tsx +++ b/src/pages/workspace/accounting/xero/XeroImportPage.tsx @@ -27,31 +27,31 @@ function XeroImportPage({policy}: WithPolicyProps) { const sections = useMemo( () => [ { - description: translate('workspace.xero.accounts'), + description: translate('workspace.accounting.accounts'), action: () => {}, hasError: !!policy?.errors?.enableNewCategories, - title: translate('workspace.xero.imported'), + title: translate('workspace.accounting.imported'), pendingAction: pendingFields?.enableNewCategories, }, { description: translate('workspace.xero.trackingCategories'), action: () => {}, hasError: !!policy?.errors?.importTrackingCategories, - title: importTrackingCategories ? translate('workspace.xero.importedAsTags') : '', + title: importTrackingCategories ? translate('workspace.accounting.importedAsTags') : '', pendingAction: pendingFields?.importTrackingCategories, }, { description: translate('workspace.xero.customers'), action: () => {}, hasError: !!policy?.errors?.importCustomers, - title: importCustomers ? translate('workspace.xero.importedAsTags') : '', + title: importCustomers ? translate('workspace.accounting.importedAsTags') : '', pendingAction: pendingFields?.importCustomers, }, { - description: translate('workspace.xero.taxes'), + description: translate('workspace.accounting.taxes'), action: () => {}, hasError: !!policy?.errors?.importTaxes, - title: importTaxRates ? translate('workspace.xero.imported') : '', + title: importTaxRates ? translate('workspace.accounting.imported') : '', pendingAction: pendingFields?.importTaxRates, }, ], @@ -83,7 +83,7 @@ function XeroImportPage({policy}: WithPolicyProps) { testID={XeroImportPage.displayName} > From b43ee07a2e462d29092e629a3c91a6fa27ff4450 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Wed, 1 May 2024 01:01:34 +0200 Subject: [PATCH 6/8] fix undefined check issue --- src/pages/workspace/accounting/PolicyAccountingPage.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/pages/workspace/accounting/PolicyAccountingPage.tsx b/src/pages/workspace/accounting/PolicyAccountingPage.tsx index 9b20e008d670..7e61c9707544 100644 --- a/src/pages/workspace/accounting/PolicyAccountingPage.tsx +++ b/src/pages/workspace/accounting/PolicyAccountingPage.tsx @@ -119,7 +119,14 @@ function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccounting const policyConnectedToXero = connectedIntegration === CONST.POLICY.CONNECTIONS.NAME.XERO; - const tenants = useMemo(() => policy?.connections?.xero?.data?.tenants ?? [], [policy?.connections?.xero.data.tenants]); + const tenants = useMemo(() => { + // Due to the way optional chain is being handled in this useMemo we are forced to use this approach to properly handle undefined values + // eslint-disable-next-line @typescript-eslint/prefer-optional-chain + if (!policy || !policy.connections || !policy.connections.xero || !policy.connections.xero.data) { + return []; + } + return policy?.connections?.xero?.data?.tenants ?? []; + }, [policy]); const currentXeroOrganization = tenants.find((tenant) => tenant.id === policy?.connections?.xero.config.tenantID); const overflowMenu: ThreeDotsMenuProps['menuItems'] = useMemo( From db5a4e90e744947e71e01b7086e248fbab96ddb0 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Wed, 1 May 2024 01:24:20 +0200 Subject: [PATCH 7/8] replace removed component wrapper with AccessOrNotFoundWrapper --- .../accounting/xero/XeroImportPage.tsx | 68 +++++++++---------- .../XeroOrganizationConfigurationPage.tsx | 46 ++++++------- 2 files changed, 55 insertions(+), 59 deletions(-) diff --git a/src/pages/workspace/accounting/xero/XeroImportPage.tsx b/src/pages/workspace/accounting/xero/XeroImportPage.tsx index 56716631a400..59ec741b6c85 100644 --- a/src/pages/workspace/accounting/xero/XeroImportPage.tsx +++ b/src/pages/workspace/accounting/xero/XeroImportPage.tsx @@ -7,12 +7,11 @@ import ScrollView from '@components/ScrollView'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; -import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import CONST from '@src/CONST'; import type {Tenant} from '@src/types/onyx/Policy'; +import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; function XeroImportPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); @@ -72,40 +71,39 @@ function XeroImportPage({policy}: WithPolicyProps) { ); return ( - - + - - - - {translate('workspace.xero.importDescription')} - {sections.map((section) => ( - - - - ))} - - - - + + + {translate('workspace.xero.importDescription')} + {sections.map((section) => ( + + + + ))} + + + ); } diff --git a/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx b/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx index 9944e2307214..85b93fd3282c 100644 --- a/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx +++ b/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx @@ -11,12 +11,11 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import {updatePolicyConnectionConfig} from '@libs/actions/connections'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; -import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; -import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import CONST from '@src/CONST'; import type SCREENS from '@src/SCREENS'; +import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; type XeroOrganizationConfigurationPageProps = WithPolicyProps & StackScreenProps; function XeroOrganizationConfigurationPage({ @@ -46,29 +45,28 @@ function XeroOrganizationConfigurationPage({ }; return ( - - + - - - - {translate('workspace.xero.organizationDescription')} - - - - - + + + {translate('workspace.xero.organizationDescription')} + + + + ); } From 942e81d1aa0868c9c4735d4f6689c62a32205a5a Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Wed, 1 May 2024 01:25:15 +0200 Subject: [PATCH 8/8] fix prettier --- src/pages/workspace/accounting/xero/XeroImportPage.tsx | 2 +- .../accounting/xero/XeroOrganizationConfigurationPage.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/accounting/xero/XeroImportPage.tsx b/src/pages/workspace/accounting/xero/XeroImportPage.tsx index 59ec741b6c85..3c1455e9ee65 100644 --- a/src/pages/workspace/accounting/xero/XeroImportPage.tsx +++ b/src/pages/workspace/accounting/xero/XeroImportPage.tsx @@ -7,11 +7,11 @@ import ScrollView from '@components/ScrollView'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; +import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import CONST from '@src/CONST'; import type {Tenant} from '@src/types/onyx/Policy'; -import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; function XeroImportPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); diff --git a/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx b/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx index 85b93fd3282c..3411f524b7d4 100644 --- a/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx +++ b/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx @@ -11,11 +11,11 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import {updatePolicyConnectionConfig} from '@libs/actions/connections'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; +import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import CONST from '@src/CONST'; import type SCREENS from '@src/SCREENS'; -import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; type XeroOrganizationConfigurationPageProps = WithPolicyProps & StackScreenProps; function XeroOrganizationConfigurationPage({