diff --git a/src/CONST.ts b/src/CONST.ts index 95cb4f94b169..efb0463457b1 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1301,6 +1301,17 @@ const CONST = { SYNC: 'sync', IMPORT_CUSTOMERS: 'importCustomers', IMPORT_TAX_RATES: 'importTaxRates', + IMPORT_TRACKING_CATEGORIES: 'importTrackingCategories', + MAPPINGS: 'mappings', + TRACKING_CATEGORY_PREFIX: 'trackingCategory_', + TRACKING_CATEGORY_FIELDS: { + COST_CENTERS: 'cost centers', + REGION: 'region', + }, + TRACKING_CATEGORY_OPTIONS: { + DEFAULT: 'DEFAULT', + TAG: 'TAG', + }, }, QUICKBOOKS_REIMBURSABLE_ACCOUNT_TYPE: { diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 9f84b3db0de1..afe806c193aa 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -780,6 +780,18 @@ const ROUTES = { route: 'settings/workspaces/:policyID/accounting/xero/organization/:currentOrganizationID', getRoute: (policyID: string, currentOrganizationID: string) => `settings/workspaces/${policyID}/accounting/xero/organization/${currentOrganizationID}` as const, }, + POLICY_ACCOUNTING_XERO_TRACKING_CATEGORIES: { + route: 'settings/workspaces/:policyID/accounting/xero/import/tracking-categories', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/import/tracking-categories` as const, + }, + POLICY_ACCOUNTING_XERO_TRACKING_CATEGORIES_MAP_COST_CENTERS: { + route: 'settings/workspaces/:policyID/accounting/xero/import/tracking-categories/cost-centers', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/import/tracking-categories/cost-centers` as const, + }, + POLICY_ACCOUNTING_XERO_TRACKING_CATEGORIES_MAP_REGION: { + route: 'settings/workspaces/:policyID/accounting/xero/import/tracking-categories/region', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/import/tracking-categories/region` as const, + }, POLICY_ACCOUNTING_XERO_CUSTOMER: { route: '/settings/workspaces/:policyID/accounting/xero/import/customers', getRoute: (policyID: string) => `/settings/workspaces/${policyID}/accounting/xero/import/customers` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index d4057c37b3dd..b76df331fe74 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -244,6 +244,9 @@ const SCREENS = { XERO_ORGANIZATION: 'Policy_Accounting_Xero_Customers', XERO_CUSTOMER: 'Policy_Acounting_Xero_Import_Customer', XERO_TAXES: 'Policy_Accounting_Xero_Taxes', + XERO_TRACKING_CATEGORIES: 'Policy_Accounting_Xero_Tracking_Categories', + XERO_MAP_COST_CENTERS: 'Policy_Accounting_Xero_Map_Cost_Centers', + XERO_MAP_REGION: 'Policy_Accounting_Xero_Map_Region', 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/ConnectToXeroButton/index.native.tsx b/src/components/ConnectToXeroButton/index.native.tsx index 36c5af4a0575..f5e819136f00 100644 --- a/src/components/ConnectToXeroButton/index.native.tsx +++ b/src/components/ConnectToXeroButton/index.native.tsx @@ -11,7 +11,7 @@ import Modal from '@components/Modal'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import {removePolicyConnection} from '@libs/actions/connections'; -import getXeroSetupLink from '@libs/actions/connections/ConnectToXero'; +import {getXeroSetupLink} from '@libs/actions/connections/ConnectToXero'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Session} from '@src/types/onyx'; diff --git a/src/components/ConnectToXeroButton/index.tsx b/src/components/ConnectToXeroButton/index.tsx index 8fad63e1a965..318c3bac4e2a 100644 --- a/src/components/ConnectToXeroButton/index.tsx +++ b/src/components/ConnectToXeroButton/index.tsx @@ -5,7 +5,7 @@ import useEnvironment from '@hooks/useEnvironment'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import {removePolicyConnection} from '@libs/actions/connections'; -import getXeroSetupLink from '@libs/actions/connections/ConnectToXero'; +import {getXeroSetupLink} from '@libs/actions/connections/ConnectToXero'; import * as Link from '@userActions/Link'; import CONST from '@src/CONST'; import type {ConnectToXeroButtonProps} from './types'; diff --git a/src/languages/en.ts b/src/languages/en.ts index bebb12ddd49d..a822e1c5c3c8 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2022,10 +2022,19 @@ export default { organizationDescription: 'Select the organization in Xero you are importing data from.', importDescription: 'Choose which coding configurations are imported from Xero to Expensify.', trackingCategories: 'Tracking categories', + trackingCategoriesDescription: 'Choose whether to import tracking categories and see where they are displayed.', + mapXeroCostCentersTo: 'Map Xero cost centers to', + mapXeroRegionsTo: 'Map Xero regions to', + mapXeroCostCentersToDescription: 'Choose where to map cost centers to when exporting to Xero.', + mapXeroRegionsToDescription: 'Choose where to map employee regions when exporting expense reports to Xero.', customers: 'Re-bill customers', 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', + trackingCategoriesOptions: { + default: 'Xero contact default', + tag: 'Tags', + }, export: 'Export', exportDescription: 'Configure how data in Expensify gets exported to Xero.', exportCompanyCard: 'Export company card expenses as', diff --git a/src/languages/es.ts b/src/languages/es.ts index 6c9fe2746ca0..2027fa80f1f6 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2054,11 +2054,20 @@ export default { organizationDescription: 'Seleccione la organización en Xero desde la que está importando los datos.', importDescription: 'Elija qué configuraciones de codificación se importan de Xero a Expensify.', trackingCategories: 'Categorías de seguimiento', + trackingCategoriesDescription: 'Elige si deseas importar categorías de seguimiento y ver dónde se muestran.', + mapXeroCostCentersTo: 'Asignar centros de coste de Xero a', + mapXeroRegionsTo: 'Asignar regiones de Xero a', + mapXeroCostCentersToDescription: 'Elige dónde mapear los centros de coste al exportar a Xero.', + mapXeroRegionsToDescription: 'Elige dónde asignar las regiones de los empleados al exportar informes de gastos a Xero.', customers: 'Volver a facturar a los clientes', customersDescription: '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', + trackingCategoriesOptions: { + default: 'Contacto de Xero por defecto', + tag: 'Etiquetas', + }, export: 'Exportar', exportDescription: 'Configura cómo se exportan los datos de Expensify a Xero.', exportCompanyCard: 'Exportar gastos de la tarjeta de empresa como', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 0fb3fbf6245f..c7910a88a57f 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -305,6 +305,10 @@ 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_TRACKING_CATEGORIES]: () => + require('../../../../pages/workspace/accounting/xero/XeroTrackingCategoryConfigurationPage').default as React.ComponentType, + [SCREENS.WORKSPACE.ACCOUNTING.XERO_MAP_COST_CENTERS]: () => require('../../../../pages/workspace/accounting/xero/XeroMapCostCentersToConfigurationPage').default as React.ComponentType, + [SCREENS.WORKSPACE.ACCOUNTING.XERO_MAP_REGION]: () => require('../../../../pages/workspace/accounting/xero/XeroMapRegionsToConfigurationPage').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]: () => 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 4024e0ad2278..00ba520d4955 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,9 @@ 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_TRACKING_CATEGORIES, + SCREENS.WORKSPACE.ACCOUNTING.XERO_MAP_COST_CENTERS, + SCREENS.WORKSPACE.ACCOUNTING.XERO_MAP_REGION, 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 5ef86bb59b75..43597df5513c 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -329,6 +329,9 @@ const config: LinkingOptions['config'] = { }, [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.ACCOUNTING.XERO_TRACKING_CATEGORIES]: {path: ROUTES.POLICY_ACCOUNTING_XERO_TRACKING_CATEGORIES.route}, + [SCREENS.WORKSPACE.ACCOUNTING.XERO_MAP_COST_CENTERS]: {path: ROUTES.POLICY_ACCOUNTING_XERO_TRACKING_CATEGORIES_MAP_COST_CENTERS.route}, + [SCREENS.WORKSPACE.ACCOUNTING.XERO_MAP_REGION]: {path: ROUTES.POLICY_ACCOUNTING_XERO_TRACKING_CATEGORIES_MAP_REGION.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}, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 380ede9dfec5..13204fe97111 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -324,6 +324,15 @@ type SettingsNavigatorParamList = { [SCREENS.WORKSPACE.ACCOUNTING.XERO_TAXES]: { policyID: string; }; + [SCREENS.WORKSPACE.ACCOUNTING.XERO_TRACKING_CATEGORIES]: { + policyID: string; + }; + [SCREENS.WORKSPACE.ACCOUNTING.XERO_MAP_COST_CENTERS]: { + policyID: string; + }; + [SCREENS.WORKSPACE.ACCOUNTING.XERO_MAP_REGION]: { + policyID: string; + }; [SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT]: { policyID: string; }; diff --git a/src/libs/actions/connections/ConnectToXero.ts b/src/libs/actions/connections/ConnectToXero.ts index b5e8d7ab3298..43972e540d58 100644 --- a/src/libs/actions/connections/ConnectToXero.ts +++ b/src/libs/actions/connections/ConnectToXero.ts @@ -1,6 +1,10 @@ +import type {OnyxEntry} from 'react-native-onyx'; import type {ConnectPolicyToAccountingIntegrationParams} from '@libs/API/parameters'; import {READ_COMMANDS} from '@libs/API/types'; import {getCommandURL} from '@libs/ApiUtils'; +import CONST from '@src/CONST'; +import type * as OnyxTypes from '@src/types/onyx'; +import type {XeroTrackingCategory} from '@src/types/onyx/Policy'; const getXeroSetupLink = (policyID: string) => { const params: ConnectPolicyToAccountingIntegrationParams = {policyID}; @@ -8,4 +12,26 @@ const getXeroSetupLink = (policyID: string) => { return commandURL + new URLSearchParams(params).toString(); }; -export default getXeroSetupLink; +/** + * Fetches the category object from the xero.data.trackingCategories based on the category name. + * This is required to get Xero category object with current value stored in the xero.config.mappings + * @param policy + * @param key + * @returns Filtered category matching the category name or undefined. + */ +const getTrackingCategory = (policy: OnyxEntry, categoryName: string): (XeroTrackingCategory & {value: string}) | undefined => { + const {trackingCategories} = policy?.connections?.xero?.data ?? {}; + const {mappings} = policy?.connections?.xero?.config ?? {}; + + const category = trackingCategories?.find((currentCategory) => currentCategory.name.toLowerCase() === categoryName.toLowerCase()); + if (!category) { + return undefined; + } + + return { + ...category, + value: mappings?.[`${CONST.XERO_CONFIG.TRACKING_CATEGORY_PREFIX}${category.id}`] ?? '', + }; +}; + +export {getXeroSetupLink, getTrackingCategory}; diff --git a/src/pages/workspace/accounting/xero/XeroImportPage.tsx b/src/pages/workspace/accounting/xero/XeroImportPage.tsx index 13011b1952ac..fbd0d6add7e5 100644 --- a/src/pages/workspace/accounting/xero/XeroImportPage.tsx +++ b/src/pages/workspace/accounting/xero/XeroImportPage.tsx @@ -36,7 +36,7 @@ function XeroImportPage({policy}: WithPolicyProps) { }, { description: translate('workspace.xero.trackingCategories'), - action: () => {}, + action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_XERO_TRACKING_CATEGORIES.getRoute(policyID)), hasError: !!policy?.errors?.importTrackingCategories, title: importTrackingCategories ? translate('workspace.accounting.importTypes.TAG') : translate('workspace.xero.notImported'), pendingAction: pendingFields?.importTrackingCategories, diff --git a/src/pages/workspace/accounting/xero/XeroMapCostCentersToConfigurationPage.tsx b/src/pages/workspace/accounting/xero/XeroMapCostCentersToConfigurationPage.tsx new file mode 100644 index 000000000000..b4f0fe04f6ce --- /dev/null +++ b/src/pages/workspace/accounting/xero/XeroMapCostCentersToConfigurationPage.tsx @@ -0,0 +1,70 @@ +import React, {useCallback, useMemo} from 'react'; +import ConnectionLayout from '@components/ConnectionLayout'; +import SelectionList from '@components/SelectionList'; +import RadioListItem from '@components/SelectionList/RadioListItem'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as Connections from '@libs/actions/connections'; +import {getTrackingCategory} from '@libs/actions/connections/ConnectToXero'; +import Navigation from '@libs/Navigation/Navigation'; +import type {WithPolicyProps} from '@pages/workspace/withPolicy'; +import withPolicyConnections from '@pages/workspace/withPolicyConnections'; +import CONST from '@src/CONST'; +import type {TranslationPaths} from '@src/languages/types'; +import ROUTES from '@src/ROUTES'; + +function XeroMapCostCentersToConfigurationPage({policy}: WithPolicyProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + + const policyID = policy?.id ?? ''; + + const category = getTrackingCategory(policy, CONST.XERO_CONFIG.TRACKING_CATEGORY_FIELDS.COST_CENTERS); + + const optionsList = useMemo( + () => + Object.values(CONST.XERO_CONFIG.TRACKING_CATEGORY_OPTIONS).map((option) => ({ + value: option, + text: translate(`workspace.xero.trackingCategoriesOptions.${option.toLowerCase()}` as TranslationPaths), + keyForList: option, + isSelected: option.toLowerCase() === category?.value?.toLowerCase(), + })), + [translate, category], + ); + + const updateMapping = useCallback( + (option: {value: string}) => { + if (option.value !== category?.value) { + Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.XERO, CONST.XERO_CONFIG.MAPPINGS, { + ...(policy?.connections?.xero?.config?.mappings ?? {}), + ...(category?.id ? {[`${CONST.XERO_CONFIG.TRACKING_CATEGORY_PREFIX}${category.id}`]: option.value} : {}), + }); + } + Navigation.goBack(ROUTES.POLICY_ACCOUNTING_XERO_TRACKING_CATEGORIES.getRoute(policyID)); + }, + [category, policyID, policy?.connections?.xero?.config?.mappings], + ); + + return ( + + + + ); +} + +XeroMapCostCentersToConfigurationPage.displayName = 'XeroMapCostCentersToConfigurationPage'; +export default withPolicyConnections(XeroMapCostCentersToConfigurationPage); diff --git a/src/pages/workspace/accounting/xero/XeroMapRegionsToConfigurationPage.tsx b/src/pages/workspace/accounting/xero/XeroMapRegionsToConfigurationPage.tsx new file mode 100644 index 000000000000..bb5870da8fc3 --- /dev/null +++ b/src/pages/workspace/accounting/xero/XeroMapRegionsToConfigurationPage.tsx @@ -0,0 +1,69 @@ +import React, {useCallback, useMemo} from 'react'; +import ConnectionLayout from '@components/ConnectionLayout'; +import SelectionList from '@components/SelectionList'; +import RadioListItem from '@components/SelectionList/RadioListItem'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as Connections from '@libs/actions/connections'; +import {getTrackingCategory} from '@libs/actions/connections/ConnectToXero'; +import Navigation from '@libs/Navigation/Navigation'; +import type {WithPolicyProps} from '@pages/workspace/withPolicy'; +import withPolicyConnections from '@pages/workspace/withPolicyConnections'; +import CONST from '@src/CONST'; +import type {TranslationPaths} from '@src/languages/types'; +import ROUTES from '@src/ROUTES'; + +function XeroMapRegionsToConfigurationPage({policy}: WithPolicyProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + + const policyID = policy?.id ?? ''; + const category = getTrackingCategory(policy, CONST.XERO_CONFIG.TRACKING_CATEGORY_FIELDS.REGION); + + const optionsList = useMemo( + () => + Object.values(CONST.XERO_CONFIG.TRACKING_CATEGORY_OPTIONS).map((option) => ({ + value: option, + text: translate(`workspace.xero.trackingCategoriesOptions.${option.toLowerCase()}` as TranslationPaths), + keyForList: option, + isSelected: option.toLowerCase() === category?.value?.toLowerCase(), + })), + [translate, category], + ); + + const updateMapping = useCallback( + (option: {value: string}) => { + if (option.value !== category?.value) { + Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.XERO, CONST.XERO_CONFIG.MAPPINGS, { + ...(policy?.connections?.xero?.config?.mappings ?? {}), + ...(category?.id ? {[`${CONST.XERO_CONFIG.TRACKING_CATEGORY_PREFIX}${category.id}`]: option.value} : {}), + }); + } + Navigation.goBack(ROUTES.POLICY_ACCOUNTING_XERO_TRACKING_CATEGORIES.getRoute(policyID)); + }, + [category, policyID, policy?.connections?.xero?.config?.mappings], + ); + + return ( + + + + ); +} + +XeroMapRegionsToConfigurationPage.displayName = 'XeroMapRegionsToConfigurationPage'; +export default withPolicyConnections(XeroMapRegionsToConfigurationPage); diff --git a/src/pages/workspace/accounting/xero/XeroTrackingCategoryConfigurationPage.tsx b/src/pages/workspace/accounting/xero/XeroTrackingCategoryConfigurationPage.tsx new file mode 100644 index 000000000000..195b93d3d73c --- /dev/null +++ b/src/pages/workspace/accounting/xero/XeroTrackingCategoryConfigurationPage.tsx @@ -0,0 +1,104 @@ +import React, {useMemo} from 'react'; +import {View} from 'react-native'; +import ConnectionLayout from '@components/ConnectionLayout'; +import type {MenuItemProps} from '@components/MenuItem'; +import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; +import OfflineWithFeedback from '@components/OfflineWithFeedback'; +import Switch from '@components/Switch'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as Connections from '@libs/actions/connections'; +import {getTrackingCategory} from '@libs/actions/connections/ConnectToXero'; +import Navigation from '@libs/Navigation/Navigation'; +import type {WithPolicyProps} from '@pages/workspace/withPolicy'; +import withPolicyConnections from '@pages/workspace/withPolicyConnections'; +import variables from '@styles/variables'; +import CONST from '@src/CONST'; +import type {TranslationPaths} from '@src/languages/types'; +import ROUTES from '@src/ROUTES'; + +function XeroTrackingCategoryConfigurationPage({policy}: WithPolicyProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const policyID = policy?.id ?? ''; + const {importTrackingCategories, pendingFields} = policy?.connections?.xero?.config ?? {}; + + const menuItems: MenuItemProps[] = useMemo(() => { + const availableCategories = []; + + const costCenterCategoryValue = getTrackingCategory(policy, CONST.XERO_CONFIG.TRACKING_CATEGORY_FIELDS.COST_CENTERS)?.value ?? ''; + const regionCategoryValue = getTrackingCategory(policy, CONST.XERO_CONFIG.TRACKING_CATEGORY_FIELDS.REGION)?.value ?? ''; + if (costCenterCategoryValue) { + const isValidOption = Object.values(CONST.XERO_CONFIG.TRACKING_CATEGORY_OPTIONS).findIndex((option) => option.toLowerCase() === costCenterCategoryValue.toLowerCase()) > -1; + availableCategories.push({ + description: translate('workspace.xero.mapXeroCostCentersTo'), + onPress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_XERO_TRACKING_CATEGORIES_MAP_COST_CENTERS.getRoute(policyID)), + title: isValidOption ? translate(`workspace.xero.trackingCategoriesOptions.${costCenterCategoryValue.toLowerCase()}` as TranslationPaths) : '', + }); + } + + if (regionCategoryValue) { + const isValidOption = Object.values(CONST.XERO_CONFIG.TRACKING_CATEGORY_OPTIONS).findIndex((option) => option.toLowerCase() === regionCategoryValue.toLowerCase()) > -1; + availableCategories.push({ + description: translate('workspace.xero.mapXeroRegionsTo'), + onPress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_XERO_TRACKING_CATEGORIES_MAP_REGION.getRoute(policyID)), + title: isValidOption ? translate(`workspace.xero.trackingCategoriesOptions.${regionCategoryValue.toLowerCase()}` as TranslationPaths) : '', + }); + } + return availableCategories; + }, [translate, policy, policyID]); + + return ( + + + + + {translate('workspace.accounting.import')} + + + + + Connections.updatePolicyConnectionConfig( + policyID, + CONST.POLICY.CONNECTIONS.NAME.XERO, + CONST.XERO_CONFIG.IMPORT_TRACKING_CATEGORIES, + !importTrackingCategories, + ) + } + /> + + + + + {importTrackingCategories && ( + + {menuItems.map((menuItem: MenuItemProps) => ( + + ))} + + )} + + ); +} + +XeroTrackingCategoryConfigurationPage.displayName = 'XeroTrackCategoriesPage'; +export default withPolicyConnections(XeroTrackingCategoryConfigurationPage); diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 04a95267215c..bd15a871a139 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -208,6 +208,11 @@ type Tenant = { value: string; }; +type XeroTrackingCategory = { + id: string; + name: string; +}; + type XeroConnectionData = { bankAccounts: Account[]; countryCode: string; @@ -217,7 +222,13 @@ type XeroConnectionData = { name: string; }>; tenants: Tenant[]; - trackingCategories: unknown[]; + trackingCategories: XeroTrackingCategory[]; +}; + +type XeroMappingType = { + customer: string; +} & { + [key in `trackingCategory_${string}`]: string; }; /** @@ -245,9 +256,7 @@ type XeroConnectionConfig = OnyxCommon.OnyxValueWithOfflineFeedback<{ importTaxRates: boolean; importTrackingCategories: boolean; isConfigured: boolean; - mappings: { - customer: string; - }; + mappings: XeroMappingType; sync: { hasChosenAutoSyncOption: boolean; hasChosenSyncReimbursedReportsOption: boolean; @@ -564,4 +573,5 @@ export type { QBONonReimbursableExportAccountType, QBOReimbursableExportAccountType, QBOConnectionConfig, + XeroTrackingCategory, };