From 087cbcddeb4ace851c591b571bb62da0b5492ee0 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Wed, 20 Mar 2024 15:09:31 +0300 Subject: [PATCH 001/769] implemented confirmed route for report preview --- .../ReportActionItemImages.tsx | 27 +++++++++++++------ .../ReportActionItem/ReportPreview.tsx | 2 +- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/components/ReportActionItem/ReportActionItemImages.tsx b/src/components/ReportActionItem/ReportActionItemImages.tsx index ffc12957dcb4..dc9ed0d371fb 100644 --- a/src/components/ReportActionItem/ReportActionItemImages.tsx +++ b/src/components/ReportActionItem/ReportActionItemImages.tsx @@ -2,11 +2,13 @@ import React from 'react'; import {View} from 'react-native'; import {Polygon, Svg} from 'react-native-svg'; +import ConfirmedRoute from '@components/ConfirmedRoute'; import Text from '@components/Text'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import type {ThumbnailAndImageURI} from '@libs/ReceiptUtils'; +import * as TransactionUtils from '@libs/TransactionUtils'; import variables from '@styles/variables'; import ReportActionItemImage from './ReportActionItemImage'; @@ -70,19 +72,28 @@ function ReportActionItemImages({images, size, total, isHovered = false}: Report // Show a border to separate multiple images. Shown to the right for each except the last. const shouldShowBorder = shownImages.length > 1 && index < shownImages.length - 1; const borderStyle = shouldShowBorder ? styles.reportActionItemImageBorder : {}; + const isDistanceRequest = TransactionUtils.isDistanceRequest(transaction); + const hasPendingWaypoints = transaction?.pendingFields?.waypoints; + const showMapAsImage = isDistanceRequest && hasPendingWaypoints; return ( - + {showMapAsImage ? ( + + + + ) : ( + + )} {isLastImage && remaining > 0 && ( diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index f1aa1751dd84..57fa568eb487 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -135,7 +135,7 @@ function ReportPreview({ const isScanning = hasReceipts && areAllRequestsBeingSmartScanned; const hasErrors = hasMissingSmartscanFields || (canUseViolations && ReportUtils.hasViolations(iouReportID, transactionViolations)); const lastThreeTransactionsWithReceipts = transactionsWithReceipts.slice(-3); - const lastThreeReceipts = lastThreeTransactionsWithReceipts.map((transaction) => ReceiptUtils.getThumbnailAndImageURIs(transaction)); + const lastThreeReceipts = lastThreeTransactionsWithReceipts.map((transaction) => ({...ReceiptUtils.getThumbnailAndImageURIs(transaction), transaction})); let formattedMerchant = numberOfRequests === 1 && hasReceipts ? TransactionUtils.getMerchant(transactionsWithReceipts[0]) : null; if (TransactionUtils.isPartialMerchant(formattedMerchant ?? '')) { From eb4b183fcfbcce82e4277c84dc1aeb1a62a2e480 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 21 Mar 2024 11:29:12 +0700 Subject: [PATCH 002/769] feature: Add validation flow to bank account set up --- src/languages/en.ts | 1 + src/languages/es.ts | 1 + src/libs/actions/User.ts | 7 +++++++ src/pages/ReimbursementAccount/BankAccountStep.js | 15 +++++++++++++++ 4 files changed, 24 insertions(+) diff --git a/src/languages/en.ts b/src/languages/en.ts index 29618b083bd5..60c051a289b1 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1413,6 +1413,7 @@ export default { validateAccountError: { phrase1: 'Hold up! We need you to validate your account first. To do so, ', phrase2: 'sign back in with a magic code', + phrase3: 'o verifique la cuenta aquí', }, hasPhoneLoginError: 'To add a verified bank account please ensure your primary login is a valid email and try again. You can add your phone number as a secondary login.', hasBeenThrottledError: 'There was an error adding your bank account. Please wait a few minutes and try again.', diff --git a/src/languages/es.ts b/src/languages/es.ts index 874921ee911a..811bfd2031d4 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1432,6 +1432,7 @@ export default { validateAccountError: { phrase1: '¡Un momento! Primero necesitas validar tu cuenta. Para hacerlo, ', phrase2: 'vuelve a iniciar sesión con un código mágico', + phrase3: '', }, hasPhoneLoginError: 'Para añadir una cuenta bancaria verificada, asegúrate de que tu nombre de usuario principal sea un correo electrónico válido y vuelve a intentarlo. Puedes añadir tu número de teléfono como nombre de usuario secundario.', diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index 2d23edfba93f..e2bc4791d465 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -390,6 +390,13 @@ function validateSecondaryLogin(contactMethod: string, validateCode: string) { isLoading: true, }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.USER, + value: { + validated: true, + }, + }, ]; const successData: OnyxUpdate[] = [ { diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index e8aacadc6e1a..0ebcb1fe891e 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -20,6 +20,7 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import compose from '@libs/compose'; import getPlaidDesktopMessage from '@libs/getPlaidDesktopMessage'; +import Navigation from '@libs/Navigation/Navigation'; import variables from '@styles/variables'; import * as BankAccounts from '@userActions/BankAccounts'; import * as Link from '@userActions/Link'; @@ -83,6 +84,7 @@ function BankAccountStep(props) { props.policyID, ROUTES.WORKSPACE_INITIAL.getRoute(props.policyID), )}`; + const loginNames = _.keys(props.loginList); const removeExistingBankAccountDetails = () => { const bankAccountData = { @@ -180,6 +182,16 @@ function BankAccountStep(props) { > {props.translate('bankAccount.validateAccountError.phrase2')} + { + const login = props.loginList[loginNames[0]]; + + Navigation.navigate(ROUTES.SETTINGS_CONTACT_METHOD_DETAILS.getRoute(login.partnerUserID || loginNames[0])); + }} + > + {props.translate('bankAccount.validateAccountError.phrase3')} + . @@ -221,5 +233,8 @@ export default compose( isPlaidDisabled: { key: ONYXKEYS.IS_PLAID_DISABLED, }, + loginList: { + key: ONYXKEYS.LOGIN_LIST, + }, }), )(BankAccountStep); From cd70586476cf318c6fc0b6da01d0ec7a12a28356 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Thu, 28 Mar 2024 22:50:35 +0300 Subject: [PATCH 003/769] minor fixes --- src/components/ReportActionItem/ReportActionItemImages.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/ReportActionItem/ReportActionItemImages.tsx b/src/components/ReportActionItem/ReportActionItemImages.tsx index 53560307b314..921bb2271c69 100644 --- a/src/components/ReportActionItem/ReportActionItemImages.tsx +++ b/src/components/ReportActionItem/ReportActionItemImages.tsx @@ -71,8 +71,8 @@ function ReportActionItemImages({images, size, total, isHovered = false}: Report // Show a border to separate multiple images. Shown to the right for each except the last. const shouldShowBorder = shownImages.length > 1 && index < shownImages.length - 1; const borderStyle = shouldShowBorder ? styles.reportActionItemImageBorder : {}; - const isDistanceRequest = TransactionUtils.isDistanceRequest(transaction); - const hasPendingWaypoints = transaction?.pendingFields?.waypoints; + const isDistanceRequest = transaction && TransactionUtils.isDistanceRequest(transaction); + const hasPendingWaypoints = transaction && TransactionUtils.isFetchingWaypointsFromServer(transaction); const showMapAsImage = isDistanceRequest && hasPendingWaypoints; return ( {showMapAsImage ? ( - + ) : ( From ec50a62af1ccfcda7df227f2efbedab5861ab590 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 3 Apr 2024 17:25:10 +0200 Subject: [PATCH 004/769] fix BaseGenericPressable defocusing after press --- .../Pressable/GenericPressable/BaseGenericPressable.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/Pressable/GenericPressable/BaseGenericPressable.tsx b/src/components/Pressable/GenericPressable/BaseGenericPressable.tsx index 9dda35f41e25..d7c7b922258c 100644 --- a/src/components/Pressable/GenericPressable/BaseGenericPressable.tsx +++ b/src/components/Pressable/GenericPressable/BaseGenericPressable.tsx @@ -85,12 +85,11 @@ function GenericPressable( if (shouldUseHapticsOnLongPress) { HapticFeedback.longPress(); } - if (ref && 'current' in ref) { + if (ref && 'current' in ref && nextFocusRef) { ref.current?.blur(); + Accessibility.moveAccessibilityFocus(nextFocusRef); } onLongPress(event); - - Accessibility.moveAccessibilityFocus(nextFocusRef); }, [shouldUseHapticsOnLongPress, onLongPress, nextFocusRef, ref, isDisabled], ); @@ -106,11 +105,11 @@ function GenericPressable( if (shouldUseHapticsOnPress) { HapticFeedback.press(); } - if (ref && 'current' in ref) { + if (ref && 'current' in ref && nextFocusRef) { ref.current?.blur(); + Accessibility.moveAccessibilityFocus(nextFocusRef); } const onPressResult = onPress(event); - Accessibility.moveAccessibilityFocus(nextFocusRef); return onPressResult; }, [shouldUseHapticsOnPress, onPress, nextFocusRef, ref, isDisabled], From 623f6cab3548c6e08b1ed56bc9110e3568193824 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 3 Apr 2024 17:25:53 +0200 Subject: [PATCH 005/769] add focus-trap-react package --- package-lock.json | 28 ++++++++++++++++++++++++++++ package.json | 3 ++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index e50cff0dbf27..a9a67f12a508 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,6 +55,7 @@ "expo-av": "~13.10.4", "expo-image": "1.11.0", "expo-image-manipulator": "11.8.0", + "focus-trap-react": "^10.2.3", "htmlparser2": "^7.2.0", "idb-keyval": "^6.2.1", "jest-expo": "50.0.1", @@ -28487,6 +28488,28 @@ "readable-stream": "^2.3.6" } }, + "node_modules/focus-trap": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.5.4.tgz", + "integrity": "sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==", + "dependencies": { + "tabbable": "^6.2.0" + } + }, + "node_modules/focus-trap-react": { + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/focus-trap-react/-/focus-trap-react-10.2.3.tgz", + "integrity": "sha512-YXBpFu/hIeSu6NnmV2xlXzOYxuWkoOtar9jzgp3lOmjWLWY59C/b8DtDHEAV4SPU07Nd/t+nS/SBNGkhUBFmEw==", + "dependencies": { + "focus-trap": "^7.5.4", + "tabbable": "^6.2.0" + }, + "peerDependencies": { + "prop-types": "^15.8.1", + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + } + }, "node_modules/follow-redirects": { "version": "1.15.5", "funding": [ @@ -43419,6 +43442,11 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" + }, "node_modules/table": { "version": "6.8.1", "dev": true, diff --git a/package.json b/package.json index d600f2dfc1bf..f11f25dcaafe 100644 --- a/package.json +++ b/package.json @@ -106,6 +106,7 @@ "expo-av": "~13.10.4", "expo-image": "1.11.0", "expo-image-manipulator": "11.8.0", + "focus-trap-react": "^10.2.3", "htmlparser2": "^7.2.0", "idb-keyval": "^6.2.1", "jest-expo": "50.0.1", @@ -248,8 +249,8 @@ "babel-plugin-transform-class-properties": "^6.24.1", "babel-plugin-transform-remove-console": "^6.9.4", "clean-webpack-plugin": "^4.0.0", - "copy-webpack-plugin": "^10.1.0", "concurrently": "^8.2.2", + "copy-webpack-plugin": "^10.1.0", "css-loader": "^6.7.2", "diff-so-fancy": "^1.3.0", "dotenv": "^16.0.3", From 770035987c28c14e5530a8b4034a7e01991b9c92 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 3 Apr 2024 17:26:21 +0200 Subject: [PATCH 006/769] add focus trap for screens and popovers --- .../FocusTrap/BOTTOM_TAB_SCREENS.ts | 5 ++ .../FocusTrapForModalProps.ts | 6 ++ .../FocusTrap/FocusTrapForModal/index.tsx | 9 +++ .../FocusTrap/FocusTrapForModal/index.web.tsx | 23 ++++++ .../FocusTrapForScreen/FocusTrapProps.ts | 5 ++ .../FocusTrap/FocusTrapForScreen/index.tsx | 9 +++ .../FocusTrapForScreen/index.web.tsx | 68 ++++++++++++++++ .../FocusTrap/SCREENS_WITH_AUTOFOCUS.ts | 15 ++++ .../FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts | 36 +++++++++ src/components/FocusTrap/sharedTrapStack.ts | 5 ++ src/components/PopoverMenu.tsx | 61 +++++++------- src/components/ScreenWrapper.tsx | 81 ++++++++++--------- .../Navigators/FullScreenNavigator.tsx | 31 +++---- 13 files changed, 272 insertions(+), 82 deletions(-) create mode 100644 src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts create mode 100644 src/components/FocusTrap/FocusTrapForModal/FocusTrapForModalProps.ts create mode 100644 src/components/FocusTrap/FocusTrapForModal/index.tsx create mode 100644 src/components/FocusTrap/FocusTrapForModal/index.web.tsx create mode 100644 src/components/FocusTrap/FocusTrapForScreen/FocusTrapProps.ts create mode 100644 src/components/FocusTrap/FocusTrapForScreen/index.tsx create mode 100644 src/components/FocusTrap/FocusTrapForScreen/index.web.tsx create mode 100644 src/components/FocusTrap/SCREENS_WITH_AUTOFOCUS.ts create mode 100644 src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts create mode 100644 src/components/FocusTrap/sharedTrapStack.ts diff --git a/src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts b/src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts new file mode 100644 index 000000000000..b62c3b563594 --- /dev/null +++ b/src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts @@ -0,0 +1,5 @@ +import SCREENS from '@src/SCREENS'; + +const BOTTOM_TAB_SCREENS: string[] = [SCREENS.HOME, SCREENS.SETTINGS.ROOT]; + +export default BOTTOM_TAB_SCREENS; diff --git a/src/components/FocusTrap/FocusTrapForModal/FocusTrapForModalProps.ts b/src/components/FocusTrap/FocusTrapForModal/FocusTrapForModalProps.ts new file mode 100644 index 000000000000..6bc2350a6c55 --- /dev/null +++ b/src/components/FocusTrap/FocusTrapForModal/FocusTrapForModalProps.ts @@ -0,0 +1,6 @@ +type FocusTrapForModalProps = { + children: React.ReactNode; + active: boolean; +}; + +export default FocusTrapForModalProps; diff --git a/src/components/FocusTrap/FocusTrapForModal/index.tsx b/src/components/FocusTrap/FocusTrapForModal/index.tsx new file mode 100644 index 000000000000..01632998b079 --- /dev/null +++ b/src/components/FocusTrap/FocusTrapForModal/index.tsx @@ -0,0 +1,9 @@ +import type FocusTrapForModalProps from './FocusTrapForModalProps'; + +function FocusTrapForModal({children}: FocusTrapForModalProps) { + return children; +} + +FocusTrapForModal.displayName = 'FocusTrapForModal'; + +export default FocusTrapForModal; diff --git a/src/components/FocusTrap/FocusTrapForModal/index.web.tsx b/src/components/FocusTrap/FocusTrapForModal/index.web.tsx new file mode 100644 index 000000000000..00fa87d3a38d --- /dev/null +++ b/src/components/FocusTrap/FocusTrapForModal/index.web.tsx @@ -0,0 +1,23 @@ +import FocusTrapOriginal from 'focus-trap-react'; +import React from 'react'; +import sharedTrapStack from '@components/FocusTrap/sharedTrapStack'; +import type FocusTrapForModalProps from './FocusTrapForModalProps'; + +function FocusTrapForModal({children, active}: FocusTrapForModalProps) { + return ( + + {children} + + ); +} + +FocusTrapForModal.displayName = 'FocusTrapForModal'; + +export default FocusTrapForModal; diff --git a/src/components/FocusTrap/FocusTrapForScreen/FocusTrapProps.ts b/src/components/FocusTrap/FocusTrapForScreen/FocusTrapProps.ts new file mode 100644 index 000000000000..d2f6e5323445 --- /dev/null +++ b/src/components/FocusTrap/FocusTrapForScreen/FocusTrapProps.ts @@ -0,0 +1,5 @@ +type FocusTrapForScreenProps = { + children: React.ReactNode; +}; + +export default FocusTrapForScreenProps; diff --git a/src/components/FocusTrap/FocusTrapForScreen/index.tsx b/src/components/FocusTrap/FocusTrapForScreen/index.tsx new file mode 100644 index 000000000000..58cb53448706 --- /dev/null +++ b/src/components/FocusTrap/FocusTrapForScreen/index.tsx @@ -0,0 +1,9 @@ +import type FocusTrapProps from './FocusTrapProps'; + +function FocusTrapView({children}: FocusTrapProps) { + return children; +} + +FocusTrapView.displayName = 'FocusTrapView'; + +export default FocusTrapView; diff --git a/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx b/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx new file mode 100644 index 000000000000..2e9a59096819 --- /dev/null +++ b/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx @@ -0,0 +1,68 @@ +import {useFocusEffect, useIsFocused, useRoute} from '@react-navigation/native'; +import FocusTrapOriginal from 'focus-trap-react'; +import React, {useMemo, useRef} from 'react'; +import BOTTOM_TAB_SCREENS from '@components/FocusTrap/BOTTOM_TAB_SCREENS'; +import SCREENS_WITH_AUTOFOCUS from '@components/FocusTrap/SCREENS_WITH_AUTOFOCUS'; +import sharedTrapStack from '@components/FocusTrap/sharedTrapStack'; +import WIDE_LAYOUT_INACTIVE_SCREENS from '@components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS'; +import useWindowDimensions from '@hooks/useWindowDimensions'; +import type FocusTrapProps from './FocusTrapProps'; + +let activeRouteName = ''; + +function FocusTrap({children}: FocusTrapProps) { + const isFocused = useIsFocused(); + const route = useRoute(); + const {isSmallScreenWidth} = useWindowDimensions(); + + const isActive = useMemo(() => { + // Focus trap can't be active on bottom tab screens because it would block access to the tab bar. + if (BOTTOM_TAB_SCREENS.includes(route.name)) { + return false; + } + + // Focus trap can't be active on these screens if the layout is wide because they may be displayed side by side. + if (WIDE_LAYOUT_INACTIVE_SCREENS.includes(route.name) && !isSmallScreenWidth) { + return false; + } + return true; + }, [isSmallScreenWidth, route]); + + useFocusEffect(() => { + activeRouteName = route.name; + }); + + const focusTrapRef = useRef(null); + + return ( + { + if (SCREENS_WITH_AUTOFOCUS.includes(activeRouteName)) { + return false; + } + return undefined; + }, + setReturnFocus: (element) => { + if (SCREENS_WITH_AUTOFOCUS.includes(activeRouteName)) { + return false; + } + return element; + }, + }} + > + {children} + + ); +} + +FocusTrap.displayName = 'FocusTrapView'; + +export default FocusTrap; diff --git a/src/components/FocusTrap/SCREENS_WITH_AUTOFOCUS.ts b/src/components/FocusTrap/SCREENS_WITH_AUTOFOCUS.ts new file mode 100644 index 000000000000..439c45a8bd00 --- /dev/null +++ b/src/components/FocusTrap/SCREENS_WITH_AUTOFOCUS.ts @@ -0,0 +1,15 @@ +import SCREENS from '@src/SCREENS'; + +const SCREENS_WITH_AUTOFOCUS: string[] = [ + SCREENS.WORKSPACE_SWITCHER.ROOT, + SCREENS.SEARCH_ROOT, + SCREENS.REPORT, + SCREENS.REPORT_DESCRIPTION_ROOT, + SCREENS.PRIVATE_NOTES.EDIT, + SCREENS.SETTINGS.PROFILE.STATUS, + SCREENS.SETTINGS.PROFILE.PRONOUNS, + SCREENS.NEW_TASK.DETAILS, + SCREENS.MONEY_REQUEST.CREATE, +]; + +export default SCREENS_WITH_AUTOFOCUS; diff --git a/src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts b/src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts new file mode 100644 index 000000000000..6815dcc455a9 --- /dev/null +++ b/src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts @@ -0,0 +1,36 @@ +import NAVIGATORS from '@src/NAVIGATORS'; +import SCREENS from '@src/SCREENS'; + +const WIDE_LAYOUT_INACTIVE_SCREENS: string[] = [ + NAVIGATORS.BOTTOM_TAB_NAVIGATOR, + SCREENS.HOME, + SCREENS.SETTINGS.ROOT, + SCREENS.REPORT, + SCREENS.SETTINGS.PROFILE.ROOT, + SCREENS.SETTINGS.PREFERENCES.ROOT, + SCREENS.SETTINGS.SECURITY, + SCREENS.SETTINGS.WALLET.ROOT, + SCREENS.SETTINGS.ABOUT, + SCREENS.SETTINGS.WORKSPACES, + + SCREENS.WORKSPACE.INITIAL, + + SCREENS.WORKSPACE.PROFILE, + SCREENS.WORKSPACE.CARD, + SCREENS.WORKSPACE.WORKFLOWS, + SCREENS.WORKSPACE.WORKFLOWS_APPROVER, + SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_FREQUENCY, + SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_MONTHLY_OFFSET, + SCREENS.WORKSPACE.REIMBURSE, + SCREENS.WORKSPACE.BILLS, + SCREENS.WORKSPACE.INVOICES, + SCREENS.WORKSPACE.TRAVEL, + SCREENS.WORKSPACE.MEMBERS, + SCREENS.WORKSPACE.CATEGORIES, + SCREENS.WORKSPACE.MORE_FEATURES, + SCREENS.WORKSPACE.TAGS, + SCREENS.WORKSPACE.TAXES, + SCREENS.WORKSPACE.DISTANCE_RATES, +]; + +export default WIDE_LAYOUT_INACTIVE_SCREENS; diff --git a/src/components/FocusTrap/sharedTrapStack.ts b/src/components/FocusTrap/sharedTrapStack.ts new file mode 100644 index 000000000000..9ee213c111fc --- /dev/null +++ b/src/components/FocusTrap/sharedTrapStack.ts @@ -0,0 +1,5 @@ +import type {FocusTrap as FocusTrapHandler} from 'focus-trap'; + +const trapStack: FocusTrapHandler[] = []; + +export default trapStack; diff --git a/src/components/PopoverMenu.tsx b/src/components/PopoverMenu.tsx index 1fd1c8ef5a3b..51bed834579a 100644 --- a/src/components/PopoverMenu.tsx +++ b/src/components/PopoverMenu.tsx @@ -9,6 +9,7 @@ import useWindowDimensions from '@hooks/useWindowDimensions'; import CONST from '@src/CONST'; import type {AnchorPosition} from '@src/styles'; import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; +import FocusTrapForModal from './FocusTrap/FocusTrapForModal'; import * as Expensicons from './Icon/Expensicons'; import type {MenuItemProps} from './MenuItem'; import MenuItem from './MenuItem'; @@ -189,35 +190,37 @@ function PopoverMenu({ withoutOverlay={withoutOverlay} shouldSetModalVisibility={shouldSetModalVisibility} > - - {!!headerText && {headerText}} - {enteredSubMenuIndexes.length > 0 && renderBackButtonItem()} - {currentMenuItems.map((item, menuIndex) => ( - selectItem(menuIndex)} - focused={focusedIndex === menuIndex} - displayInDefaultIconColor={item.displayInDefaultIconColor} - shouldShowRightIcon={item.shouldShowRightIcon} - shouldPutLeftPaddingWhenNoIcon={item.shouldPutLeftPaddingWhenNoIcon} - label={item.label} - isLabelHoverable={item.isLabelHoverable} - floatRightAvatars={item.floatRightAvatars} - floatRightAvatarSize={item.floatRightAvatarSize} - shouldShowSubscriptRightAvatar={item.shouldShowSubscriptRightAvatar} - disabled={item.disabled} - /> - ))} - + + + {!!headerText && {headerText}} + {enteredSubMenuIndexes.length > 0 && renderBackButtonItem()} + {currentMenuItems.map((item, menuIndex) => ( + selectItem(menuIndex)} + focused={focusedIndex === menuIndex} + displayInDefaultIconColor={item.displayInDefaultIconColor} + shouldShowRightIcon={item.shouldShowRightIcon} + shouldPutLeftPaddingWhenNoIcon={item.shouldPutLeftPaddingWhenNoIcon} + label={item.label} + isLabelHoverable={item.isLabelHoverable} + floatRightAvatars={item.floatRightAvatars} + floatRightAvatarSize={item.floatRightAvatarSize} + shouldShowSubscriptRightAvatar={item.shouldShowSubscriptRightAvatar} + disabled={item.disabled} + /> + ))} + + ); } diff --git a/src/components/ScreenWrapper.tsx b/src/components/ScreenWrapper.tsx index b78e274371ca..8ca5877e1d51 100644 --- a/src/components/ScreenWrapper.tsx +++ b/src/components/ScreenWrapper.tsx @@ -18,6 +18,7 @@ import type {CentralPaneNavigatorParamList, RootStackParamList} from '@libs/Navi import toggleTestToolsModal from '@userActions/TestTool'; import CONST from '@src/CONST'; import CustomDevMenu from './CustomDevMenu'; +import FocusTrapForScreens from './FocusTrap/FocusTrapForScreen'; import HeaderGap from './HeaderGap'; import KeyboardAvoidingView from './KeyboardAvoidingView'; import OfflineIndicator from './OfflineIndicator'; @@ -227,51 +228,53 @@ function ScreenWrapper( } return ( - + - - - - - {isDevelopment && } - { - // If props.children is a function, call it to provide the insets to the children. - typeof children === 'function' - ? children({ - insets, - safeAreaPaddingBottomStyle, - didScreenTransitionEnd, - }) - : children - } - {isSmallScreenWidth && shouldShowOfflineIndicator && } - {!isSmallScreenWidth && shouldShowOfflineIndicatorInWideScreen && ( - - )} - - + + + + {isDevelopment && } + { + // If props.children is a function, call it to provide the insets to the children. + typeof children === 'function' + ? children({ + insets, + safeAreaPaddingBottomStyle, + didScreenTransitionEnd, + }) + : children + } + {isSmallScreenWidth && shouldShowOfflineIndicator && } + {!isSmallScreenWidth && shouldShowOfflineIndicatorInWideScreen && ( + + )} + + + - + ); }} diff --git a/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx index 07b069462dd1..7631115f82b5 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx @@ -1,5 +1,6 @@ import React from 'react'; import {View} from 'react-native'; +import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; @@ -19,20 +20,22 @@ function FullScreenNavigator() { const screenOptions = getRootNavigatorScreenOptions(isSmallScreenWidth, styles, StyleUtils); return ( - - - - - - + + + + + + + + ); } From ee852a4fefb9e8c06253929b05544420c2d54237 Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Mon, 8 Apr 2024 13:17:08 +0200 Subject: [PATCH 007/769] fix back button --- src/CONST.ts | 2 ++ src/components/HeaderWithBackButton/index.tsx | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index e7358b382f14..45fe2018e9b0 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3161,6 +3161,8 @@ const CONST = { TIMER: 'timer', /** Use for toolbars containing action buttons or components. */ TOOLBAR: 'toolbar', + /** Use for navigation elements */ + NAVIGATION: 'navigation', }, TRANSLATION_KEYS: { ATTACHMENT: 'common.attachment', diff --git a/src/components/HeaderWithBackButton/index.tsx b/src/components/HeaderWithBackButton/index.tsx index f3293596aa46..6e6722744376 100755 --- a/src/components/HeaderWithBackButton/index.tsx +++ b/src/components/HeaderWithBackButton/index.tsx @@ -6,6 +6,7 @@ import Header from '@components/Header'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import PinButton from '@components/PinButton'; +import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; import ThreeDotsMenu from '@components/ThreeDotsMenu'; import Tooltip from '@components/Tooltip'; @@ -100,7 +101,7 @@ function HeaderWithBackButton({ } }} style={[styles.touchableButtonImage]} - role="button" + role={CONST.ROLE.NAVIGATION} accessibilityLabel={translate('common.back')} nativeID={CONST.BACK_BUTTON_NATIVE_ID} > From 4828b6270f4cc3a13661b272111fc525730c6c37 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Mon, 8 Apr 2024 21:01:55 +0300 Subject: [PATCH 008/769] Changed empty state route pending icon --- assets/images/emptystate__routepending.svg | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/assets/images/emptystate__routepending.svg b/assets/images/emptystate__routepending.svg index 90f3296d37d6..aba08554d02f 100644 --- a/assets/images/emptystate__routepending.svg +++ b/assets/images/emptystate__routepending.svg @@ -1 +1,18 @@ - \ No newline at end of file + + + + + + + + + From 77e3ca4cf5c1bdfbf8b60ac3fde93228a374ddf7 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Mon, 8 Apr 2024 21:14:46 +0300 Subject: [PATCH 009/769] add icon fill color --- src/components/DistanceMapView/index.android.tsx | 3 +++ src/components/MapView/PendingMapView.tsx | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/components/DistanceMapView/index.android.tsx b/src/components/DistanceMapView/index.android.tsx index 168a480c6100..629b05d7bccf 100644 --- a/src/components/DistanceMapView/index.android.tsx +++ b/src/components/DistanceMapView/index.android.tsx @@ -5,6 +5,7 @@ import * as Expensicons from '@components/Icon/Expensicons'; import MapView from '@components/MapView'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; +import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import type DistanceMapViewProps from './types'; @@ -13,6 +14,7 @@ function DistanceMapView({overlayStyle, ...rest}: DistanceMapViewProps) { const [isMapReady, setIsMapReady] = useState(false); const {isOffline} = useNetwork(); const {translate} = useLocalize(); + const theme = useTheme(); return ( <> @@ -33,6 +35,7 @@ function DistanceMapView({overlayStyle, ...rest}: DistanceMapViewProps) { title={translate('distance.mapPending.title')} subtitle={isOffline ? translate('distance.mapPending.subtitle') : translate('distance.mapPending.onlineSubtitle')} shouldShowLink={false} + iconColor={theme.border} /> )} diff --git a/src/components/MapView/PendingMapView.tsx b/src/components/MapView/PendingMapView.tsx index 32bf42a14b10..e729d03ad477 100644 --- a/src/components/MapView/PendingMapView.tsx +++ b/src/components/MapView/PendingMapView.tsx @@ -4,6 +4,7 @@ import {View} from 'react-native'; import BlockingView from '@components/BlockingViews/BlockingView'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; +import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import variables from '@styles/variables'; import type {PendingMapViewProps} from './MapViewTypes'; @@ -11,11 +12,13 @@ import type {PendingMapViewProps} from './MapViewTypes'; function PendingMapView({title = '', subtitle = '', style}: PendingMapViewProps) { const hasTextContent = !_.isEmpty(title) || !_.isEmpty(subtitle); const styles = useThemeStyles(); + const theme = useTheme(); return ( {hasTextContent ? ( )} From 420850de85d9ee701402a027b0692f42814432c7 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Mon, 8 Apr 2024 21:43:23 +0300 Subject: [PATCH 010/769] down sized icon for multiple previews --- src/components/ConfirmedRoute.tsx | 7 +++++-- src/components/MapView/MapViewTypes.ts | 3 +++ src/components/MapView/PendingMapView.tsx | 7 ++++--- src/components/ReportActionItem/ReportActionItemImages.tsx | 5 ++++- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/components/ConfirmedRoute.tsx b/src/components/ConfirmedRoute.tsx index 17c5097b8154..596fc74dbbf6 100644 --- a/src/components/ConfirmedRoute.tsx +++ b/src/components/ConfirmedRoute.tsx @@ -26,9 +26,12 @@ type ConfirmedRoutePropsOnyxProps = { type ConfirmedRouteProps = ConfirmedRoutePropsOnyxProps & { /** Transaction that stores the distance request data */ transaction: OnyxEntry; + + /** Whether the size of the route pending icon is small. */ + isSmallIcon?: boolean; }; -function ConfirmedRoute({mapboxAccessToken, transaction}: ConfirmedRouteProps) { +function ConfirmedRoute({mapboxAccessToken, transaction, isSmallIcon}: ConfirmedRouteProps) { const {isOffline} = useNetwork(); const {route0: route} = transaction?.routes ?? {}; const waypoints = transaction?.comment?.waypoints ?? {}; @@ -102,7 +105,7 @@ function ConfirmedRoute({mapboxAccessToken, transaction}: ConfirmedRouteProps) { styleURL={CONST.MAPBOX.STYLE_URL} /> ) : ( - + ); } diff --git a/src/components/MapView/MapViewTypes.ts b/src/components/MapView/MapViewTypes.ts index 3fa52c54339b..d5c903fdeccb 100644 --- a/src/components/MapView/MapViewTypes.ts +++ b/src/components/MapView/MapViewTypes.ts @@ -36,6 +36,9 @@ type PendingMapViewProps = { /** Style applied to PendingMapView */ style?: StyleProp; + + /** Whether the size of the route pending icon is small. */ + isSmallIcon?: boolean; }; // Initial state of the map diff --git a/src/components/MapView/PendingMapView.tsx b/src/components/MapView/PendingMapView.tsx index e729d03ad477..2c79a0446f5e 100644 --- a/src/components/MapView/PendingMapView.tsx +++ b/src/components/MapView/PendingMapView.tsx @@ -9,10 +9,11 @@ import useThemeStyles from '@hooks/useThemeStyles'; import variables from '@styles/variables'; import type {PendingMapViewProps} from './MapViewTypes'; -function PendingMapView({title = '', subtitle = '', style}: PendingMapViewProps) { +function PendingMapView({title = '', subtitle = '', style, isSmallIcon = false}: PendingMapViewProps) { const hasTextContent = !_.isEmpty(title) || !_.isEmpty(subtitle); const styles = useThemeStyles(); const theme = useTheme(); + const iconSize = isSmallIcon ? variables.iconSizeSuperLarge : variables.iconSizeUltraLarge; return ( {hasTextContent ? ( @@ -27,8 +28,8 @@ function PendingMapView({title = '', subtitle = '', style}: PendingMapViewProps) diff --git a/src/components/ReportActionItem/ReportActionItemImages.tsx b/src/components/ReportActionItem/ReportActionItemImages.tsx index 921bb2271c69..04f5e5e7fdbb 100644 --- a/src/components/ReportActionItem/ReportActionItemImages.tsx +++ b/src/components/ReportActionItem/ReportActionItemImages.tsx @@ -81,7 +81,10 @@ function ReportActionItemImages({images, size, total, isHovered = false}: Report > {showMapAsImage ? ( - + ) : ( Date: Tue, 9 Apr 2024 11:12:59 +0300 Subject: [PATCH 011/769] change ultra large icon size --- src/styles/variables.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/variables.ts b/src/styles/variables.ts index 309c90fc631e..e70d2bf5c575 100644 --- a/src/styles/variables.ts +++ b/src/styles/variables.ts @@ -81,7 +81,7 @@ export default { iconSizeXLarge: 28, iconSizeExtraLarge: 40, iconSizeSuperLarge: 60, - iconSizeUltraLarge: 120, + iconSizeUltraLarge: 80, iconBottomBar: 24, sidebarAvatarSize: 28, iconHeader: 48, From 3a7f04cdbaa1232244d5c1efe4f1c587c81f7d64 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Tue, 9 Apr 2024 13:02:58 +0300 Subject: [PATCH 012/769] changed background color --- src/styles/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/index.ts b/src/styles/index.ts index f165974119ff..d775fa04920a 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -4341,7 +4341,7 @@ const styles = (theme: ThemeColors) => }, mapPendingView: { - backgroundColor: theme.highlightBG, + backgroundColor: theme.hoverComponentBG, ...flex.flex1, borderRadius: variables.componentBorderRadiusLarge, }, From 05f1ad6d0d50a45b188c4d8fccd8f72788205fc6 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Thu, 11 Apr 2024 19:19:37 +0800 Subject: [PATCH 013/769] navigate back when delete modal hides --- src/components/MoneyReportHeader.tsx | 18 +++++++++++++----- src/components/MoneyRequestHeader.tsx | 17 +++++++++++++---- src/libs/actions/IOU.ts | 7 +++---- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 14227d6a2051..5d68440266f3 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useEffect, useMemo, useState} from 'react'; +import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; @@ -13,7 +13,7 @@ import * as ReportUtils from '@libs/ReportUtils'; import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; +import ROUTES, { Route } from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -83,6 +83,8 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money const isDraft = ReportUtils.isOpenExpenseReport(moneyRequestReport); const [isConfirmModalVisible, setIsConfirmModalVisible] = useState(false); + const navigateBackToAfterDelete = useRef(); + const cancelPayment = useCallback(() => { if (!chatReport) { return; @@ -136,10 +138,10 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money if (requestParentReportAction) { const iouTransactionID = requestParentReportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? requestParentReportAction.originalMessage?.IOUTransactionID ?? '' : ''; if (ReportActionsUtils.isTrackExpenseAction(requestParentReportAction)) { - IOU.deleteTrackExpense(moneyRequestReport?.reportID ?? '', iouTransactionID, requestParentReportAction, true); - return; + navigateBackToAfterDelete.current = IOU.deleteTrackExpense(moneyRequestReport?.reportID ?? '', iouTransactionID, requestParentReportAction, true); + } else { + navigateBackToAfterDelete.current = IOU.deleteMoneyRequest(iouTransactionID, requestParentReportAction, true); } - IOU.deleteMoneyRequest(iouTransactionID, requestParentReportAction, true); } setIsDeleteRequestModalVisible(false); @@ -292,6 +294,12 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money isVisible={isDeleteRequestModalVisible} onConfirm={deleteTransaction} onCancel={() => setIsDeleteRequestModalVisible(false)} + onModalHide={() => { + if (!navigateBackToAfterDelete.current) { + return; + } + Navigation.goBack(navigateBackToAfterDelete.current) + }} prompt={translate('iou.deleteConfirmation')} confirmText={translate('common.delete')} cancelText={translate('common.cancel')} diff --git a/src/components/MoneyRequestHeader.tsx b/src/components/MoneyRequestHeader.tsx index f451f5f15581..2aea42d46503 100644 --- a/src/components/MoneyRequestHeader.tsx +++ b/src/components/MoneyRequestHeader.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useEffect, useState} from 'react'; +import React, {useCallback, useEffect, useRef, useState} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; @@ -14,6 +14,7 @@ import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type {Route} from '@src/ROUTES'; import type {Policy, Report, ReportAction, ReportActions, Session, Transaction} from '@src/types/onyx'; import type {OriginalMessageIOU} from '@src/types/onyx/OriginalMessage'; import ConfirmModal from './ConfirmModal'; @@ -63,6 +64,8 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, const isOnHold = TransactionUtils.isOnHold(transaction); const {isSmallScreenWidth, windowWidth} = useWindowDimensions(); + const navigateBackToAfterDelete = useRef(); + // Only the requestor can take delete the request, admins can only edit it. const isActionOwner = typeof parentReportAction?.actorAccountID === 'number' && typeof session?.accountID === 'number' && parentReportAction.actorAccountID === session?.accountID; const isPolicyAdmin = policy?.role === CONST.POLICY.ROLE.ADMIN; @@ -72,10 +75,10 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, if (parentReportAction) { const iouTransactionID = parentReportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? parentReportAction.originalMessage?.IOUTransactionID ?? '' : ''; if (ReportActionsUtils.isTrackExpenseAction(parentReportAction)) { - IOU.deleteTrackExpense(parentReport?.reportID ?? '', iouTransactionID, parentReportAction, true); - return; + navigateBackToAfterDelete.current = IOU.deleteTrackExpense(parentReport?.reportID ?? '', iouTransactionID, parentReportAction, true); + } else { + navigateBackToAfterDelete.current = IOU.deleteMoneyRequest(iouTransactionID, parentReportAction, true); } - IOU.deleteMoneyRequest(iouTransactionID, parentReportAction, true); } setIsDeleteModalVisible(false); @@ -200,6 +203,12 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, isVisible={isDeleteModalVisible} onConfirm={deleteTransaction} onCancel={() => setIsDeleteModalVisible(false)} + onModalHide={() => { + if (!navigateBackToAfterDelete.current) { + return; + } + Navigation.goBack(navigateBackToAfterDelete.current) + }} prompt={translate('iou.deleteConfirmation')} confirmText={translate('common.delete')} cancelText={translate('common.cancel')} diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index c2d462bbc4a8..ab50e709a972 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -4133,13 +4133,12 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor // STEP 7: Navigate the user depending on which page they are on and which resources were deleted if (iouReport && isSingleTransactionView && shouldDeleteTransactionThread && !shouldDeleteIOUReport) { // Pop the deleted report screen before navigating. This prevents navigating to the Concierge chat due to the missing report. - Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(iouReport.reportID)); - return; + return ROUTES.REPORT_WITH_ID.getRoute(iouReport.reportID); } if (iouReport?.chatReportID && shouldDeleteIOUReport) { // Pop the deleted report screen before navigating. This prevents navigating to the Concierge chat due to the missing report. - Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(iouReport.chatReportID)); + return ROUTES.REPORT_WITH_ID.getRoute(iouReport.chatReportID); } } @@ -4304,7 +4303,7 @@ function deleteTrackExpense(chatReportID: string, transactionID: string, reportA // STEP 7: Navigate the user depending on which page they are on and which resources were deleted if (isSingleTransactionView && shouldDeleteTransactionThread) { // Pop the deleted report screen before navigating. This prevents navigating to the Concierge chat due to the missing report. - Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(chatReport?.reportID ?? '')); + return ROUTES.REPORT_WITH_ID.getRoute(chatReport?.reportID ?? ''); } } From 23d62ea94184a054843ec5c3b20f273ceea6327c Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Thu, 11 Apr 2024 22:42:57 +0300 Subject: [PATCH 014/769] fix border radius --- src/components/ConfirmedRoute.tsx | 7 ++++++- src/styles/utils/index.ts | 8 ++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/components/ConfirmedRoute.tsx b/src/components/ConfirmedRoute.tsx index 596fc74dbbf6..fb0b4ddbb534 100644 --- a/src/components/ConfirmedRoute.tsx +++ b/src/components/ConfirmedRoute.tsx @@ -3,6 +3,7 @@ import type {ReactNode} from 'react'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import useNetwork from '@hooks/useNetwork'; +import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import * as TransactionUtils from '@libs/TransactionUtils'; @@ -38,6 +39,7 @@ function ConfirmedRoute({mapboxAccessToken, transaction, isSmallIcon}: Confirmed const coordinates = route?.geometry?.coordinates ?? []; const theme = useTheme(); const styles = useThemeStyles(); + const StyleUtils = useStyleUtils(); const getMarkerComponent = useCallback( (icon: IconAsset): ReactNode => ( @@ -105,7 +107,10 @@ function ConfirmedRoute({mapboxAccessToken, transaction, isSmallIcon}: Confirmed styleURL={CONST.MAPBOX.STYLE_URL} /> ) : ( - + ); } diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts index e9efc84e8807..dd66a72faafa 100644 --- a/src/styles/utils/index.ts +++ b/src/styles/utils/index.ts @@ -419,6 +419,13 @@ function getBackgroundAndBorderStyle(backgroundColor: ColorValue | undefined): V }; } +/** + * Returns a style with the specified borderRadius + */ +function getBorderRadiusStyle(borderRadius: number): ViewStyle { + return {borderRadius}; +} + /** * Returns a style with the specified backgroundColor */ @@ -1108,6 +1115,7 @@ const staticStyleUtils = { getAvatarSize, getAvatarWidthStyle, getBackgroundAndBorderStyle, + getBorderRadiusStyle, getBackgroundColorStyle, getBackgroundColorWithOpacityStyle, getPaddingLeft, From b7cdaf83cbf947f9566005bca083f08e1a0047b9 Mon Sep 17 00:00:00 2001 From: gijoe0295 Date: Fri, 12 Apr 2024 04:04:11 +0700 Subject: [PATCH 015/769] feat: surfacing potential duplicates --- src/components/HoldBanner.tsx | 11 +++++-- src/components/MoneyRequestHeader.tsx | 29 +++++++++++++++-- src/languages/en.ts | 2 ++ src/languages/es.ts | 2 ++ src/libs/Permissions.ts | 2 +- src/libs/TransactionUtils.ts | 47 +++++++++++++++++++++++++-- src/types/onyx/Transaction.ts | 2 ++ 7 files changed, 87 insertions(+), 8 deletions(-) diff --git a/src/components/HoldBanner.tsx b/src/components/HoldBanner.tsx index af77d9076629..5376087ba849 100644 --- a/src/components/HoldBanner.tsx +++ b/src/components/HoldBanner.tsx @@ -5,14 +5,19 @@ import useThemeStyles from '@hooks/useThemeStyles'; import Text from './Text'; import TextPill from './TextPill'; -function HoldBanner() { +type HoldBannerProps = { + isRequestDuplicate?: boolean; + shouldShowBorderBottom?: boolean; +}; + +function HoldBanner({isRequestDuplicate = false, shouldShowBorderBottom = false}: HoldBannerProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); return ( - + {translate('iou.hold')} - {translate('iou.requestOnHold')} + {isRequestDuplicate ? translate('iou.requestDuplicate') : translate('iou.requestOnHold')} ); } diff --git a/src/components/MoneyRequestHeader.tsx b/src/components/MoneyRequestHeader.tsx index f451f5f15581..6588b8167e62 100644 --- a/src/components/MoneyRequestHeader.tsx +++ b/src/components/MoneyRequestHeader.tsx @@ -16,6 +16,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Policy, Report, ReportAction, ReportActions, Session, Transaction} from '@src/types/onyx'; import type {OriginalMessageIOU} from '@src/types/onyx/OriginalMessage'; +import Button from './Button'; import ConfirmModal from './ConfirmModal'; import HeaderWithBackButton from './HeaderWithBackButton'; import HoldBanner from './HoldBanner'; @@ -61,6 +62,7 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, const isSettled = ReportUtils.isSettled(moneyRequestReport?.reportID); const isApproved = ReportUtils.isReportApproved(moneyRequestReport); const isOnHold = TransactionUtils.isOnHold(transaction); + const isDuplicate = TransactionUtils.isDuplicate(transaction?.transactionID ?? ''); const {isSmallScreenWidth, windowWidth} = useWindowDimensions(); // Only the requestor can take delete the request, admins can only edit it. @@ -178,7 +180,15 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, policy={policy} shouldShowBackButton={isSmallScreenWidth} onBackButtonPress={() => Navigation.goBack(undefined, false, true)} - /> + > + {isDuplicate && !isSmallScreenWidth && ( +