From 779fbb387a0944f77729477d14f261142d31a0c8 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 21 Aug 2024 10:56:28 +0800 Subject: [PATCH 1/9] update to fix autolink doesn't work if put before img markdown --- ios/Podfile.lock | 8 ++++---- package-lock.json | 16 ++++++++-------- package.json | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index e665278197b6..0b1847863a3f 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1871,7 +1871,7 @@ PODS: - RNGoogleSignin (10.0.1): - GoogleSignIn (~> 7.0) - React-Core - - RNLiveMarkdown (0.1.113): + - RNLiveMarkdown (0.1.116): - glog - hermes-engine - RCT-Folly (= 2022.05.16.00) @@ -1889,9 +1889,9 @@ PODS: - React-utils - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNLiveMarkdown/common (= 0.1.113) + - RNLiveMarkdown/common (= 0.1.116) - Yoga - - RNLiveMarkdown/common (0.1.113): + - RNLiveMarkdown/common (0.1.116): - glog - hermes-engine - RCT-Folly (= 2022.05.16.00) @@ -2614,7 +2614,7 @@ SPEC CHECKSUMS: RNFS: 4ac0f0ea233904cb798630b3c077808c06931688 RNGestureHandler: 74b7b3d06d667ba0bbf41da7718f2607ae0dfe8f RNGoogleSignin: ccaa4a81582cf713eea562c5dd9dc1961a715fd0 - RNLiveMarkdown: 235376cd828014e8bad6949ea5bb202688fa5bb0 + RNLiveMarkdown: 19b5b73960ca70a47582c9376bb20e6dc52f021e RNLocalize: d4b8af4e442d4bcca54e68fc687a2129b4d71a81 rnmapbox-maps: df8fe93dbd251f25022f4023d31bc04160d4d65c RNPermissions: d2392b754e67bc14491f5b12588bef2864e783f3 diff --git a/package-lock.json b/package-lock.json index 4c0b1948c009..47ed9331a4bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@babel/plugin-proposal-private-methods": "^7.18.6", "@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@dotlottie/react-player": "^1.6.3", - "@expensify/react-native-live-markdown": "^0.1.113", + "@expensify/react-native-live-markdown": "^0.1.115", "@expo/metro-runtime": "~3.1.1", "@formatjs/intl-datetimeformat": "^6.10.0", "@formatjs/intl-listformat": "^7.2.2", @@ -55,7 +55,7 @@ "date-fns-tz": "^2.0.0", "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", - "expensify-common": "2.0.72", + "expensify-common": "2.0.76", "expo": "^50.0.3", "expo-av": "~13.10.4", "expo-image": "1.11.0", @@ -3952,9 +3952,9 @@ } }, "node_modules/@expensify/react-native-live-markdown": { - "version": "0.1.113", - "resolved": "https://registry.npmjs.org/@expensify/react-native-live-markdown/-/react-native-live-markdown-0.1.113.tgz", - "integrity": "sha512-MeZTqW1Dd2oUAVmedaU6p/TE+mmhWibSkcz8VC10PyCn6HkwO7ZykaSXMjsJHoUyvx9vYaG/4iF9enWXe4+h5w==", + "version": "0.1.116", + "resolved": "https://registry.npmjs.org/@expensify/react-native-live-markdown/-/react-native-live-markdown-0.1.116.tgz", + "integrity": "sha512-+l3SarKLyHUaeRWl+FU/Hrjk0iz5Caeps+aBfQgR5T1XQITDYtpSAruy4ZCw0R0wC6l7c44z8tDU7g5Biniq+A==", "workspaces": [ "parser", "example", @@ -26135,9 +26135,9 @@ } }, "node_modules/expensify-common": { - "version": "2.0.72", - "resolved": "https://registry.npmjs.org/expensify-common/-/expensify-common-2.0.72.tgz", - "integrity": "sha512-/mrlSic8y3D7pbbGMe3ZtDhHOS+WmrqgBEy3P/o9qW6CFpczs9cqjp9DfF8L53qvGtiD7cm5au4tapj01Yas/g==", + "version": "2.0.76", + "resolved": "https://registry.npmjs.org/expensify-common/-/expensify-common-2.0.76.tgz", + "integrity": "sha512-nCM6laaj25kurdiD9rhAXmQKhi8eciIFlshN8P4A7gsjFIScXnRG8fwXM5tX+8ET0vqAOA2SACeNVTT3vGUUsQ==", "dependencies": { "awesome-phonenumber": "^5.4.0", "classnames": "2.5.0", diff --git a/package.json b/package.json index 679ca1793b2d..179e3162c214 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "@babel/plugin-proposal-private-methods": "^7.18.6", "@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@dotlottie/react-player": "^1.6.3", - "@expensify/react-native-live-markdown": "^0.1.113", + "@expensify/react-native-live-markdown": "^0.1.115", "@expo/metro-runtime": "~3.1.1", "@formatjs/intl-datetimeformat": "^6.10.0", "@formatjs/intl-listformat": "^7.2.2", @@ -111,7 +111,7 @@ "date-fns-tz": "^2.0.0", "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", - "expensify-common": "2.0.72", + "expensify-common": "2.0.76", "expo": "^50.0.3", "expo-av": "~13.10.4", "expo-image": "1.11.0", From 7c045ab7b966a05d6a8063f9f5c5bd3fffd62941 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 21 Aug 2024 10:56:38 +0800 Subject: [PATCH 2/9] pass alt to the image --- .../HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx | 2 ++ src/components/ImageWithSizeCalculation.tsx | 6 +++++- src/components/ThumbnailImage.tsx | 5 +++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx index 1e73cce1630f..5eb7290fa3aa 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx @@ -57,6 +57,7 @@ function ImageRenderer({tnode}: ImageRendererProps) { const previewSource = tryResolveUrlFromApiRoot(htmlAttribs.src); const source = tryResolveUrlFromApiRoot(isAttachmentOrReceipt ? attachmentSourceAttribute : htmlAttribs.src); + const alt = htmlAttribs.alt const imageWidth = (htmlAttribs['data-expensify-width'] && parseInt(htmlAttribs['data-expensify-width'], 10)) || undefined; const imageHeight = (htmlAttribs['data-expensify-height'] && parseInt(htmlAttribs['data-expensify-height'], 10)) || undefined; const imagePreviewModalDisabled = htmlAttribs['data-expensify-preview-modal-disabled'] === 'true'; @@ -71,6 +72,7 @@ function ImageRenderer({tnode}: ImageRendererProps) { fallbackIcon={fallbackIcon} imageWidth={imageWidth} imageHeight={imageHeight} + altText={alt} /> ); diff --git a/src/components/ImageWithSizeCalculation.tsx b/src/components/ImageWithSizeCalculation.tsx index 3d940103715d..c25ce07f44be 100644 --- a/src/components/ImageWithSizeCalculation.tsx +++ b/src/components/ImageWithSizeCalculation.tsx @@ -25,6 +25,9 @@ type ImageWithSizeCalculationProps = { /** Url for image to display */ url: string | ImageSourcePropType; + /** alt text for the image */ + altText: string; + /** Any additional styles to apply */ style?: StyleProp; @@ -46,7 +49,7 @@ type ImageWithSizeCalculationProps = { * performing some calculation on a network image after fetching dimensions so * it can be appropriately resized. */ -function ImageWithSizeCalculation({url, style, onMeasure, onLoadFailure, isAuthTokenRequired, objectPosition = CONST.IMAGE_OBJECT_POSITION.INITIAL}: ImageWithSizeCalculationProps) { +function ImageWithSizeCalculation({url, altText, style, onMeasure, onLoadFailure, isAuthTokenRequired, objectPosition = CONST.IMAGE_OBJECT_POSITION.INITIAL}: ImageWithSizeCalculationProps) { const styles = useThemeStyles(); const isLoadedRef = useRef(null); const [isImageCached, setIsImageCached] = useState(true); @@ -97,6 +100,7 @@ function ImageWithSizeCalculation({url, style, onMeasure, onLoadFailure, isAuthT { diff --git a/src/components/ThumbnailImage.tsx b/src/components/ThumbnailImage.tsx index 04d0200ea228..d457d0ae5dd7 100644 --- a/src/components/ThumbnailImage.tsx +++ b/src/components/ThumbnailImage.tsx @@ -23,6 +23,9 @@ type ThumbnailImageProps = { /** Source URL for the preview image */ previewSourceURL: string | ImageSourcePropType; + /** alt text for the image */ + altText: string; + /** Any additional styles to apply */ style?: StyleProp; @@ -61,6 +64,7 @@ type UpdateImageSizeParams = { function ThumbnailImage({ previewSourceURL, + altText, style, isAuthTokenRequired, imageWidth = 200, @@ -132,6 +136,7 @@ function ThumbnailImage({ setFailedToLoad(true)} isAuthTokenRequired={isAuthTokenRequired} From f830c70838c4164de83335479f2c5d764935e4cb Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 21 Aug 2024 11:06:12 +0800 Subject: [PATCH 3/9] prettier --- .../HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx index 5eb7290fa3aa..12e2f11d943a 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx @@ -57,7 +57,7 @@ function ImageRenderer({tnode}: ImageRendererProps) { const previewSource = tryResolveUrlFromApiRoot(htmlAttribs.src); const source = tryResolveUrlFromApiRoot(isAttachmentOrReceipt ? attachmentSourceAttribute : htmlAttribs.src); - const alt = htmlAttribs.alt + const alt = htmlAttribs.alt; const imageWidth = (htmlAttribs['data-expensify-width'] && parseInt(htmlAttribs['data-expensify-width'], 10)) || undefined; const imageHeight = (htmlAttribs['data-expensify-height'] && parseInt(htmlAttribs['data-expensify-height'], 10)) || undefined; const imagePreviewModalDisabled = htmlAttribs['data-expensify-preview-modal-disabled'] === 'true'; From cdf7fc70daa9983ca23c4aaf0db97c102b3dbc62 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 21 Aug 2024 11:12:56 +0800 Subject: [PATCH 4/9] typing --- src/components/ImageWithSizeCalculation.tsx | 2 +- src/components/ThumbnailImage.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ImageWithSizeCalculation.tsx b/src/components/ImageWithSizeCalculation.tsx index c25ce07f44be..ebea1a90efca 100644 --- a/src/components/ImageWithSizeCalculation.tsx +++ b/src/components/ImageWithSizeCalculation.tsx @@ -26,7 +26,7 @@ type ImageWithSizeCalculationProps = { url: string | ImageSourcePropType; /** alt text for the image */ - altText: string; + altText?: string; /** Any additional styles to apply */ style?: StyleProp; diff --git a/src/components/ThumbnailImage.tsx b/src/components/ThumbnailImage.tsx index d457d0ae5dd7..cea528e4537c 100644 --- a/src/components/ThumbnailImage.tsx +++ b/src/components/ThumbnailImage.tsx @@ -24,7 +24,7 @@ type ThumbnailImageProps = { previewSourceURL: string | ImageSourcePropType; /** alt text for the image */ - altText: string; + altText?: string; /** Any additional styles to apply */ style?: StyleProp; From b3f00c76477648cd76c98dbf673f5d28129ab90d Mon Sep 17 00:00:00 2001 From: cretadn22 Date: Thu, 22 Aug 2024 01:05:47 +0700 Subject: [PATCH 5/9] adjust all selected --- .../workspace/reportFields/ReportFieldsListValuesPage.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx b/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx index 61967a729cd3..95c06b2331e9 100644 --- a/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx @@ -116,9 +116,9 @@ function ReportFieldsListValuesPage({ }; const toggleAllValues = () => { - const isAllSelected = listValues.length === Object.keys(selectedValues).length; + const areAllSelected = listValues.length === selectedValuesArray.length; - setSelectedValues(isAllSelected ? {} : Object.fromEntries(listValues.map((value) => [value, true]))); + setSelectedValues(areAllSelected ? {} : Object.fromEntries(listValues.map((value) => [value, true]))); }; const handleDeleteValues = () => { @@ -176,7 +176,7 @@ function ReportFieldsListValuesPage({ const getHeaderButtons = () => { const options: Array>> = []; - if ((isSmallScreenWidth ? selectionMode?.isEnabled : true) && selectedValuesArray.length > 0) { + if (isSmallScreenWidth ? selectionMode?.isEnabled : selectedValuesArray.length > 0) { if (selectedValuesArray.length > 0) { options.push({ icon: Expensicons.Trashcan, From c5815e63d0484eabcbb3f40a057718a2aa68869e Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 23 Aug 2024 15:57:17 +0700 Subject: [PATCH 6/9] inital tenant API --- .../ConnectToXeroFlow/index.native.tsx | 2 +- src/components/ConnectToXeroFlow/index.tsx | 2 +- .../parameters/UpdateXeroGenericTypeParams.ts | 7 + src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 10 ++ src/libs/actions/connections/ConnectToXero.ts | 29 ---- src/libs/actions/connections/Xero.ts | 145 ++++++++++++++++++ src/pages/workspace/accounting/utils.tsx | 2 +- .../accounting/xero/XeroImportPage.tsx | 2 +- .../XeroOrganizationConfigurationPage.tsx | 4 +- .../XeroTrackingCategoryConfigurationPage.tsx | 2 +- 11 files changed, 170 insertions(+), 36 deletions(-) create mode 100644 src/libs/API/parameters/UpdateXeroGenericTypeParams.ts delete mode 100644 src/libs/actions/connections/ConnectToXero.ts create mode 100644 src/libs/actions/connections/Xero.ts diff --git a/src/components/ConnectToXeroFlow/index.native.tsx b/src/components/ConnectToXeroFlow/index.native.tsx index e603fece6bd0..735c4bf131a3 100644 --- a/src/components/ConnectToXeroFlow/index.native.tsx +++ b/src/components/ConnectToXeroFlow/index.native.tsx @@ -8,7 +8,7 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Modal from '@components/Modal'; import RequireTwoFactorAuthenticationModal from '@components/RequireTwoFactorAuthenticationModal'; import useLocalize from '@hooks/useLocalize'; -import {getXeroSetupLink} from '@libs/actions/connections/ConnectToXero'; +import {getXeroSetupLink} from '@libs/actions/connections/Xero'; import getUAForWebView from '@libs/getUAForWebView'; import Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; diff --git a/src/components/ConnectToXeroFlow/index.tsx b/src/components/ConnectToXeroFlow/index.tsx index ade4c1191bb0..0a3403be78ec 100644 --- a/src/components/ConnectToXeroFlow/index.tsx +++ b/src/components/ConnectToXeroFlow/index.tsx @@ -3,7 +3,7 @@ import {useOnyx} from 'react-native-onyx'; import RequireTwoFactorAuthenticationModal from '@components/RequireTwoFactorAuthenticationModal'; import useEnvironment from '@hooks/useEnvironment'; import useLocalize from '@hooks/useLocalize'; -import {getXeroSetupLink} from '@libs/actions/connections/ConnectToXero'; +import {getXeroSetupLink} from '@libs/actions/connections/Xero'; import Navigation from '@libs/Navigation/Navigation'; import * as Link from '@userActions/Link'; import ONYXKEYS from '@src/ONYXKEYS'; diff --git a/src/libs/API/parameters/UpdateXeroGenericTypeParams.ts b/src/libs/API/parameters/UpdateXeroGenericTypeParams.ts new file mode 100644 index 000000000000..02667483bdd3 --- /dev/null +++ b/src/libs/API/parameters/UpdateXeroGenericTypeParams.ts @@ -0,0 +1,7 @@ +type UpdateXeroGenericTypeParams = { + policyID: string; + settingValue: string; + idempotencyKey: string; +}; + +export default UpdateXeroGenericTypeParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index a72220c3d943..351b6da47505 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -279,3 +279,4 @@ export type {default as UpdateExpensifyCardTitleParams} from './UpdateExpensifyC export type {default as OpenCardDetailsPageParams} from './OpenCardDetailsPageParams'; export type {default as ToggleCardContinuousReconciliationParams} from './ToggleCardContinuousReconciliationParams'; export type {default as UpdateExpensifyCardLimitTypeParams} from './UpdateExpensifyCardLimitTypeParams'; +export type {default as UpdateXeroGenericTypeParams} from './UpdateXeroGenericTypeParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index de63ed032afe..cdd56bdc6f2e 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -335,6 +335,10 @@ const WRITE_COMMANDS = { CREATE_EXPENSIFY_CARD: 'CreateExpensifyCard', CREATE_ADMIN_ISSUED_VIRTUAL_CARD: 'CreateAdminIssuedVirtualCard', TOGGLE_CARD_CONTINUOUS_RECONCILIATION: 'ToggleCardContinuousReconciliation', + UPDATE_XERO_IMPORT_TRACKING_CATEGORIES: 'UpdateXeroImportTrackingCategories', + UPDATE_XERO_IMPORT_TAX_RATES: 'UpdateXeroImportTaxRates', + UPDATE_XERO_TENANT_ID: 'UpdateXeroTenantID', + UPDATE_XERO_MAPPING: 'UpdateXeroMappings', } as const; type WriteCommand = ValueOf; @@ -675,6 +679,12 @@ type WriteCommandParameters = { [WRITE_COMMANDS.CREATE_EXPENSIFY_CARD]: Parameters.CreateExpensifyCardParams; [WRITE_COMMANDS.CREATE_ADMIN_ISSUED_VIRTUAL_CARD]: Omit; [WRITE_COMMANDS.TOGGLE_CARD_CONTINUOUS_RECONCILIATION]: Parameters.ToggleCardContinuousReconciliationParams; + + // Xero API + [WRITE_COMMANDS.UPDATE_XERO_TENANT_ID]: Parameters.UpdateXeroGenericTypeParams; + [WRITE_COMMANDS.UPDATE_XERO_IMPORT_TAX_RATES]: Parameters.UpdateXeroGenericTypeParams; + [WRITE_COMMANDS.UPDATE_XERO_MAPPING]: Parameters.UpdateXeroGenericTypeParams; + [WRITE_COMMANDS.UPDATE_XERO_IMPORT_TRACKING_CATEGORIES]: Parameters.UpdateXeroGenericTypeParams; }; const READ_COMMANDS = { diff --git a/src/libs/actions/connections/ConnectToXero.ts b/src/libs/actions/connections/ConnectToXero.ts deleted file mode 100644 index e327b218989c..000000000000 --- a/src/libs/actions/connections/ConnectToXero.ts +++ /dev/null @@ -1,29 +0,0 @@ -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}; - const commandURL = getCommandURL({command: READ_COMMANDS.CONNECT_POLICY_TO_XERO, shouldSkipWebProxy: true}); - return commandURL + new URLSearchParams(params).toString(); -}; - -const getTrackingCategories = (policy: OnyxEntry): Array => { - const {trackingCategories} = policy?.connections?.xero?.data ?? {}; - const {mappings} = policy?.connections?.xero?.config ?? {}; - - if (!trackingCategories) { - return []; - } - - return trackingCategories.map((category) => ({ - ...category, - value: mappings?.[`${CONST.XERO_CONFIG.TRACKING_CATEGORY_PREFIX}${category.id}`] ?? '', - })); -}; - -export {getXeroSetupLink, getTrackingCategories}; diff --git a/src/libs/actions/connections/Xero.ts b/src/libs/actions/connections/Xero.ts new file mode 100644 index 000000000000..4339c0663fd0 --- /dev/null +++ b/src/libs/actions/connections/Xero.ts @@ -0,0 +1,145 @@ +import isObject from 'lodash/isObject'; +import type {OnyxEntry, OnyxUpdate} from 'react-native-onyx'; +import Onyx from 'react-native-onyx'; +import * as API from '@libs/API'; +import type {ConnectPolicyToAccountingIntegrationParams, UpdateXeroGenericTypeParams} from '@libs/API/parameters'; +import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; +import {getCommandURL} from '@libs/ApiUtils'; +import * as ErrorUtils from '@libs/ErrorUtils'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type * as OnyxTypes from '@src/types/onyx'; +import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; +import type {Connections, XeroTrackingCategory} from '@src/types/onyx/Policy'; + +const getXeroSetupLink = (policyID: string) => { + const params: ConnectPolicyToAccountingIntegrationParams = {policyID}; + const commandURL = getCommandURL({command: READ_COMMANDS.CONNECT_POLICY_TO_XERO, shouldSkipWebProxy: true}); + return commandURL + new URLSearchParams(params).toString(); +}; + +const getTrackingCategories = (policy: OnyxEntry): Array => { + const {trackingCategories} = policy?.connections?.xero?.data ?? {}; + const {mappings} = policy?.connections?.xero?.config ?? {}; + + if (!trackingCategories) { + return []; + } + + return trackingCategories.map((category) => ({ + ...category, + value: mappings?.[`${CONST.XERO_CONFIG.TRACKING_CATEGORY_PREFIX}${category.id}`] ?? '', + })); +}; + +function createXeroPendingFields( + settingName: TSettingName, + settingValue: Partial, + pendingValue: OnyxCommon.PendingAction, +) { + if (!isObject(settingValue)) { + return {[settingName]: pendingValue}; + } + + return Object.keys(settingValue).reduce>((acc, setting) => { + acc[setting] = pendingValue; + return acc; + }, {}); +} + +function createXeroErrorFields( + settingName: TSettingName, + settingValue: Partial, + errorValue: OnyxCommon.Errors | null, +) { + if (!isObject(settingValue)) { + return {[settingName]: errorValue}; + } + + return Object.keys(settingValue).reduce((acc, setting) => { + acc[setting] = errorValue; + return acc; + }, {}); +} + +function prepareXeroOptimisticData( + policyID: string, + settingName: TSettingName, + settingValue: Partial, + oldSettingValue?: Partial | null, +) { + const optimisticData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: { + connections: { + xero: { + config: { + [settingName]: settingValue ?? null, + pendingFields: createXeroPendingFields(settingName, settingValue, CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE), + errorFields: createXeroErrorFields(settingName, settingValue, null), + }, + }, + }, + }, + }, + ]; + + const failureData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: { + connections: { + xero: { + config: { + [settingName]: oldSettingValue ?? null, + pendingFields: createXeroPendingFields(settingName, settingValue, null), + errorFields: createXeroErrorFields(settingName, settingValue, ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage')), + }, + }, + }, + }, + }, + ]; + + const successData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: { + connections: { + xero: { + config: { + pendingFields: createXeroPendingFields(settingName, settingValue, null), + errorFields: createXeroErrorFields(settingName, settingValue, null), + }, + }, + }, + }, + }, + ]; + + return {optimisticData, failureData, successData}; +} + +function updateXeroImportTrackingCategories() {} + +function updateXeroImportTaxRates() {} + +function updateXeroTenantID(policyID: string, settingValue: string, oldSettingValue?: string) { + const parameters: UpdateXeroGenericTypeParams = { + policyID, + settingValue: JSON.stringify(settingValue), + idempotencyKey: String(CONST.XERO_CONFIG.TENANT_ID), + }; + + const {optimisticData, successData, failureData} = prepareXeroOptimisticData(policyID, CONST.XERO_CONFIG.TENANT_ID, settingValue, oldSettingValue); + + API.write(WRITE_COMMANDS.UPDATE_XERO_TENANT_ID, parameters, {optimisticData, successData, failureData}); +} + +function updateXeroMappings() {} + +export {getXeroSetupLink, getTrackingCategories, updateXeroImportTrackingCategories, updateXeroImportTaxRates, updateXeroTenantID, updateXeroMappings}; diff --git a/src/pages/workspace/accounting/utils.tsx b/src/pages/workspace/accounting/utils.tsx index 22bc97236b70..05ee41b85b9b 100644 --- a/src/pages/workspace/accounting/utils.tsx +++ b/src/pages/workspace/accounting/utils.tsx @@ -6,7 +6,7 @@ import ConnectToXeroFlow from '@components/ConnectToXeroFlow'; import * as Expensicons from '@components/Icon/Expensicons'; import type {LocaleContextProps} from '@components/LocaleContextProvider'; import Navigation from '@navigation/Navigation'; -import {getTrackingCategories} from '@userActions/connections/ConnectToXero'; +import {getTrackingCategories} from '@userActions/connections/Xero'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type {Policy} from '@src/types/onyx'; diff --git a/src/pages/workspace/accounting/xero/XeroImportPage.tsx b/src/pages/workspace/accounting/xero/XeroImportPage.tsx index db0252098b89..87f4b3a8ac9a 100644 --- a/src/pages/workspace/accounting/xero/XeroImportPage.tsx +++ b/src/pages/workspace/accounting/xero/XeroImportPage.tsx @@ -10,7 +10,7 @@ import {getCurrentXeroOrganizationName} from '@libs/PolicyUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; -import {getTrackingCategories} from '@userActions/connections/ConnectToXero'; +import {getTrackingCategories} from '@userActions/connections/Xero'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; diff --git a/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx b/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx index b23363c79963..5137c98811b8 100644 --- a/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx +++ b/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx @@ -9,7 +9,7 @@ import SelectionScreen from '@components/SelectionScreen'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import {updatePolicyXeroConnectionConfig} from '@libs/actions/connections'; +import {updateXeroTenantID} from '@libs/actions/connections/Xero'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; @@ -59,7 +59,7 @@ function XeroOrganizationConfigurationPage({ return; } - updatePolicyXeroConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.XERO, CONST.XERO_CONFIG.TENANT_ID, keyForList, xeroConfig?.tenantID); + updateXeroTenantID(policyID, keyForList, xeroConfig?.tenantID); Navigation.goBack(); }; diff --git a/src/pages/workspace/accounting/xero/XeroTrackingCategoryConfigurationPage.tsx b/src/pages/workspace/accounting/xero/XeroTrackingCategoryConfigurationPage.tsx index 9d27c8887e6e..3a1b154e08d9 100644 --- a/src/pages/workspace/accounting/xero/XeroTrackingCategoryConfigurationPage.tsx +++ b/src/pages/workspace/accounting/xero/XeroTrackingCategoryConfigurationPage.tsx @@ -6,7 +6,7 @@ import OfflineWithFeedback from '@components/OfflineWithFeedback'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as Connections from '@libs/actions/connections'; -import {getTrackingCategories} from '@libs/actions/connections/ConnectToXero'; +import {getTrackingCategories} from '@libs/actions/connections/Xero'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import {areSettingsInErrorFields, settingsPendingAction} from '@libs/PolicyUtils'; From 1baf50fe5c4740c6810b8bcefec3f56f00643911 Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 23 Aug 2024 17:07:56 +0700 Subject: [PATCH 7/9] update rest of the api --- src/libs/actions/connections/Xero.ts | 49 +++++++++++++++++-- ...roMapTrackingCategoryConfigurationPage.tsx | 6 +-- .../xero/XeroTaxesConfigurationPage.tsx | 12 +---- .../XeroTrackingCategoryConfigurationPage.tsx | 12 +---- 4 files changed, 52 insertions(+), 27 deletions(-) diff --git a/src/libs/actions/connections/Xero.ts b/src/libs/actions/connections/Xero.ts index 4339c0663fd0..fa08dec2e391 100644 --- a/src/libs/actions/connections/Xero.ts +++ b/src/libs/actions/connections/Xero.ts @@ -124,9 +124,42 @@ function prepareXeroOptimisticData, + oldImportTrackingCategories?: Partial, +) { + const parameters: UpdateXeroGenericTypeParams = { + policyID, + settingValue: JSON.stringify(importTrackingCategories), + idempotencyKey: String(CONST.XERO_CONFIG.IMPORT_TRACKING_CATEGORIES), + }; + + const {optimisticData, failureData, successData} = prepareXeroOptimisticData( + policyID, + CONST.XERO_CONFIG.IMPORT_TRACKING_CATEGORIES, + importTrackingCategories, + oldImportTrackingCategories, + ); -function updateXeroImportTaxRates() {} + API.write(WRITE_COMMANDS.UPDATE_XERO_IMPORT_TRACKING_CATEGORIES, parameters, {optimisticData, failureData, successData}); +} + +function updateXeroImportTaxRates( + policyID: string, + importTaxesRate: Partial, + oldImportTaxesRate?: Partial, +) { + const parameters: UpdateXeroGenericTypeParams = { + policyID, + settingValue: JSON.stringify(importTaxesRate), + idempotencyKey: String(CONST.XERO_CONFIG.IMPORT_TAX_RATES), + }; + + const {optimisticData, failureData, successData} = prepareXeroOptimisticData(policyID, CONST.XERO_CONFIG.IMPORT_TAX_RATES, importTaxesRate, oldImportTaxesRate); + + API.write(WRITE_COMMANDS.UPDATE_XERO_IMPORT_TAX_RATES, parameters, {optimisticData, failureData, successData}); +} function updateXeroTenantID(policyID: string, settingValue: string, oldSettingValue?: string) { const parameters: UpdateXeroGenericTypeParams = { @@ -140,6 +173,16 @@ function updateXeroTenantID(policyID: string, settingValue: string, oldSettingVa API.write(WRITE_COMMANDS.UPDATE_XERO_TENANT_ID, parameters, {optimisticData, successData, failureData}); } -function updateXeroMappings() {} +function updateXeroMappings(policyID: string, mappingValue: Partial, oldMappingValue?: Partial) { + const parameters: UpdateXeroGenericTypeParams = { + policyID, + settingValue: JSON.stringify(mappingValue), + idempotencyKey: String(CONST.XERO_CONFIG.MAPPINGS), + }; + + const {optimisticData, failureData, successData} = prepareXeroOptimisticData(policyID, CONST.XERO_CONFIG.MAPPINGS, mappingValue, oldMappingValue); + + API.write(WRITE_COMMANDS.UPDATE_XERO_MAPPING, parameters, {optimisticData, failureData, successData}); +} export {getXeroSetupLink, getTrackingCategories, updateXeroImportTrackingCategories, updateXeroImportTaxRates, updateXeroTenantID, updateXeroMappings}; diff --git a/src/pages/workspace/accounting/xero/XeroMapTrackingCategoryConfigurationPage.tsx b/src/pages/workspace/accounting/xero/XeroMapTrackingCategoryConfigurationPage.tsx index 42e3f50bae0a..dae46f32dc54 100644 --- a/src/pages/workspace/accounting/xero/XeroMapTrackingCategoryConfigurationPage.tsx +++ b/src/pages/workspace/accounting/xero/XeroMapTrackingCategoryConfigurationPage.tsx @@ -6,7 +6,7 @@ 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 * as Xero from '@libs/actions/connections/Xero'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import {settingsPendingAction} from '@libs/PolicyUtils'; @@ -60,10 +60,8 @@ function XeroMapTrackingCategoryConfigurationPage({policy}: WithPolicyProps) { const updateMapping = useCallback( (option: {value: string}) => { if (option.value !== categoryName) { - Connections.updatePolicyXeroConnectionConfig( + Xero.updateXeroMappings( policyID, - CONST.POLICY.CONNECTIONS.NAME.XERO, - CONST.XERO_CONFIG.MAPPINGS, categoryId ? {[`${CONST.XERO_CONFIG.TRACKING_CATEGORY_PREFIX}${categoryId}`]: option.value} : {}, categoryId ? {[`${CONST.XERO_CONFIG.TRACKING_CATEGORY_PREFIX}${categoryId}`]: currentTrackingCategoryValue} : {}, ); diff --git a/src/pages/workspace/accounting/xero/XeroTaxesConfigurationPage.tsx b/src/pages/workspace/accounting/xero/XeroTaxesConfigurationPage.tsx index 57053cb30808..cf695b57aa38 100644 --- a/src/pages/workspace/accounting/xero/XeroTaxesConfigurationPage.tsx +++ b/src/pages/workspace/accounting/xero/XeroTaxesConfigurationPage.tsx @@ -2,7 +2,7 @@ import React from 'react'; import ConnectionLayout from '@components/ConnectionLayout'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as Connections from '@libs/actions/connections'; +import * as Xero from '@libs/actions/connections/Xero'; import * as ErrorUtils from '@libs/ErrorUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; @@ -33,15 +33,7 @@ function XeroTaxesConfigurationPage({policy}: WithPolicyProps) { title={translate('workspace.accounting.import')} switchAccessibilityLabel={translate('workspace.xero.customers')} isActive={isSwitchOn} - onToggle={() => - Connections.updatePolicyXeroConnectionConfig( - policyID, - CONST.POLICY.CONNECTIONS.NAME.XERO, - CONST.XERO_CONFIG.IMPORT_TAX_RATES, - !xeroConfig?.importTaxRates, - xeroConfig?.importTaxRates, - ) - } + onToggle={() => Xero.updateXeroImportTaxRates(policyID, !xeroConfig?.importTaxRates, xeroConfig?.importTaxRates)} errors={ErrorUtils.getLatestErrorField(xeroConfig ?? {}, CONST.XERO_CONFIG.IMPORT_TAX_RATES)} onCloseError={() => Policy.clearXeroErrorField(policyID, CONST.XERO_CONFIG.IMPORT_TAX_RATES)} pendingAction={PolicyUtils.settingsPendingAction([CONST.XERO_CONFIG.IMPORT_TAX_RATES], xeroConfig?.pendingFields)} diff --git a/src/pages/workspace/accounting/xero/XeroTrackingCategoryConfigurationPage.tsx b/src/pages/workspace/accounting/xero/XeroTrackingCategoryConfigurationPage.tsx index 3a1b154e08d9..98b8bbb3a89c 100644 --- a/src/pages/workspace/accounting/xero/XeroTrackingCategoryConfigurationPage.tsx +++ b/src/pages/workspace/accounting/xero/XeroTrackingCategoryConfigurationPage.tsx @@ -5,7 +5,7 @@ import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as Connections from '@libs/actions/connections'; +import * as Xero from '@libs/actions/connections/Xero'; import {getTrackingCategories} from '@libs/actions/connections/Xero'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; @@ -53,15 +53,7 @@ function XeroTrackingCategoryConfigurationPage({policy}: WithPolicyProps) { switchAccessibilityLabel={translate('workspace.xero.trackingCategories')} isActive={isSwitchOn} wrapperStyle={styles.mv3} - onToggle={() => - Connections.updatePolicyXeroConnectionConfig( - policyID, - CONST.POLICY.CONNECTIONS.NAME.XERO, - CONST.XERO_CONFIG.IMPORT_TRACKING_CATEGORIES, - !xeroConfig?.importTrackingCategories, - xeroConfig?.importTrackingCategories, - ) - } + onToggle={() => Xero.updateXeroImportTrackingCategories(policyID, !xeroConfig?.importTrackingCategories, xeroConfig?.importTrackingCategories)} pendingAction={settingsPendingAction([CONST.XERO_CONFIG.IMPORT_TRACKING_CATEGORIES], xeroConfig?.pendingFields)} errors={ErrorUtils.getLatestErrorField(xeroConfig ?? {}, CONST.XERO_CONFIG.IMPORT_TRACKING_CATEGORIES)} onCloseError={() => Policy.clearXeroErrorField(policyID, CONST.XERO_CONFIG.IMPORT_TRACKING_CATEGORIES)} From 9485198ebba281dfdae1acf70b29680ce7aed7b2 Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 23 Aug 2024 17:21:51 +0700 Subject: [PATCH 8/9] small cleanup --- .../accounting/xero/XeroOrganizationConfigurationPage.tsx | 4 ++-- .../accounting/xero/XeroTrackingCategoryConfigurationPage.tsx | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx b/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx index 5137c98811b8..bb49c5212fb2 100644 --- a/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx +++ b/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx @@ -9,7 +9,7 @@ import SelectionScreen from '@components/SelectionScreen'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import {updateXeroTenantID} from '@libs/actions/connections/Xero'; +import * as Xero from '@libs/actions/connections/Xero'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; @@ -59,7 +59,7 @@ function XeroOrganizationConfigurationPage({ return; } - updateXeroTenantID(policyID, keyForList, xeroConfig?.tenantID); + Xero.updateXeroTenantID(policyID, keyForList, xeroConfig?.tenantID); Navigation.goBack(); }; diff --git a/src/pages/workspace/accounting/xero/XeroTrackingCategoryConfigurationPage.tsx b/src/pages/workspace/accounting/xero/XeroTrackingCategoryConfigurationPage.tsx index 98b8bbb3a89c..5aa6b2cd4efe 100644 --- a/src/pages/workspace/accounting/xero/XeroTrackingCategoryConfigurationPage.tsx +++ b/src/pages/workspace/accounting/xero/XeroTrackingCategoryConfigurationPage.tsx @@ -6,7 +6,6 @@ import OfflineWithFeedback from '@components/OfflineWithFeedback'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as Xero from '@libs/actions/connections/Xero'; -import {getTrackingCategories} from '@libs/actions/connections/Xero'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import {areSettingsInErrorFields, settingsPendingAction} from '@libs/PolicyUtils'; @@ -28,7 +27,7 @@ function XeroTrackingCategoryConfigurationPage({policy}: WithPolicyProps) { const isSwitchOn = !!xeroConfig?.importTrackingCategories; const menuItems = useMemo(() => { - const trackingCategories = getTrackingCategories(policy); + const trackingCategories = Xero.getTrackingCategories(policy); return trackingCategories.map((category: XeroTrackingCategory & {value: string}) => ({ id: category.id, description: translate('workspace.xero.mapTrackingCategoryTo', {categoryName: category.name}) as TranslationPaths, From 49680df86267bbc668959a26c87fe1d4dc02dd64 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Mon, 26 Aug 2024 15:22:24 +0000 Subject: [PATCH 9/9] Update version to 9.0.24-2 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 10b5f74ce660..9bef5fd7cb32 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -108,8 +108,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1009002401 - versionName "9.0.24-1" + versionCode 1009002402 + versionName "9.0.24-2" // Supported language variants must be declared here to avoid from being removed during the compilation. // This also helps us to not include unnecessary language variants in the APK. resConfigs "en", "es" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 4b272838832b..daf97c0ab588 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 9.0.24.1 + 9.0.24.2 FullStory OrgId diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index fff7dd6f3d55..fecfe9e01604 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 9.0.24.1 + 9.0.24.2 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 94f999e972c4..8b2a1c7af855 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 9.0.24 CFBundleVersion - 9.0.24.1 + 9.0.24.2 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index 11f192564162..8eaf09d73eda 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "9.0.24-1", + "version": "9.0.24-2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "9.0.24-1", + "version": "9.0.24-2", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index bc0036ce3cc6..7ac754944273 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "9.0.24-1", + "version": "9.0.24-2", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",