From ec50a62af1ccfcda7df227f2efbedab5861ab590 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 3 Apr 2024 17:25:10 +0200 Subject: [PATCH 001/144] 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 002/144] 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 003/144] 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 004/144] 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 3b45b392f04b677ca39a59e4b90f3c206c3d5293 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 17 Apr 2024 15:16:23 +0700 Subject: [PATCH 005/144] animate sign-in pages --- assets/animations/Abracadabra.lottie | Bin 0 -> 15694 bytes assets/animations/MagicCode.lottie | Bin 0 -> 21405 bytes src/components/LottieAnimations/index.tsx | 10 ++++++++++ .../ValidateCode/JustSignedInModal.tsx | 13 ++++++++----- .../ValidateCode/ValidateCodeModal.tsx | 13 ++++++++----- src/styles/index.ts | 9 +++++++++ 6 files changed, 35 insertions(+), 10 deletions(-) create mode 100644 assets/animations/Abracadabra.lottie create mode 100644 assets/animations/MagicCode.lottie diff --git a/assets/animations/Abracadabra.lottie b/assets/animations/Abracadabra.lottie new file mode 100644 index 0000000000000000000000000000000000000000..8805aed1944e6a00a0ebcb33496f36a122e9df37 GIT binary patch literal 15694 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 WRgwjV_=g4L@0s)Wp2hc1?*9OB|0t3G literal 0 HcmV?d00001 diff --git a/assets/animations/MagicCode.lottie b/assets/animations/MagicCode.lottie new file mode 100644 index 0000000000000000000000000000000000000000..ea94f1138f97e960e9254b08c8176590cce7a9dd GIT binary patch literal 21405 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 UU{th!O+o(a*?;4q#=o-v0Wb!wc>n+a literal 0 HcmV?d00001 diff --git a/src/components/LottieAnimations/index.tsx b/src/components/LottieAnimations/index.tsx index 18cb9188d60c..c4c76ec8cc95 100644 --- a/src/components/LottieAnimations/index.tsx +++ b/src/components/LottieAnimations/index.tsx @@ -3,6 +3,11 @@ import variables from '@styles/variables'; import type DotLottieAnimation from './types'; const DotLottieAnimations = { + Abracadabra: { + file: require('@assets/animations/Abracadabra.lottie'), + w: 375, + h: 400, + }, FastMoney: { file: require('@assets/animations/FastMoney.lottie'), w: 375, @@ -46,6 +51,11 @@ const DotLottieAnimations = { h: 400, backgroundColor: colors.ice500, }, + MagicCode: { + file: require('@assets/animations/MagicCode.lottie'), + w: 200, + h: 164, + }, Magician: { file: require('@assets/animations/Magician.lottie'), w: 853, diff --git a/src/components/ValidateCode/JustSignedInModal.tsx b/src/components/ValidateCode/JustSignedInModal.tsx index 19e67b0c56fe..923ea14a3f51 100644 --- a/src/components/ValidateCode/JustSignedInModal.tsx +++ b/src/components/ValidateCode/JustSignedInModal.tsx @@ -2,7 +2,8 @@ import React from 'react'; import {View} from 'react-native'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; -import * as Illustrations from '@components/Icon/Illustrations'; +import Lottie from '@components/Lottie'; +import LottieAnimations from '@components/LottieAnimations'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; @@ -22,10 +23,12 @@ function JustSignedInModal({is2FARequired}: JustSignedInModalProps) { - diff --git a/src/components/ValidateCode/ValidateCodeModal.tsx b/src/components/ValidateCode/ValidateCodeModal.tsx index 1e42773c2dc2..07fc8cb7167e 100644 --- a/src/components/ValidateCode/ValidateCodeModal.tsx +++ b/src/components/ValidateCode/ValidateCodeModal.tsx @@ -4,7 +4,8 @@ import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; -import * as Illustrations from '@components/Icon/Illustrations'; +import Lottie from '@components/Lottie'; +import LottieAnimations from '@components/LottieAnimations'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; @@ -37,10 +38,12 @@ function ValidateCodeModal({code, accountID, session = {}}: ValidateCodeModalPro - {translate('validateCodeModal.title')} diff --git a/src/styles/index.ts b/src/styles/index.ts index 537038d9f2e1..fee143b2a95c 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -4294,6 +4294,15 @@ const styles = (theme: ThemeColors) => borderColor: theme.highlightBG, borderWidth: 2, }, + + magicCodeAnimationWidth: { + width: variables.modalTopIconWidth, + }, + + justSignedInModalAnimationHeight: (is2FARequired: boolean) => ({ + height: is2FARequired ? variables.modalTopIconHeight : variables.modalTopBigIconHeight, + }), + moneyRequestViewImage: { ...spacing.mh5, ...spacing.mv3, From 1e0e916ffc25a7573657d1680f3c859fe6ddb326 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Wed, 17 Apr 2024 21:49:04 +0200 Subject: [PATCH 006/144] feat: verify identity step setup --- .../VerifyIdentity/VerifyIdentity.tsx | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 src/pages/EnablePayments/VerifyIdentity/VerifyIdentity.tsx diff --git a/src/pages/EnablePayments/VerifyIdentity/VerifyIdentity.tsx b/src/pages/EnablePayments/VerifyIdentity/VerifyIdentity.tsx new file mode 100644 index 000000000000..f402f52255ab --- /dev/null +++ b/src/pages/EnablePayments/VerifyIdentity/VerifyIdentity.tsx @@ -0,0 +1,120 @@ +import React, {useCallback} from 'react'; +import {View} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; +import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import InteractiveStepSubHeader from '@components/InteractiveStepSubHeader'; +import Onfido from '@components/Onfido'; +import type {OnfidoData} from '@components/Onfido/types'; +import ScreenWrapper from '@components/ScreenWrapper'; +import ScrollView from '@components/ScrollView'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Growl from '@libs/Growl'; +import * as BankAccounts from '@userActions/BankAccounts'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {PersonalBankAccount, WalletOnfido} from '@src/types/onyx'; + +const DEFAULT_WALLET_ONFIDO_DATA = { + loading: false, + hasAcceptedPrivacyPolicy: false, +}; + +type VerifyIdentityOnyxProps = { + /** Reimbursement account from ONYX */ + personalBankAccount: OnyxEntry; + + /** Onfido applicant ID from ONYX */ + onfidoApplicantID: OnyxEntry; + + /** The token required to initialize the Onfido SDK */ + onfidoToken: OnyxEntry; + + /** The wallet onfido data */ + walletOnfidoData: OnyxEntry; +}; + +type VerifyIdentityProps = VerifyIdentityOnyxProps & { + /** Goes to the previous step */ + onBackButtonPress: () => void; +}; + +const ONFIDO_ERROR_DISPLAY_DURATION = 10000; + +function VerifyIdentity({personalBankAccount, onBackButtonPress, onfidoApplicantID, onfidoToken, walletOnfidoData = DEFAULT_WALLET_ONFIDO_DATA}: VerifyIdentityProps) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + + const handleOnfidoSuccess = useCallback( + (onfidoData: OnfidoData) => { + BankAccounts.verifyIdentity({ + onfidoData: JSON.stringify({ + ...onfidoData, + applicantID: walletOnfidoData?.applicantID, + }), + }); + BankAccounts.updateAddPersonalBankAccountDraft({isOnfidoSetupComplete: true}); + }, + [personalBankAccount, onfidoApplicantID], + ); + + const handleOnfidoError = () => { + // In case of any unexpected error we log it to the server, show a growl, and return the user back to the requestor step so they can try again. + Growl.error(translate('onfidoStep.genericError'), ONFIDO_ERROR_DISPLAY_DURATION); + BankAccounts.clearOnfidoToken(); + // BankAccounts.goToWithdrawalAccountSetupStep(CONST.BANK_ACCOUNT.STEP.REQUESTOR); + }; + + const handleOnfidoUserExit = () => { + BankAccounts.clearOnfidoToken(); + // BankAccounts.goToWithdrawalAccountSetupStep(CONST.BANK_ACCOUNT.STEP.REQUESTOR); + }; + + return ( + + + + + + + + + + + + ); +} + +VerifyIdentity.displayName = 'VerifyIdentity'; + +export default withOnyx({ + // @ts-expect-error: ONYXKEYS.PERSONAL_BANK_ACCOUNT is conflicting with ONYXKEYS.FORMS.PERSONAL_BANK_ACCOUNT_FORM + personalBankAccount: { + key: ONYXKEYS.PERSONAL_BANK_ACCOUNT, + }, + onfidoApplicantID: { + key: ONYXKEYS.ONFIDO_APPLICANT_ID, + }, + onfidoToken: { + key: ONYXKEYS.ONFIDO_TOKEN, + }, + walletOnfidoData: { + key: ONYXKEYS.WALLET_ONFIDO, + + // Let's get a new onfido token each time the user hits this flow (as it should only be once) + initWithStoredValues: false, + }, +})(VerifyIdentity); From 987f3f783283cc2be16b12346a601c9971d2a759 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 24 Apr 2024 18:30:56 +0700 Subject: [PATCH 007/144] rename variables --- src/components/ValidateCode/JustSignedInModal.tsx | 4 ++-- src/components/ValidateCode/ValidateCodeModal.tsx | 4 ++-- src/styles/index.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/ValidateCode/JustSignedInModal.tsx b/src/components/ValidateCode/JustSignedInModal.tsx index 923ea14a3f51..527493c778cb 100644 --- a/src/components/ValidateCode/JustSignedInModal.tsx +++ b/src/components/ValidateCode/JustSignedInModal.tsx @@ -25,8 +25,8 @@ function JustSignedInModal({is2FARequired}: JustSignedInModalProps) { diff --git a/src/components/ValidateCode/ValidateCodeModal.tsx b/src/components/ValidateCode/ValidateCodeModal.tsx index 07fc8cb7167e..a1d5c4ff3faa 100644 --- a/src/components/ValidateCode/ValidateCodeModal.tsx +++ b/src/components/ValidateCode/ValidateCodeModal.tsx @@ -40,8 +40,8 @@ function ValidateCodeModal({code, accountID, session = {}}: ValidateCodeModalPro diff --git a/src/styles/index.ts b/src/styles/index.ts index a579df46b8e4..bb30e5cf279d 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -4364,11 +4364,11 @@ const styles = (theme: ThemeColors) => borderWidth: 2, }, - magicCodeAnimationWidth: { + magicCodeAnimation: { width: variables.modalTopIconWidth, }, - justSignedInModalAnimationHeight: (is2FARequired: boolean) => ({ + justSignedInModalAnimation: (is2FARequired: boolean) => ({ height: is2FARequired ? variables.modalTopIconHeight : variables.modalTopBigIconHeight, }), From 7f2598766711bd79a98054b6cf5a35dfa6540564 Mon Sep 17 00:00:00 2001 From: Jan Nowakowski Date: Tue, 7 May 2024 09:45:18 +0200 Subject: [PATCH 008/144] Add focus trap to report context menu --- .../FocusTrapForScreen/index.web.tsx | 5 +- .../BaseReportActionContextMenu.tsx | 119 +++++++++--------- 2 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx b/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx index 2e9a59096819..3dd12f232d25 100644 --- a/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx +++ b/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx @@ -1,6 +1,6 @@ import {useFocusEffect, useIsFocused, useRoute} from '@react-navigation/native'; import FocusTrapOriginal from 'focus-trap-react'; -import React, {useMemo, useRef} from 'react'; +import React, {useMemo} 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'; @@ -32,11 +32,8 @@ function FocusTrap({children}: FocusTrapProps) { activeRouteName = route.name; }); - const focusTrapRef = useRef(null); - return ( - {filteredContextMenuActions.map((contextAction, index) => { - const closePopup = !isMini; - const payload: ContextMenuActionPayload = { - reportAction: reportAction as ReportAction, - reportID, - draftMessage, - selection, - close: () => setShouldKeepOpen(false), - openContextMenu: () => setShouldKeepOpen(true), - interceptAnonymousUser, - openOverflowMenu, - setIsEmojiPickerActive, - }; - - if ('renderContent' in contextAction) { - return contextAction.renderContent(closePopup, payload); - } - - const {textTranslateKey} = contextAction; - const isKeyInActionUpdateKeys = - textTranslateKey === 'reportActionContextMenu.editAction' || - textTranslateKey === 'reportActionContextMenu.deleteAction' || - textTranslateKey === 'reportActionContextMenu.deleteConfirmation'; - const text = textTranslateKey && (isKeyInActionUpdateKeys ? translate(textTranslateKey, {action: reportAction}) : translate(textTranslateKey)); - const transactionPayload = textTranslateKey === 'reportActionContextMenu.copyToClipboard' && transaction && {transaction}; - const isMenuAction = textTranslateKey === 'reportActionContextMenu.menu'; - - return ( - { - menuItemRefs.current[index] = ref; - }} - buttonRef={isMenuAction ? threedotRef : {current: null}} - icon={contextAction.icon} - text={text ?? ''} - successIcon={contextAction.successIcon} - successText={contextAction.successTextTranslateKey ? translate(contextAction.successTextTranslateKey) : undefined} - isMini={isMini} - key={contextAction.textTranslateKey} - onPress={(event) => - interceptAnonymousUser( - () => contextAction.onPress?.(closePopup, {...payload, ...transactionPayload, event, ...(isMenuAction ? {anchorRef: threedotRef} : {})}), - contextAction.isAnonymousAction, - ) - } - description={contextAction.getDescription?.(selection) ?? ''} - isAnonymousAction={contextAction.isAnonymousAction} - isFocused={focusedIndex === index} - shouldPreventDefaultFocusOnPress={contextAction.shouldPreventDefaultFocusOnPress} - onFocus={() => setFocusedIndex(index)} - /> - ); - })} - + + + {filteredContextMenuActions.map((contextAction, index) => { + const closePopup = !isMini; + const payload: ContextMenuActionPayload = { + reportAction: reportAction as ReportAction, + reportID, + draftMessage, + selection, + close: () => setShouldKeepOpen(false), + openContextMenu: () => setShouldKeepOpen(true), + interceptAnonymousUser, + openOverflowMenu, + setIsEmojiPickerActive, + }; + + if ('renderContent' in contextAction) { + return contextAction.renderContent(closePopup, payload); + } + + const {textTranslateKey} = contextAction; + const isKeyInActionUpdateKeys = + textTranslateKey === 'reportActionContextMenu.editAction' || + textTranslateKey === 'reportActionContextMenu.deleteAction' || + textTranslateKey === 'reportActionContextMenu.deleteConfirmation'; + const text = textTranslateKey && (isKeyInActionUpdateKeys ? translate(textTranslateKey, {action: reportAction}) : translate(textTranslateKey)); + const transactionPayload = textTranslateKey === 'reportActionContextMenu.copyToClipboard' && transaction && {transaction}; + const isMenuAction = textTranslateKey === 'reportActionContextMenu.menu'; + + return ( + { + menuItemRefs.current[index] = ref; + }} + buttonRef={isMenuAction ? threedotRef : {current: null}} + icon={contextAction.icon} + text={text ?? ''} + successIcon={contextAction.successIcon} + successText={contextAction.successTextTranslateKey ? translate(contextAction.successTextTranslateKey) : undefined} + isMini={isMini} + key={contextAction.textTranslateKey} + onPress={(event) => + interceptAnonymousUser( + () => contextAction.onPress?.(closePopup, {...payload, ...transactionPayload, event, ...(isMenuAction ? {anchorRef: threedotRef} : {})}), + contextAction.isAnonymousAction, + ) + } + description={contextAction.getDescription?.(selection) ?? ''} + isAnonymousAction={contextAction.isAnonymousAction} + isFocused={focusedIndex === index} + shouldPreventDefaultFocusOnPress={contextAction.shouldPreventDefaultFocusOnPress} + onFocus={() => setFocusedIndex(index)} + /> + ); + })} + + ) ); } From ca6201f94fdf16b0977ea208b746ee0da495dde0 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Tue, 7 May 2024 15:13:55 +0200 Subject: [PATCH 009/144] refactor: wip - connect all the steps --- .../ModalStackNavigators/index.tsx | 4 +- .../AddBankAccount/AddBankAccount.tsx | 2 +- src/pages/EnablePayments/EnablePayments.tsx | 102 ++++++++++++++++++ .../PersonalInfo/PersonalInfo.tsx | 30 +++--- .../VerifyIdentity/VerifyIdentity.tsx | 16 +-- 5 files changed, 126 insertions(+), 28 deletions(-) create mode 100644 src/pages/EnablePayments/EnablePayments.tsx diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index ce8ea271182d..b9c1e94f0497 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -216,9 +216,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/settings/Wallet/ChooseTransferAccountPage').default as React.ComponentType, [SCREENS.SETTINGS.WALLET.ENABLE_PAYMENTS]: () => require('../../../../pages/EnablePayments/EnablePaymentsPage').default as React.ComponentType, // TODO: Added temporarily for testing purposes, remove after refactor - https://github.com/Expensify/App/issues/36648 - [SCREENS.SETTINGS.WALLET.ENABLE_PAYMENTS_REFACTOR]: () => require('../../../../pages/EnablePayments/PersonalInfo/PersonalInfo').default as React.ComponentType, - // TODO: Added temporarily for testing purposes, remove after refactor - https://github.com/Expensify/App/issues/36648 - [SCREENS.SETTINGS.WALLET.ENABLE_PAYMENTS_TEMPORARY_TERMS]: () => require('../../../../pages/EnablePayments/FeesAndTerms/FeesAndTerms').default as React.ComponentType, + [SCREENS.SETTINGS.WALLET.ENABLE_PAYMENTS_REFACTOR]: () => require('../../../../pages/EnablePayments/EnablePayments').default as React.ComponentType, [SCREENS.SETTINGS.ADD_DEBIT_CARD]: () => require('../../../../pages/settings/Wallet/AddDebitCardPage').default as React.ComponentType, [SCREENS.SETTINGS.ADD_BANK_ACCOUNT]: () => require('../../../../pages/AddPersonalBankAccountPage').default as React.ComponentType, [SCREENS.SETTINGS.ADD_BANK_ACCOUNT_REFACTOR]: () => require('../../../../pages/EnablePayments/AddBankAccount/AddBankAccount').default as React.ComponentType, diff --git a/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx b/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx index 79c91af178c3..9fde5456226b 100644 --- a/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx +++ b/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx @@ -44,7 +44,7 @@ function AddBankAccount({personalBankAccount, plaidData, personalBankAccountDraf if (selectedPlaidBankAccount) { BankAccounts.addPersonalBankAccount(selectedPlaidBankAccount); - Navigation.navigate(ROUTES.SETTINGS_ENABLE_PAYMENTS); + Navigation.navigate(ROUTES.SETTINGS_ENABLE_PAYMENTS_REFACTOR); } }, [personalBankAccountDraft?.plaidAccountID, plaidData?.bankAccounts]); diff --git a/src/pages/EnablePayments/EnablePayments.tsx b/src/pages/EnablePayments/EnablePayments.tsx new file mode 100644 index 000000000000..6df56afced57 --- /dev/null +++ b/src/pages/EnablePayments/EnablePayments.tsx @@ -0,0 +1,102 @@ +import React, {useEffect} from 'react'; +import {withOnyx} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; +import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import useLocalize from '@hooks/useLocalize'; +import useNetwork from '@hooks/useNetwork'; +import Navigation from '@libs/Navigation/Navigation'; +import FeesAndTerms from '@pages/EnablePayments/FeesAndTerms/FeesAndTerms'; +import PersonalInfo from '@pages/EnablePayments/PersonalInfo/PersonalInfo'; +import VerifyIdentity from '@pages/EnablePayments/VerifyIdentity/VerifyIdentity'; +import * as Wallet from '@userActions/Wallet'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import type {UserWallet} from '@src/types/onyx'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import ActivateStep from './ActivateStep'; +import FailedKYC from './FailedKYC'; + +type EnablePaymentsPageOnyxProps = { + /** The user's wallet */ + userWallet: OnyxEntry; +}; + +type EnablePaymentsPageProps = EnablePaymentsPageOnyxProps; + +function EnablePaymentsPage({userWallet}: EnablePaymentsPageProps) { + const {translate} = useLocalize(); + const {isOffline} = useNetwork(); + + const {isPendingOnfidoResult, hasFailedOnfido} = userWallet ?? {}; + + useEffect(() => { + if (isOffline) { + return; + } + + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + if (isPendingOnfidoResult || hasFailedOnfido) { + Navigation.navigate(ROUTES.SETTINGS_WALLET, CONST.NAVIGATION.TYPE.UP); + return; + } + + Wallet.openEnablePaymentsPage(); + }, [isOffline, isPendingOnfidoResult, hasFailedOnfido]); + + if (isEmptyObject(userWallet)) { + return ; + } + + return ( + + {() => { + if (userWallet?.errorCode === CONST.WALLET.ERROR.KYC) { + return ( + <> + Navigation.goBack(ROUTES.SETTINGS_WALLET)} + /> + + + ); + } + + const currentStep = userWallet?.currentStep || CONST.WALLET.STEP.ADDITIONAL_DETAILS; + + switch (currentStep) { + case CONST.WALLET.STEP.ADDITIONAL_DETAILS: + case CONST.WALLET.STEP.ADDITIONAL_DETAILS_KBA: + return ; + case CONST.WALLET.STEP.ONFIDO: + return ; + case CONST.WALLET.STEP.TERMS: + return ; + case CONST.WALLET.STEP.ACTIVATE: + return ; + default: + return null; + } + }} + + ); +} + +EnablePaymentsPage.displayName = 'EnablePaymentsPage'; + +export default withOnyx({ + userWallet: { + key: ONYXKEYS.USER_WALLET, + + // We want to refresh the wallet each time the user attempts to activate the wallet so we won't use the + // stored values here. + initWithStoredValues: false, + }, +})(EnablePaymentsPage); diff --git a/src/pages/EnablePayments/PersonalInfo/PersonalInfo.tsx b/src/pages/EnablePayments/PersonalInfo/PersonalInfo.tsx index c23b8bcb12fa..22e9a3731581 100644 --- a/src/pages/EnablePayments/PersonalInfo/PersonalInfo.tsx +++ b/src/pages/EnablePayments/PersonalInfo/PersonalInfo.tsx @@ -9,8 +9,7 @@ import useLocalize from '@hooks/useLocalize'; import useSubStep from '@hooks/useSubStep'; import type {SubStepProps} from '@hooks/useSubStep/types'; import useThemeStyles from '@hooks/useThemeStyles'; -// TODO: uncomment after connecting steps https://github.com/Expensify/App/issues/36648 -// import {parsePhoneNumber} from '@libs/PhoneNumber'; +import {parsePhoneNumber} from '@libs/PhoneNumber'; import Navigation from '@navigation/Navigation'; import getInitialSubstepForPersonalInfo from '@pages/EnablePayments/utils/getInitialSubstepForPersonalInfo'; import getSubstepValues from '@pages/EnablePayments/utils/getSubstepValues'; @@ -47,22 +46,19 @@ function PersonalInfoPage({walletAdditionalDetails, walletAdditionalDetailsDraft const values = useMemo(() => getSubstepValues(PERSONAL_INFO_STEP_KEYS, walletAdditionalDetailsDraft, walletAdditionalDetails), [walletAdditionalDetails, walletAdditionalDetailsDraft]); const submit = () => { - // TODO: uncomment after connecting steps https://github.com/Expensify/App/issues/36648 - // const personalDetails = { - // phoneNumber: (values.phoneNumber && parsePhoneNumber(values.phoneNumber, {regionCode: CONST.COUNTRY.US}).number?.significant) ?? '', - // legalFirstName: values?.[PERSONAL_INFO_STEP_KEYS.FIRST_NAME] ?? '', - // legalLastName: values?.[PERSONAL_INFO_STEP_KEYS.LAST_NAME] ?? '', - // addressStreet: values?.[PERSONAL_INFO_STEP_KEYS.STREET] ?? '', - // addressCity: values?.[PERSONAL_INFO_STEP_KEYS.CITY] ?? '', - // addressState: values?.[PERSONAL_INFO_STEP_KEYS.STATE] ?? '', - // addressZip: values?.[PERSONAL_INFO_STEP_KEYS.ZIP_CODE] ?? '', - // dob: values?.[PERSONAL_INFO_STEP_KEYS.DOB] ?? '', - // ssn: values?.[PERSONAL_INFO_STEP_KEYS.SSN_LAST_4] ?? '', - // }; + const personalDetails = { + phoneNumber: (values.phoneNumber && parsePhoneNumber(values.phoneNumber, {regionCode: CONST.COUNTRY.US}).number?.significant) ?? '', + legalFirstName: values?.[PERSONAL_INFO_STEP_KEYS.FIRST_NAME] ?? '', + legalLastName: values?.[PERSONAL_INFO_STEP_KEYS.LAST_NAME] ?? '', + addressStreet: values?.[PERSONAL_INFO_STEP_KEYS.STREET] ?? '', + addressCity: values?.[PERSONAL_INFO_STEP_KEYS.CITY] ?? '', + addressState: values?.[PERSONAL_INFO_STEP_KEYS.STATE] ?? '', + addressZip: values?.[PERSONAL_INFO_STEP_KEYS.ZIP_CODE] ?? '', + dob: values?.[PERSONAL_INFO_STEP_KEYS.DOB] ?? '', + ssn: values?.[PERSONAL_INFO_STEP_KEYS.SSN_LAST_4] ?? '', + }; // Attempt to set the personal details - // Wallet.updatePersonalDetails(personalDetails); - Navigation.goBack(ROUTES.SETTINGS_WALLET); - Wallet.resetWalletAdditionalDetailsDraft(); + Wallet.updatePersonalDetails(personalDetails); }; const startFrom = useMemo(() => getInitialSubstepForPersonalInfo(values), [values]); diff --git a/src/pages/EnablePayments/VerifyIdentity/VerifyIdentity.tsx b/src/pages/EnablePayments/VerifyIdentity/VerifyIdentity.tsx index f402f52255ab..40aab5ba8b35 100644 --- a/src/pages/EnablePayments/VerifyIdentity/VerifyIdentity.tsx +++ b/src/pages/EnablePayments/VerifyIdentity/VerifyIdentity.tsx @@ -13,6 +13,7 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import Growl from '@libs/Growl'; import * as BankAccounts from '@userActions/BankAccounts'; +import * as Wallet from '@userActions/Wallet'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalBankAccount, WalletOnfido} from '@src/types/onyx'; @@ -36,14 +37,11 @@ type VerifyIdentityOnyxProps = { walletOnfidoData: OnyxEntry; }; -type VerifyIdentityProps = VerifyIdentityOnyxProps & { - /** Goes to the previous step */ - onBackButtonPress: () => void; -}; +type VerifyIdentityProps = VerifyIdentityOnyxProps; const ONFIDO_ERROR_DISPLAY_DURATION = 10000; -function VerifyIdentity({personalBankAccount, onBackButtonPress, onfidoApplicantID, onfidoToken, walletOnfidoData = DEFAULT_WALLET_ONFIDO_DATA}: VerifyIdentityProps) { +function VerifyIdentity({personalBankAccount, onfidoApplicantID, onfidoToken, walletOnfidoData = DEFAULT_WALLET_ONFIDO_DATA}: VerifyIdentityProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -72,16 +70,20 @@ function VerifyIdentity({personalBankAccount, onBackButtonPress, onfidoApplicant // BankAccounts.goToWithdrawalAccountSetupStep(CONST.BANK_ACCOUNT.STEP.REQUESTOR); }; + const handleBackButtonPress = () => { + Wallet.updateCurrentStep(CONST.WALLET.STEP.ADDITIONAL_DETAILS); + }; + return ( From 97408438b6830a544d9e5fb504f9e32dfa98f0a6 Mon Sep 17 00:00:00 2001 From: Jan Nowakowski Date: Wed, 8 May 2024 14:56:44 +0200 Subject: [PATCH 010/144] Fix focus and tab navigation in Context Menu --- src/components/ContextMenuItem.tsx | 5 +++ src/components/MenuItem.tsx | 6 ++- src/components/ScreenWrapper.tsx | 39 ++++++++++--------- src/hooks/useScreenWrapperTransitionStatus.ts | 6 +++ src/hooks/useSyncFocus/index.ts | 6 ++- .../BaseReportActionContextMenu.tsx | 2 + 6 files changed, 42 insertions(+), 22 deletions(-) diff --git a/src/components/ContextMenuItem.tsx b/src/components/ContextMenuItem.tsx index f252cc5b734f..2cc6a0ecec44 100644 --- a/src/components/ContextMenuItem.tsx +++ b/src/components/ContextMenuItem.tsx @@ -52,6 +52,9 @@ type ContextMenuItemProps = { /** Handles what to do when the item is focused */ onFocus?: () => void; + + /** Handles what to do when the item loose focus */ + onBlur?: () => void; }; type ContextMenuItemHandle = { @@ -74,6 +77,7 @@ function ContextMenuItem( shouldPreventDefaultFocusOnPress = true, buttonRef = {current: null}, onFocus = () => {}, + onBlur = () => {}, }: ContextMenuItemProps, ref: ForwardedRef, ) { @@ -130,6 +134,7 @@ function ContextMenuItem( focused={isFocused} interactive={isThrottledButtonActive} onFocus={onFocus} + onBlur={onBlur} /> ); } diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx index 42de7e2fb7f4..b796337813ef 100644 --- a/src/components/MenuItem.tsx +++ b/src/components/MenuItem.tsx @@ -265,6 +265,9 @@ type MenuItemBaseProps = { /** Handles what to do when the item is focused */ onFocus?: () => void; + + /** Handles what to do when the item loose focus */ + onBlur?: () => void; }; type MenuItemProps = (IconProps | AvatarProps | NoIcon) & MenuItemBaseProps; @@ -342,6 +345,7 @@ function MenuItem( isPaneMenu = false, shouldPutLeftPaddingWhenNoIcon = false, onFocus, + onBlur, }: MenuItemProps, ref: PressableRef, ) { @@ -438,7 +442,7 @@ function MenuItem( }; return ( - + {!!label && !isLabelHoverable && ( {label} diff --git a/src/components/ScreenWrapper.tsx b/src/components/ScreenWrapper.tsx index f7f5a90aa765..111b1b583e30 100644 --- a/src/components/ScreenWrapper.tsx +++ b/src/components/ScreenWrapper.tsx @@ -100,7 +100,9 @@ type ScreenWrapperProps = { shouldShowOfflineIndicatorInWideScreen?: boolean; }; -const ScreenWrapperStatusContext = createContext({didScreenTransitionEnd: false}); +type ScreenWrapperStatusContextType = {didScreenTransitionEnd: boolean}; + +const ScreenWrapperStatusContext = createContext(undefined); function ScreenWrapper( { @@ -257,24 +259,23 @@ function ScreenWrapper( {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 && ( - - )} + { + // 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/hooks/useScreenWrapperTransitionStatus.ts b/src/hooks/useScreenWrapperTransitionStatus.ts index b9e94abfc024..8692677fdb68 100644 --- a/src/hooks/useScreenWrapperTransitionStatus.ts +++ b/src/hooks/useScreenWrapperTransitionStatus.ts @@ -15,3 +15,9 @@ export default function useScreenWrapperTranstionStatus() { return value; } + +function useScreenWrapperTransitionStatusUnsafe() { + return useContext(ScreenWrapperStatusContext); +} + +export {useScreenWrapperTransitionStatusUnsafe}; diff --git a/src/hooks/useSyncFocus/index.ts b/src/hooks/useSyncFocus/index.ts index afc4e7e351ab..e0c68c584b82 100644 --- a/src/hooks/useSyncFocus/index.ts +++ b/src/hooks/useSyncFocus/index.ts @@ -1,7 +1,7 @@ import {useLayoutEffect} from 'react'; import type {RefObject} from 'react'; import type {View} from 'react-native'; -import useScreenWrapperTranstionStatus from '@hooks/useScreenWrapperTransitionStatus'; +import {useScreenWrapperTransitionStatusUnsafe} from '@hooks/useScreenWrapperTransitionStatus'; /** * Custom React hook created to handle sync of focus on an element when the user navigates through the app with keyboard. @@ -9,7 +9,9 @@ import useScreenWrapperTranstionStatus from '@hooks/useScreenWrapperTransitionSt * To maintain consistency when an element is focused in the app, the focus() method is additionally called on the focused element to eliminate the difference between native browser focus and application focus. */ const useSyncFocus = (ref: RefObject, isFocused: boolean, shouldSyncFocus = true) => { - const {didScreenTransitionEnd} = useScreenWrapperTranstionStatus(); + const contextValue = useScreenWrapperTransitionStatusUnsafe(); + + const didScreenTransitionEnd = contextValue ? contextValue.didScreenTransitionEnd : true; useLayoutEffect(() => { if (!isFocused || !shouldSyncFocus || !didScreenTransitionEnd) { diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx index fe872ee1681a..7a95c371f179 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx @@ -164,6 +164,7 @@ function BaseReportActionContextMenu({ disabledIndexes, maxIndex: filteredContextMenuActions.length - 1, isActive: shouldEnableArrowNavigation, + disableCyclicTraversal: true, }); /** @@ -285,6 +286,7 @@ function BaseReportActionContextMenu({ isFocused={focusedIndex === index} shouldPreventDefaultFocusOnPress={contextAction.shouldPreventDefaultFocusOnPress} onFocus={() => setFocusedIndex(index)} + onBlur={() => (index === filteredContextMenuActions.length - 1 || index === 1) && setFocusedIndex(-1)} /> ); })} From 368610e6e9a346aa7717e8b1919826cdc4126ccb Mon Sep 17 00:00:00 2001 From: Jan Nowakowski Date: Wed, 8 May 2024 16:43:12 +0200 Subject: [PATCH 011/144] Point to new search screen in autofocus --- src/components/FocusTrap/SCREENS_WITH_AUTOFOCUS.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/FocusTrap/SCREENS_WITH_AUTOFOCUS.ts b/src/components/FocusTrap/SCREENS_WITH_AUTOFOCUS.ts index 439c45a8bd00..b88e51f6caaf 100644 --- a/src/components/FocusTrap/SCREENS_WITH_AUTOFOCUS.ts +++ b/src/components/FocusTrap/SCREENS_WITH_AUTOFOCUS.ts @@ -2,7 +2,7 @@ import SCREENS from '@src/SCREENS'; const SCREENS_WITH_AUTOFOCUS: string[] = [ SCREENS.WORKSPACE_SWITCHER.ROOT, - SCREENS.SEARCH_ROOT, + SCREENS.SEARCH.CENTRAL_PANE, SCREENS.REPORT, SCREENS.REPORT_DESCRIPTION_ROOT, SCREENS.PRIVATE_NOTES.EDIT, From 5ced21b8a4908373fd14a7bc76eca0cf09525e88 Mon Sep 17 00:00:00 2001 From: Jan Nowakowski Date: Thu, 9 May 2024 09:35:49 +0200 Subject: [PATCH 012/144] Fix linter --- src/components/HeaderWithBackButton/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/HeaderWithBackButton/index.tsx b/src/components/HeaderWithBackButton/index.tsx index 2f32de92e80a..70ddb0888972 100755 --- a/src/components/HeaderWithBackButton/index.tsx +++ b/src/components/HeaderWithBackButton/index.tsx @@ -6,7 +6,6 @@ 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'; From 9928153fe28701f9305e48432234d2693e8f5892 Mon Sep 17 00:00:00 2001 From: Jan Nowakowski Date: Thu, 9 May 2024 10:49:35 +0200 Subject: [PATCH 013/144] Apply review comment --- src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts b/src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts index b62c3b563594..2056073eb054 100644 --- a/src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts +++ b/src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts @@ -1,5 +1,6 @@ +import type { BottomTabName } from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; -const BOTTOM_TAB_SCREENS: string[] = [SCREENS.HOME, SCREENS.SETTINGS.ROOT]; +const BOTTOM_TAB_SCREENS: BottomTabName[] = [SCREENS.HOME, SCREENS.SETTINGS.ROOT]; export default BOTTOM_TAB_SCREENS; From 41862adbc879c1e44d6ee980b3fc87ac70779a28 Mon Sep 17 00:00:00 2001 From: Jan Nowakowski Date: Mon, 13 May 2024 09:23:45 +0200 Subject: [PATCH 014/144] Fix ts --- src/components/FocusTrap/FocusTrapForScreen/index.web.tsx | 2 +- src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx b/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx index 3dd12f232d25..afcc185ff18c 100644 --- a/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx +++ b/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx @@ -17,7 +17,7 @@ function FocusTrap({children}: FocusTrapProps) { 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)) { + if (BOTTOM_TAB_SCREENS.find((screen) => screen === route.name)) { return false; } diff --git a/src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts b/src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts index 6815dcc455a9..e1277d8d4409 100644 --- a/src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts +++ b/src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts @@ -12,9 +12,7 @@ const WIDE_LAYOUT_INACTIVE_SCREENS: string[] = [ SCREENS.SETTINGS.WALLET.ROOT, SCREENS.SETTINGS.ABOUT, SCREENS.SETTINGS.WORKSPACES, - SCREENS.WORKSPACE.INITIAL, - SCREENS.WORKSPACE.PROFILE, SCREENS.WORKSPACE.CARD, SCREENS.WORKSPACE.WORKFLOWS, From 6e3ba8ca2e731198963df2f7c31a1603f70574af Mon Sep 17 00:00:00 2001 From: Jan Nowakowski Date: Mon, 13 May 2024 14:15:07 +0200 Subject: [PATCH 015/144] Fix prettier --- src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts b/src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts index 2056073eb054..e6af466b12c5 100644 --- a/src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts +++ b/src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts @@ -1,4 +1,4 @@ -import type { BottomTabName } from '@libs/Navigation/types'; +import type {BottomTabName} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; const BOTTOM_TAB_SCREENS: BottomTabName[] = [SCREENS.HOME, SCREENS.SETTINGS.ROOT]; From 1ac3596a90e6cef9484ac783c0d13075a7f146ab Mon Sep 17 00:00:00 2001 From: Jan Nowakowski Date: Tue, 14 May 2024 12:19:44 +0200 Subject: [PATCH 016/144] useCallback --- .../FocusTrap/FocusTrapForScreen/index.web.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx b/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx index afcc185ff18c..e4b2c7f8d39f 100644 --- a/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx +++ b/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx @@ -1,6 +1,6 @@ import {useFocusEffect, useIsFocused, useRoute} from '@react-navigation/native'; import FocusTrapOriginal from 'focus-trap-react'; -import React, {useMemo} from 'react'; +import React, {useCallback, useMemo} 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'; @@ -28,9 +28,11 @@ function FocusTrap({children}: FocusTrapProps) { return true; }, [isSmallScreenWidth, route]); - useFocusEffect(() => { - activeRouteName = route.name; - }); + useFocusEffect( + useCallback(() => { + activeRouteName = route.name; + }, [route]), + ); return ( Date: Wed, 15 May 2024 09:20:32 +0200 Subject: [PATCH 017/144] Workspace screens in autofocus --- src/components/FocusTrap/SCREENS_WITH_AUTOFOCUS.ts | 3 ++- .../AppNavigator/Navigators/FullScreenNavigator.tsx | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/FocusTrap/SCREENS_WITH_AUTOFOCUS.ts b/src/components/FocusTrap/SCREENS_WITH_AUTOFOCUS.ts index b88e51f6caaf..7fcaa8a15045 100644 --- a/src/components/FocusTrap/SCREENS_WITH_AUTOFOCUS.ts +++ b/src/components/FocusTrap/SCREENS_WITH_AUTOFOCUS.ts @@ -1,7 +1,8 @@ +import {CENTRAL_PANE_WORKSPACE_SCREENS} from '@libs/Navigation/AppNavigator/Navigators/FullScreenNavigator'; import SCREENS from '@src/SCREENS'; const SCREENS_WITH_AUTOFOCUS: string[] = [ - SCREENS.WORKSPACE_SWITCHER.ROOT, + ...Object.keys(CENTRAL_PANE_WORKSPACE_SCREENS), SCREENS.SEARCH.CENTRAL_PANE, SCREENS.REPORT, SCREENS.REPORT_DESCRIPTION_ROOT, diff --git a/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx index 41ed26b5ff1b..64485872544f 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx @@ -15,7 +15,7 @@ const RootStack = createCustomFullScreenNavigator(); type Screens = Partial React.ComponentType>>; -const centralPaneWorkspaceScreens = { +const CENTRAL_PANE_WORKSPACE_SCREENS = { [SCREENS.WORKSPACE.PROFILE]: () => require('../../../../pages/workspace/WorkspaceProfilePage').default as React.ComponentType, [SCREENS.WORKSPACE.CARD]: () => require('../../../../pages/workspace/card/WorkspaceCardPage').default as React.ComponentType, [SCREENS.WORKSPACE.WORKFLOWS]: () => require('../../../../pages/workspace/workflows/WorkspaceWorkflowsPage').default as React.ComponentType, @@ -47,7 +47,7 @@ function FullScreenNavigator() { options={screenOptions.homeScreen} getComponent={loadWorkspaceInitialPage} /> - {Object.entries(centralPaneWorkspaceScreens).map(([screenName, componentGetter]) => ( + {Object.entries(CENTRAL_PANE_WORKSPACE_SCREENS).map(([screenName, componentGetter]) => ( Date: Wed, 15 May 2024 14:40:43 +0200 Subject: [PATCH 018/144] feat: add verify identity intro page --- src/languages/en.ts | 2 + src/languages/es.ts | 2 + .../VerifyIdentity/VerifyIdentity.tsx | 50 ++++++++++++++++--- 3 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index c174c2182ef2..b079a7ecc624 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1571,6 +1571,8 @@ export default { facialScan: 'Onfido’s Facial Scan Policy and Release', tryAgain: 'Try again', verifyIdentity: 'Verify identity', + letsVerifyIdentity: "Let's verify your identity.", + butFirst: `But first, the boring stuff. Read up on the legalese in the next step and click "Accept" when you're ready.`, genericError: 'There was an error while processing this step. Please try again.', cameraPermissionsNotGranted: 'Enable camera access', cameraRequestMessage: 'We need access to your camera to complete bank account verification. Please enable via Settings > New Expensify.', diff --git a/src/languages/es.ts b/src/languages/es.ts index e9e1ed6eb815..eca0e3ac16ad 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1590,6 +1590,8 @@ export default { facialScan: 'Política y lanzamiento de la exploración facial de Onfido', tryAgain: 'Intentar otra vez', verifyIdentity: 'Verificar identidad', + letsVerifyIdentity: '¡Vamos a verificar tu identidad!', + butFirst: 'Pero primero, lo aburrido. Lee la jerga legal en el siguiente paso y haz clic en "Aceptar" cuando estés listo.', genericError: 'Hubo un error al procesar este paso. Inténtalo de nuevo.', cameraPermissionsNotGranted: 'Permiso para acceder a la cámara', cameraRequestMessage: 'Necesitamos acceso a tu cámara para completar la verificación de tu cuenta de banco. Por favor habilita los permisos en Configuración > Nuevo Expensify.', diff --git a/src/pages/EnablePayments/VerifyIdentity/VerifyIdentity.tsx b/src/pages/EnablePayments/VerifyIdentity/VerifyIdentity.tsx index 40aab5ba8b35..0bcb0beb675f 100644 --- a/src/pages/EnablePayments/VerifyIdentity/VerifyIdentity.tsx +++ b/src/pages/EnablePayments/VerifyIdentity/VerifyIdentity.tsx @@ -3,14 +3,20 @@ import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; +import FixedFooter from '@components/FixedFooter'; +import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import Icon from '@components/Icon'; +import * as Illustrations from '@components/Icon/Illustrations'; import InteractiveStepSubHeader from '@components/InteractiveStepSubHeader'; import Onfido from '@components/Onfido'; import type {OnfidoData} from '@components/Onfido/types'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; +import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; +import * as ErrorUtils from '@libs/ErrorUtils'; import Growl from '@libs/Growl'; import * as BankAccounts from '@userActions/BankAccounts'; import * as Wallet from '@userActions/Wallet'; @@ -45,6 +51,8 @@ function VerifyIdentity({personalBankAccount, onfidoApplicantID, onfidoToken, wa const styles = useThemeStyles(); const {translate} = useLocalize(); + console.log({personalBankAccount, onfidoApplicantID, onfidoToken, walletOnfidoData}); + const handleOnfidoSuccess = useCallback( (onfidoData: OnfidoData) => { BankAccounts.verifyIdentity({ @@ -58,6 +66,8 @@ function VerifyIdentity({personalBankAccount, onfidoApplicantID, onfidoToken, wa [personalBankAccount, onfidoApplicantID], ); + const onfidoError = ErrorUtils.getLatestErrorMessage(walletOnfidoData) ?? ''; + const handleOnfidoError = () => { // In case of any unexpected error we log it to the server, show a growl, and return the user back to the requestor step so they can try again. Growl.error(translate('onfidoStep.genericError'), ONFIDO_ERROR_DISPLAY_DURATION); @@ -74,6 +84,8 @@ function VerifyIdentity({personalBankAccount, onfidoApplicantID, onfidoToken, wa Wallet.updateCurrentStep(CONST.WALLET.STEP.ADDITIONAL_DETAILS); }; + const {isLoading = false, hasAcceptedPrivacyPolicy} = walletOnfidoData; + return ( - + {hasAcceptedPrivacyPolicy ? ( + + ) : ( + <> + + + {translate('onfidoStep.letsVerifyIdentity')} + {translate('onfidoStep.butFirst')} + + + {}} + onFixTheErrorsLinkPressed={() => {}} + message={onfidoError} + isLoading={isLoading} + buttonText={onfidoError ? translate('onfidoStep.tryAgain') : translate('common.continue')} + containerStyles={[styles.mh0, styles.mv0, styles.mb0]} + /> + + + )} From 7c78aaafe99891d588cea3f08127e736cfdf777e Mon Sep 17 00:00:00 2001 From: Jan Nowakowski Date: Wed, 15 May 2024 17:38:45 +0200 Subject: [PATCH 019/144] Fix --- src/components/MenuItem.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx index e53e0783843b..fe187f49a357 100644 --- a/src/components/MenuItem.tsx +++ b/src/components/MenuItem.tsx @@ -32,6 +32,7 @@ import * as Expensicons from './Icon/Expensicons'; import * as defaultWorkspaceAvatars from './Icon/WorkspaceDefaultAvatars'; import {MenuItemGroupContext} from './MenuItemGroup'; import MultipleAvatars from './MultipleAvatars'; +import type {PressableRef} from './Pressable/GenericPressable/types'; import PressableWithSecondaryInteraction from './PressableWithSecondaryInteraction'; import RenderHTML from './RenderHTML'; import SelectCircle from './SelectCircle'; @@ -267,7 +268,7 @@ type MenuItemBaseProps = { /** Handles what to do when the item loose focus */ onBlur?: () => void; - + /** Optional account id if it's user avatar or policy id if it's workspace avatar */ avatarID?: number | string; }; @@ -350,6 +351,7 @@ function MenuItem( onBlur, avatarID, }: MenuItemProps, + ref: PressableRef, ) { const theme = useTheme(); const styles = useThemeStyles(); From 2ec341172ba1daa9bd17d29659b9bfbbf62270f4 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Thu, 16 May 2024 20:43:38 +0200 Subject: [PATCH 020/144] fix: get token and applicantID from walletOnfidoData --- .../VerifyIdentity/VerifyIdentity.tsx | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/pages/EnablePayments/VerifyIdentity/VerifyIdentity.tsx b/src/pages/EnablePayments/VerifyIdentity/VerifyIdentity.tsx index 0bcb0beb675f..c2023077af50 100644 --- a/src/pages/EnablePayments/VerifyIdentity/VerifyIdentity.tsx +++ b/src/pages/EnablePayments/VerifyIdentity/VerifyIdentity.tsx @@ -47,11 +47,15 @@ type VerifyIdentityProps = VerifyIdentityOnyxProps; const ONFIDO_ERROR_DISPLAY_DURATION = 10000; -function VerifyIdentity({personalBankAccount, onfidoApplicantID, onfidoToken, walletOnfidoData = DEFAULT_WALLET_ONFIDO_DATA}: VerifyIdentityProps) { +function VerifyIdentity({personalBankAccount, walletOnfidoData = DEFAULT_WALLET_ONFIDO_DATA}: VerifyIdentityProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - console.log({personalBankAccount, onfidoApplicantID, onfidoToken, walletOnfidoData}); + const openOnfidoFlow = () => { + BankAccounts.openOnfidoFlow(); + }; + + const {isLoading = false, hasAcceptedPrivacyPolicy, sdkToken, applicantID} = walletOnfidoData; const handleOnfidoSuccess = useCallback( (onfidoData: OnfidoData) => { @@ -63,7 +67,7 @@ function VerifyIdentity({personalBankAccount, onfidoApplicantID, onfidoToken, wa }); BankAccounts.updateAddPersonalBankAccountDraft({isOnfidoSetupComplete: true}); }, - [personalBankAccount, onfidoApplicantID], + [personalBankAccount, applicantID], ); const onfidoError = ErrorUtils.getLatestErrorMessage(walletOnfidoData) ?? ''; @@ -84,8 +88,6 @@ function VerifyIdentity({personalBankAccount, onfidoApplicantID, onfidoToken, wa Wallet.updateCurrentStep(CONST.WALLET.STEP.ADDITIONAL_DETAILS); }; - const {isLoading = false, hasAcceptedPrivacyPolicy} = walletOnfidoData; - return ( {hasAcceptedPrivacyPolicy ? ( {}} + onSubmit={openOnfidoFlow} onFixTheErrorsLinkPressed={() => {}} message={onfidoError} isLoading={isLoading} @@ -145,12 +147,6 @@ export default withOnyx({ personalBankAccount: { key: ONYXKEYS.PERSONAL_BANK_ACCOUNT, }, - onfidoApplicantID: { - key: ONYXKEYS.ONFIDO_APPLICANT_ID, - }, - onfidoToken: { - key: ONYXKEYS.ONFIDO_TOKEN, - }, walletOnfidoData: { key: ONYXKEYS.WALLET_ONFIDO, From 4706357c1d51789d9f747f5f0b90ac472e04952b Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Mon, 20 May 2024 18:09:32 +0200 Subject: [PATCH 021/144] feat: change wallet agreement url for bancorp --- src/CONST.ts | 1 + .../FeesAndTerms/substeps/TermsStep.tsx | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 6517ece4276d..af5f32808034 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -574,6 +574,7 @@ const CONST = { LICENSES_URL: `${USE_EXPENSIFY_URL}/licenses`, ACH_TERMS_URL: `${USE_EXPENSIFY_URL}/achterms`, WALLET_AGREEMENT_URL: `${USE_EXPENSIFY_URL}/walletagreement`, + BANCORP_WALLET_AGREEMENT_URL: `${USE_EXPENSIFY_URL}/bancorp-bank-wallet-terms-of-service`, HELP_LINK_URL: `${USE_EXPENSIFY_URL}/usa-patriot-act`, ELECTRONIC_DISCLOSURES_URL: `${USE_EXPENSIFY_URL}/esignagreement`, GITHUB_RELEASE_URL: 'https://api.github.com/repos/expensify/app/releases/latest', diff --git a/src/pages/EnablePayments/FeesAndTerms/substeps/TermsStep.tsx b/src/pages/EnablePayments/FeesAndTerms/substeps/TermsStep.tsx index fe17ea7e1afb..270f0c1f1699 100644 --- a/src/pages/EnablePayments/FeesAndTerms/substeps/TermsStep.tsx +++ b/src/pages/EnablePayments/FeesAndTerms/substeps/TermsStep.tsx @@ -9,8 +9,7 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@navigation/Navigation'; -// TODO: uncomment at the end of the refactor https://github.com/Expensify/App/issues/36648 -// import * as BankAccounts from '@userActions/BankAccounts'; +import * as BankAccounts from '@userActions/BankAccounts'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -28,13 +27,15 @@ function HaveReadAndAgreeLabel() { function AgreeToTheLabel() { const {translate} = useLocalize(); + const [userWallet] = useOnyx(ONYXKEYS.USER_WALLET); + const walletAgreementUrl = userWallet?.walletProgramID === CONST.WALLET.MTL_WALLET_PROGRAM_ID ? CONST.WALLET_AGREEMENT_URL : CONST.BANCORP_WALLET_AGREEMENT_URL; return ( {`${translate('termsStep.agreeToThe')} `} {`${translate('common.privacy')} `} {`${translate('common.and')} `} - {`${translate('termsStep.walletAgreement')}.`} + {`${translate('termsStep.walletAgreement')}.`} ); } @@ -93,11 +94,10 @@ function TermsStep() { } setError(false); - // TODO: uncomment at the end of the refactor https://github.com/Expensify/App/issues/36648 - // BankAccounts.acceptWalletTerms({ - // hasAcceptedTerms: hasAcceptedDisclosure && hasAcceptedPrivacyPolicyAndWalletAgreement, - // reportID: walletTerms?.chatReportID ?? '', - // }); + BankAccounts.acceptWalletTerms({ + hasAcceptedTerms: hasAcceptedDisclosure && hasAcceptedPrivacyPolicyAndWalletAgreement, + reportID: walletTerms?.chatReportID ?? '', + }); Navigation.navigate(ROUTES.SETTINGS_WALLET); }} message={errorMessage} From 8f019fd2507569145f0fcf179c767d46d249e3fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barbara=20Gawe=C5=82-Kucab?= Date: Wed, 22 May 2024 15:11:28 +0200 Subject: [PATCH 022/144] enable no-unsafe-call rule --- .eslintrc.js | 1 - .../javascript/getGraphiteString/getGraphiteString.ts | 3 ++- .../ComposerWithSuggestions/ComposerWithSuggestions.tsx | 6 +++++- tests/unit/markPullRequestsAsDeployedTest.ts | 2 +- workflow_tests/utils/ExtendedAct.ts | 3 ++- workflow_tests/utils/preGenerateTest.ts | 3 ++- 6 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index eb50d1fcc5f3..2cf5ba68aa9a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -100,7 +100,6 @@ module.exports = { __DEV__: 'readonly', }, rules: { - '@typescript-eslint/no-unsafe-call': 'off', '@typescript-eslint/no-unsafe-member-access': 'off', '@typescript-eslint/no-unsafe-assignment': 'off', diff --git a/.github/actions/javascript/getGraphiteString/getGraphiteString.ts b/.github/actions/javascript/getGraphiteString/getGraphiteString.ts index c486fdbd39f3..15b5e885c921 100644 --- a/.github/actions/javascript/getGraphiteString/getGraphiteString.ts +++ b/.github/actions/javascript/getGraphiteString/getGraphiteString.ts @@ -32,7 +32,8 @@ const run = () => { } if (current.name && current.meanDuration && current.meanCount && timestamp) { - const formattedName = current.name.split(' ').join('-'); + const currentName = current.name as string; + const formattedName = currentName.split(' ').join('-'); const renderDurationString = `${GRAPHITE_PATH}.${formattedName}.renderDuration ${current.meanDuration} ${timestamp}`; const renderCountString = `${GRAPHITE_PATH}.${formattedName}.renderCount ${current.meanCount} ${timestamp}`; diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx index 0b585de8f059..1a490a26867a 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx @@ -182,7 +182,11 @@ type SwitchToCurrentReportProps = { callback: () => void; }; -const {RNTextInputReset} = NativeModules; +type RNTextInputResetProps = { + resetKeyboardInput: (nodeHandle: number | null) => void; +}; + +const RNTextInputReset: RNTextInputResetProps = NativeModules.RNTextInputReset; const isIOSNative = getPlatform() === CONST.PLATFORM.IOS; diff --git a/tests/unit/markPullRequestsAsDeployedTest.ts b/tests/unit/markPullRequestsAsDeployedTest.ts index 24a6733d1244..8d8b25968a28 100644 --- a/tests/unit/markPullRequestsAsDeployedTest.ts +++ b/tests/unit/markPullRequestsAsDeployedTest.ts @@ -35,7 +35,7 @@ type CommitData = { }; }; -let run; +let run: () => Promise; const mockGetInput = jest.fn(); const mockGetPullRequest = jest.fn(); diff --git a/workflow_tests/utils/ExtendedAct.ts b/workflow_tests/utils/ExtendedAct.ts index e2bb12ec8e01..7b35eb260ba3 100644 --- a/workflow_tests/utils/ExtendedAct.ts +++ b/workflow_tests/utils/ExtendedAct.ts @@ -17,7 +17,8 @@ type ActOptions = { // @ts-expect-error Override shouldn't be done on private methods wait until https://github.com/kiegroup/act-js/issues/77 is resolved or try to create a params workaround class ExtendedAct extends Act { async parseRunOpts(opts?: ExtendedActOpts): Promise { - const {cwd, actArguments, proxy} = await super['parseRunOpts'](opts); + const parseSuperRunOpts: (opts?: ExtendedActOpts) => Promise = super['parseRunOpts']; + const {cwd, actArguments, proxy} = await parseSuperRunOpts(opts); if (opts?.actor) { actArguments.push('--actor', opts.actor); diff --git a/workflow_tests/utils/preGenerateTest.ts b/workflow_tests/utils/preGenerateTest.ts index 1e7e7bb04184..eb1d2e8f9b69 100644 --- a/workflow_tests/utils/preGenerateTest.ts +++ b/workflow_tests/utils/preGenerateTest.ts @@ -219,7 +219,8 @@ const getMockFileContent = (workflowName: string, jobs: Record { - const stepMockName = `${workflowName.toUpperCase()}__${jobId.toUpperCase()}__${step.name + const stepName = step.name as string; + const stepMockName = `${workflowName.toUpperCase()}__${jobId.toUpperCase()}__${stepName .replaceAll(' ', '_') .replaceAll('-', '_') .replaceAll(',', '') From c6028f762608b9dc68b863b24e7e32006b50c1e2 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Wed, 22 May 2024 20:39:27 +0200 Subject: [PATCH 023/144] refactor: cleanup --- src/pages/EnablePayments/EnablePayments.tsx | 20 ++------- .../FeesAndTerms/FeesAndTerms.tsx | 16 ++++++- .../FeesAndTerms/substeps/TermsStep.tsx | 6 +-- .../VerifyIdentity/VerifyIdentity.tsx | 42 ++++++------------- src/types/form/PersonalBankAccountForm.ts | 6 ++- 5 files changed, 36 insertions(+), 54 deletions(-) diff --git a/src/pages/EnablePayments/EnablePayments.tsx b/src/pages/EnablePayments/EnablePayments.tsx index 6df56afced57..fdee18e8147d 100644 --- a/src/pages/EnablePayments/EnablePayments.tsx +++ b/src/pages/EnablePayments/EnablePayments.tsx @@ -7,17 +7,16 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import Navigation from '@libs/Navigation/Navigation'; -import FeesAndTerms from '@pages/EnablePayments/FeesAndTerms/FeesAndTerms'; -import PersonalInfo from '@pages/EnablePayments/PersonalInfo/PersonalInfo'; -import VerifyIdentity from '@pages/EnablePayments/VerifyIdentity/VerifyIdentity'; import * as Wallet from '@userActions/Wallet'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {UserWallet} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; -import ActivateStep from './ActivateStep'; import FailedKYC from './FailedKYC'; +import FeesAndTerms from './FeesAndTerms/FeesAndTerms'; +import PersonalInfo from './PersonalInfo/PersonalInfo'; +import VerifyIdentity from './VerifyIdentity/VerifyIdentity'; type EnablePaymentsPageOnyxProps = { /** The user's wallet */ @@ -30,21 +29,13 @@ function EnablePaymentsPage({userWallet}: EnablePaymentsPageProps) { const {translate} = useLocalize(); const {isOffline} = useNetwork(); - const {isPendingOnfidoResult, hasFailedOnfido} = userWallet ?? {}; - useEffect(() => { if (isOffline) { return; } - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - if (isPendingOnfidoResult || hasFailedOnfido) { - Navigation.navigate(ROUTES.SETTINGS_WALLET, CONST.NAVIGATION.TYPE.UP); - return; - } - Wallet.openEnablePaymentsPage(); - }, [isOffline, isPendingOnfidoResult, hasFailedOnfido]); + }, [isOffline]); if (isEmptyObject(userWallet)) { return ; @@ -73,14 +64,11 @@ function EnablePaymentsPage({userWallet}: EnablePaymentsPageProps) { switch (currentStep) { case CONST.WALLET.STEP.ADDITIONAL_DETAILS: - case CONST.WALLET.STEP.ADDITIONAL_DETAILS_KBA: return ; case CONST.WALLET.STEP.ONFIDO: return ; case CONST.WALLET.STEP.TERMS: return ; - case CONST.WALLET.STEP.ACTIVATE: - return ; default: return null; } diff --git a/src/pages/EnablePayments/FeesAndTerms/FeesAndTerms.tsx b/src/pages/EnablePayments/FeesAndTerms/FeesAndTerms.tsx index b54564eff254..64e99bd9be05 100644 --- a/src/pages/EnablePayments/FeesAndTerms/FeesAndTerms.tsx +++ b/src/pages/EnablePayments/FeesAndTerms/FeesAndTerms.tsx @@ -1,5 +1,6 @@ import React from 'react'; import {View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import InteractiveStepSubHeader from '@components/InteractiveStepSubHeader'; import ScreenWrapper from '@components/ScreenWrapper'; @@ -8,7 +9,10 @@ import useSubStep from '@hooks/useSubStep'; import type {SubStepProps} from '@hooks/useSubStep/types'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@navigation/Navigation'; +import * as BankAccounts from '@userActions/BankAccounts'; +import * as Wallet from '@userActions/Wallet'; import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import FeesStep from './substeps/FeesStep'; import TermsStep from './substeps/TermsStep'; @@ -18,13 +22,21 @@ const termsAndFeesSubsteps: Array> = [FeesStep function FeesAndTerms() { const {translate} = useLocalize(); const styles = useThemeStyles(); + const [walletTerms] = useOnyx(ONYXKEYS.WALLET_TERMS); - const submit = () => {}; + const submit = () => { + BankAccounts.acceptWalletTerms({ + hasAcceptedTerms: true, + reportID: walletTerms?.chatReportID ?? '', + }); + BankAccounts.clearPersonalBankAccount(); + // TODO: clear wallet draft + Navigation.navigate(ROUTES.SETTINGS_WALLET); + }; const {componentToRender: SubStep, isEditing, screenIndex, nextScreen, prevScreen, moveTo} = useSubStep({bodyContent: termsAndFeesSubsteps, startFrom: 0, onFinished: submit}); const handleBackButtonPress = () => { if (screenIndex === 0) { - // TODO: temporary for refactor https://github.com/Expensify/App/issues/36648 Navigation.navigate(ROUTES.SETTINGS_WALLET); return; } diff --git a/src/pages/EnablePayments/FeesAndTerms/substeps/TermsStep.tsx b/src/pages/EnablePayments/FeesAndTerms/substeps/TermsStep.tsx index 270f0c1f1699..afbd6d594274 100644 --- a/src/pages/EnablePayments/FeesAndTerms/substeps/TermsStep.tsx +++ b/src/pages/EnablePayments/FeesAndTerms/substeps/TermsStep.tsx @@ -28,6 +28,7 @@ function HaveReadAndAgreeLabel() { function AgreeToTheLabel() { const {translate} = useLocalize(); const [userWallet] = useOnyx(ONYXKEYS.USER_WALLET); + const walletAgreementUrl = userWallet?.walletProgramID === CONST.WALLET.MTL_WALLET_PROGRAM_ID ? CONST.WALLET_AGREEMENT_URL : CONST.BANCORP_WALLET_AGREEMENT_URL; return ( @@ -94,11 +95,6 @@ function TermsStep() { } setError(false); - BankAccounts.acceptWalletTerms({ - hasAcceptedTerms: hasAcceptedDisclosure && hasAcceptedPrivacyPolicyAndWalletAgreement, - reportID: walletTerms?.chatReportID ?? '', - }); - Navigation.navigate(ROUTES.SETTINGS_WALLET); }} message={errorMessage} isAlertVisible={error || Boolean(errorMessage)} diff --git a/src/pages/EnablePayments/VerifyIdentity/VerifyIdentity.tsx b/src/pages/EnablePayments/VerifyIdentity/VerifyIdentity.tsx index c2023077af50..0c27fb5980af 100644 --- a/src/pages/EnablePayments/VerifyIdentity/VerifyIdentity.tsx +++ b/src/pages/EnablePayments/VerifyIdentity/VerifyIdentity.tsx @@ -22,23 +22,16 @@ import * as BankAccounts from '@userActions/BankAccounts'; import * as Wallet from '@userActions/Wallet'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {PersonalBankAccount, WalletOnfido} from '@src/types/onyx'; +import type {WalletOnfido} from '@src/types/onyx'; const DEFAULT_WALLET_ONFIDO_DATA = { - loading: false, + isLoading: false, hasAcceptedPrivacyPolicy: false, + sdkToken: '', + applicantID: '', }; type VerifyIdentityOnyxProps = { - /** Reimbursement account from ONYX */ - personalBankAccount: OnyxEntry; - - /** Onfido applicant ID from ONYX */ - onfidoApplicantID: OnyxEntry; - - /** The token required to initialize the Onfido SDK */ - onfidoToken: OnyxEntry; - /** The wallet onfido data */ walletOnfidoData: OnyxEntry; }; @@ -47,7 +40,7 @@ type VerifyIdentityProps = VerifyIdentityOnyxProps; const ONFIDO_ERROR_DISPLAY_DURATION = 10000; -function VerifyIdentity({personalBankAccount, walletOnfidoData = DEFAULT_WALLET_ONFIDO_DATA}: VerifyIdentityProps) { +function VerifyIdentity({walletOnfidoData = DEFAULT_WALLET_ONFIDO_DATA}: VerifyIdentityProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -55,8 +48,6 @@ function VerifyIdentity({personalBankAccount, walletOnfidoData = DEFAULT_WALLET_ BankAccounts.openOnfidoFlow(); }; - const {isLoading = false, hasAcceptedPrivacyPolicy, sdkToken, applicantID} = walletOnfidoData; - const handleOnfidoSuccess = useCallback( (onfidoData: OnfidoData) => { BankAccounts.verifyIdentity({ @@ -67,24 +58,16 @@ function VerifyIdentity({personalBankAccount, walletOnfidoData = DEFAULT_WALLET_ }); BankAccounts.updateAddPersonalBankAccountDraft({isOnfidoSetupComplete: true}); }, - [personalBankAccount, applicantID], + [walletOnfidoData?.applicantID], ); const onfidoError = ErrorUtils.getLatestErrorMessage(walletOnfidoData) ?? ''; const handleOnfidoError = () => { - // In case of any unexpected error we log it to the server, show a growl, and return the user back to the requestor step so they can try again. Growl.error(translate('onfidoStep.genericError'), ONFIDO_ERROR_DISPLAY_DURATION); - BankAccounts.clearOnfidoToken(); - // BankAccounts.goToWithdrawalAccountSetupStep(CONST.BANK_ACCOUNT.STEP.REQUESTOR); - }; - - const handleOnfidoUserExit = () => { - BankAccounts.clearOnfidoToken(); - // BankAccounts.goToWithdrawalAccountSetupStep(CONST.BANK_ACCOUNT.STEP.REQUESTOR); }; - const handleBackButtonPress = () => { + const goBack = () => { Wallet.updateCurrentStep(CONST.WALLET.STEP.ADDITIONAL_DETAILS); }; @@ -92,7 +75,7 @@ function VerifyIdentity({personalBankAccount, walletOnfidoData = DEFAULT_WALLET_ - {hasAcceptedPrivacyPolicy ? ( + {walletOnfidoData?.hasAcceptedPrivacyPolicy ? ( @@ -125,9 +108,8 @@ function VerifyIdentity({personalBankAccount, walletOnfidoData = DEFAULT_WALLET_ {}} message={onfidoError} - isLoading={isLoading} + isLoading={walletOnfidoData?.isLoading} buttonText={onfidoError ? translate('onfidoStep.tryAgain') : translate('common.continue')} containerStyles={[styles.mh0, styles.mv0, styles.mb0]} /> diff --git a/src/types/form/PersonalBankAccountForm.ts b/src/types/form/PersonalBankAccountForm.ts index 1a1922bf8013..a5b95b20e684 100644 --- a/src/types/form/PersonalBankAccountForm.ts +++ b/src/types/form/PersonalBankAccountForm.ts @@ -32,7 +32,11 @@ type PlaidAccountProps = { [INPUT_IDS.BANK_INFO_STEP.SELECTED_PLAID_ACCOUNT_ID]: string; }; -type PersonalBankAccountForm = Form; +type OnfidoStepProps = { + isOnfidoSetupComplete: boolean; +}; + +type PersonalBankAccountForm = Form & OnfidoStepProps; export type {BankAccountStepProps, PlaidAccountProps, PersonalBankAccountForm}; From ec1846c2568cd745facfbbb103c9f402443c83c1 Mon Sep 17 00:00:00 2001 From: dragnoir Date: Thu, 23 May 2024 12:35:47 +0100 Subject: [PATCH 024/144] Fix; add spacing between comment and Uploading attachment... --- .../HTMLEngineProvider/BaseHTMLEngineProvider.tsx | 7 ++++++- src/libs/ReportUtils.ts | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.tsx b/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.tsx index 51f9981f1524..406e5e1cbc8b 100755 --- a/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.tsx +++ b/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.tsx @@ -77,8 +77,13 @@ function BaseHTMLEngineProvider({textSelectable = false, children, enableExperim mixedUAStyles: {...styles.textSupporting, ...styles.textLineThrough}, contentModel: HTMLContentModel.textual, }), + 'uploading-attachment': HTMLElementModel.fromCustomModel({ + tagName: 'uploading-attachment', + mixedUAStyles: {...styles.mt3}, + contentModel: HTMLContentModel.block, + }), }), - [styles.formError, styles.mb0, styles.colorMuted, styles.textLabelSupporting, styles.lh16, styles.textSupporting, styles.textLineThrough], + [styles.formError, styles.mb0, styles.colorMuted, styles.textLabelSupporting, styles.lh16, styles.textSupporting, styles.textLineThrough, styles.mt3], ); /* eslint-enable @typescript-eslint/naming-convention */ diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index b8e4c448fdc2..ecd0a94230c0 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3450,7 +3450,7 @@ function buildOptimisticAddCommentReportAction( htmlForNewComment = commentText; textForNewComment = parser.htmlToText(htmlForNewComment); } else { - htmlForNewComment = `${commentText}\n${CONST.ATTACHMENT_UPLOADING_MESSAGE_HTML}`; + htmlForNewComment = `${commentText}\n${CONST.ATTACHMENT_UPLOADING_MESSAGE_HTML}`; textForNewComment = `${parser.htmlToText(commentText)}\n${CONST.ATTACHMENT_UPLOADING_MESSAGE_HTML}`; } From 9764c602fbf58b74790457f1b4836bf6c4c32da4 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Thu, 23 May 2024 16:56:27 +0200 Subject: [PATCH 025/144] chore: clean wallet draft after finishing the flow --- src/pages/EnablePayments/FeesAndTerms/FeesAndTerms.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/EnablePayments/FeesAndTerms/FeesAndTerms.tsx b/src/pages/EnablePayments/FeesAndTerms/FeesAndTerms.tsx index 64e99bd9be05..5b462c278509 100644 --- a/src/pages/EnablePayments/FeesAndTerms/FeesAndTerms.tsx +++ b/src/pages/EnablePayments/FeesAndTerms/FeesAndTerms.tsx @@ -30,7 +30,7 @@ function FeesAndTerms() { reportID: walletTerms?.chatReportID ?? '', }); BankAccounts.clearPersonalBankAccount(); - // TODO: clear wallet draft + Wallet.resetWalletAdditionalDetailsDraft(); Navigation.navigate(ROUTES.SETTINGS_WALLET); }; const {componentToRender: SubStep, isEditing, screenIndex, nextScreen, prevScreen, moveTo} = useSubStep({bodyContent: termsAndFeesSubsteps, startFrom: 0, onFinished: submit}); From aa7d744a1736bf3cde203caacc2dd2eabb7ba307 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Thu, 23 May 2024 18:50:24 +0200 Subject: [PATCH 026/144] fix: remove old add plaid bank account layout --- src/components/AddPlaidBankAccount.tsx | 68 +++++-------------- src/pages/AddPersonalBankAccountPage.tsx | 1 + .../BankInfo/substeps/Plaid.tsx | 1 - 3 files changed, 18 insertions(+), 52 deletions(-) diff --git a/src/components/AddPlaidBankAccount.tsx b/src/components/AddPlaidBankAccount.tsx index 366f14ec9780..fddfe5b8e8d9 100644 --- a/src/components/AddPlaidBankAccount.tsx +++ b/src/components/AddPlaidBankAccount.tsx @@ -59,9 +59,6 @@ type AddPlaidBankAccountProps = AddPlaidBankAccountOnyxProps & { /** Are we adding a withdrawal account? */ allowDebit?: boolean; - /** Is displayed in new VBBA */ - isDisplayedInNewVBBA?: boolean; - /** Is displayed in new enable wallet flow */ isDisplayedInWalletFlow?: boolean; @@ -84,7 +81,6 @@ function AddPlaidBankAccount({ bankAccountID = 0, allowDebit = false, isPlaidDisabled, - isDisplayedInNewVBBA = false, errorText = '', onInputChange = () => {}, isDisplayedInWalletFlow = false, @@ -259,62 +255,32 @@ function AddPlaidBankAccount({ return {renderPlaidLink()}; } - if (isDisplayedInNewVBBA || isDisplayedInWalletFlow) { - return ( - - {translate(isDisplayedInWalletFlow ? 'walletPage.chooseYourBankAccount' : 'bankAccount.chooseAnAccount')} - {!!text && {text}} - - - - {bankName} - {selectedPlaidAccountMask.length > 0 && ( - {`${translate('bankAccount.accountEnding')} ${selectedPlaidAccountMask}`} - )} - - - {`${translate('bankAccount.chooseAnAccountBelow')}:`} - - - - ); - } - - // Plaid bank accounts view return ( - {!!text && {text}} - + {translate(isDisplayedInWalletFlow ? 'walletPage.chooseYourBankAccount' : 'bankAccount.chooseAnAccount')} + {!!text && {text}} + - {bankName} - - - + + {bankName} + {selectedPlaidAccountMask.length > 0 && ( + {`${translate('bankAccount.accountEnding')} ${selectedPlaidAccountMask}`} + )} + + {`${translate('bankAccount.chooseAnAccountBelow')}:`} + + ); } diff --git a/src/pages/AddPersonalBankAccountPage.tsx b/src/pages/AddPersonalBankAccountPage.tsx index 5cd0f3ef8026..98506477eaf9 100644 --- a/src/pages/AddPersonalBankAccountPage.tsx +++ b/src/pages/AddPersonalBankAccountPage.tsx @@ -90,6 +90,7 @@ function AddPersonalBankAccountPage({personalBankAccount, plaidData}: AddPersona Navigation.goBack()} receivedRedirectURI={getPlaidOAuthReceivedRedirectURI()} selectedPlaidAccountID={selectedPlaidAccountId} diff --git a/src/pages/ReimbursementAccount/BankInfo/substeps/Plaid.tsx b/src/pages/ReimbursementAccount/BankInfo/substeps/Plaid.tsx index c58c2f40aa07..03409e4adddf 100644 --- a/src/pages/ReimbursementAccount/BankInfo/substeps/Plaid.tsx +++ b/src/pages/ReimbursementAccount/BankInfo/substeps/Plaid.tsx @@ -88,7 +88,6 @@ function Plaid({reimbursementAccount, reimbursementAccountDraft, onNext, plaidDa allowDebit bankAccountID={bankAccountID} selectedPlaidAccountID={selectedPlaidAccountID} - isDisplayedInNewVBBA inputID={BANK_INFO_STEP_KEYS.SELECTED_PLAID_ACCOUNT_ID} defaultValue={selectedPlaidAccountID} /> From f189a8cc3cbf50a5c7758d004a46011454cb5853 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Thu, 23 May 2024 21:23:02 +0200 Subject: [PATCH 027/144] fix: include add bank acount to the flow --- src/CONST.ts | 1 + src/pages/AddPersonalBankAccountPage.tsx | 1 + src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx | 4 ++-- src/pages/EnablePayments/EnablePayments.tsx | 5 ++++- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index af5f32808034..6ef98d656e14 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1423,6 +1423,7 @@ const CONST = { }, STEP: { // In the order they appear in the Wallet flow + ADD_BANK_ACCOUNT: 'AddBankAccountStep', ADDITIONAL_DETAILS: 'AdditionalDetailsStep', ADDITIONAL_DETAILS_KBA: 'AdditionalDetailsKBAStep', ONFIDO: 'OnfidoStep', diff --git a/src/pages/AddPersonalBankAccountPage.tsx b/src/pages/AddPersonalBankAccountPage.tsx index 98506477eaf9..59046e103c6b 100644 --- a/src/pages/AddPersonalBankAccountPage.tsx +++ b/src/pages/AddPersonalBankAccountPage.tsx @@ -89,6 +89,7 @@ function AddPersonalBankAccountPage({personalBankAccount, plaidData}: AddPersona > Navigation.goBack()} diff --git a/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx b/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx index 9fde5456226b..149d6a41aac7 100644 --- a/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx +++ b/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx @@ -12,9 +12,9 @@ import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@navigation/Navigation'; import * as BankAccounts from '@userActions/BankAccounts'; import * as PaymentMethods from '@userActions/PaymentMethods'; +import * as Wallet from '@userActions/Wallet'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; import type {PersonalBankAccountForm} from '@src/types/form'; import type {PersonalBankAccount, PlaidData} from '@src/types/onyx'; import SetupMethod from './SetupMethod'; @@ -44,7 +44,7 @@ function AddBankAccount({personalBankAccount, plaidData, personalBankAccountDraf if (selectedPlaidBankAccount) { BankAccounts.addPersonalBankAccount(selectedPlaidBankAccount); - Navigation.navigate(ROUTES.SETTINGS_ENABLE_PAYMENTS_REFACTOR); + Wallet.updateCurrentStep(CONST.WALLET.STEP.ADDITIONAL_DETAILS); } }, [personalBankAccountDraft?.plaidAccountID, plaidData?.bankAccounts]); diff --git a/src/pages/EnablePayments/EnablePayments.tsx b/src/pages/EnablePayments/EnablePayments.tsx index fdee18e8147d..752705cd6d27 100644 --- a/src/pages/EnablePayments/EnablePayments.tsx +++ b/src/pages/EnablePayments/EnablePayments.tsx @@ -7,6 +7,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import Navigation from '@libs/Navigation/Navigation'; +import AddBankAccount from '@pages/EnablePayments/AddBankAccount/AddBankAccount'; import * as Wallet from '@userActions/Wallet'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -60,9 +61,11 @@ function EnablePaymentsPage({userWallet}: EnablePaymentsPageProps) { ); } - const currentStep = userWallet?.currentStep || CONST.WALLET.STEP.ADDITIONAL_DETAILS; + const currentStep = userWallet?.currentStep || (userWallet?.bankAccountID ? CONST.WALLET.STEP.ADDITIONAL_DETAILS : CONST.WALLET.STEP.ADD_BANK_ACCOUNT); switch (currentStep) { + case CONST.WALLET.STEP.ADD_BANK_ACCOUNT: + return ; case CONST.WALLET.STEP.ADDITIONAL_DETAILS: return ; case CONST.WALLET.STEP.ONFIDO: From 034b82df570a5822c65be0d8a1f475ef4104cf8a Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Fri, 24 May 2024 11:55:44 +0200 Subject: [PATCH 028/144] fix: show loading when confirming personal info, fetch userWallet only when missing data --- src/pages/EnablePayments/EnablePayments.tsx | 10 ++++------ .../PersonalInfo/substeps/ConfirmationStep.tsx | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/pages/EnablePayments/EnablePayments.tsx b/src/pages/EnablePayments/EnablePayments.tsx index 752705cd6d27..5d7dd52c1e89 100644 --- a/src/pages/EnablePayments/EnablePayments.tsx +++ b/src/pages/EnablePayments/EnablePayments.tsx @@ -35,8 +35,10 @@ function EnablePaymentsPage({userWallet}: EnablePaymentsPageProps) { return; } - Wallet.openEnablePaymentsPage(); - }, [isOffline]); + if (isEmptyObject(userWallet)) { + Wallet.openEnablePaymentsPage(); + } + }, [isOffline, userWallet]); if (isEmptyObject(userWallet)) { return ; @@ -85,9 +87,5 @@ EnablePaymentsPage.displayName = 'EnablePaymentsPage'; export default withOnyx({ userWallet: { key: ONYXKEYS.USER_WALLET, - - // We want to refresh the wallet each time the user attempts to activate the wallet so we won't use the - // stored values here. - initWithStoredValues: false, }, })(EnablePaymentsPage); diff --git a/src/pages/EnablePayments/PersonalInfo/substeps/ConfirmationStep.tsx b/src/pages/EnablePayments/PersonalInfo/substeps/ConfirmationStep.tsx index b24400face07..ea1b70cd6074 100644 --- a/src/pages/EnablePayments/PersonalInfo/substeps/ConfirmationStep.tsx +++ b/src/pages/EnablePayments/PersonalInfo/substeps/ConfirmationStep.tsx @@ -29,7 +29,7 @@ function ConfirmationStep({onNext, onMove}: SubStepProps) { const [walletAdditionalDetails] = useOnyx(ONYXKEYS.WALLET_ADDITIONAL_DETAILS); const [walletAdditionalDetailsDraft] = useOnyx(ONYXKEYS.FORMS.WALLET_ADDITIONAL_DETAILS_DRAFT); - const isLoading = walletAdditionalDetailsDraft?.isLoading ?? false; + const isLoading = walletAdditionalDetails?.isLoading ?? false; const error = ErrorUtils.getLatestErrorMessage(walletAdditionalDetails ?? {}); const values = useMemo(() => getSubstepValues(PERSONAL_INFO_STEP_KEYS, walletAdditionalDetailsDraft, walletAdditionalDetails), [walletAdditionalDetails, walletAdditionalDetailsDraft]); From c5291d7abd9521f9ea0b6d8afb7853b8f049c1fd Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Fri, 24 May 2024 13:25:22 +0200 Subject: [PATCH 029/144] fix: proper submit/go back handling for the terms step --- .../FeesAndTerms/FeesAndTerms.tsx | 2 +- .../FeesAndTerms/substeps/TermsStep.tsx | 24 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/pages/EnablePayments/FeesAndTerms/FeesAndTerms.tsx b/src/pages/EnablePayments/FeesAndTerms/FeesAndTerms.tsx index 5b462c278509..512abc57a990 100644 --- a/src/pages/EnablePayments/FeesAndTerms/FeesAndTerms.tsx +++ b/src/pages/EnablePayments/FeesAndTerms/FeesAndTerms.tsx @@ -37,7 +37,7 @@ function FeesAndTerms() { const handleBackButtonPress = () => { if (screenIndex === 0) { - Navigation.navigate(ROUTES.SETTINGS_WALLET); + Wallet.updateCurrentStep(CONST.WALLET.STEP.ONFIDO); return; } prevScreen(); diff --git a/src/pages/EnablePayments/FeesAndTerms/substeps/TermsStep.tsx b/src/pages/EnablePayments/FeesAndTerms/substeps/TermsStep.tsx index afbd6d594274..12fce0b2ec50 100644 --- a/src/pages/EnablePayments/FeesAndTerms/substeps/TermsStep.tsx +++ b/src/pages/EnablePayments/FeesAndTerms/substeps/TermsStep.tsx @@ -6,13 +6,11 @@ import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; +import type {SubStepProps} from '@hooks/useSubStep/types'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; -import Navigation from '@navigation/Navigation'; -import * as BankAccounts from '@userActions/BankAccounts'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; function HaveReadAndAgreeLabel() { const {translate} = useLocalize(); @@ -41,7 +39,7 @@ function AgreeToTheLabel() { ); } -function TermsStep() { +function TermsStep({onNext}: SubStepProps) { const styles = useThemeStyles(); const [hasAcceptedDisclosure, setHasAcceptedDisclosure] = useState(false); const [hasAcceptedPrivacyPolicyAndWalletAgreement, setHasAcceptedPrivacyPolicyAndWalletAgreement] = useState(false); @@ -60,6 +58,15 @@ function TermsStep() { setHasAcceptedPrivacyPolicyAndWalletAgreement(!hasAcceptedPrivacyPolicyAndWalletAgreement); }; + const submit = () => { + if (!hasAcceptedDisclosure || !hasAcceptedPrivacyPolicyAndWalletAgreement) { + setError(true); + return; + } + setError(false); + onNext(); + }; + /** clear error */ useEffect(() => { if (!hasAcceptedDisclosure || !hasAcceptedPrivacyPolicyAndWalletAgreement) { @@ -88,14 +95,7 @@ function TermsStep() { { - if (!hasAcceptedDisclosure || !hasAcceptedPrivacyPolicyAndWalletAgreement) { - setError(true); - return; - } - - setError(false); - }} + onSubmit={submit} message={errorMessage} isAlertVisible={error || Boolean(errorMessage)} isLoading={!!walletTerms?.isLoading} From 3538c6951b2b98a88ed5430d60f657061b1d9220 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Fri, 24 May 2024 14:43:47 +0200 Subject: [PATCH 030/144] fix: properly show the first step --- src/pages/EnablePayments/EnablePayments.tsx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/pages/EnablePayments/EnablePayments.tsx b/src/pages/EnablePayments/EnablePayments.tsx index 5d7dd52c1e89..ff0aa7b353bb 100644 --- a/src/pages/EnablePayments/EnablePayments.tsx +++ b/src/pages/EnablePayments/EnablePayments.tsx @@ -7,13 +7,13 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import Navigation from '@libs/Navigation/Navigation'; -import AddBankAccount from '@pages/EnablePayments/AddBankAccount/AddBankAccount'; import * as Wallet from '@userActions/Wallet'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {UserWallet} from '@src/types/onyx'; +import type {BankAccountList, UserWallet} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import AddBankAccount from './AddBankAccount/AddBankAccount'; import FailedKYC from './FailedKYC'; import FeesAndTerms from './FeesAndTerms/FeesAndTerms'; import PersonalInfo from './PersonalInfo/PersonalInfo'; @@ -22,11 +22,14 @@ import VerifyIdentity from './VerifyIdentity/VerifyIdentity'; type EnablePaymentsPageOnyxProps = { /** The user's wallet */ userWallet: OnyxEntry; + + /** The list of bank accounts */ + bankAccountList: OnyxEntry; }; type EnablePaymentsPageProps = EnablePaymentsPageOnyxProps; -function EnablePaymentsPage({userWallet}: EnablePaymentsPageProps) { +function EnablePaymentsPage({userWallet, bankAccountList}: EnablePaymentsPageProps) { const {translate} = useLocalize(); const {isOffline} = useNetwork(); @@ -63,7 +66,7 @@ function EnablePaymentsPage({userWallet}: EnablePaymentsPageProps) { ); } - const currentStep = userWallet?.currentStep || (userWallet?.bankAccountID ? CONST.WALLET.STEP.ADDITIONAL_DETAILS : CONST.WALLET.STEP.ADD_BANK_ACCOUNT); + const currentStep = userWallet?.currentStep || (isEmptyObject(bankAccountList) ? CONST.WALLET.STEP.ADD_BANK_ACCOUNT : CONST.WALLET.STEP.ADDITIONAL_DETAILS); switch (currentStep) { case CONST.WALLET.STEP.ADD_BANK_ACCOUNT: @@ -88,4 +91,7 @@ export default withOnyx({ userWallet: { key: ONYXKEYS.USER_WALLET, }, + bankAccountList: { + key: ONYXKEYS.BANK_ACCOUNT_LIST, + }, })(EnablePaymentsPage); From c1bea82678c9a16796fdef26b914c48a2795691f Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Fri, 24 May 2024 15:02:55 +0200 Subject: [PATCH 031/144] fix: remove unnecessary comment --- src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx b/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx index 149d6a41aac7..574034159e06 100644 --- a/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx +++ b/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx @@ -54,7 +54,6 @@ function AddBankAccount({personalBankAccount, plaidData, personalBankAccountDraf const exitFlow = (shouldContinue = false) => { const exitReportID = personalBankAccount?.exitReportID; - // TODO: https://github.com/Expensify/App/issues/36648 This should be updated to the correct route once the refactor is complete const onSuccessFallbackRoute = personalBankAccount?.onSuccessFallbackRoute ?? ''; if (exitReportID) { From f3287b8e9acfc57977821d6ccd918fb3a46a5d9f Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Fri, 24 May 2024 15:27:06 +0200 Subject: [PATCH 032/144] feat: routes cleanup --- src/ROUTES.ts | 5 ----- src/SCREENS.ts | 3 --- .../AppNavigator/ModalStackNavigators/index.tsx | 5 +---- src/libs/Navigation/linkingConfig/config.ts | 14 -------------- .../EnablePayments/AddBankAccount/SetupMethod.tsx | 4 ++-- src/pages/EnablePayments/EnablePayments.tsx | 2 +- .../settings/Wallet/WalletPage/WalletPage.tsx | 2 +- 7 files changed, 5 insertions(+), 30 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 2bc04c4a99ea..20520a2eb9ce 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -123,12 +123,7 @@ const ROUTES = { }, SETTINGS_ADD_DEBIT_CARD: 'settings/wallet/add-debit-card', SETTINGS_ADD_BANK_ACCOUNT: 'settings/wallet/add-bank-account', - SETTINGS_ADD_BANK_ACCOUNT_REFACTOR: 'settings/wallet/add-bank-account-refactor', SETTINGS_ENABLE_PAYMENTS: 'settings/wallet/enable-payments', - // TODO: Added temporarily for testing purposes, remove after refactor - https://github.com/Expensify/App/issues/36648 - SETTINGS_ENABLE_PAYMENTS_REFACTOR: 'settings/wallet/enable-payments-refactor', - // TODO: Added temporarily for testing purposes, remove after refactor - https://github.com/Expensify/App/issues/36648 - SETTINGS_ENABLE_PAYMENTS_TEMPORARY_TERMS: 'settings/wallet/enable-payments-temporary-terms', SETTINGS_WALLET_CARD_DIGITAL_DETAILS_UPDATE_ADDRESS: { route: 'settings/wallet/card/:domain/digital-details/update-address', getRoute: (domain: string) => `settings/wallet/card/${domain}/digital-details/update-address` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index f74002312623..fc57724614b5 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -42,7 +42,6 @@ const SCREENS = { APP_DOWNLOAD_LINKS: 'Settings_App_Download_Links', ADD_DEBIT_CARD: 'Settings_Add_Debit_Card', ADD_BANK_ACCOUNT: 'Settings_Add_Bank_Account', - ADD_BANK_ACCOUNT_REFACTOR: 'Settings_Add_Bank_Account_Refactor', CLOSE: 'Settings_Close', TWO_FACTOR_AUTH: 'Settings_TwoFactorAuth', REPORT_CARD_LOST_OR_DAMAGED: 'Settings_ReportCardLostOrDamaged', @@ -91,8 +90,6 @@ const SCREENS = { ENABLE_PAYMENTS: 'Settings_Wallet_EnablePayments', // TODO: Added temporarily for testing purposes, remove after refactor - https://github.com/Expensify/App/issues/36648 ENABLE_PAYMENTS_REFACTOR: 'Settings_Wallet_EnablePayments_Refactor', - // TODO: Added temporarily for testing purposes, remove after refactor - https://github.com/Expensify/App/issues/36648 - ENABLE_PAYMENTS_TEMPORARY_TERMS: 'Settings_Wallet_EnablePayments_Temporary_Terms', CARD_ACTIVATE: 'Settings_Wallet_Card_Activate', REPORT_VIRTUAL_CARD_FRAUD: 'Settings_Wallet_ReportVirtualCardFraud', CARDS_DIGITAL_DETAILS_UPDATE_ADDRESS: 'Settings_Wallet_Cards_Digital_Details_Update_Address', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index ca46a61787b9..f19a9f5be1ad 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -203,12 +203,9 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/settings/Wallet/Card/GetPhysicalCardConfirm').default as React.ComponentType, [SCREENS.SETTINGS.WALLET.TRANSFER_BALANCE]: () => require('../../../../pages/settings/Wallet/TransferBalancePage').default as React.ComponentType, [SCREENS.SETTINGS.WALLET.CHOOSE_TRANSFER_ACCOUNT]: () => require('../../../../pages/settings/Wallet/ChooseTransferAccountPage').default as React.ComponentType, - [SCREENS.SETTINGS.WALLET.ENABLE_PAYMENTS]: () => require('../../../../pages/EnablePayments/EnablePaymentsPage').default as React.ComponentType, - // TODO: Added temporarily for testing purposes, remove after refactor - https://github.com/Expensify/App/issues/36648 - [SCREENS.SETTINGS.WALLET.ENABLE_PAYMENTS_REFACTOR]: () => require('../../../../pages/EnablePayments/EnablePayments').default as React.ComponentType, + [SCREENS.SETTINGS.WALLET.ENABLE_PAYMENTS]: () => require('../../../../pages/EnablePayments/EnablePayments').default as React.ComponentType, [SCREENS.SETTINGS.ADD_DEBIT_CARD]: () => require('../../../../pages/settings/Wallet/AddDebitCardPage').default as React.ComponentType, [SCREENS.SETTINGS.ADD_BANK_ACCOUNT]: () => require('../../../../pages/AddPersonalBankAccountPage').default as React.ComponentType, - [SCREENS.SETTINGS.ADD_BANK_ACCOUNT_REFACTOR]: () => require('../../../../pages/EnablePayments/AddBankAccount/AddBankAccount').default as React.ComponentType, [SCREENS.SETTINGS.PROFILE.STATUS]: () => require('../../../../pages/settings/Profile/CustomStatus/StatusPage').default as React.ComponentType, [SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER]: () => require('../../../../pages/settings/Profile/CustomStatus/StatusClearAfterPage').default as React.ComponentType, [SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER_DATE]: () => require('../../../../pages/settings/Profile/CustomStatus/SetDatePage').default as React.ComponentType, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index a093b778360e..d9982a0bf00c 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -161,16 +161,6 @@ const config: LinkingOptions['config'] = { path: ROUTES.SETTINGS_ENABLE_PAYMENTS, exact: true, }, - // TODO: Added temporarily for testing purposes, remove after refactor - https://github.com/Expensify/App/issues/36648 - [SCREENS.SETTINGS.WALLET.ENABLE_PAYMENTS_REFACTOR]: { - path: ROUTES.SETTINGS_ENABLE_PAYMENTS_REFACTOR, - exact: true, - }, - // TODO: Added temporarily for testing purposes, remove after refactor - https://github.com/Expensify/App/issues/36648 - [SCREENS.SETTINGS.WALLET.ENABLE_PAYMENTS_TEMPORARY_TERMS]: { - path: ROUTES.SETTINGS_ENABLE_PAYMENTS_TEMPORARY_TERMS, - exact: true, - }, [SCREENS.SETTINGS.WALLET.TRANSFER_BALANCE]: { path: ROUTES.SETTINGS_WALLET_TRANSFER_BALANCE, exact: true, @@ -199,10 +189,6 @@ const config: LinkingOptions['config'] = { path: ROUTES.SETTINGS_ADD_BANK_ACCOUNT, exact: true, }, - [SCREENS.SETTINGS.ADD_BANK_ACCOUNT_REFACTOR]: { - path: ROUTES.SETTINGS_ADD_BANK_ACCOUNT_REFACTOR, - exact: true, - }, [SCREENS.SETTINGS.PROFILE.PRONOUNS]: { path: ROUTES.SETTINGS_PRONOUNS, exact: true, diff --git a/src/pages/EnablePayments/AddBankAccount/SetupMethod.tsx b/src/pages/EnablePayments/AddBankAccount/SetupMethod.tsx index e70d5979e92e..f58c158ba448 100644 --- a/src/pages/EnablePayments/AddBankAccount/SetupMethod.tsx +++ b/src/pages/EnablePayments/AddBankAccount/SetupMethod.tsx @@ -28,7 +28,7 @@ type SetupMethodOnyxProps = { type SetupMethodProps = SetupMethodOnyxProps; const plaidDesktopMessage = getPlaidDesktopMessage(); -const bankAccountRoute = `${CONFIG.EXPENSIFY.NEW_EXPENSIFY_URL}${ROUTES.SETTINGS_ADD_BANK_ACCOUNT_REFACTOR}`; +const enablePayments = `${CONFIG.EXPENSIFY.NEW_EXPENSIFY_URL}${ROUTES.SETTINGS_ENABLE_PAYMENTS}`; function SetupMethod({isPlaidDisabled, user}: SetupMethodProps) { const styles = useThemeStyles(); @@ -46,7 +46,7 @@ function SetupMethod({isPlaidDisabled, user}: SetupMethodProps) { {!!plaidDesktopMessage && ( - {translate(plaidDesktopMessage)} + {translate(plaidDesktopMessage)} )}