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) => ( { - 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, diff --git a/src/pages/workspace/tags/TagGLCodePage.tsx b/src/pages/workspace/tags/TagGLCodePage.tsx index 895275e1c112..54e5c034ca07 100644 --- a/src/pages/workspace/tags/TagGLCodePage.tsx +++ b/src/pages/workspace/tags/TagGLCodePage.tsx @@ -18,6 +18,7 @@ import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import * as Tag from '@userActions/Policy/Tag'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import INPUT_IDS from '@src/types/form/WorkspaceTagForm'; import type {PolicyTagLists} from '@src/types/onyx'; @@ -45,7 +46,7 @@ function TagGLCodePage({route, policyTags}: EditTagGLCodePageProps) { if (newGLCode !== glCode) { Tag.setPolicyTagGLCode(route.params.policyID, tagName, orderWeight, newGLCode); } - Navigation.dismissModal(); + Navigation.goBack(ROUTES.WORKSPACE_TAG_SETTINGS.getRoute(route.params.policyID, orderWeight, tagName)); }, [glCode, route.params.policyID, tagName, orderWeight], ); diff --git a/src/pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage.tsx b/src/pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage.tsx index 704f1def7ad3..d026c218910f 100644 --- a/src/pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage.tsx @@ -1,5 +1,5 @@ import type {StackScreenProps} from '@react-navigation/stack'; -import React, {useState} from 'react'; +import React from 'react'; import type {ValueOf} from 'type-fest'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; @@ -52,17 +52,14 @@ function WorkspaceAutoReportingFrequencyPage({policy, route}: WorkspaceAutoRepor const {translate, preferredLocale, toLocaleOrdinal} = useLocalize(); const styles = useThemeStyles(); - const [isMonthlyFrequency, setIsMonthlyFrequency] = useState(autoReportingFrequency === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MONTHLY); const onSelectAutoReportingFrequency = (item: WorkspaceAutoReportingFrequencyPageItem) => { Policy.setWorkspaceAutoReportingFrequency(policy?.id ?? '-1', item.keyForList as AutoReportingFrequencyKey); if (item.keyForList === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MONTHLY) { - setIsMonthlyFrequency(true); return; } - setIsMonthlyFrequency(false); Navigation.goBack(); }; @@ -103,7 +100,7 @@ function WorkspaceAutoReportingFrequencyPage({policy, route}: WorkspaceAutoRepor text: getAutoReportingFrequencyDisplayNames(preferredLocale)[frequencyKey as AutoReportingFrequencyKey] || '', keyForList: frequencyKey, isSelected: frequencyKey === autoReportingFrequency, - footerContent: isMonthlyFrequency && frequencyKey === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MONTHLY ? monthlyFrequencyDetails() : null, + footerContent: frequencyKey === autoReportingFrequency && frequencyKey === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MONTHLY ? monthlyFrequencyDetails() : null, })); return ( @@ -137,6 +134,7 @@ function WorkspaceAutoReportingFrequencyPage({policy, route}: WorkspaceAutoRepor sections={[{data: autoReportingFrequencyItems}]} onSelectRow={onSelectAutoReportingFrequency} initiallyFocusedOptionKey={autoReportingFrequency} + shouldUpdateFocusedIndex />