From 8424a1cc62901f49680b5968037769757e93b464 Mon Sep 17 00:00:00 2001 From: Hans Date: Thu, 2 May 2024 22:49:40 +0700 Subject: [PATCH 01/10] add initial account selector page --- src/CONST.ts | 1 + src/ROUTES.ts | 4 + src/SCREENS.ts | 1 + src/languages/en.ts | 1 + src/languages/es.ts | 2 + .../ModalStackNavigators/index.tsx | 2 + .../FULL_SCREEN_TO_RHP_MAPPING.ts | 1 + src/libs/Navigation/linkingConfig/config.ts | 1 + src/libs/Navigation/types.ts | 3 + .../xero/advanced/XeroAdvancedPage.tsx | 10 +-- .../XeroInvoiceAccountSelectorPage.tsx | 88 +++++++++++++++++++ src/types/onyx/Policy.ts | 2 +- 12 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 src/pages/workspace/accounting/xero/advanced/XeroInvoiceAccountSelectorPage.tsx diff --git a/src/CONST.ts b/src/CONST.ts index b89d4a01b5a6..38e073cbcd7c 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1271,6 +1271,7 @@ const CONST = { SYNC: 'sync', IMPORT_CUSTOMERS: 'importCustomers', IMPORT_TAX_RATES: 'importTaxRates', + INVOICE_COLLECTION_ACCOUNT_ID: 'invoiceCollectionsAccountID', }, QUICKBOOKS_OUT_OF_POCKET_EXPENSE_ACCOUNT_TYPE: { diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 2d853623b520..f06615e4214c 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -786,6 +786,10 @@ const ROUTES = { route: 'settings/workspaces/:policyID/accounting/xero/advanced', getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/advanced` as const, }, + POLICY_ACCOUNTING_XERO_INVOICE_SELECTOR: { + route: 'settings/workspaces/:policyID/accounting/xero/advanced/invoice-account-selector', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/advanced/invoice-account-selector` 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 8a318c6011cb..fcb4b5d0d546 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -239,6 +239,7 @@ const SCREENS = { XERO_CUSTOMER: 'Policy_Acounting_Xero_Import_Customer', XERO_TAXES: 'Policy_Accounting_Xero_Taxes', XERO_ADVANCED: 'Policy_Accounting_Xero_Advanced', + XERO_INVOICE_ACCOUNT_SELECTOR: 'Policy_Accounting_Xero_Invoice_Account_Selector', }, INITIAL: 'Workspace_Initial', PROFILE: 'Workspace_Profile', diff --git a/src/languages/en.ts b/src/languages/en.ts index 763b4b315ff8..a0d2af762446 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2012,6 +2012,7 @@ export default { reimbursedReportsDescription: 'Any time a report is paid using Expensify ACH, the corresponding bill payment will be created in the Xero account below.', xeroBillPaymentAccount: 'Xero Bill Payment Account', xeroInvoiceCollectionAccount: 'Xero Invoice Collections Account', + invoiceAccountSelectDescription: "As you've enabled exporting Invoices from Expensify to Xero, this is the account the Invoice will appear against once marked as Paid.", }, }, type: { diff --git a/src/languages/es.ts b/src/languages/es.ts index 9a27e801393e..8f6893ebaff0 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2046,6 +2046,8 @@ export default { 'Cada vez que se pague un informe utilizando Expensify ACH, se creará el correspondiente pago de la factura en la cuenta de Xero indicadas a continuación.', xeroBillPaymentAccount: 'Cuenta de pago de las facturas de Xero', xeroInvoiceCollectionAccount: 'Cuenta de cobro de las facturas Xero', + invoiceAccountSelectDescription: + 'Como ha activado la exportación de facturas de Expensify a Xero, esta es la cuenta en la que aparecerá la factura una vez marcada como Pagada.', }, }, type: { diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 78293fdd5873..ad5722c55826 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -298,6 +298,8 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/workspace/accounting/xero/import/XeroCustomerConfigurationPage').default as React.ComponentType, [SCREENS.WORKSPACE.ACCOUNTING.XERO_TAXES]: () => require('../../../../pages/workspace/accounting/xero/XeroTaxesConfigurationPage').default as React.ComponentType, [SCREENS.WORKSPACE.ACCOUNTING.XERO_ADVANCED]: () => require('../../../../pages/workspace/accounting/xero/advanced/XeroAdvancedPage').default as React.ComponentType, + [SCREENS.WORKSPACE.ACCOUNTING.XERO_INVOICE_ACCOUNT_SELECTOR]: () => + require('../../../../pages/workspace/accounting/xero/advanced/XeroInvoiceAccountSelectorPage').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 0ecce07fa4e3..2a8eedb84e38 100755 --- a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts @@ -44,6 +44,7 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial> = { SCREENS.WORKSPACE.ACCOUNTING.XERO_CUSTOMER, SCREENS.WORKSPACE.ACCOUNTING.XERO_TAXES, SCREENS.WORKSPACE.ACCOUNTING.XERO_ADVANCED, + SCREENS.WORKSPACE.ACCOUNTING.XERO_INVOICE_ACCOUNT_SELECTOR, ], [SCREENS.WORKSPACE.TAXES]: [ SCREENS.WORKSPACE.TAXES_SETTINGS, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index c3d43d03282f..4dfbf3aac787 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -329,6 +329,7 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE.ACCOUNTING.XERO_CUSTOMER]: {path: ROUTES.POLICY_ACCOUNTING_XERO_CUSTOMER.route}, [SCREENS.WORKSPACE.ACCOUNTING.XERO_TAXES]: {path: ROUTES.POLICY_ACCOUNTING_XERO_TAXES.route}, [SCREENS.WORKSPACE.ACCOUNTING.XERO_ADVANCED]: {path: ROUTES.POLICY_ACCOUNTING_XERO_ADVANCED.route}, + [SCREENS.WORKSPACE.ACCOUNTING.XERO_INVOICE_ACCOUNT_SELECTOR]: {path: ROUTES.POLICY_ACCOUNTING_XERO_INVOICE_SELECTOR.route}, [SCREENS.WORKSPACE.DESCRIPTION]: { path: ROUTES.WORKSPACE_PROFILE_DESCRIPTION.route, }, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index cb089342943f..953f2f2f92e5 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -324,6 +324,9 @@ type SettingsNavigatorParamList = { [SCREENS.WORKSPACE.ACCOUNTING.XERO_ADVANCED]: { policyID: string; }; + [SCREENS.WORKSPACE.ACCOUNTING.XERO_INVOICE_ACCOUNT_SELECTOR]: { + policyID: string; + }; [SCREENS.GET_ASSISTANCE]: { backTo: Routes; }; diff --git a/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx b/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx index b4728dec7bf2..7b40351d735d 100644 --- a/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx +++ b/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx @@ -1,20 +1,18 @@ import React from 'react'; import ConnectionLayout from '@components/ConnectionLayout'; -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 useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as Connections from '@libs/actions/connections'; import * as ErrorUtils from '@libs/ErrorUtils'; -import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; +import Navigation from '@libs/Navigation/Navigation'; import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections'; import withPolicyConnections from '@pages/workspace/withPolicyConnections'; import ToggleSettingOptionRow from '@pages/workspace/workflows/ToggleSettingsOptionRow'; import * as Policy from '@userActions/Policy'; import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; function XeroAdvancedPage({policy}: WithPolicyConnectionsProps) { const styles = useThemeStyles(); @@ -94,7 +92,9 @@ function XeroAdvancedPage({policy}: WithPolicyConnectionsProps) { description={translate('workspace.xero.advancedConfig.xeroInvoiceCollectionAccount')} key={translate('workspace.xero.advancedConfig.xeroInvoiceCollectionAccount')} wrapperStyle={[styles.sectionMenuItemTopDescription]} - onPress={() => {}} + onPress={() => { + Navigation.navigate(ROUTES.POLICY_ACCOUNTING_XERO_INVOICE_SELECTOR.getRoute(policyID)); + }} /> diff --git a/src/pages/workspace/accounting/xero/advanced/XeroInvoiceAccountSelectorPage.tsx b/src/pages/workspace/accounting/xero/advanced/XeroInvoiceAccountSelectorPage.tsx new file mode 100644 index 000000000000..891dc89a1384 --- /dev/null +++ b/src/pages/workspace/accounting/xero/advanced/XeroInvoiceAccountSelectorPage.tsx @@ -0,0 +1,88 @@ +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 Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as Connections from '@libs/actions/connections'; +import Navigation from '@libs/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'; + +type SelectorType = ListItem & { + value: string; +}; + +function XeroInvoiceAccountSelectorPage({policy}: WithPolicyConnectionsProps) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + + const policyID = policy?.id ?? ''; + const {bankAccounts} = policy?.connections?.xero?.data ?? {}; + + const {invoiceCollectionsAccountID} = policy?.connections?.xero?.config.sync ?? {}; + + const xeroSelectorOptions = useMemo( + () => + (bankAccounts ?? []).map(({id, name}) => ({ + value: id, + text: name, + keyForList: id, + isSelected: invoiceCollectionsAccountID === id, + })), + [invoiceCollectionsAccountID, bankAccounts], + ); + + const listHeaderComponent = useMemo( + () => ( + + {translate('workspace.xero.advancedConfig.invoiceAccountSelectDescription')} + + ), + [translate, styles.pb2, styles.ph5, styles.pb5, styles.textNormal], + ); + + const initiallyFocusedOptionKey = useMemo(() => xeroSelectorOptions?.find((mode) => mode.isSelected)?.keyForList, [xeroSelectorOptions]); + + const updateMode = useCallback( + ({value}: SelectorType) => { + Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.XERO, CONST.XERO_CONFIG.INVOICE_COLLECTION_ACCOUNT_ID, value); + Navigation.goBack(ROUTES.POLICY_ACCOUNTING_XERO_ADVANCED.getRoute(policyID)); + }, + [policyID], + ); + + return ( + + + + + + + + ); +} + +XeroInvoiceAccountSelectorPage.displayName = 'XeroInvoiceAccountSelectorPage'; + +export default withPolicyConnections(XeroInvoiceAccountSelectorPage); diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index d64de6196985..7239d46df5cc 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -208,7 +208,7 @@ type Tenant = { }; type XeroConnectionData = { - bankAccounts: unknown[]; + bankAccounts: Account[]; countryCode: string; organisationID: string; revenueAccounts: Array<{ From aa998bcd7f2a89f851b88bdb60070444aea0c957 Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 3 May 2024 14:50:11 +0700 Subject: [PATCH 02/10] add selection screen --- src/components/SelectionScreen.tsx | 81 +++++++++++++++++++ .../XeroInvoiceAccountSelectorPage.tsx | 41 ++++------ 2 files changed, 96 insertions(+), 26 deletions(-) create mode 100644 src/components/SelectionScreen.tsx diff --git a/src/components/SelectionScreen.tsx b/src/components/SelectionScreen.tsx new file mode 100644 index 000000000000..df650dffd40e --- /dev/null +++ b/src/components/SelectionScreen.tsx @@ -0,0 +1,81 @@ +import React from 'react'; +import useLocalize from '@hooks/useLocalize'; +import type {PolicyAccessVariant} from '@pages/workspace/AccessOrNotFoundWrapper'; +import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; +import type {TranslationPaths} from '@src/languages/types'; +import type {PolicyFeatureName} from '@src/types/onyx/Policy'; +import HeaderWithBackButton from './HeaderWithBackButton'; +import ScreenWrapper from './ScreenWrapper'; +import SelectionList from './SelectionList'; +import type RadioListItem from './SelectionList/RadioListItem'; +import type TableListItem from './SelectionList/TableListItem'; +import type {ListItem, SectionListDataType} from './SelectionList/types'; +import type UserListItem from './SelectionList/UserListItem'; + +type SelectorType = ListItem & { + value: string; +}; + +type SelectionScreenProps = { + displayName: string; + title: TranslationPaths; + headerContent?: React.ReactNode; + sections: Array>; + listItem: typeof RadioListItem | typeof UserListItem | typeof TableListItem; + initiallyFocusedOptionKey?: string | null | undefined; + onSelectRow: (selection: SelectorType) => void; + onBackButtonPress: () => void; + /** The current policyID */ + policyID: string; + /** Defines which types of access should be verified */ + accessVariants?: PolicyAccessVariant[]; + /** The current feature name that the user tries to get access to */ + featureName?: PolicyFeatureName; +}; + +function SelectionScreen({ + displayName, + title, + headerContent, + sections, + listItem, + initiallyFocusedOptionKey, + onSelectRow, + onBackButtonPress, + policyID, + accessVariants, + featureName, +}: SelectionScreenProps) { + const {translate} = useLocalize(); + return ( + + + + + + + ); +} + +export type {SelectorType}; + +SelectionScreen.displayName = 'SelectionScreen'; +export default SelectionScreen; diff --git a/src/pages/workspace/accounting/xero/advanced/XeroInvoiceAccountSelectorPage.tsx b/src/pages/workspace/accounting/xero/advanced/XeroInvoiceAccountSelectorPage.tsx index 891dc89a1384..ee65daf97ba5 100644 --- a/src/pages/workspace/accounting/xero/advanced/XeroInvoiceAccountSelectorPage.tsx +++ b/src/pages/workspace/accounting/xero/advanced/XeroInvoiceAccountSelectorPage.tsx @@ -1,25 +1,19 @@ 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 type {SelectorType} from '@components/SelectionScreen'; +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 Navigation from '@libs/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'; -type SelectorType = ListItem & { - value: string; -}; - function XeroInvoiceAccountSelectorPage({policy}: WithPolicyConnectionsProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -53,33 +47,28 @@ function XeroInvoiceAccountSelectorPage({policy}: WithPolicyConnectionsProps) { const updateMode = useCallback( ({value}: SelectorType) => { - Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.XERO, CONST.XERO_CONFIG.INVOICE_COLLECTION_ACCOUNT_ID, value); + Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.XERO, CONST.XERO_CONFIG.SYNC, { + invoiceCollectionsAccountID: value, + }); Navigation.goBack(ROUTES.POLICY_ACCOUNTING_XERO_ADVANCED.getRoute(policyID)); }, [policyID], ); return ( - - - - - - - + displayName={XeroInvoiceAccountSelectorPage.displayName} + sections={[{data: xeroSelectorOptions}]} + listItem={RadioListItem} + onSelectRow={updateMode} + initiallyFocusedOptionKey={initiallyFocusedOptionKey} + headerContent={listHeaderComponent} + onBackButtonPress={() => Navigation.goBack()} + title="workspace.xero.advancedConfig.xeroInvoiceCollectionAccount" + /> ); } From 45f2288008c5df1c08163ff817edc7f84f1b1e5b Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 3 May 2024 15:05:15 +0700 Subject: [PATCH 03/10] update selected bank account --- .../xero/advanced/XeroAdvancedPage.tsx | 19 +++++++++++++------ .../XeroInvoiceAccountSelectorPage.tsx | 1 - 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx b/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx index cbb9f8cc608b..7ce1850b13b6 100644 --- a/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx +++ b/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useMemo } from 'react'; import ConnectionLayout from '@components/ConnectionLayout'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -19,9 +19,16 @@ function XeroAdvancedPage({policy}: WithPolicyConnectionsProps) { const {translate} = useLocalize(); const policyID = policy?.id ?? ''; - const xeroConfig = policy?.connections?.xero?.config; - const {autoSync, pendingFields, sync} = xeroConfig ?? {}; - const xeroData = policy?.connections?.xero?.data; + const xeroConfig = policy?.connections?.xero?.config; + const {autoSync, pendingFields, sync, } = xeroConfig ?? {}; + const {bankAccounts} = policy?.connections?.xero?.data ?? {}; + + const selectedBankAccountName = useMemo(() => { + const {invoiceCollectionsAccountID} = sync ?? {}; + const selectedAccount = (bankAccounts ?? []).find((bank) => bank.id === invoiceCollectionsAccountID); + + return selectedAccount?.name ?? ''; + }, [sync, bankAccounts]); return ( Date: Fri, 3 May 2024 15:16:18 +0700 Subject: [PATCH 04/10] address comment and linting --- src/components/SelectionScreen.tsx | 8 ++++++++ .../accounting/xero/advanced/XeroAdvancedPage.tsx | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/components/SelectionScreen.tsx b/src/components/SelectionScreen.tsx index df650dffd40e..470437a5bd3f 100644 --- a/src/components/SelectionScreen.tsx +++ b/src/components/SelectionScreen.tsx @@ -17,13 +17,21 @@ type SelectorType = ListItem & { }; type SelectionScreenProps = { + /** Used to set the testID for tests */ displayName: string; + /** Title of the selection component */ title: TranslationPaths; + /** Custom content to display in the header */ headerContent?: React.ReactNode; + /** Sections for the section list */ sections: Array>; + /** Default renderer for every item in the list */ listItem: typeof RadioListItem | typeof UserListItem | typeof TableListItem; + /** Item `keyForList` to focus initially */ initiallyFocusedOptionKey?: string | null | undefined; + /** Callback to fire when a row is pressed */ onSelectRow: (selection: SelectorType) => void; + /** Callback to fire when back button is pressed */ onBackButtonPress: () => void; /** The current policyID */ policyID: string; diff --git a/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx b/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx index 7ce1850b13b6..008a6c1e7f7d 100644 --- a/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx +++ b/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx @@ -1,4 +1,4 @@ -import React, { useMemo } from 'react'; +import React, {useMemo} from 'react'; import ConnectionLayout from '@components/ConnectionLayout'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -6,23 +6,23 @@ 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 type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections'; import withPolicyConnections from '@pages/workspace/withPolicyConnections'; import ToggleSettingOptionRow from '@pages/workspace/workflows/ToggleSettingsOptionRow'; import * as Policy from '@userActions/Policy'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; -import Navigation from '@libs/Navigation/Navigation'; function XeroAdvancedPage({policy}: WithPolicyConnectionsProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const policyID = policy?.id ?? ''; - const xeroConfig = policy?.connections?.xero?.config; - const {autoSync, pendingFields, sync, } = xeroConfig ?? {}; + const xeroConfig = policy?.connections?.xero?.config; + const {autoSync, pendingFields, sync} = xeroConfig ?? {}; const {bankAccounts} = policy?.connections?.xero?.data ?? {}; - + const selectedBankAccountName = useMemo(() => { const {invoiceCollectionsAccountID} = sync ?? {}; const selectedAccount = (bankAccounts ?? []).find((bank) => bank.id === invoiceCollectionsAccountID); From a011dc5394577eaea9849a8628e3a1e101bfbc12 Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 3 May 2024 15:20:19 +0700 Subject: [PATCH 05/10] remove redundant variable --- src/CONST.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index a6f6ea51ba0f..310bb3959300 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1272,7 +1272,6 @@ const CONST = { SYNC: 'sync', IMPORT_CUSTOMERS: 'importCustomers', IMPORT_TAX_RATES: 'importTaxRates', - INVOICE_COLLECTION_ACCOUNT_ID: 'invoiceCollectionsAccountID', }, QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE: { From cf2cd2ff741d84e9f4590b35b597b0558abc5132 Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 3 May 2024 22:19:16 +0700 Subject: [PATCH 06/10] add spacing for selection screen prop --- src/components/SelectionScreen.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/components/SelectionScreen.tsx b/src/components/SelectionScreen.tsx index 470437a5bd3f..2d6c6e299a1d 100644 --- a/src/components/SelectionScreen.tsx +++ b/src/components/SelectionScreen.tsx @@ -19,24 +19,34 @@ type SelectorType = ListItem & { type SelectionScreenProps = { /** Used to set the testID for tests */ displayName: string; + /** Title of the selection component */ title: TranslationPaths; + /** Custom content to display in the header */ headerContent?: React.ReactNode; + /** Sections for the section list */ sections: Array>; + /** Default renderer for every item in the list */ listItem: typeof RadioListItem | typeof UserListItem | typeof TableListItem; + /** Item `keyForList` to focus initially */ initiallyFocusedOptionKey?: string | null | undefined; + /** Callback to fire when a row is pressed */ onSelectRow: (selection: SelectorType) => void; + /** Callback to fire when back button is pressed */ onBackButtonPress: () => void; + /** The current policyID */ policyID: string; + /** Defines which types of access should be verified */ accessVariants?: PolicyAccessVariant[]; + /** The current feature name that the user tries to get access to */ featureName?: PolicyFeatureName; }; From 056648cf20b256a88d3d86ebeac345a9a0005e0a Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 3 May 2024 22:32:14 +0700 Subject: [PATCH 07/10] minor improvement --- .../workspace/accounting/xero/advanced/XeroAdvancedPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx b/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx index 008a6c1e7f7d..694176523a05 100644 --- a/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx +++ b/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx @@ -22,13 +22,13 @@ function XeroAdvancedPage({policy}: WithPolicyConnectionsProps) { const xeroConfig = policy?.connections?.xero?.config; const {autoSync, pendingFields, sync} = xeroConfig ?? {}; const {bankAccounts} = policy?.connections?.xero?.data ?? {}; + const {invoiceCollectionsAccountID} = sync ?? {}; const selectedBankAccountName = useMemo(() => { - const {invoiceCollectionsAccountID} = sync ?? {}; const selectedAccount = (bankAccounts ?? []).find((bank) => bank.id === invoiceCollectionsAccountID); return selectedAccount?.name ?? ''; - }, [sync, bankAccounts]); + }, [sync, bankAccounts, invoiceCollectionsAccountID]); return ( Date: Fri, 3 May 2024 22:39:55 +0700 Subject: [PATCH 08/10] remove unnecessary depedencies --- .../workspace/accounting/xero/advanced/XeroAdvancedPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx b/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx index 694176523a05..516180145406 100644 --- a/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx +++ b/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx @@ -28,7 +28,7 @@ function XeroAdvancedPage({policy}: WithPolicyConnectionsProps) { const selectedAccount = (bankAccounts ?? []).find((bank) => bank.id === invoiceCollectionsAccountID); return selectedAccount?.name ?? ''; - }, [sync, bankAccounts, invoiceCollectionsAccountID]); + }, [bankAccounts, invoiceCollectionsAccountID]); return ( Date: Fri, 3 May 2024 23:33:51 +0700 Subject: [PATCH 09/10] update typo.. --- src/languages/en.ts | 4 ++-- src/languages/es.ts | 6 +++--- .../accounting/qbo/advanced/QuickbooksAccountSelectPage.tsx | 2 +- .../qbo/advanced/QuickbooksInvoiceAccountSelectPage.tsx | 2 +- .../workspace/accounting/xero/advanced/XeroAdvancedPage.tsx | 2 +- .../xero/advanced/XeroInvoiceAccountSelectorPage.tsx | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index dbe5943b9215..8db64180f789 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1966,7 +1966,7 @@ export default { qboInvoiceCollectionAccount: 'QuickBooks invoice collections account', accountSelectDescription: "As you've enabled sync reimbursed reports, you will need select the bank account your reimbursements are coming out of, and we'll create the payment in QuickBooks.", - invoiceAccountSelectDescription: + invoiceAccountSelectorDescription: 'If you are exporting invoices from Expensify to Quickbooks Online, this is the account the invoice will appear against once marked as paid.', }, accounts: { @@ -2010,7 +2010,7 @@ export default { reimbursedReportsDescription: 'Any time a report is paid using Expensify ACH, the corresponding bill payment will be created in the Xero account below.', xeroBillPaymentAccount: 'Xero Bill Payment Account', xeroInvoiceCollectionAccount: 'Xero Invoice Collections Account', - invoiceAccountSelectDescription: "As you've enabled exporting Invoices from Expensify to Xero, this is the account the Invoice will appear against once marked as Paid.", + invoiceAccountSelectorDescription: "As you've enabled exporting invoices from Expensify to Xero, this is the account the invoice will appear against once marked as paid.", }, }, type: { diff --git a/src/languages/es.ts b/src/languages/es.ts index 71d883bcfab2..a156b0073442 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1993,7 +1993,7 @@ export default { qboInvoiceCollectionAccount: 'Cuenta de cobro de las facturas QuickBooks', accountSelectDescription: 'Como has activado la sincronización de los informes de reembolso, tendrás que seleccionar la cuenta bancaria de la que saldrán tus reembolsos y crearemos el pago en QuickBooks.', - invoiceAccountSelectDescription: + invoiceAccountSelectorDescription: 'Si está exportando facturas de Expensify a Quickbooks Online, ésta es la cuenta en la que aparecerá la factura una vez marcada como pagada.', }, accounts: { @@ -2044,8 +2044,8 @@ export default { 'Cada vez que se pague un informe utilizando Expensify ACH, se creará el correspondiente pago de la factura en la cuenta de Xero indicadas a continuación.', xeroBillPaymentAccount: 'Cuenta de pago de las facturas de Xero', xeroInvoiceCollectionAccount: 'Cuenta de cobro de las facturas Xero', - invoiceAccountSelectDescription: - 'Como ha activado la exportación de facturas de Expensify a Xero, esta es la cuenta en la que aparecerá la factura una vez marcada como Pagada.', + invoiceAccountSelectorDescription: + 'Como ha activado la exportación de facturas de Expensify a Xero, esta es la cuenta en la que aparecerá la factura una vez marcada como pagada.', }, }, type: { diff --git a/src/pages/workspace/accounting/qbo/advanced/QuickbooksAccountSelectPage.tsx b/src/pages/workspace/accounting/qbo/advanced/QuickbooksAccountSelectPage.tsx index 38dc517d57de..e9cc481eb23e 100644 --- a/src/pages/workspace/accounting/qbo/advanced/QuickbooksAccountSelectPage.tsx +++ b/src/pages/workspace/accounting/qbo/advanced/QuickbooksAccountSelectPage.tsx @@ -42,7 +42,7 @@ function QuickbooksAccountSelectPage({policy}: WithPolicyConnectionsProps) { const listHeaderComponent = useMemo( () => ( - {translate('workspace.qbo.advancedConfig.invoiceAccountSelectDescription')} + {translate('workspace.qbo.advancedConfig.invoiceAccountSelectorDescription')} ), [translate, styles.pb2, styles.ph5, styles.pb5, styles.textNormal], diff --git a/src/pages/workspace/accounting/qbo/advanced/QuickbooksInvoiceAccountSelectPage.tsx b/src/pages/workspace/accounting/qbo/advanced/QuickbooksInvoiceAccountSelectPage.tsx index 31667da4ff6d..fd6bfde869f3 100644 --- a/src/pages/workspace/accounting/qbo/advanced/QuickbooksInvoiceAccountSelectPage.tsx +++ b/src/pages/workspace/accounting/qbo/advanced/QuickbooksInvoiceAccountSelectPage.tsx @@ -43,7 +43,7 @@ function QuickbooksInvoiceAccountSelectPage({policy}: WithPolicyConnectionsProps const listHeaderComponent = useMemo( () => ( - {translate('workspace.qbo.advancedConfig.invoiceAccountSelectDescription')} + {translate('workspace.qbo.advancedConfig.invoiceAccountSelectorDescription')} ), [translate, styles.pb2, styles.ph5, styles.pb5, styles.textNormal], diff --git a/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx b/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx index 516180145406..9d84fbb206d2 100644 --- a/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx +++ b/src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx @@ -57,7 +57,7 @@ function XeroAdvancedPage({policy}: WithPolicyConnectionsProps) { ( - {translate('workspace.xero.advancedConfig.invoiceAccountSelectDescription')} + {translate('workspace.xero.advancedConfig.invoiceAccountSelectorDescription')} ), [translate, styles.pb2, styles.ph5, styles.pb5, styles.textNormal], @@ -65,7 +65,7 @@ function XeroInvoiceAccountSelectorPage({policy}: WithPolicyConnectionsProps) { onSelectRow={updateMode} initiallyFocusedOptionKey={initiallyFocusedOptionKey} headerContent={listHeaderComponent} - onBackButtonPress={() => Navigation.goBack()} + onBackButtonPress={() => Navigation.goBack(ROUTES.POLICY_ACCOUNTING_XERO_ADVANCED.getRoute(policyID))} title="workspace.xero.advancedConfig.xeroInvoiceCollectionAccount" /> ); From fa7ba2770d09fc6f70ee64633c699ed77c49af45 Mon Sep 17 00:00:00 2001 From: Hans Date: Sun, 5 May 2024 16:43:30 +0700 Subject: [PATCH 10/10] add shouldBeBlocked for AccessOrNotFoundWrapper --- src/components/SelectionScreen.tsx | 5 +++++ src/pages/workspace/AccessOrNotFoundWrapper.tsx | 8 ++++++-- .../xero/advanced/XeroInvoiceAccountSelectorPage.tsx | 3 ++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/components/SelectionScreen.tsx b/src/components/SelectionScreen.tsx index 2d6c6e299a1d..a2ab477accef 100644 --- a/src/components/SelectionScreen.tsx +++ b/src/components/SelectionScreen.tsx @@ -49,6 +49,9 @@ type SelectionScreenProps = { /** The current feature name that the user tries to get access to */ featureName?: PolicyFeatureName; + + /** Whether or not to block user from accessing the page */ + shouldBeBlocked?: boolean; }; function SelectionScreen({ @@ -63,6 +66,7 @@ function SelectionScreen({ policyID, accessVariants, featureName, + shouldBeBlocked, }: SelectionScreenProps) { const {translate} = useLocalize(); return ( @@ -70,6 +74,7 @@ function SelectionScreen({ policyID={policyID} accessVariants={accessVariants} featureName={featureName} + shouldBeBlocked={shouldBeBlocked} > ; type PageNotFoundFallbackProps = Pick & {shouldShowFullScreenFallback: boolean}; @@ -68,7 +71,7 @@ function PageNotFoundFallback({policyID, shouldShowFullScreenFallback, fullPageN ); } -function AccessOrNotFoundWrapper({accessVariants = [], fullPageNotFoundViewProps, ...props}: AccessOrNotFoundWrapperProps) { +function AccessOrNotFoundWrapper({accessVariants = [], fullPageNotFoundViewProps, shouldBeBlocked, ...props}: AccessOrNotFoundWrapperProps) { const {policy, policyID, featureName, isLoadingReportData} = props; const isPolicyIDInRoute = !!policyID?.length; @@ -92,7 +95,8 @@ function AccessOrNotFoundWrapper({accessVariants = [], fullPageNotFoundViewProps return acc && accessFunction(policy); }, true); - const shouldShowNotFoundPage = isEmptyObject(policy) || (Object.keys(policy).length === 1 && !isEmptyObject(policy.errors)) || !policy?.id || !isPageAccessible || !isFeatureEnabled; + const shouldShowNotFoundPage = + isEmptyObject(policy) || (Object.keys(policy).length === 1 && !isEmptyObject(policy.errors)) || !policy?.id || !isPageAccessible || !isFeatureEnabled || shouldBeBlocked; if (shouldShowFullScreenLoadingIndicator) { return ; diff --git a/src/pages/workspace/accounting/xero/advanced/XeroInvoiceAccountSelectorPage.tsx b/src/pages/workspace/accounting/xero/advanced/XeroInvoiceAccountSelectorPage.tsx index 23c3bfc8af29..460eca1a153b 100644 --- a/src/pages/workspace/accounting/xero/advanced/XeroInvoiceAccountSelectorPage.tsx +++ b/src/pages/workspace/accounting/xero/advanced/XeroInvoiceAccountSelectorPage.tsx @@ -20,7 +20,7 @@ function XeroInvoiceAccountSelectorPage({policy}: WithPolicyConnectionsProps) { const policyID = policy?.id ?? ''; const {bankAccounts} = policy?.connections?.xero?.data ?? {}; - const {invoiceCollectionsAccountID} = policy?.connections?.xero?.config.sync ?? {}; + const {invoiceCollectionsAccountID, syncReimbursedReports} = policy?.connections?.xero?.config.sync ?? {}; const xeroSelectorOptions = useMemo( () => @@ -62,6 +62,7 @@ function XeroInvoiceAccountSelectorPage({policy}: WithPolicyConnectionsProps) { displayName={XeroInvoiceAccountSelectorPage.displayName} sections={[{data: xeroSelectorOptions}]} listItem={RadioListItem} + shouldBeBlocked={!syncReimbursedReports} onSelectRow={updateMode} initiallyFocusedOptionKey={initiallyFocusedOptionKey} headerContent={listHeaderComponent}