diff --git a/android/app/build.gradle b/android/app/build.gradle
index 10b5f74ce660..cfd339b4c7da 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 1009002403
+ versionName "9.0.24-3"
// 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/docs/articles/new-expensify/connections/quickbooks-online/Quickbooks-Online-Troubleshooting.md b/docs/articles/new-expensify/connections/quickbooks-online/Quickbooks-Online-Troubleshooting.md
index b132a75e9297..ff1b9bfab9fb 100644
--- a/docs/articles/new-expensify/connections/quickbooks-online/Quickbooks-Online-Troubleshooting.md
+++ b/docs/articles/new-expensify/connections/quickbooks-online/Quickbooks-Online-Troubleshooting.md
@@ -9,13 +9,13 @@ If an error occurs during an automatic export to QuickBooks Online:
- You’ll receive an email detailing the error.
- The error will appear in the related Workspace Chat, indicated by a red dot next to the report.
-- For auto-sync errors, a message will be posted in the related #admins room. The message contains a link to the workspace’s Accounting settings where an explanation for the error appears next to the connection.
+- For auto-sync errors, a message will be posted in the related #admins room. The message contains a link to the workspace’s accounting settings where an explanation for the error appears next to the connection.
An error on a report will prevent it from automatically exporting.
-### How to resolve:
+### How to resolve
-To resolve this, open the expense and make the required changes. Then an admin must manually export the report to QuickBooks Online by clicking on Details > Export:
+Open the expense and make the required changes. Then an admin must manually export the report to QuickBooks Online by clicking Details > Export.
![Click the Export button found in the Details tab](https://help.expensify.com/assets/images/QBO_help_02.png){:width="100%"}
@@ -27,11 +27,26 @@ To export a report, it must be in the Approved, Closed, or Reimbursed state. If
![If the Report is in the Open status, the Not Ready to Export message shows](https://help.expensify.com/assets/images/QBO_help_04.png){:width="100%"}
-### How to resolve:
+### How to resolve
-To resolve this, open the report and make the required changes:
+Open the report and make the required changes:
-1. If the report is in the Open status, please ensure that it is submitted.
+1. If the report is in the Open status, ensure that it is submitted.
2. If the Report is in the Processing status, an admin or approver will need to approve it.
-Once this is done, then an admin must manually export the report to QuickBooks Online.
+Once this is done, an admin must manually export the report to QuickBooks Online.
+
+{% include faq-begin.md %}
+
+**How do I disconnect the QuickBooks Online connection?**
+
+1. Click your profile image or icon in the bottom left menu.
+2. Scroll down and click **Workspaces** in the left menu.
+3. Select the workspace you want to disconnect from QuickBooks Online.
+4. Click **Accounting** in the left menu.
+5. Click the three dot menu icon to the right of QuickBooks Online and select **Disconnect**.
+6. Click **Disconnect** to confirm.
+
+You will no longer see the imported options from QuickBooks Online.
+
+{% include faq-end.md %}
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index 4b272838832b..a690017617dd 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -40,7 +40,7 @@
CFBundleVersion
- 9.0.24.1
+ 9.0.24.3
FullStory
OrgId
diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist
index fff7dd6f3d55..63a754c008d6 100644
--- a/ios/NewExpensifyTests/Info.plist
+++ b/ios/NewExpensifyTests/Info.plist
@@ -19,6 +19,6 @@
CFBundleSignature
????
CFBundleVersion
- 9.0.24.1
+ 9.0.24.3
diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist
index 94f999e972c4..81200c8db51b 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.3
NSExtension
NSExtensionPointIdentifier
diff --git a/package-lock.json b/package-lock.json
index 71278ea481af..b0663d943923 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-3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "new.expensify",
- "version": "9.0.24-1",
+ "version": "9.0.24-3",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -56,7 +56,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",
@@ -104,7 +104,7 @@
"react-native-localize": "^2.2.6",
"react-native-modal": "^13.0.0",
"react-native-onyx": "2.0.65",
- "react-native-pager-view": "6.3.4",
+ "react-native-pager-view": "6.2.3",
"react-native-pdf": "6.7.3",
"react-native-performance": "^5.1.0",
"react-native-permissions": "^3.10.0",
@@ -26142,9 +26142,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",
@@ -37593,9 +37593,9 @@
}
},
"node_modules/react-native-pager-view": {
- "version": "6.3.4",
- "resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.3.4.tgz",
- "integrity": "sha512-4PEQd52EOwWcfiFJZ4VGSlY+GZfumvUzNbAozsMEgJaLvOHOMMl+Arfsc0txgtGdS49uEiHFLLZthZQzxx/Mog==",
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.2.3.tgz",
+ "integrity": "sha512-dqVpXWFtPNfD3D2QQQr8BP+ullS5MhjRJuF8Z/qml4QTILcrWaW8F5iAxKkQR3Jl0ikcEryG/+SQlNcwlo0Ggg==",
"peerDependencies": {
"react": "*",
"react-native": "*"
diff --git a/package.json b/package.json
index 3fc98b583b89..df772917c218 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "9.0.24-1",
+ "version": "9.0.24-3",
"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.",
@@ -112,7 +112,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",
@@ -160,7 +160,7 @@
"react-native-localize": "^2.2.6",
"react-native-modal": "^13.0.0",
"react-native-onyx": "2.0.65",
- "react-native-pager-view": "6.3.4",
+ "react-native-pager-view": "6.2.3",
"react-native-pdf": "6.7.3",
"react-native-performance": "^5.1.0",
"react-native-permissions": "^3.10.0",
diff --git a/src/CONST.ts b/src/CONST.ts
index 971fefc2d1b7..7b5320e7c6ef 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -3771,69 +3771,6 @@ const CONST = {
EXPENSIFY_LOGO_SIZE_RATIO: 0.22,
EXPENSIFY_LOGO_MARGIN_RATIO: 0.03,
},
- /**
- * Acceptable values for the `accessibilityRole` prop on react native components.
- *
- * **IMPORTANT:** Do not use with the `role` prop as it can cause errors.
- *
- * @deprecated ACCESSIBILITY_ROLE is deprecated. Please use CONST.ROLE instead.
- */
- ACCESSIBILITY_ROLE: {
- /**
- * @deprecated Please stop using the accessibilityRole prop and use the role prop instead.
- */
- BUTTON: 'button',
-
- /**
- * @deprecated Please stop using the accessibilityRole prop and use the role prop instead.
- */
- LINK: 'link',
-
- /**
- * @deprecated Please stop using the accessibilityRole prop and use the role prop instead.
- */
- MENUITEM: 'menuitem',
-
- /**
- * @deprecated Please stop using the accessibilityRole prop and use the role prop instead.
- */
- TEXT: 'text',
-
- /**
- * @deprecated Please stop using the accessibilityRole prop and use the role prop instead.
- */
- RADIO: 'radio',
-
- /**
- * @deprecated Please stop using the accessibilityRole prop and use the role prop instead.
- */
- IMAGEBUTTON: 'imagebutton',
-
- /**
- * @deprecated Please stop using the accessibilityRole prop and use the role prop instead.
- */
- CHECKBOX: 'checkbox',
-
- /**
- * @deprecated Please stop using the accessibilityRole prop and use the role prop instead.
- */
- SWITCH: 'switch',
-
- /**
- * @deprecated Please stop using the accessibilityRole prop and use the role prop instead.
- */
- ADJUSTABLE: 'adjustable',
-
- /**
- * @deprecated Please stop using the accessibilityRole prop and use the role prop instead.
- */
- IMAGE: 'image',
-
- /**
- * @deprecated Please stop using the accessibilityRole prop and use the role prop instead.
- */
- TEXTBOX: 'textbox',
- },
/**
* Acceptable values for the `role` attribute on react native components.
*
diff --git a/src/components/Attachments/AttachmentCarousel/CarouselItem.tsx b/src/components/Attachments/AttachmentCarousel/CarouselItem.tsx
index a9b5dfb7feb6..453b7b4fd106 100644
--- a/src/components/Attachments/AttachmentCarousel/CarouselItem.tsx
+++ b/src/components/Attachments/AttachmentCarousel/CarouselItem.tsx
@@ -58,7 +58,7 @@ function CarouselItem({item, onPress, isFocused, isModalHovered}: CarouselItemPr
diff --git a/src/components/Attachments/AttachmentView/AttachmentViewImage/index.tsx b/src/components/Attachments/AttachmentView/AttachmentViewImage/index.tsx
index c195c1e34554..0ec2bb5ef0b5 100644
--- a/src/components/Attachments/AttachmentView/AttachmentViewImage/index.tsx
+++ b/src/components/Attachments/AttachmentView/AttachmentViewImage/index.tsx
@@ -34,7 +34,7 @@ function AttachmentViewImage({url, file, isAuthTokenRequired, loadComplete, onPr
onPress={onPress}
disabled={loadComplete}
style={[styles.flex1, styles.flexRow, styles.alignSelfStretch]}
- accessibilityRole={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON}
+ accessibilityRole={CONST.ROLE.BUTTON}
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
accessibilityLabel={file?.name || translate('attachmentView.unknownFilename')}
>
diff --git a/src/components/AvatarWithImagePicker.tsx b/src/components/AvatarWithImagePicker.tsx
index a1b8524dd293..337bbaf98ca1 100644
--- a/src/components/AvatarWithImagePicker.tsx
+++ b/src/components/AvatarWithImagePicker.tsx
@@ -368,7 +368,7 @@ function AvatarWithImagePicker({
>
onPressAvatar(openPicker)}
- accessibilityRole={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON}
+ accessibilityRole={CONST.ROLE.BUTTON}
accessibilityLabel={translate('avatarWithImagePicker.editImage')}
disabled={isAvatarCropModalOpen || (disabled && !enablePreview)}
disabledStyle={disabledStyle}
diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx
index 126c81961cee..e1b663a7e344 100644
--- a/src/components/Button/index.tsx
+++ b/src/components/Button/index.tsx
@@ -128,13 +128,13 @@ type ButtonProps = Partial & {
type KeyboardShortcutComponentProps = Pick;
-const accessibilityRoles: string[] = Object.values(CONST.ACCESSIBILITY_ROLE);
+const accessibilityRoles: string[] = Object.values(CONST.ROLE);
function KeyboardShortcutComponent({isDisabled = false, isLoading = false, onPress = () => {}, pressOnEnter, allowBubble, enterKeyEventListenerPriority}: KeyboardShortcutComponentProps) {
const isFocused = useIsFocused();
const activeElementRole = useActiveElementRole();
- const shouldDisableEnterShortcut = useMemo(() => accessibilityRoles.includes(activeElementRole ?? '') && activeElementRole !== CONST.ACCESSIBILITY_ROLE.TEXT, [activeElementRole]);
+ const shouldDisableEnterShortcut = useMemo(() => accessibilityRoles.includes(activeElementRole ?? '') && activeElementRole !== CONST.ROLE.PRESENTATION, [activeElementRole]);
const keyboardShortcutCallback = useCallback(
(event?: GestureResponderEvent | KeyboardEvent) => {
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/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.tsx
index 1e73cce1630f..771d2631379e 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}
/>
);
@@ -97,7 +99,7 @@ function ImageRenderer({tnode}: ImageRendererProps) {
showContextMenuForReport(event, anchor, report?.reportID ?? '-1', action, checkIfContextMenuActive, ReportUtils.isArchivedRoom(report, reportNameValuePairs))
}
shouldUseHapticsOnLongPress
- accessibilityRole={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON}
+ accessibilityRole={CONST.ROLE.BUTTON}
accessibilityLabel={translate('accessibilityHints.viewAttachment')}
>
{thumbnailImageComponent}
diff --git a/src/components/ImageWithSizeCalculation.tsx b/src/components/ImageWithSizeCalculation.tsx
index 3d940103715d..ebea1a90efca 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/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx
index c9e030809f18..c825b40c6266 100755
--- a/src/components/MoneyRequestConfirmationList.tsx
+++ b/src/components/MoneyRequestConfirmationList.tsx
@@ -528,33 +528,35 @@ function MoneyRequestConfirmationList({
const currencySymbol = currencyList?.[iouCurrencyCode ?? '']?.symbol ?? iouCurrencyCode;
const formattedTotalAmount = CurrencyUtils.convertToDisplayStringWithoutCurrency(iouAmount, iouCurrencyCode);
- return [payeeOption, ...selectedParticipants].map((participantOption: Participant) => ({
- ...participantOption,
- tabIndex: -1,
- isSelected: false,
- isInteractive: !shouldDisableParticipant(participantOption),
- rightElement: (
- onSplitShareChange(participantOption.accountID ?? -1, Number(value))}
- maxLength={formattedTotalAmount.length}
- contentWidth={formattedTotalAmount.length * 8}
- />
- ),
- }));
+ return [payeeOption, ...selectedParticipants]
+ .filter((participantOption) => !PolicyUtils.isExpensifyTeam(participantOption.login))
+ .map((participantOption: Participant) => ({
+ ...participantOption,
+ tabIndex: -1,
+ isSelected: false,
+ isInteractive: !shouldDisableParticipant(participantOption),
+ rightElement: (
+ onSplitShareChange(participantOption.accountID ?? -1, Number(value))}
+ maxLength={formattedTotalAmount.length}
+ contentWidth={formattedTotalAmount.length * 8}
+ />
+ ),
+ }));
}, [
isTypeSplit,
payeePersonalDetails,
diff --git a/src/components/PDFView/index.native.tsx b/src/components/PDFView/index.native.tsx
index 55f85aa74b37..44ef894cb994 100644
--- a/src/components/PDFView/index.native.tsx
+++ b/src/components/PDFView/index.native.tsx
@@ -172,7 +172,7 @@ function PDFView({onToggleKeyboard, onLoadComplete, fileName, onPress, isFocused
onPress={onPress}
fullDisabled={successToLoadPDF}
style={[themeStyles.flex1, themeStyles.alignSelfStretch, !failedToLoadPDF && themeStyles.flexRow]}
- accessibilityRole={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON}
+ accessibilityRole={CONST.ROLE.BUTTON}
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
accessibilityLabel={fileName || translate('attachmentView.unknownFilename')}
>
diff --git a/src/components/PDFView/index.tsx b/src/components/PDFView/index.tsx
index 2edf699affab..69d886dc7c37 100644
--- a/src/components/PDFView/index.tsx
+++ b/src/components/PDFView/index.tsx
@@ -131,7 +131,7 @@ function PDFView({onToggleKeyboard, fileName, onPress, isFocused, sourceURL, max
diff --git a/src/components/ReferralProgramCTA.tsx b/src/components/ReferralProgramCTA.tsx
index 086b875451c0..808df9c4d94d 100644
--- a/src/components/ReferralProgramCTA.tsx
+++ b/src/components/ReferralProgramCTA.tsx
@@ -54,7 +54,7 @@ function ReferralProgramCTA({referralContentType, style, onDismiss}: ReferralPro
}}
style={[styles.br2, styles.highlightBG, styles.flexRow, styles.justifyContentBetween, styles.alignItemsCenter, {gap: 10, padding: 10}, styles.pl5, style]}
accessibilityLabel="referral"
- role={CONST.ACCESSIBILITY_ROLE.BUTTON}
+ role={CONST.ROLE.BUTTON}
>
{translate(`referralProgram.${referralContentType}.buttonText1`)}
@@ -72,7 +72,7 @@ function ReferralProgramCTA({referralContentType, style, onDismiss}: ReferralPro
e.preventDefault();
}}
style={[styles.touchableButtonImage]}
- role={CONST.ACCESSIBILITY_ROLE.BUTTON}
+ role={CONST.ROLE.BUTTON}
accessibilityLabel={translate('common.close')}
>
{
+ const tagList = policyTagLists.map(({name, orderWeight, tags}, index) => {
+ const tagForDisplay = TransactionUtils.getTagForDisplay(updatedTransaction ?? transaction, index);
+ const shouldShow = !!tagForDisplay || OptionsListUtils.hasEnabledOptions(tags);
+ if (!shouldShow) {
+ return null;
+ }
+
const tagError = getErrorForField(
'tag',
{
@@ -418,7 +424,7 @@ function MoneyRequestView({
tagListName: name,
},
PolicyUtils.hasDependentTags(policy, policyTagList),
- TransactionUtils.getTagForDisplay(updatedTransaction ?? transaction, index),
+ tagForDisplay,
);
return (
navigateToAvatarPage(icons[0])}
- accessibilityRole={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON}
+ accessibilityRole={CONST.ROLE.BUTTON}
accessibilityLabel={icons[0].name ?? ''}
disabled={icons[0].source === Expensicons.FallbackAvatar}
>
@@ -77,7 +77,7 @@ function RoomHeaderAvatars({icons, reportID}: RoomHeaderAvatarsProps) {
navigateToAvatarPage(icon)}
- accessibilityRole={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON}
+ accessibilityRole={CONST.ROLE.BUTTON}
accessibilityLabel={icon.name ?? ''}
disabled={icon.source === Expensicons.FallbackAvatar}
>
diff --git a/src/components/TextLink.tsx b/src/components/TextLink.tsx
index b6ffb14753c1..2d390f9811e6 100644
--- a/src/components/TextLink.tsx
+++ b/src/components/TextLink.tsx
@@ -62,7 +62,7 @@ function TextLink({href, onPress, children, style, onMouseDown = (event) => even
return (
;
@@ -61,6 +64,7 @@ type UpdateImageSizeParams = {
function ThumbnailImage({
previewSourceURL,
+ altText,
style,
isAuthTokenRequired,
imageWidth = 200,
@@ -132,6 +136,7 @@ function ThumbnailImage({
setFailedToLoad(true)}
isAuthTokenRequired={isAuthTokenRequired}
diff --git a/src/components/VideoPlayerPreview/VideoPlayerThumbnail.tsx b/src/components/VideoPlayerPreview/VideoPlayerThumbnail.tsx
index 5900e3097b96..48465e208b70 100644
--- a/src/components/VideoPlayerPreview/VideoPlayerThumbnail.tsx
+++ b/src/components/VideoPlayerPreview/VideoPlayerThumbnail.tsx
@@ -44,7 +44,7 @@ function VideoPlayerThumbnail({thumbnailUrl, onPress, accessibilityLabel}: Video
DeviceCapabilities.canUseTouchScreen() && ControlSelection.block()}
onPressOut={() => ControlSelection.unblock()}
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 9696f4213a48..2de13f817f29 100644
--- a/src/libs/API/parameters/index.ts
+++ b/src/libs/API/parameters/index.ts
@@ -280,3 +280,4 @@ export type {default as OpenCardDetailsPageParams} from './OpenCardDetailsPagePa
export type {default as EnablePolicyCompanyCardsParams} from './EnablePolicyCompanyCardsParams';
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 5ea2ae44b74d..943cf8febc1e 100644
--- a/src/libs/API/types.ts
+++ b/src/libs/API/types.ts
@@ -336,6 +336,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;
@@ -677,6 +681,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/Navigation/setupCustomAndroidBackHandler/index.android.ts b/src/libs/Navigation/setupCustomAndroidBackHandler/index.android.ts
index 10aa8b99a484..107dae2bb74c 100644
--- a/src/libs/Navigation/setupCustomAndroidBackHandler/index.android.ts
+++ b/src/libs/Navigation/setupCustomAndroidBackHandler/index.android.ts
@@ -13,8 +13,7 @@ type SearchPageProps = StackScreenProps {
const rootState = navigationRef.getRootState();
-
- const bottomTabRoute = rootState.routes.find((route) => route.name === NAVIGATORS.BOTTOM_TAB_NAVIGATOR);
+ const bottomTabRoute = rootState?.routes?.find((route) => route.name === NAVIGATORS.BOTTOM_TAB_NAVIGATOR);
const bottomTabRoutes = bottomTabRoute?.state?.routes;
const focusedRoute = findFocusedRoute(rootState);
@@ -23,7 +22,7 @@ function setupCustomAndroidBackHandler() {
return false;
}
- const isLastScreenOnStack = bottomTabRoutes.length === 1 && rootState.routes.length === 1;
+ const isLastScreenOnStack = bottomTabRoutes.length === 1 && rootState?.routes?.length === 1;
if (NativeModules.HybridAppModule && isLastScreenOnStack) {
NativeModules.HybridAppModule.exitApp();
@@ -35,7 +34,7 @@ function setupCustomAndroidBackHandler() {
navigationRef.dispatch({...StackActions.pop(), target: bottomTabRoute?.state?.key});
navigationRef.dispatch({...StackActions.pop()});
- const centralPaneRouteAfterPop = getTopmostCentralPaneRoute({routes: [rootState.routes.at(-2)]} as State);
+ const centralPaneRouteAfterPop = getTopmostCentralPaneRoute({routes: [rootState?.routes?.at(-2)]} as State);
const bottomTabRouteAfterPop = bottomTabRoutes.at(-2);
// It's possible that central pane search is desynchronized with the bottom tab search.
@@ -57,7 +56,7 @@ function setupCustomAndroidBackHandler() {
// It's possible that central pane search is desynchronized with the bottom tab search.
// e.g. opening a tab different than search will wipe out central pane screens.
// In that case we have to push the proper one.
- if (bottomTabRoutes && bottomTabRoutes?.length >= 2 && bottomTabRoutes[bottomTabRoutes.length - 2].name === SCREENS.SEARCH.BOTTOM_TAB && rootState.routes.length === 1) {
+ if (bottomTabRoutes && bottomTabRoutes?.length >= 2 && bottomTabRoutes[bottomTabRoutes.length - 2].name === SCREENS.SEARCH.BOTTOM_TAB && rootState?.routes?.length === 1) {
const {policyID, ...restParams} = bottomTabRoutes[bottomTabRoutes.length - 2].params as SearchPageProps['route']['params'];
navigationRef.dispatch({...StackActions.push(SCREENS.SEARCH.CENTRAL_PANE, {...restParams, policyIDs: policyID})});
navigationRef.dispatch({...StackActions.pop(), target: bottomTabRoute?.state?.key});
diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 38b73ffc2057..9ba7eba3b419 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -6374,7 +6374,9 @@ function getMoneyRequestOptions(report: OnyxEntry, policy: OnyxEntry currentUserPersonalDetails?.accountID !== accountID);
+ const otherParticipants = reportParticipants.filter(
+ (accountID) => currentUserPersonalDetails?.accountID !== accountID && !PolicyUtils.isExpensifyTeam(allPersonalDetails?.[accountID]?.login),
+ );
const hasSingleParticipantInReport = otherParticipants.length === 1;
let options: IOUType[] = [];
diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts
index 90d8d7311b1c..f935b813cebd 100644
--- a/src/libs/actions/IOU.ts
+++ b/src/libs/actions/IOU.ts
@@ -7644,7 +7644,9 @@ function putOnHold(transactionID: string, comment: string, reportID: string) {
const currentTime = DateUtils.getDBTime();
const createdReportAction = ReportUtils.buildOptimisticHoldReportAction(currentTime);
const createdReportActionComment = ReportUtils.buildOptimisticHoldReportActionComment(comment, DateUtils.addMillisecondsFromDateTime(currentTime, 1));
-
+ const newViolation = {name: CONST.VIOLATIONS.HOLD, type: CONST.VIOLATION_TYPES.VIOLATION};
+ const transactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`] ?? [];
+ const updatedViolations = [...transactionViolations, newViolation];
const optimisticData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
@@ -7664,6 +7666,11 @@ function putOnHold(transactionID: string, comment: string, reportID: string) {
},
},
},
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`,
+ value: updatedViolations,
+ },
];
const successData: OnyxUpdate[] = [
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..fa08dec2e391
--- /dev/null
+++ b/src/libs/actions/connections/Xero.ts
@@ -0,0 +1,188 @@
+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(
+ policyID: string,
+ importTrackingCategories: Partial,
+ 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,
+ );
+
+ 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 = {
+ 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(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/NewChatPage.tsx b/src/pages/NewChatPage.tsx
index 4b8557dfbac3..b11e92e2f4ca 100755
--- a/src/pages/NewChatPage.tsx
+++ b/src/pages/NewChatPage.tsx
@@ -255,8 +255,8 @@ function NewChatPage({isGroupChat}: NewChatPageProps) {
toggleOption(item)}
disabled={item.isDisabled}
- role={CONST.ACCESSIBILITY_ROLE.CHECKBOX}
- accessibilityLabel={CONST.ACCESSIBILITY_ROLE.CHECKBOX}
+ role={CONST.ROLE.BUTTON}
+ accessibilityLabel={CONST.ROLE.BUTTON}
style={[styles.flexRow, styles.alignItemsCenter, styles.ml3]}
>
diff --git a/src/pages/ProfilePage.tsx b/src/pages/ProfilePage.tsx
index d172e2089983..8b12ae4b63ab 100755
--- a/src/pages/ProfilePage.tsx
+++ b/src/pages/ProfilePage.tsx
@@ -197,7 +197,7 @@ function ProfilePage({route}: ProfilePageProps) {
style={[styles.noOutline, styles.mb4]}
onPress={() => Navigation.navigate(ROUTES.PROFILE_AVATAR.getRoute(String(accountID)))}
accessibilityLabel={translate('common.profile')}
- accessibilityRole={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON}
+ accessibilityRole={CONST.ROLE.BUTTON}
disabled={!hasAvatar}
>
diff --git a/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerCheckUBO.tsx b/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerCheckUBO.tsx
index fc98ee21aff2..438551cf4044 100644
--- a/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerCheckUBO.tsx
+++ b/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerCheckUBO.tsx
@@ -47,7 +47,7 @@ function BeneficialOwnerCheckUBO({title, onSelectedValue, defaultValue}: Benefic
submitButtonText={translate('common.confirm')}
onSubmit={handleSubmit}
style={[styles.mh5, styles.flexGrow1]}
- submitButtonStyles={[styles.pb5, styles.mb0]}
+ submitButtonStyles={[styles.mb0]}
>
{title}
{translate('beneficialOwnerInfoStep.regulationRequiresUsToVerifyTheIdentity')}
diff --git a/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerDetailsFormSubsteps/AddressUBO.tsx b/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerDetailsFormSubsteps/AddressUBO.tsx
index 284a27108a48..1b03432b7f3e 100644
--- a/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerDetailsFormSubsteps/AddressUBO.tsx
+++ b/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerDetailsFormSubsteps/AddressUBO.tsx
@@ -69,7 +69,7 @@ function AddressUBO({reimbursementAccountDraft, onNext, isEditing, beneficialOwn
submitButtonText={translate(isEditing ? 'common.confirm' : 'common.next')}
validate={validate}
onSubmit={handleSubmit}
- submitButtonStyles={[styles.mb0, styles.pb5]}
+ submitButtonStyles={[styles.mb0]}
style={[styles.mh5, styles.flexGrow1]}
>
{translate('beneficialOwnerInfoStep.enterTheOwnersAddress')}
diff --git a/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerDetailsFormSubsteps/DateOfBirthUBO.tsx b/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerDetailsFormSubsteps/DateOfBirthUBO.tsx
index 2173d19887ad..b5a4a6a94bed 100644
--- a/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerDetailsFormSubsteps/DateOfBirthUBO.tsx
+++ b/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerDetailsFormSubsteps/DateOfBirthUBO.tsx
@@ -62,7 +62,7 @@ function DateOfBirthUBO({reimbursementAccountDraft, onNext, isEditing, beneficia
validate={validate}
onSubmit={handleSubmit}
style={[styles.mh5, styles.flexGrow2, styles.justifyContentBetween]}
- submitButtonStyles={[styles.pb5, styles.mb0]}
+ submitButtonStyles={[styles.mb0]}
>
{translate('beneficialOwnerInfoStep.enterTheDateOfBirthOfTheOwner')}
{translate('beneficialOwnerInfoStep.enterLegalFirstAndLastName')}
{translate('beneficialOwnerInfoStep.enterTheLast4')}
diff --git a/src/pages/ReimbursementAccount/BusinessInfo/substeps/AddressBusiness.tsx b/src/pages/ReimbursementAccount/BusinessInfo/substeps/AddressBusiness.tsx
index bd9524626a14..2526e15042b1 100644
--- a/src/pages/ReimbursementAccount/BusinessInfo/substeps/AddressBusiness.tsx
+++ b/src/pages/ReimbursementAccount/BusinessInfo/substeps/AddressBusiness.tsx
@@ -76,7 +76,7 @@ function AddressBusiness({reimbursementAccount, onNext, isEditing}: AddressBusin
submitButtonText={translate(isEditing ? 'common.confirm' : 'common.next')}
validate={validate}
onSubmit={handleSubmit}
- submitButtonStyles={[styles.mb0, styles.pb5]}
+ submitButtonStyles={[styles.mb0]}
style={[styles.mh5, styles.flexGrow1]}
>
{translate('businessInfoStep.enterYourCompanysAddress')}
diff --git a/src/pages/ReimbursementAccount/BusinessInfo/substeps/IncorporationDateBusiness.tsx b/src/pages/ReimbursementAccount/BusinessInfo/substeps/IncorporationDateBusiness.tsx
index 274e087cc415..168cb02fd925 100644
--- a/src/pages/ReimbursementAccount/BusinessInfo/substeps/IncorporationDateBusiness.tsx
+++ b/src/pages/ReimbursementAccount/BusinessInfo/substeps/IncorporationDateBusiness.tsx
@@ -63,7 +63,7 @@ function IncorporationDateBusiness({reimbursementAccount, reimbursementAccountDr
validate={validate}
onSubmit={handleSubmit}
style={[styles.mh5, styles.flexGrow1]}
- submitButtonStyles={[styles.pb5, styles.mb0]}
+ submitButtonStyles={[styles.mb0]}
>
{translate('businessInfoStep.selectYourCompanysIncorporationDate')}
{translate('businessInfoStep.pleaseSelectTheStateYourCompanyWasIncorporatedIn')}
{translate('businessInfoStep.enterTheNameOfYourBusiness')}
{translate('businessInfoStep.enterYourCompanysPhoneNumber')}
{translate('businessInfoStep.enterYourCompanysTaxIdNumber')}
{translate('businessInfoStep.selectYourCompanysType')}
{translate('businessInfoStep.enterYourCompanysWebsite')}
{translate('common.websiteExample')}
diff --git a/src/pages/ReimbursementAccount/PersonalInfo/substeps/Address.tsx b/src/pages/ReimbursementAccount/PersonalInfo/substeps/Address.tsx
index e802b9f5d765..b37dd207ea37 100644
--- a/src/pages/ReimbursementAccount/PersonalInfo/substeps/Address.tsx
+++ b/src/pages/ReimbursementAccount/PersonalInfo/substeps/Address.tsx
@@ -74,7 +74,7 @@ function Address({reimbursementAccount, onNext, isEditing}: AddressProps) {
submitButtonText={translate(isEditing ? 'common.confirm' : 'common.next')}
validate={validate}
onSubmit={handleSubmit}
- submitButtonStyles={[styles.mb0, styles.pb5]}
+ submitButtonStyles={[styles.mb0]}
style={[styles.mh5, styles.flexGrow1]}
>
diff --git a/src/pages/ReimbursementAccount/PersonalInfo/substeps/DateOfBirth.tsx b/src/pages/ReimbursementAccount/PersonalInfo/substeps/DateOfBirth.tsx
index 6fe391bbe957..8c68380d6e55 100644
--- a/src/pages/ReimbursementAccount/PersonalInfo/substeps/DateOfBirth.tsx
+++ b/src/pages/ReimbursementAccount/PersonalInfo/substeps/DateOfBirth.tsx
@@ -71,7 +71,7 @@ function DateOfBirth({reimbursementAccount, reimbursementAccountDraft, onNext, i
validate={validate}
onSubmit={handleSubmit}
style={[styles.mh5, styles.flexGrow2, styles.justifyContentBetween]}
- submitButtonStyles={[styles.pb5, styles.mb0]}
+ submitButtonStyles={[styles.mb0]}
>
{translate('personalInfoStep.enterYourDateOfBirth')}
{translate('personalInfoStep.enterYourLegalFirstAndLast')}
diff --git a/src/pages/ReimbursementAccount/PersonalInfo/substeps/SocialSecurityNumber.tsx b/src/pages/ReimbursementAccount/PersonalInfo/substeps/SocialSecurityNumber.tsx
index 390880fa65f2..2f08980f2bd0 100644
--- a/src/pages/ReimbursementAccount/PersonalInfo/substeps/SocialSecurityNumber.tsx
+++ b/src/pages/ReimbursementAccount/PersonalInfo/substeps/SocialSecurityNumber.tsx
@@ -60,7 +60,7 @@ function SocialSecurityNumber({reimbursementAccount, onNext, isEditing}: SocialS
validate={validate}
onSubmit={handleSubmit}
style={[styles.mh5, styles.flexGrow1]}
- submitButtonStyles={[styles.pb5, styles.mb0]}
+ submitButtonStyles={[styles.mb0]}
>
{translate('personalInfoStep.enterTheLast4')}
diff --git a/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx b/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx
index 5d7b5b1390c2..9c61e0178a54 100644
--- a/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx
+++ b/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx
@@ -7,6 +7,7 @@ import type {FileObject} from '@components/AttachmentModal';
import AttachmentPicker from '@components/AttachmentPicker';
import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';
+import {usePersonalDetails} from '@components/OnyxProvider';
import type {PopoverMenuItem} from '@components/PopoverMenu';
import PopoverMenu from '@components/PopoverMenu';
import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
@@ -122,6 +123,7 @@ function AttachmentPickerWithMenuItems({
const {translate} = useLocalize();
const {windowHeight, windowWidth} = useWindowDimensions();
const {shouldUseNarrowLayout} = useResponsiveLayout();
+ const allPersonalDetails = usePersonalDetails();
/**
* Returns the list of IOU Options
@@ -167,7 +169,8 @@ function AttachmentPickerWithMenuItems({
return ReportUtils.temporary_getMoneyRequestOptions(report, policy, reportParticipantIDs ?? []).map((option) => ({
...options[option],
}));
- }, [translate, report, policy, reportParticipantIDs]);
+ // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
+ }, [translate, report, policy, reportParticipantIDs, allPersonalDetails]);
/**
* Determines if we can show the task option
diff --git a/src/pages/iou/request/step/IOURequestStepAmount.tsx b/src/pages/iou/request/step/IOURequestStepAmount.tsx
index 069f86ce0899..a7457c88280d 100644
--- a/src/pages/iou/request/step/IOURequestStepAmount.tsx
+++ b/src/pages/iou/request/step/IOURequestStepAmount.tsx
@@ -10,6 +10,7 @@ import * as TransactionEdit from '@libs/actions/TransactionEdit';
import * as CurrencyUtils from '@libs/CurrencyUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as PolicyUtils from '@libs/PolicyUtils';
import * as ReportUtils from '@libs/ReportUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import {getRequestType} from '@libs/TransactionUtils';
@@ -79,6 +80,7 @@ function IOURequestStepAmount({
const isSaveButtonPressed = useRef(false);
const iouRequestType = getRequestType(transaction);
const [reportNameValuePairs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.reportID ?? -1}`);
+ const [allPersonalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST);
const isEditing = action === CONST.IOU.ACTION.EDIT;
const isSplitBill = iouType === CONST.IOU.TYPE.SPLIT;
@@ -253,7 +255,9 @@ function IOURequestStepAmount({
}
IOU.setMoneyRequestParticipantsFromReport(transactionID, report);
if (isSplitBill && !report.isOwnPolicyExpenseChat && report.participants) {
- const participantAccountIDs = Object.keys(report.participants).map((accountID) => Number(accountID));
+ const participantAccountIDs = Object.keys(report.participants)
+ .map((accountID) => Number(accountID))
+ .filter((accountID) => !PolicyUtils.isExpensifyTeam(allPersonalDetails?.[accountID]?.login));
IOU.setSplitShares(transaction, amountInSmallestCurrencyUnits, currency || CONST.CURRENCY.USD, participantAccountIDs);
}
navigateToConfirmationPage();
diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx
index 528b3ab1e88f..9c24e92689cc 100644
--- a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx
+++ b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx
@@ -552,7 +552,7 @@ function IOURequestStepScan({
{({openPicker}) => (
{
@@ -571,7 +571,7 @@ function IOURequestStepScan({
)}
{hasFlash && (
(
{
openPicker({
onPicked: setReceiptAndNavigate,
@@ -619,7 +619,7 @@ function IOURequestStepScan({
)}
{
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/XeroOrganizationConfigurationPage.tsx b/src/pages/workspace/accounting/xero/XeroOrganizationConfigurationPage.tsx
index b23363c79963..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 {updatePolicyXeroConnectionConfig} 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 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);
+ Xero.updateXeroTenantID(policyID, keyForList, xeroConfig?.tenantID);
Navigation.goBack();
};
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 9d27c8887e6e..5aa6b2cd4efe 100644
--- a/src/pages/workspace/accounting/xero/XeroTrackingCategoryConfigurationPage.tsx
+++ b/src/pages/workspace/accounting/xero/XeroTrackingCategoryConfigurationPage.tsx
@@ -5,8 +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 {getTrackingCategories} from '@libs/actions/connections/ConnectToXero';
+import * as Xero 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,
@@ -53,15 +52,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)}
diff --git a/src/pages/workspace/categories/CategoryGLCodePage.tsx b/src/pages/workspace/categories/CategoryGLCodePage.tsx
index 12660597247f..131f17a14242 100644
--- a/src/pages/workspace/categories/CategoryGLCodePage.tsx
+++ b/src/pages/workspace/categories/CategoryGLCodePage.tsx
@@ -38,7 +38,7 @@ function CategoryGLCodePage({route}: EditCategoryPageProps) {
if (newGLCode !== glCode) {
Category.setPolicyCategoryGLCode(route.params.policyID, categoryName, newGLCode);
}
- Navigation.dismissModal();
+ Navigation.goBack(ROUTES.WORKSPACE_CATEGORY_SETTINGS.getRoute(route.params.policyID, categoryName));
},
[categoryName, glCode, route.params.policyID],
);
diff --git a/src/pages/workspace/categories/CategoryPayrollCodePage.tsx b/src/pages/workspace/categories/CategoryPayrollCodePage.tsx
index a72e4238d91b..df5ba802a566 100644
--- a/src/pages/workspace/categories/CategoryPayrollCodePage.tsx
+++ b/src/pages/workspace/categories/CategoryPayrollCodePage.tsx
@@ -38,7 +38,7 @@ function CategoryPayrollCodePage({route}: EditCategoryPageProps) {
if (newPayrollCode !== payrollCode) {
Category.setPolicyCategoryPayrollCode(route.params.policyID, categoryName, newPayrollCode);
}
- Navigation.dismissModal();
+ Navigation.goBack(ROUTES.WORKSPACE_CATEGORY_SETTINGS.getRoute(route.params.policyID, categoryName));
},
[categoryName, payrollCode, route.params.policyID],
);
diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPageEmptyState.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPageEmptyState.tsx
index 15ad69b3ba13..4d4a2927d194 100644
--- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPageEmptyState.tsx
+++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPageEmptyState.tsx
@@ -50,7 +50,7 @@ function WorkspaceExpensifyCardPageEmptyState({route, policy}: WorkspaceExpensif
const eligibleBankAccounts = CardUtils.getEligibleBankAccountsForCard(bankAccountList ?? {});
const reimbursementAccountStatus = reimbursementAccount?.achData?.state ?? '';
- const isSetupUnfinished = isEmptyObject(bankAccountList) && reimbursementAccountStatus !== CONST.BANK_ACCOUNT.STATE.OPEN;
+ const isSetupUnfinished = isEmptyObject(bankAccountList) && reimbursementAccountStatus && reimbursementAccountStatus !== CONST.BANK_ACCOUNT.STATE.OPEN;
const startFlow = useCallback(() => {
if (!eligibleBankAccounts.length || isSetupUnfinished) {
diff --git a/src/pages/workspace/expensifyCard/issueNew/AssigneeStep.tsx b/src/pages/workspace/expensifyCard/issueNew/AssigneeStep.tsx
index 3190c4ba295c..042e93ae2fae 100644
--- a/src/pages/workspace/expensifyCard/issueNew/AssigneeStep.tsx
+++ b/src/pages/workspace/expensifyCard/issueNew/AssigneeStep.tsx
@@ -22,7 +22,6 @@ import Navigation from '@navigation/Navigation';
import * as Card from '@userActions/Card';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
-import ROUTES from '@src/ROUTES';
import type * as OnyxTypes from '@src/types/onyx';
const MINIMUM_MEMBER_TO_SHOW_SEARCH = 8;
@@ -57,7 +56,7 @@ function AssigneeStep({policy}: AssigneeStepProps) {
Card.setIssueNewCardStepAndData({step: CONST.EXPENSIFY_CARD.STEP.CONFIRMATION, isEditing: false});
return;
}
- Navigation.navigate(ROUTES.WORKSPACE_EXPENSIFY_CARD.getRoute(policy?.id ?? '-1'));
+ Navigation.goBack();
Card.clearIssueNewCardFlow();
};
diff --git a/src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx b/src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx
index 75758e84e62c..aed246227d7d 100644
--- a/src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx
+++ b/src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx
@@ -18,6 +18,7 @@ import Navigation from '@navigation/Navigation';
import * as Card from '@userActions/Card';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import type {IssueNewCardStep} from '@src/types/onyx/Card';
type ConfirmationStepProps = {
@@ -36,7 +37,7 @@ function ConfirmationStep({policyID}: ConfirmationStepProps) {
const submit = () => {
Card.issueExpensifyCard(policyID, CONST.COUNTRY.US, data);
- Navigation.goBack();
+ Navigation.navigate(ROUTES.WORKSPACE_EXPENSIFY_CARD.getRoute(policyID ?? '-1'));
Card.clearIssueNewCardFlow();
};
diff --git a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx
index 2742033430ba..60216745c11e 100644
--- a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx
+++ b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx
@@ -75,12 +75,22 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM
const ownerDetails = personalDetails?.[policy?.ownerAccountID ?? -1] ?? ({} as PersonalDetails);
const policyOwnerDisplayName = ownerDetails.displayName ?? policy?.owner ?? '';
+ const memberCards = useMemo(() => {
+ if (!cardsList) {
+ return [];
+ }
+ return Object.values(cardsList).filter((card) => card.accountID === accountID);
+ }, [cardsList, accountID]);
+
const confirmModalPrompt = useMemo(() => {
const isApprover = Member.isApprover(policy, accountID);
if (!isApprover) {
return translate('workspace.people.removeMemberPrompt', {memberName: displayName});
}
- return translate('workspace.people.removeMembersWarningPrompt', {memberName: displayName, ownerName: policyOwnerDisplayName});
+ return translate('workspace.people.removeMembersWarningPrompt', {
+ memberName: displayName,
+ ownerName: policyOwnerDisplayName,
+ });
}, [accountID, policy, displayName, policyOwnerDisplayName, translate]);
const roleItems: ListItemType[] = useMemo(
@@ -259,7 +269,7 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM
{translate('walletPage.assignedCards')}
- {Object.values(cardsList ?? {}).map((card) => (
+ {memberCards.map((card) => (