Skip to content

Commit c1acc8e

Browse files
authored
Merge pull request #42340 from Expensify/xero-merge-freeze
Merge Xero freeze branch #2
2 parents dc17b1b + ef55d3a commit c1acc8e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+670
-431
lines changed

src/CONST.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1305,12 +1305,13 @@ const CONST = {
13051305
SYNC: 'sync',
13061306
ENABLE_NEW_CATEGORIES: 'enableNewCategories',
13071307
EXPORT: 'export',
1308+
TENANT_ID: 'tenantID',
13081309
IMPORT_CUSTOMERS: 'importCustomers',
13091310
IMPORT_TAX_RATES: 'importTaxRates',
13101311
INVOICE_STATUS: {
1311-
AWAITING_PAYMENT: 'AWT_PAYMENT',
13121312
DRAFT: 'DRAFT',
13131313
AWAITING_APPROVAL: 'AWT_APPROVAL',
1314+
AWAITING_PAYMENT: 'AWT_PAYMENT',
13141315
},
13151316
IMPORT_TRACKING_CATEGORIES: 'importTrackingCategories',
13161317
MAPPINGS: 'mappings',
@@ -1778,7 +1779,8 @@ const CONST = {
17781779
XERO: 'xero',
17791780
},
17801781
SYNC_STAGE_NAME: {
1781-
STARTING_IMPORT: 'startingImport',
1782+
STARTING_IMPORT_QBO: 'startingImportQBO',
1783+
STARTING_IMPORT_XERO: 'startingImportXero',
17821784
QBO_IMPORT_MAIN: 'quickbooksOnlineImportMain',
17831785
QBO_IMPORT_CUSTOMERS: 'quickbooksOnlineImportCustomers',
17841786
QBO_IMPORT_EMPLOYEES: 'quickbooksOnlineImportEmployees',

src/ROUTES.ts

+16-15
Original file line numberDiff line numberDiff line change
@@ -689,12 +689,12 @@ const ROUTES = {
689689
getRoute: (policyID: string, orderWeight: number) => `settings/workspaces/${policyID}/tags/${orderWeight}/edit` as const,
690690
},
691691
WORKSPACE_TAG_EDIT: {
692-
route: 'settings/workspace/:policyID/tag/:tagName/edit',
693-
getRoute: (policyID: string, tagName: string) => `settings/workspace/${policyID}/tag/${encodeURIComponent(tagName)}/edit` as const,
692+
route: 'settings/workspaces/:policyID/tag/:orderWeight/:tagName/edit',
693+
getRoute: (policyID: string, orderWeight: number, tagName: string) => `settings/workspaces/${policyID}/tag/${orderWeight}/${encodeURIComponent(tagName)}/edit` as const,
694694
},
695695
WORKSPACE_TAG_SETTINGS: {
696-
route: 'settings/workspaces/:policyID/tag/:tagName',
697-
getRoute: (policyID: string, tagName: string) => `settings/workspaces/${policyID}/tag/${encodeURIComponent(tagName)}` as const,
696+
route: 'settings/workspaces/:policyID/tag/:orderWeight/:tagName',
697+
getRoute: (policyID: string, orderWeight: number, tagName: string) => `settings/workspaces/${policyID}/tag/${orderWeight}/${encodeURIComponent(tagName)}` as const,
698698
},
699699
WORKSPACE_TAG_LIST_VIEW: {
700700
route: 'settings/workspaces/:policyID/tag-list/:orderWeight',
@@ -812,17 +812,14 @@ const ROUTES = {
812812
route: 'settings/workspaces/:policyID/accounting/xero/import/tracking-categories',
813813
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/import/tracking-categories` as const,
814814
},
815-
POLICY_ACCOUNTING_XERO_TRACKING_CATEGORIES_MAP_COST_CENTERS: {
816-
route: 'settings/workspaces/:policyID/accounting/xero/import/tracking-categories/cost-centers',
817-
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/import/tracking-categories/cost-centers` as const,
818-
},
819-
POLICY_ACCOUNTING_XERO_TRACKING_CATEGORIES_MAP_REGION: {
820-
route: 'settings/workspaces/:policyID/accounting/xero/import/tracking-categories/region',
821-
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/import/tracking-categories/region` as const,
815+
POLICY_ACCOUNTING_XERO_TRACKING_CATEGORIES_MAP: {
816+
route: 'settings/workspaces/:policyID/accounting/xero/import/tracking-categories/mapping/:categoryId/:categoryName',
817+
getRoute: (policyID: string, categoryId: string, categoryName: string) =>
818+
`settings/workspaces/${policyID}/accounting/xero/import/tracking-categories/mapping/${categoryId}/${encodeURIComponent(categoryName)}` as const,
822819
},
823820
POLICY_ACCOUNTING_XERO_CUSTOMER: {
824-
route: '/settings/workspaces/:policyID/accounting/xero/import/customers',
825-
getRoute: (policyID: string) => `/settings/workspaces/${policyID}/accounting/xero/import/customers` as const,
821+
route: 'settings/workspaces/:policyID/accounting/xero/import/customers',
822+
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/import/customers` as const,
826823
},
827824
POLICY_ACCOUNTING_XERO_TAXES: {
828825
route: 'settings/workspaces/:policyID/accounting/xero/import/taxes',
@@ -833,8 +830,8 @@ const ROUTES = {
833830
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/export` as const,
834831
},
835832
POLICY_ACCOUNTING_XERO_PREFERRED_EXPORTER_SELECT: {
836-
route: '/settings/workspaces/:policyID/connections/xero/export/preferred-exporter/select',
837-
getRoute: (policyID: string) => `/settings/workspaces/${policyID}/connections/xero/export/preferred-exporter/select` as const,
833+
route: 'settings/workspaces/:policyID/connections/xero/export/preferred-exporter/select',
834+
getRoute: (policyID: string) => `settings/workspaces/${policyID}/connections/xero/export/preferred-exporter/select` as const,
838835
},
839836
POLICY_ACCOUNTING_XERO_EXPORT_PURCHASE_BILL_DATE_SELECT: {
840837
route: 'settings/workspaces/:policyID/accounting/xero/export/purchase-bill-date-select',
@@ -848,6 +845,10 @@ const ROUTES = {
848845
route: 'settings/workspaces/:policyID/accounting/xero/advanced',
849846
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/advanced` as const,
850847
},
848+
POLICY_ACCOUNTING_XERO_BILL_STATUS_SELECTOR: {
849+
route: 'settings/workspaces/:policyID/accounting/xero/export/purchase-bill-status-selector',
850+
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/export/purchase-bill-status-selector` as const,
851+
},
851852
POLICY_ACCOUNTING_XERO_INVOICE_SELECTOR: {
852853
route: 'settings/workspaces/:policyID/accounting/xero/advanced/invoice-account-selector',
853854
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/advanced/invoice-account-selector` as const,

src/SCREENS.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -248,11 +248,11 @@ const SCREENS = {
248248
XERO_CUSTOMER: 'Policy_Acounting_Xero_Import_Customer',
249249
XERO_TAXES: 'Policy_Accounting_Xero_Taxes',
250250
XERO_TRACKING_CATEGORIES: 'Policy_Accounting_Xero_Tracking_Categories',
251-
XERO_MAP_COST_CENTERS: 'Policy_Accounting_Xero_Map_Cost_Centers',
252-
XERO_MAP_REGION: 'Policy_Accounting_Xero_Map_Region',
251+
XERO_MAP_TRACKING_CATEGORY: 'Policy_Accounting_Xero_Map_Tracking_Category',
253252
XERO_EXPORT: 'Policy_Accounting_Xero_Export',
254253
XERO_EXPORT_PURCHASE_BILL_DATE_SELECT: 'Policy_Accounting_Xero_Export_Purchase_Bill_Date_Select',
255254
XERO_ADVANCED: 'Policy_Accounting_Xero_Advanced',
255+
XERO_BILL_STATUS_SELECTOR: 'Policy_Accounting_Xero_Export_Bill_Status_Selector',
256256
XERO_INVOICE_ACCOUNT_SELECTOR: 'Policy_Accounting_Xero_Invoice_Account_Selector',
257257
XERO_EXPORT_PREFERRED_EXPORTER_SELECT: 'Workspace_Accounting_Xero_Export_Preferred_Exporter_Select',
258258
XERO_BILL_PAYMENT_ACCOUNT_SELECTOR: 'Policy_Accounting_Xero_Bill_Payment_Account_Selector',

src/components/ConnectToQuickbooksOnlineButton/index.native.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import useLocalize from '@hooks/useLocalize';
1212
import useNetwork from '@hooks/useNetwork';
1313
import useThemeStyles from '@hooks/useThemeStyles';
1414
import {removePolicyConnection} from '@libs/actions/connections';
15-
import {getQuickBooksOnlineSetupLink} from '@libs/actions/connections/QuickBooksOnline';
15+
import getQuickBooksOnlineSetupLink from '@libs/actions/connections/QuickBooksOnline';
1616
import CONST from '@src/CONST';
1717
import ONYXKEYS from '@src/ONYXKEYS';
1818
import type {Session} from '@src/types/onyx';

src/components/ConnectToQuickbooksOnlineButton/index.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import useLocalize from '@hooks/useLocalize';
66
import useNetwork from '@hooks/useNetwork';
77
import useThemeStyles from '@hooks/useThemeStyles';
88
import {removePolicyConnection} from '@libs/actions/connections';
9-
import {getQuickBooksOnlineSetupLink} from '@libs/actions/connections/QuickBooksOnline';
9+
import getQuickBooksOnlineSetupLink from '@libs/actions/connections/QuickBooksOnline';
1010
import * as Link from '@userActions/Link';
11+
import * as PolicyAction from '@userActions/Policy/Policy';
1112
import CONST from '@src/CONST';
1213
import type {ConnectToQuickbooksOnlineButtonProps} from './types';
1314

@@ -27,6 +28,8 @@ function ConnectToQuickbooksOnlineButton({policyID, shouldDisconnectIntegrationB
2728
setIsDisconnectModalOpen(true);
2829
return;
2930
}
31+
// Since QBO doesn't support Taxes, we should disable them from the LHN when connecting to QBO
32+
PolicyAction.enablePolicyTaxes(policyID, false);
3033
Link.openLink(getQuickBooksOnlineSetupLink(policyID), environmentURL);
3134
}}
3235
isDisabled={isOffline}

src/components/ConnectionLayout.tsx

+33-10
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1+
import {isEmpty} from 'lodash';
12
import React, {useMemo} from 'react';
23
import type {StyleProp, TextStyle, ViewStyle} from 'react-native';
34
import {View} from 'react-native';
45
import useLocalize from '@hooks/useLocalize';
56
import useThemeStyles from '@hooks/useThemeStyles';
67
import Navigation from '@libs/Navigation/Navigation';
8+
import * as PolicyUtils from '@libs/PolicyUtils';
79
import type {AccessVariant} from '@pages/workspace/AccessOrNotFoundWrapper';
810
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
911
import type {TranslationPaths} from '@src/languages/types';
10-
import type {PolicyFeatureName} from '@src/types/onyx/Policy';
12+
import type {ConnectionName, PolicyFeatureName} from '@src/types/onyx/Policy';
1113
import HeaderWithBackButton from './HeaderWithBackButton';
1214
import ScreenWrapper from './ScreenWrapper';
1315
import ScrollView from './ScrollView';
@@ -17,16 +19,16 @@ type ConnectionLayoutProps = {
1719
/** Used to set the testID for tests */
1820
displayName: string;
1921

20-
/** Header title for the connection */
21-
headerTitle: TranslationPaths;
22+
/** Header title to be translated for the connection component */
23+
headerTitle?: TranslationPaths;
2224

2325
/** The subtitle to show in the header */
2426
headerSubtitle?: string;
2527

2628
/** React nodes that will be shown */
2729
children?: React.ReactNode;
2830

29-
/** Title of the connection component */
31+
/** Title to be translated for the connection component */
3032
title?: TranslationPaths;
3133

3234
/** The current policyID */
@@ -44,18 +46,30 @@ type ConnectionLayoutProps = {
4446
/** Style of the title text */
4547
titleStyle?: StyleProp<TextStyle> | undefined;
4648

49+
/** Whether to include safe area padding bottom or not */
50+
shouldIncludeSafeAreaPaddingBottom?: boolean;
51+
4752
/** Whether to use ScrollView or not */
4853
shouldUseScrollView?: boolean;
54+
55+
/** Used for dynamic header title translation with parameters */
56+
headerTitleAlreadyTranslated?: string;
57+
58+
/** Used for dynamic title translation with parameters */
59+
titleAlreadyTranslated?: string;
60+
61+
/** Name of the current connection */
62+
connectionName: ConnectionName;
4963
};
5064

51-
type ConnectionLayoutContentProps = Pick<ConnectionLayoutProps, 'title' | 'titleStyle' | 'children'>;
65+
type ConnectionLayoutContentProps = Pick<ConnectionLayoutProps, 'title' | 'titleStyle' | 'children' | 'titleAlreadyTranslated'>;
5266

53-
function ConnectionLayoutContent({title, titleStyle, children}: ConnectionLayoutContentProps) {
67+
function ConnectionLayoutContent({title, titleStyle, children, titleAlreadyTranslated}: ConnectionLayoutContentProps) {
5468
const {translate} = useLocalize();
5569
const styles = useThemeStyles();
5670
return (
5771
<>
58-
{title && <Text style={[styles.pb5, titleStyle]}>{translate(title)}</Text>}
72+
{title && <Text style={[styles.pb5, titleStyle]}>{titleAlreadyTranslated ?? translate(title)}</Text>}
5973
{children}
6074
</>
6175
);
@@ -72,35 +86,44 @@ function ConnectionLayout({
7286
featureName,
7387
contentContainerStyle,
7488
titleStyle,
89+
shouldIncludeSafeAreaPaddingBottom,
90+
connectionName,
7591
shouldUseScrollView = true,
92+
headerTitleAlreadyTranslated,
93+
titleAlreadyTranslated,
7694
}: ConnectionLayoutProps) {
7795
const {translate} = useLocalize();
7896

97+
const policy = PolicyUtils.getPolicy(policyID ?? '');
98+
const isConnectionEmpty = isEmpty(policy.connections?.[connectionName]);
99+
79100
const renderSelectionContent = useMemo(
80101
() => (
81102
<ConnectionLayoutContent
82103
title={title}
83104
titleStyle={titleStyle}
105+
titleAlreadyTranslated={titleAlreadyTranslated}
84106
>
85107
{children}
86108
</ConnectionLayoutContent>
87109
),
88-
[title, titleStyle, children],
110+
[title, titleStyle, children, titleAlreadyTranslated],
89111
);
90112

91113
return (
92114
<AccessOrNotFoundWrapper
93115
policyID={policyID}
94116
accessVariants={accessVariants}
95117
featureName={featureName}
118+
shouldBeBlocked={isConnectionEmpty}
96119
>
97120
<ScreenWrapper
98-
includeSafeAreaPaddingBottom={false}
121+
includeSafeAreaPaddingBottom={!!shouldIncludeSafeAreaPaddingBottom}
99122
shouldEnableMaxHeight
100123
testID={displayName}
101124
>
102125
<HeaderWithBackButton
103-
title={translate(headerTitle)}
126+
title={headerTitleAlreadyTranslated ?? (headerTitle ? translate(headerTitle as TranslationPaths) : '')}
104127
subtitle={headerSubtitle}
105128
onBackButtonPress={() => Navigation.goBack()}
106129
/>

src/components/MenuItem.tsx

+10-2
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,15 @@ type MenuItemBaseProps = {
153153
/** Error to display at the bottom of the component */
154154
errorText?: MaybePhraseKey;
155155

156+
/** Any additional styles to pass to error text. */
157+
errorTextStyle?: StyleProp<ViewStyle>;
158+
156159
/** Hint to display at the bottom of the component */
157160
hintText?: MaybePhraseKey;
158161

162+
/** Should the error text red dot indicator be shown */
163+
shouldShowRedDotIndicator?: boolean;
164+
159165
/** A boolean flag that gives the icon a green fill if true */
160166
success?: boolean;
161167

@@ -308,6 +314,8 @@ function MenuItem(
308314
helperText,
309315
helperTextStyle,
310316
errorText,
317+
errorTextStyle,
318+
shouldShowRedDotIndicator,
311319
hintText,
312320
success = false,
313321
focused = false,
@@ -684,9 +692,9 @@ function MenuItem(
684692
{!!errorText && (
685693
<FormHelpMessage
686694
isError
687-
shouldShowRedDotIndicator={false}
695+
shouldShowRedDotIndicator={!!shouldShowRedDotIndicator}
688696
message={errorText}
689-
style={styles.menuItemError}
697+
style={[styles.menuItemError, errorTextStyle]}
690698
/>
691699
)}
692700
{!!hintText && (

src/components/SelectionScreen.tsx

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import {isEmpty} from 'lodash';
12
import React from 'react';
23
import useLocalize from '@hooks/useLocalize';
4+
import * as PolicyUtils from '@libs/PolicyUtils';
35
import type {AccessVariant} from '@pages/workspace/AccessOrNotFoundWrapper';
46
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
57
import type {TranslationPaths} from '@src/languages/types';
6-
import type {PolicyFeatureName} from '@src/types/onyx/Policy';
8+
import type {ConnectionName, PolicyFeatureName} from '@src/types/onyx/Policy';
79
import HeaderWithBackButton from './HeaderWithBackButton';
810
import ScreenWrapper from './ScreenWrapper';
911
import SelectionList from './SelectionList';
@@ -52,6 +54,9 @@ type SelectionScreenProps = {
5254

5355
/** Whether or not to block user from accessing the page */
5456
shouldBeBlocked?: boolean;
57+
58+
/** Name of the current connection */
59+
connectionName: ConnectionName;
5560
};
5661

5762
function SelectionScreen({
@@ -67,14 +72,19 @@ function SelectionScreen({
6772
accessVariants,
6873
featureName,
6974
shouldBeBlocked,
75+
connectionName,
7076
}: SelectionScreenProps) {
7177
const {translate} = useLocalize();
78+
79+
const policy = PolicyUtils.getPolicy(policyID ?? '');
80+
const isConnectionEmpty = isEmpty(policy.connections?.[connectionName]);
81+
7282
return (
7383
<AccessOrNotFoundWrapper
7484
policyID={policyID}
7585
accessVariants={accessVariants}
7686
featureName={featureName}
77-
shouldBeBlocked={shouldBeBlocked}
87+
shouldBeBlocked={isConnectionEmpty || shouldBeBlocked}
7888
>
7989
<ScreenWrapper
8090
includeSafeAreaPaddingBottom={false}

src/components/Switch.tsx

+5-2
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,17 @@ type SwitchProps = {
2020

2121
/** Whether the switch is disabled */
2222
disabled?: boolean;
23+
24+
/** Whether to show the lock icon even if the switch is enabled */
25+
showLockIcon?: boolean;
2326
};
2427

2528
const OFFSET_X = {
2629
OFF: 0,
2730
ON: 20,
2831
};
2932

30-
function Switch({isOn, onToggle, accessibilityLabel, disabled}: SwitchProps) {
33+
function Switch({isOn, onToggle, accessibilityLabel, disabled, showLockIcon}: SwitchProps) {
3134
const styles = useThemeStyles();
3235
const offsetX = useRef(new Animated.Value(isOn ? OFFSET_X.ON : OFFSET_X.OFF));
3336
const theme = useTheme();
@@ -60,7 +63,7 @@ function Switch({isOn, onToggle, accessibilityLabel, disabled}: SwitchProps) {
6063
pressDimmingValue={0.8}
6164
>
6265
<Animated.View style={[styles.switchThumb, styles.switchThumbTransformation(offsetX.current)]}>
63-
{disabled && (
66+
{(Boolean(disabled) || Boolean(showLockIcon)) && (
6467
<Icon
6568
src={Expensicons.Lock}
6669
fill={isOn ? theme.text : theme.icon}

0 commit comments

Comments
 (0)