diff --git a/src/ROUTES.ts b/src/ROUTES.ts index d59bb9a3a981..9f84b3db0de1 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -788,6 +788,10 @@ const ROUTES = { route: 'settings/workspaces/:policyID/accounting/xero/import/taxes', getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/import/taxes` as const, }, + POLICY_ACCOUNTING_XERO_EXPORT: { + route: 'settings/workspaces/:policyID/accounting/xero/export', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/export` as const, + }, POLICY_ACCOUNTING_XERO_ADVANCED: { route: 'settings/workspaces/:policyID/accounting/xero/advanced', getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/advanced` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index d9f92382bc95..d4057c37b3dd 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -244,6 +244,7 @@ const SCREENS = { XERO_ORGANIZATION: 'Policy_Accounting_Xero_Customers', XERO_CUSTOMER: 'Policy_Acounting_Xero_Import_Customer', XERO_TAXES: 'Policy_Accounting_Xero_Taxes', + XERO_EXPORT: 'Policy_Accounting_Xero_Export', XERO_ADVANCED: 'Policy_Accounting_Xero_Advanced', XERO_INVOICE_ACCOUNT_SELECTOR: 'Policy_Accounting_Xero_Invoice_Account_Selector', }, diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx index bf35d65340fc..42de7e2fb7f4 100644 --- a/src/components/MenuItem.tsx +++ b/src/components/MenuItem.tsx @@ -141,6 +141,12 @@ type MenuItemBaseProps = { /** A description text to show under the title */ description?: string; + /** Text to show below menu item. This text is not interactive */ + helperText?: string; + + /** Any additional styles to pass to helper text. */ + helperTextStyle?: StyleProp; + /** Should the description be shown above the title (instead of the other way around) */ shouldShowDescriptionOnTop?: boolean; @@ -296,6 +302,8 @@ function MenuItem( furtherDetailsIcon, furtherDetails, description, + helperText, + helperTextStyle, error, errorText, success = false, @@ -679,6 +687,7 @@ function MenuItem( )} + {!!helperText && {helperText}} ); } diff --git a/src/languages/en.ts b/src/languages/en.ts index 179ad777234d..5daab7db06d3 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2024,11 +2024,26 @@ export default { customersDescription: 'Import customer contacts. Billable expenses need tags for export. Expenses will carry the customer information to Xero for sales invoices.', taxesDescription: 'Choose whether to import tax rates and tax defaults from your accounting integration.', notImported: 'Not imported', + export: 'Export', + exportDescription: 'Configure how data in Expensify gets exported to Xero.', + exportCompanyCard: 'Export company card expenses as', + purchaseBill: 'Purchase bill', + exportDeepDiveCompanyCard: + 'Each exported expense posts as a bank transaction to the Xero bank account you select below, and transaction dates will match the dates on your bank statement.', + bankTransactions: 'Bank transactions', + xeroBankAccount: 'Xero bank account', + preferredExporter: 'Preferred exporter', + exportExpenses: 'Export out-of-pocket expenses as', + exportExpensesDescription: 'Reports will export as a purchase bill, using the date and status you select below.', + purchaseBillDate: 'Purchase bill date', + exportInvoices: 'Export invoices as', + salesInvoice: 'Sales invoice', + exportInvoicesDescription: 'Sales invoices always display the date on which the invoice was sent.', advancedConfig: { advanced: 'Advanced', autoSync: 'Auto-Sync', autoSyncDescription: 'Sync Xero and Expensify automatically every day.', - purchaseBillStatusTitle: 'Set purchase bill status (optional)', + purchaseBillStatusTitle: 'Purchase bill status', reimbursedReports: 'Sync reimbursed reports', 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', diff --git a/src/languages/es.ts b/src/languages/es.ts index b7c32027c40a..d4a6919b3a22 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2057,11 +2057,26 @@ export default { 'Importar contactos de clientes. Los gastos facturables necesitan etiquetas para la exportación. Los gastos llevarán la información del cliente a Xero para las facturas de ventas.', taxesDescription: 'Elige si quires importar las tasas de impuestos y los impuestos por defecto de tu integración de contaduría.', notImported: 'No importado', + export: 'Exportar', + exportDescription: 'Configura cómo se exportan los datos de Expensify a Xero.', + exportCompanyCard: 'Exportar gastos de la tarjeta de empresa como', + purchaseBill: 'Factura de compra', + exportDeepDiveCompanyCard: + 'Cada gasto exportado se contabiliza como una transacción bancaria en la cuenta bancaria de Xero que selecciones a continuación. Las fechas de las transacciones coincidirán con las fechas de el extracto bancario.', + bankTransactions: 'Transacciones bancarias', + xeroBankAccount: 'Cuenta bancaria de Xero', + preferredExporter: 'Exportador preferido', + exportExpenses: 'Exportar gastos por cuenta propia como', + exportExpensesDescription: 'Los informes se exportarán como una factura de compra utilizando la fecha y el estado que seleccione a continuación', + purchaseBillDate: 'Fecha de la factura de compra', + exportInvoices: 'Exportar facturas como', + salesInvoice: 'Factura de venta', + exportInvoicesDescription: 'Las facturas de venta siempre muestran la fecha en la que se envió la factura.', advancedConfig: { advanced: 'Avanzado', autoSync: 'Autosincronización', autoSyncDescription: 'Sincroniza Xero y Expensify automáticamente todos los días.', - purchaseBillStatusTitle: 'Set purchase bill status (optional)', + purchaseBillStatusTitle: 'Estado de la factura de compra', reimbursedReports: 'Sincronizar informes reembolsados', reimbursedReportsDescription: '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.', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 0190434f73a3..0fb3fbf6245f 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -305,6 +305,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/workspace/accounting/xero/XeroOrganizationConfigurationPage').default as React.ComponentType, [SCREENS.WORKSPACE.ACCOUNTING.XERO_CUSTOMER]: () => 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_EXPORT]: () => require('../../../../pages/workspace/accounting/xero/export/XeroExportConfigurationPage').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, 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 7f9a366145da..4024e0ad2278 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_ORGANIZATION, SCREENS.WORKSPACE.ACCOUNTING.XERO_CUSTOMER, SCREENS.WORKSPACE.ACCOUNTING.XERO_TAXES, + SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT, SCREENS.WORKSPACE.ACCOUNTING.XERO_ADVANCED, SCREENS.WORKSPACE.ACCOUNTING.XERO_INVOICE_ACCOUNT_SELECTOR, ], diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 71f1bb3e761b..5ef86bb59b75 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -331,6 +331,7 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE.ACCOUNTING.XERO_ORGANIZATION]: {path: ROUTES.POLICY_ACCOUNTING_XERO_ORGANIZATION.route}, [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_EXPORT]: {path: ROUTES.POLICY_ACCOUNTING_XERO_EXPORT.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]: { diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 37ab9e3e4032..380ede9dfec5 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -324,6 +324,9 @@ type SettingsNavigatorParamList = { [SCREENS.WORKSPACE.ACCOUNTING.XERO_TAXES]: { policyID: string; }; + [SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT]: { + policyID: string; + }; [SCREENS.WORKSPACE.ACCOUNTING.XERO_ADVANCED]: { policyID: string; }; diff --git a/src/pages/workspace/accounting/PolicyAccountingPage.tsx b/src/pages/workspace/accounting/PolicyAccountingPage.tsx index 0b40cd46fd3a..fbd5b669fa62 100644 --- a/src/pages/workspace/accounting/PolicyAccountingPage.tsx +++ b/src/pages/workspace/accounting/PolicyAccountingPage.tsx @@ -92,7 +92,7 @@ function accountingIntegrationData( /> ), onImportPagePress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_XERO_IMPORT.getRoute(policyID)), - onExportPagePress: () => {}, + onExportPagePress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_XERO_EXPORT.getRoute(policyID)), onAdvancedPagePress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_XERO_ADVANCED.getRoute(policyID)), }; default: diff --git a/src/pages/workspace/accounting/xero/export/XeroExportConfigurationPage.tsx b/src/pages/workspace/accounting/xero/export/XeroExportConfigurationPage.tsx new file mode 100644 index 000000000000..934c41dab614 --- /dev/null +++ b/src/pages/workspace/accounting/xero/export/XeroExportConfigurationPage.tsx @@ -0,0 +1,110 @@ +import React from 'react'; +import ConnectionLayout from '@components/ConnectionLayout'; +import type {MenuItemProps} from '@components/MenuItem'; +import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; +import OfflineWithFeedback from '@components/OfflineWithFeedback'; +import type {OfflineWithFeedbackProps} from '@components/OfflineWithFeedback'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections'; +import withPolicyConnections from '@pages/workspace/withPolicyConnections'; +import CONST from '@src/CONST'; + +type MenuItem = MenuItemProps & {pendingAction?: OfflineWithFeedbackProps['pendingAction']}; + +function XeroExportConfigurationPage({policy}: WithPolicyConnectionsProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const policyID = policy?.id ?? ''; + const policyOwner = policy?.owner ?? ''; + + const {export: exportConfiguration, errorFields, pendingFields} = policy?.connections?.xero?.config ?? {}; + const menuItems: MenuItem[] = [ + { + description: translate('workspace.xero.preferredExporter'), + onPress: () => {}, + brickRoadIndicator: errorFields?.exporter ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, + title: exportConfiguration?.exporter ?? policyOwner, + pendingAction: pendingFields?.export, + error: errorFields?.exporter ? translate('common.genericErrorMessage') : undefined, + }, + { + description: translate('workspace.xero.exportExpenses'), + title: translate('workspace.xero.purchaseBill'), + interactive: false, + shouldShowRightIcon: false, + helperText: translate('workspace.xero.exportExpensesDescription'), + }, + { + description: translate('workspace.xero.purchaseBillDate'), + brickRoadIndicator: errorFields?.billDate ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, + title: exportConfiguration?.billDate, + pendingAction: pendingFields?.export, + error: errorFields?.billDate ? translate('common.genericErrorMessage') : undefined, + }, + { + description: translate('workspace.xero.advancedConfig.purchaseBillStatusTitle'), + onPress: () => {}, + title: exportConfiguration?.billStatus?.purchase, + pendingAction: pendingFields?.export, + error: errorFields?.purchase ? translate('common.genericErrorMessage') : undefined, + }, + { + description: translate('workspace.xero.exportInvoices'), + title: translate('workspace.xero.salesInvoice'), + interactive: false, + shouldShowRightIcon: false, + helperText: translate('workspace.xero.exportInvoicesDescription'), + }, + { + description: translate('workspace.xero.exportCompanyCard'), + title: translate('workspace.xero.bankTransactions'), + shouldShowRightIcon: false, + interactive: false, + helperText: translate('workspace.xero.exportDeepDiveCompanyCard'), + }, + { + description: translate('workspace.xero.xeroBankAccount'), + onPress: () => {}, + brickRoadIndicator: errorFields?.nonReimbursableAccount ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, + title: undefined, + pendingAction: pendingFields?.export, + error: undefined, + }, + ]; + + return ( + + {menuItems.map((menuItem) => ( + + + + ))} + + ); +} + +XeroExportConfigurationPage.displayName = 'XeroExportConfigurationPage'; + +export default withPolicyConnections(XeroExportConfigurationPage);