From 6373c37e92374365e4391afb8371236c6d1b5237 Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Wed, 22 Jan 2025 12:22:05 +0900 Subject: [PATCH 01/39] fix:blank page appears in validate code form page --- .../ValidateCodeActionModal/type.ts | 2 +- .../ValidateCodeActionWithoutModal.tsx | 79 +++++++++++ .../Contacts/ContactMethodDetailsPage.tsx | 129 +++++++++++------- 3 files changed, 161 insertions(+), 49 deletions(-) create mode 100644 src/components/ValidateCodeActionWithoutModal.tsx diff --git a/src/components/ValidateCodeActionModal/type.ts b/src/components/ValidateCodeActionModal/type.ts index 4f70870ead3c..81743304ff9c 100644 --- a/src/components/ValidateCodeActionModal/type.ts +++ b/src/components/ValidateCodeActionModal/type.ts @@ -7,7 +7,7 @@ type ValidateCodeActionModalProps = { isVisible: boolean; /** Title of the modal */ - title: string; + title?: string; /** Primary description of the modal */ descriptionPrimary: string; diff --git a/src/components/ValidateCodeActionWithoutModal.tsx b/src/components/ValidateCodeActionWithoutModal.tsx new file mode 100644 index 000000000000..39a1a5d0cc5f --- /dev/null +++ b/src/components/ValidateCodeActionWithoutModal.tsx @@ -0,0 +1,79 @@ +import React, {forwardRef, useEffect, useRef} from 'react'; +import type {ForwardedRef} from 'react'; +import {View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; +import useThemeStyles from '@hooks/useThemeStyles'; +import ONYXKEYS from '@src/ONYXKEYS'; +import Text from './Text'; +import type {ValidateCodeActionModalProps} from './ValidateCodeActionModal/type'; +import ValidateCodeForm from './ValidateCodeActionModal/ValidateCodeForm'; +import type {ValidateCodeFormHandle} from './ValidateCodeActionModal/ValidateCodeForm/BaseValidateCodeForm'; + +type ValidateCodeActionWithoutModalProps = { + forwardedRef: ForwardedRef; +}; + +type ValidateCodeActionProps = ValidateCodeActionModalProps & ValidateCodeActionWithoutModalProps; + +function ValidateCodeActionWithoutModal({ + isVisible, + descriptionPrimary, + descriptionSecondary, + validatePendingAction, + validateError, + handleSubmitForm, + clearError, + sendValidateCode, + hasMagicCodeBeenSent, + isLoading, + forwardedRef, +}: ValidateCodeActionProps) { + const themeStyles = useThemeStyles(); + const firstRenderRef = useRef(true); + + const [validateCodeAction] = useOnyx(ONYXKEYS.VALIDATE_ACTION_CODE); + + useEffect( + () => () => { + clearError(); + firstRenderRef.current = true; + }, + [clearError], + ); + + useEffect(() => { + if (!firstRenderRef.current || !isVisible || hasMagicCodeBeenSent) { + return; + } + firstRenderRef.current = false; + sendValidateCode(); + }, [isVisible, sendValidateCode, hasMagicCodeBeenSent]); + + return ( + + {descriptionPrimary} + {!!descriptionSecondary && {descriptionSecondary}} + + + ); +} + +ValidateCodeActionWithoutModal.displayName = 'ValidateCodeActionWithoutModal'; + +export default forwardRef((props, ref) => ( + +)); diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index 37fc4d26c7f4..044a43f6ae21 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -7,27 +7,36 @@ import ConfirmModal from '@components/ConfirmModal'; import ErrorMessageRow from '@components/ErrorMessageRow'; import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import * as Expensicons from '@components/Icon/Expensicons'; +import {Star, Trashcan} from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; import Text from '@components/Text'; -import ValidateCodeActionModal from '@components/ValidateCodeActionModal'; +import ValidateCodeActionWithoutModal from '@components/ValidateCodeActionWithoutModal'; import useBeforeRemove from '@hooks/useBeforeRemove'; import useLocalize from '@hooks/useLocalize'; import usePrevious from '@hooks/usePrevious'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; +import useWindowDimensions from '@hooks/useWindowDimensions'; import blurActiveElement from '@libs/Accessibility/blurActiveElement'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; -import * as ErrorUtils from '@libs/ErrorUtils'; +import {getEarliestErrorField, getLatestErrorField} from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; import {addSMSDomainIfPhoneNumber} from '@libs/PhoneNumber'; -import * as Modal from '@userActions/Modal'; -import * as User from '@userActions/User'; +import {close} from '@userActions/Modal'; +import { + clearContactMethod, + clearContactMethodErrors, + clearUnvalidatedNewContactMethodAction, + deleteContactMethod, + requestContactMethodValidateCode, + setContactMethodAsDefault, + validateSecondaryLogin, +} from '@userActions/User'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -52,6 +61,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { const {formatPhoneNumber, translate} = useLocalize(); const theme = useTheme(); const themeStyles = useThemeStyles(); + const {windowWidth} = useWindowDimensions(); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const validateCodeFormRef = useRef(null); @@ -80,13 +90,13 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { }, [route.params.contactMethod]); const loginData = useMemo(() => loginList?.[contactMethod], [loginList, contactMethod]); const isDefaultContactMethod = useMemo(() => session?.email === loginData?.partnerUserID, [session?.email, loginData?.partnerUserID]); - const validateLoginError = ErrorUtils.getEarliestErrorField(loginData, 'validateLogin'); + const validateLoginError = getEarliestErrorField(loginData, 'validateLogin'); /** * Attempt to set this contact method as user's "Default contact method" */ const setAsDefault = useCallback(() => { - User.setContactMethodAsDefault(contactMethod, backTo); + setContactMethodAsDefault(contactMethod, backTo); }, [contactMethod, backTo]); /** @@ -136,7 +146,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { */ const confirmDeleteAndHideModal = useCallback(() => { toggleDeleteModal(false); - User.deleteContactMethod(contactMethod, loginList ?? {}, backTo); + deleteContactMethod(contactMethod, loginList ?? {}, backTo); }, [contactMethod, loginList, toggleDeleteModal, backTo]); const prevValidatedDate = usePrevious(loginData?.validatedDate); @@ -161,9 +171,9 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { const menuItems = []; if (isValidateCodeActionModalVisible && !isDefaultContactMethod) { menuItems.push({ - icon: Expensicons.Trashcan, + icon: Trashcan, text: translate('common.remove'), - onSelected: () => Modal.close(() => toggleDeleteModal(true)), + onSelected: () => close(() => toggleDeleteModal(true)), }); } return menuItems; @@ -214,13 +224,13 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { <> {canChangeDefaultContactMethod ? ( User.clearContactMethodErrors(contactMethod, 'defaultLogin')} + onClose={() => clearContactMethodErrors(contactMethod, 'defaultLogin')} > @@ -228,22 +238,22 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { {isDefaultContactMethod ? ( User.clearContactMethodErrors(contactMethod, isFailedRemovedContactMethod ? 'deletedLogin' : 'defaultLogin')} + onClose={() => clearContactMethodErrors(contactMethod, isFailedRemovedContactMethod ? 'deletedLogin' : 'defaultLogin')} > {translate('contacts.yourDefaultContactMethod')} ) : ( User.clearContactMethodErrors(contactMethod, 'deletedLogin')} + onClose={() => clearContactMethodErrors(contactMethod, 'deletedLogin')} > toggleDeleteModal(true)} /> @@ -257,51 +267,74 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { validateCodeFormRef.current?.focus?.()} testID={ContactMethodDetailsPage.displayName} + focusTrapSettings={{ + focusTrapOptions: { + checkCanFocusTrap: (trapContainers: Array) => { + return new Promise((resolve) => { + const interval = setInterval(() => { + const trapContainer = trapContainers.at(0) as HTMLElement | SVGElement; + if (getComputedStyle(trapContainer).visibility !== 'hidden') { + resolve(); + clearInterval(interval); + } + }, 5); + }); + }, + }, + }} > Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS.getRoute(backTo))} + threeDotsMenuItems={getThreeDotsMenuItems()} + shouldShowThreeDotsButton={getThreeDotsMenuItems().length > 0} + shouldOverlayDots + threeDotsAnchorPosition={themeStyles.threeDotsPopoverOffset(windowWidth)} + onThreeDotsButtonPress={() => { + // Hide the keyboard when the user clicks the three-dot menu. + // Use blurActiveElement() for mWeb and KeyboardUtils.dismiss() for native apps. + blurActiveElement(); + KeyboardUtils.dismiss(); + }} /> - + {isFailedAddContactMethod && ( { - User.clearContactMethod(contactMethod); - User.clearUnvalidatedNewContactMethodAction(); + clearContactMethod(contactMethod); + clearUnvalidatedNewContactMethodAction(); Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS.getRoute(backTo)); }} canDismissError /> )} - {}} - hasMagicCodeBeenSent={hasMagicCodeBeenSent} - isVisible={isValidateCodeActionModalVisible && !loginData.validatedDate && !!loginData} - validatePendingAction={loginData.pendingFields?.validateCodeSent} - handleSubmitForm={(validateCode) => User.validateSecondaryLogin(loginList, contactMethod, validateCode)} - validateError={!isEmptyObject(validateLoginError) ? validateLoginError : ErrorUtils.getLatestErrorField(loginData, 'validateCodeSent')} - clearError={() => User.clearContactMethodErrors(contactMethod, !isEmptyObject(validateLoginError) ? 'validateLogin' : 'validateCodeSent')} - onClose={() => { - Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS.getRoute(backTo)); - setIsValidateCodeActionModalVisible(false); - }} - sendValidateCode={() => User.requestContactMethodValidateCode(contactMethod)} - descriptionPrimary={translate('contacts.enterMagicCode', {contactMethod: formattedContactMethod})} - onThreeDotsButtonPress={() => { - // Hide the keyboard when the user clicks the three-dot menu. - // Use blurActiveElement() for mWeb and KeyboardUtils.dismiss() for native apps. - blurActiveElement(); - KeyboardUtils.dismiss(); - }} - threeDotsMenuItems={getThreeDotsMenuItems()} - footer={getDeleteConfirmationModal} - /> + {!loginData?.validatedDate && ( + validateSecondaryLogin(loginList, contactMethod, validateCode)} + validateError={!isEmptyObject(validateLoginError) ? validateLoginError : getLatestErrorField(loginData, 'validateCodeSent')} + clearError={() => clearContactMethodErrors(contactMethod, !isEmptyObject(validateLoginError) ? 'validateLogin' : 'validateCodeSent')} + sendValidateCode={() => requestContactMethodValidateCode(contactMethod)} + descriptionPrimary={translate('contacts.enterMagicCode', {contactMethod: formattedContactMethod})} + onThreeDotsButtonPress={() => { + // Hide the keyboard when the user clicks the three-dot menu. + // Use blurActiveElement() for mWeb and KeyboardUtils.dismiss() for native apps. + blurActiveElement(); + KeyboardUtils.dismiss(); + }} + threeDotsMenuItems={getThreeDotsMenuItems()} + forwardedRef={validateCodeFormRef} + /> + )} - {!isValidateCodeActionModalVisible && getMenuItems()} + {!isValidateCodeActionModalVisible && loginData?.validatedDate && getMenuItems()} ); From 172c7b0c26a2b296812f45347f8636b9fc481f9e Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Wed, 22 Jan 2025 12:27:43 +0900 Subject: [PATCH 02/39] lint: fixed ! assertion error --- src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index 044a43f6ae21..702fb89c2d83 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -272,6 +272,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { checkCanFocusTrap: (trapContainers: Array) => { return new Promise((resolve) => { const interval = setInterval(() => { + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style const trapContainer = trapContainers.at(0) as HTMLElement | SVGElement; if (getComputedStyle(trapContainer).visibility !== 'hidden') { resolve(); From c4e944fdeceba6b7214016e6bb6c8ea43d4d1355 Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Thu, 23 Jan 2025 05:20:42 +0900 Subject: [PATCH 03/39] pulled original/main --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 64b213b76147..a1474cd56fd5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "dependencies": { "@dotlottie/react-player": "^1.6.3", "@expensify/react-native-background-task": "file:./modules/background-task", - "@expensify/react-native-live-markdown": "0.1.210", + "@expensify/react-native-live-markdown": "^0.1.210", "@expo/metro-runtime": "^4.0.0", "@firebase/app": "^0.10.10", "@firebase/performance": "^0.6.8", diff --git a/package.json b/package.json index 9ab7cf7cdad2..44e72ed5d3b8 100644 --- a/package.json +++ b/package.json @@ -76,8 +76,8 @@ }, "dependencies": { "@dotlottie/react-player": "^1.6.3", - "@expensify/react-native-live-markdown": "0.1.210", "@expensify/react-native-background-task": "file:./modules/background-task", + "@expensify/react-native-live-markdown": "^0.1.210", "@expo/metro-runtime": "^4.0.0", "@firebase/app": "^0.10.10", "@firebase/performance": "^0.6.8", From 623247686cd07c22924306f5445767cd38296a76 Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Thu, 23 Jan 2025 09:25:32 +0900 Subject: [PATCH 04/39] lint assertion err fixed --- .../settings/Profile/Contacts/ContactMethodDetailsPage.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index 702fb89c2d83..0ac5ee02ca6d 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -270,11 +270,10 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { focusTrapSettings={{ focusTrapOptions: { checkCanFocusTrap: (trapContainers: Array) => { - return new Promise((resolve) => { + return new Promise((resolve) => { const interval = setInterval(() => { - // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style - const trapContainer = trapContainers.at(0) as HTMLElement | SVGElement; - if (getComputedStyle(trapContainer).visibility !== 'hidden') { + const trapContainer = trapContainers.at(0); + if (trapContainer && getComputedStyle(trapContainer).visibility !== 'hidden') { resolve(); clearInterval(interval); } From d216e60c2cc8c4e1f7df36c1f9df6243ccecf501 Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Thu, 23 Jan 2025 10:03:33 +0900 Subject: [PATCH 05/39] lint disabled prop spreading --- src/components/ValidateCodeActionWithoutModal.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/ValidateCodeActionWithoutModal.tsx b/src/components/ValidateCodeActionWithoutModal.tsx index 39a1a5d0cc5f..cddb4382deb5 100644 --- a/src/components/ValidateCodeActionWithoutModal.tsx +++ b/src/components/ValidateCodeActionWithoutModal.tsx @@ -73,6 +73,7 @@ ValidateCodeActionWithoutModal.displayName = 'ValidateCodeActionWithoutModal'; export default forwardRef((props, ref) => ( From 217ac601ec3511beeb83b6826ad79f4b3da05588 Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Thu, 23 Jan 2025 10:06:19 +0900 Subject: [PATCH 06/39] Revert "pulled original/main" This reverts commit c4e944fdeceba6b7214016e6bb6c8ea43d4d1355. --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index a1474cd56fd5..64b213b76147 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "dependencies": { "@dotlottie/react-player": "^1.6.3", "@expensify/react-native-background-task": "file:./modules/background-task", - "@expensify/react-native-live-markdown": "^0.1.210", + "@expensify/react-native-live-markdown": "0.1.210", "@expo/metro-runtime": "^4.0.0", "@firebase/app": "^0.10.10", "@firebase/performance": "^0.6.8", diff --git a/package.json b/package.json index 44e72ed5d3b8..9ab7cf7cdad2 100644 --- a/package.json +++ b/package.json @@ -76,8 +76,8 @@ }, "dependencies": { "@dotlottie/react-player": "^1.6.3", + "@expensify/react-native-live-markdown": "0.1.210", "@expensify/react-native-background-task": "file:./modules/background-task", - "@expensify/react-native-live-markdown": "^0.1.210", "@expo/metro-runtime": "^4.0.0", "@firebase/app": "^0.10.10", "@firebase/performance": "^0.6.8", From 622df4fcc45af38daa4253f00f310eb2080d07cf Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Thu, 23 Jan 2025 11:33:38 +0900 Subject: [PATCH 07/39] comment type for ref --- src/components/ValidateCodeActionWithoutModal.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/ValidateCodeActionWithoutModal.tsx b/src/components/ValidateCodeActionWithoutModal.tsx index cddb4382deb5..e299292fb030 100644 --- a/src/components/ValidateCodeActionWithoutModal.tsx +++ b/src/components/ValidateCodeActionWithoutModal.tsx @@ -10,6 +10,7 @@ import ValidateCodeForm from './ValidateCodeActionModal/ValidateCodeForm'; import type {ValidateCodeFormHandle} from './ValidateCodeActionModal/ValidateCodeForm/BaseValidateCodeForm'; type ValidateCodeActionWithoutModalProps = { + /** Ref for validate code form */ forwardedRef: ForwardedRef; }; From 9f1f2077ef5c98ddf09301994daece1581ae3d76 Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Thu, 23 Jan 2025 11:35:01 +0900 Subject: [PATCH 08/39] should resolve() if container is undefined --- .../settings/Profile/Contacts/ContactMethodDetailsPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index 0ac5ee02ca6d..f2cd8d87a171 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -273,7 +273,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { return new Promise((resolve) => { const interval = setInterval(() => { const trapContainer = trapContainers.at(0); - if (trapContainer && getComputedStyle(trapContainer).visibility !== 'hidden') { + if (!trapContainer || (trapContainer && getComputedStyle(trapContainer).visibility !== 'hidden')) { resolve(); clearInterval(interval); } From 5493c6b5d4483f7023218c6c4607170202af83bf Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Thu, 23 Jan 2025 11:40:40 +0900 Subject: [PATCH 09/39] comment about focus trap for animation --- .../settings/Profile/Contacts/ContactMethodDetailsPage.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index f2cd8d87a171..4e8f334c998b 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -269,6 +269,8 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { testID={ContactMethodDetailsPage.displayName} focusTrapSettings={{ focusTrapOptions: { + //It is added because input form's focusing bothers transition animation: + // https://github.com/Expensify/App/issues/53884#issuecomment-2594568960 checkCanFocusTrap: (trapContainers: Array) => { return new Promise((resolve) => { const interval = setInterval(() => { From dd436e923b10cad970a4b850ba6007065d54b987 Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Thu, 23 Jan 2025 18:56:57 +0900 Subject: [PATCH 10/39] fix: clicking header back err occurs --- .../settings/Profile/Contacts/ContactMethodDetailsPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index 4e8f334c998b..e3c820178014 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -336,7 +336,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { /> )} - {!isValidateCodeActionModalVisible && loginData?.validatedDate && getMenuItems()} + {!isValidateCodeActionModalVisible && !!loginData?.validatedDate && getMenuItems()} ); From a40482613264c27eaf55f1d0573ec2c1dd88c77f Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Fri, 24 Jan 2025 13:00:42 +0900 Subject: [PATCH 11/39] clear error only after closing the modal --- src/components/ValidateCodeActionWithoutModal.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/ValidateCodeActionWithoutModal.tsx b/src/components/ValidateCodeActionWithoutModal.tsx index e299292fb030..b50ab81a54e4 100644 --- a/src/components/ValidateCodeActionWithoutModal.tsx +++ b/src/components/ValidateCodeActionWithoutModal.tsx @@ -36,19 +36,20 @@ function ValidateCodeActionWithoutModal({ useEffect( () => () => { - clearError(); firstRenderRef.current = true; }, - [clearError], + [] ); useEffect(() => { if (!firstRenderRef.current || !isVisible || hasMagicCodeBeenSent) { - return; + return () => { + clearError(); + }; } firstRenderRef.current = false; sendValidateCode(); - }, [isVisible, sendValidateCode, hasMagicCodeBeenSent]); + }, [isVisible, sendValidateCode, hasMagicCodeBeenSent, clearError]); return ( From 6a12518597a41e3f61b7bc9878dc715ca6eae53c Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Fri, 24 Jan 2025 22:49:07 +0900 Subject: [PATCH 12/39] lint fixed --- src/components/ValidateCodeActionWithoutModal.tsx | 2 +- .../settings/Profile/Contacts/ContactMethodDetailsPage.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ValidateCodeActionWithoutModal.tsx b/src/components/ValidateCodeActionWithoutModal.tsx index b50ab81a54e4..fd3750187e78 100644 --- a/src/components/ValidateCodeActionWithoutModal.tsx +++ b/src/components/ValidateCodeActionWithoutModal.tsx @@ -38,7 +38,7 @@ function ValidateCodeActionWithoutModal({ () => () => { firstRenderRef.current = true; }, - [] + [], ); useEffect(() => { diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index 64a2da8b51f1..487af705ef1d 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -274,7 +274,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { testID={ContactMethodDetailsPage.displayName} focusTrapSettings={{ focusTrapOptions: { - //It is added because input form's focusing bothers transition animation: + // It is added because input form's focusing bothers transition animation: // https://github.com/Expensify/App/issues/53884#issuecomment-2594568960 checkCanFocusTrap: (trapContainers: Array) => { return new Promise((resolve) => { From 3f12bb5d83da92c35a438322fcc04b7b48f9a728 Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Fri, 24 Jan 2025 22:49:38 +0900 Subject: [PATCH 13/39] Revert "lint fixed" This reverts commit 6a12518597a41e3f61b7bc9878dc715ca6eae53c. --- src/components/ValidateCodeActionWithoutModal.tsx | 2 +- .../settings/Profile/Contacts/ContactMethodDetailsPage.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ValidateCodeActionWithoutModal.tsx b/src/components/ValidateCodeActionWithoutModal.tsx index fd3750187e78..b50ab81a54e4 100644 --- a/src/components/ValidateCodeActionWithoutModal.tsx +++ b/src/components/ValidateCodeActionWithoutModal.tsx @@ -38,7 +38,7 @@ function ValidateCodeActionWithoutModal({ () => () => { firstRenderRef.current = true; }, - [], + [] ); useEffect(() => { diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index 487af705ef1d..64a2da8b51f1 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -274,7 +274,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { testID={ContactMethodDetailsPage.displayName} focusTrapSettings={{ focusTrapOptions: { - // It is added because input form's focusing bothers transition animation: + //It is added because input form's focusing bothers transition animation: // https://github.com/Expensify/App/issues/53884#issuecomment-2594568960 checkCanFocusTrap: (trapContainers: Array) => { return new Promise((resolve) => { From 433778f0dbda089916ae0497553116179ad4a1df Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Fri, 24 Jan 2025 22:50:30 +0900 Subject: [PATCH 14/39] lint fixed --- src/components/ValidateCodeActionWithoutModal.tsx | 2 +- .../settings/Profile/Contacts/ContactMethodDetailsPage.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ValidateCodeActionWithoutModal.tsx b/src/components/ValidateCodeActionWithoutModal.tsx index b50ab81a54e4..fd3750187e78 100644 --- a/src/components/ValidateCodeActionWithoutModal.tsx +++ b/src/components/ValidateCodeActionWithoutModal.tsx @@ -38,7 +38,7 @@ function ValidateCodeActionWithoutModal({ () => () => { firstRenderRef.current = true; }, - [] + [], ); useEffect(() => { diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index 64a2da8b51f1..487af705ef1d 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -274,7 +274,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { testID={ContactMethodDetailsPage.displayName} focusTrapSettings={{ focusTrapOptions: { - //It is added because input form's focusing bothers transition animation: + // It is added because input form's focusing bothers transition animation: // https://github.com/Expensify/App/issues/53884#issuecomment-2594568960 checkCanFocusTrap: (trapContainers: Array) => { return new Promise((resolve) => { From 0afd14a55f3042f115b260f125c38d4cc9c82682 Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Thu, 30 Jan 2025 11:55:07 +0900 Subject: [PATCH 15/39] moved isVisible in the validate code form --- .../ValidateCodeActionWithoutModal.tsx | 38 ++++++++++--------- .../Contacts/ContactMethodDetailsPage.tsx | 26 ++++++------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/components/ValidateCodeActionWithoutModal.tsx b/src/components/ValidateCodeActionWithoutModal.tsx index fd3750187e78..1485f26e1964 100644 --- a/src/components/ValidateCodeActionWithoutModal.tsx +++ b/src/components/ValidateCodeActionWithoutModal.tsx @@ -51,24 +51,26 @@ function ValidateCodeActionWithoutModal({ sendValidateCode(); }, [isVisible, sendValidateCode, hasMagicCodeBeenSent, clearError]); - return ( - - {descriptionPrimary} - {!!descriptionSecondary && {descriptionSecondary}} - - - ); + if (isVisible) { + return ( + + {descriptionPrimary} + {!!descriptionSecondary && {descriptionSecondary}} + + + ); + } } ValidateCodeActionWithoutModal.displayName = 'ValidateCodeActionWithoutModal'; diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index 487af705ef1d..0d50307702bc 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -320,21 +320,19 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { /> )} - {!loginData?.validatedDate && ( - validateSecondaryLogin(loginList, contactMethod, validateCode)} - validateError={!isEmptyObject(validateLoginError) ? validateLoginError : getLatestErrorField(loginData, 'validateCodeSent')} - clearError={() => clearContactMethodErrors(contactMethod, !isEmptyObject(validateLoginError) ? 'validateLogin' : 'validateCodeSent')} - sendValidateCode={() => requestContactMethodValidateCode(contactMethod)} - descriptionPrimary={translate('contacts.enterMagicCode', {contactMethod: formattedContactMethod})} - forwardedRef={validateCodeFormRef} - /> - )} + validateSecondaryLogin(loginList, contactMethod, validateCode)} + validateError={!isEmptyObject(validateLoginError) ? validateLoginError : getLatestErrorField(loginData, 'validateCodeSent')} + clearError={() => clearContactMethodErrors(contactMethod, !isEmptyObject(validateLoginError) ? 'validateLogin' : 'validateCodeSent')} + sendValidateCode={() => requestContactMethodValidateCode(contactMethod)} + descriptionPrimary={translate('contacts.enterMagicCode', {contactMethod: formattedContactMethod})} + forwardedRef={validateCodeFormRef} + /> - {!isValidateCodeActionModalVisible && !!loginData?.validatedDate && getMenuItems()} + {!isValidateCodeActionModalVisible && getMenuItems()} ); From c19c2af3646224f8e32fa0caee229ab2f81fb5ef Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Fri, 31 Jan 2025 15:24:01 +0900 Subject: [PATCH 16/39] hide menu items while sliding out of validate page --- .../Profile/Contacts/ContactMethodDetailsPage.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index 0d50307702bc..821017e37719 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -65,6 +65,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { const {windowWidth} = useWindowDimensions(); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [isValidateCodeFormRendered, setIsValidateCodeFormRendered] = useState(false); const validateCodeFormRef = useRef(null); const backTo = route.params.backTo; @@ -165,8 +166,11 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { useBeforeRemove(() => setIsValidateCodeActionModalVisible(false)); useEffect(() => { + if (!isValidateCodeFormRendered && !loginData?.validatedDate) { + setIsValidateCodeFormRendered(true); + } setIsValidateCodeActionModalVisible(!loginData?.validatedDate); - }, [loginData?.validatedDate, loginData?.errorFields?.addedLogin]); + }, [loginData?.validatedDate, loginData?.errorFields?.addedLogin, isValidateCodeFormRendered]); useEffect(() => { resetContactMethodValidateCodeSentState(contactMethod); @@ -332,7 +336,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { forwardedRef={validateCodeFormRef} /> - {!isValidateCodeActionModalVisible && getMenuItems()} + {!isValidateCodeActionModalVisible && !isValidateCodeFormRendered && getMenuItems()} ); From 0c12b86009142e3b6b973be46fbff085ed02b661 Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Fri, 31 Jan 2025 15:25:43 +0900 Subject: [PATCH 17/39] Revert "hide menu items while sliding out of validate page" This reverts commit c19c2af3646224f8e32fa0caee229ab2f81fb5ef. --- .../Profile/Contacts/ContactMethodDetailsPage.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index 821017e37719..0d50307702bc 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -65,7 +65,6 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { const {windowWidth} = useWindowDimensions(); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); - const [isValidateCodeFormRendered, setIsValidateCodeFormRendered] = useState(false); const validateCodeFormRef = useRef(null); const backTo = route.params.backTo; @@ -166,11 +165,8 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { useBeforeRemove(() => setIsValidateCodeActionModalVisible(false)); useEffect(() => { - if (!isValidateCodeFormRendered && !loginData?.validatedDate) { - setIsValidateCodeFormRendered(true); - } setIsValidateCodeActionModalVisible(!loginData?.validatedDate); - }, [loginData?.validatedDate, loginData?.errorFields?.addedLogin, isValidateCodeFormRendered]); + }, [loginData?.validatedDate, loginData?.errorFields?.addedLogin]); useEffect(() => { resetContactMethodValidateCodeSentState(contactMethod); @@ -336,7 +332,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { forwardedRef={validateCodeFormRef} /> - {!isValidateCodeActionModalVisible && !isValidateCodeFormRendered && getMenuItems()} + {!isValidateCodeActionModalVisible && getMenuItems()} ); From b6e01384cf6a30adc5a5a48710604664dca6baf7 Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Sun, 2 Feb 2025 12:55:40 +0900 Subject: [PATCH 18/39] fix: trashcan shows as navigating out on mWeb --- .../settings/Profile/Contacts/ContactMethodDetailsPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index 0d50307702bc..d2b1ebcef5be 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -332,7 +332,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { forwardedRef={validateCodeFormRef} /> - {!isValidateCodeActionModalVisible && getMenuItems()} + {!isValidateCodeActionModalVisible && !!loginData.validatedDate && getMenuItems()} ); From 426d8bef582b373767ffa3a71e1cd5ee4d84458e Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Mon, 3 Feb 2025 12:36:03 +0900 Subject: [PATCH 19/39] delete this becuase transition anim works w/o it --- .../settings/Profile/Contacts/ContactMethodDetailsPage.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index d2b1ebcef5be..7b55993b31b1 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -162,8 +162,6 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS.getRoute(backTo)); }, [prevValidatedDate, loginData?.validatedDate, isDefaultContactMethod, backTo, loginData]); - useBeforeRemove(() => setIsValidateCodeActionModalVisible(false)); - useEffect(() => { setIsValidateCodeActionModalVisible(!loginData?.validatedDate); }, [loginData?.validatedDate, loginData?.errorFields?.addedLogin]); From 00d7c511c4054d0c2228aebaee5905c62d0e8ce0 Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Mon, 3 Feb 2025 14:18:41 +0900 Subject: [PATCH 20/39] renamed and deleted ValidateCodeActionWithoutModal --- ...thoutModal.tsx => ValidateCodeActionForm.tsx} | 10 +++++----- .../Contacts/ContactMethodDetailsPage.tsx | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) rename src/components/{ValidateCodeActionWithoutModal.tsx => ValidateCodeActionForm.tsx} (92%) diff --git a/src/components/ValidateCodeActionWithoutModal.tsx b/src/components/ValidateCodeActionForm.tsx similarity index 92% rename from src/components/ValidateCodeActionWithoutModal.tsx rename to src/components/ValidateCodeActionForm.tsx index 1485f26e1964..11b3e36cde4a 100644 --- a/src/components/ValidateCodeActionWithoutModal.tsx +++ b/src/components/ValidateCodeActionForm.tsx @@ -9,14 +9,14 @@ import type {ValidateCodeActionModalProps} from './ValidateCodeActionModal/type' import ValidateCodeForm from './ValidateCodeActionModal/ValidateCodeForm'; import type {ValidateCodeFormHandle} from './ValidateCodeActionModal/ValidateCodeForm/BaseValidateCodeForm'; -type ValidateCodeActionWithoutModalProps = { +type ValidateCodeActionFormProps = { /** Ref for validate code form */ forwardedRef: ForwardedRef; }; -type ValidateCodeActionProps = ValidateCodeActionModalProps & ValidateCodeActionWithoutModalProps; +type ValidateCodeActionProps = ValidateCodeActionModalProps & ValidateCodeActionFormProps; -function ValidateCodeActionWithoutModal({ +function ValidateCodeActionForm({ isVisible, descriptionPrimary, descriptionSecondary, @@ -73,10 +73,10 @@ function ValidateCodeActionWithoutModal({ } } -ValidateCodeActionWithoutModal.displayName = 'ValidateCodeActionWithoutModal'; +ValidateCodeActionForm.displayName = 'ValidateCodeActionForm'; export default forwardRef((props, ref) => ( - { - setIsValidateCodeActionModalVisible(!loginData?.validatedDate); + setIsValidateCodeFormVisible(!loginData?.validatedDate); }, [loginData?.validatedDate, loginData?.errorFields?.addedLogin]); useEffect(() => { @@ -172,7 +172,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { const getThreeDotsMenuItems = useCallback(() => { const menuItems = []; - if (isValidateCodeActionModalVisible && !isDefaultContactMethod) { + if (isValidateCodeFormVisible && !isDefaultContactMethod) { menuItems.push({ icon: Trashcan, text: translate('common.remove'), @@ -180,7 +180,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { }); } return menuItems; - }, [isValidateCodeActionModalVisible, translate, toggleDeleteModal, isDefaultContactMethod]); + }, [isValidateCodeFormVisible, translate, toggleDeleteModal, isDefaultContactMethod]); if (isLoadingOnyxValues || (isLoadingReportData && isEmptyObject(loginList))) { return ; @@ -318,9 +318,9 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { /> )} - validateSecondaryLogin(loginList, contactMethod, validateCode)} validateError={!isEmptyObject(validateLoginError) ? validateLoginError : getLatestErrorField(loginData, 'validateCodeSent')} @@ -330,7 +330,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { forwardedRef={validateCodeFormRef} /> - {!isValidateCodeActionModalVisible && !!loginData.validatedDate && getMenuItems()} + {!isValidateCodeFormVisible && !!loginData.validatedDate && getMenuItems()} ); From 23498e9032f15cc16f451634feffe1aed7dec4cb Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Mon, 3 Feb 2025 18:34:20 +0900 Subject: [PATCH 21/39] lint fixed --- src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index 3474f1f01f95..c6fa107b0534 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -14,7 +14,6 @@ import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; import Text from '@components/Text'; import ValidateCodeActionForm from '@components/ValidateCodeActionForm'; -import useBeforeRemove from '@hooks/useBeforeRemove'; import useLocalize from '@hooks/useLocalize'; import usePrevious from '@hooks/usePrevious'; import useTheme from '@hooks/useTheme'; From 0d1f9fe8717e8ff5938f59d4d616cedf5fa8ee46 Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Mon, 3 Feb 2025 21:17:52 +0900 Subject: [PATCH 22/39] focusTrap not needed in mSafari --- .../Contacts/ContactMethodDetailsPage.tsx | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index c6fa107b0534..3a9bd26501a4 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -30,6 +30,7 @@ import { setContactMethodAsDefault, validateSecondaryLogin, } from '@libs/actions/User'; +import {isMobileSafari} from '@libs/Browser'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; import {getEarliestErrorField, getLatestErrorField} from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; @@ -270,21 +271,23 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { onEntryTransitionEnd={() => validateCodeFormRef.current?.focus?.()} testID={ContactMethodDetailsPage.displayName} focusTrapSettings={{ - focusTrapOptions: { - // It is added because input form's focusing bothers transition animation: - // https://github.com/Expensify/App/issues/53884#issuecomment-2594568960 - checkCanFocusTrap: (trapContainers: Array) => { - return new Promise((resolve) => { - const interval = setInterval(() => { - const trapContainer = trapContainers.at(0); - if (!trapContainer || (trapContainer && getComputedStyle(trapContainer).visibility !== 'hidden')) { - resolve(); - clearInterval(interval); - } - }, 5); - }); - }, - }, + focusTrapOptions: !isMobileSafari() + ? undefined + : { + // It is added because input form's focusing bothers transition animation: + // https://github.com/Expensify/App/issues/53884#issuecomment-2594568960 + checkCanFocusTrap: (trapContainers: Array) => { + return new Promise((resolve) => { + const interval = setInterval(() => { + const trapContainer = trapContainers.at(0); + if (!trapContainer || (trapContainer && getComputedStyle(trapContainer).visibility !== 'hidden')) { + resolve(); + clearInterval(interval); + } + }, 5); + }); + }, + }, }} > Date: Tue, 4 Feb 2025 11:32:32 +0900 Subject: [PATCH 23/39] fix: keyboard not show on Android app, iOS app --- src/components/ValidateCodeActionForm.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/components/ValidateCodeActionForm.tsx b/src/components/ValidateCodeActionForm.tsx index 11b3e36cde4a..b50b2100d3d5 100644 --- a/src/components/ValidateCodeActionForm.tsx +++ b/src/components/ValidateCodeActionForm.tsx @@ -1,6 +1,6 @@ -import React, {forwardRef, useEffect, useRef} from 'react'; +import React, {forwardRef, useEffect, useRef, useState} from 'react'; import type {ForwardedRef} from 'react'; -import {View} from 'react-native'; +import {InteractionManager, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import useThemeStyles from '@hooks/useThemeStyles'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -34,6 +34,8 @@ function ValidateCodeActionForm({ const [validateCodeAction] = useOnyx(ONYXKEYS.VALIDATE_ACTION_CODE); + const [canSendHasMagicCodeBeenSent, setCanSendHasMagicCodeBeenSent] = useState(false); + useEffect( () => () => { firstRenderRef.current = true; @@ -49,6 +51,11 @@ function ValidateCodeActionForm({ } firstRenderRef.current = false; sendValidateCode(); + if (hasMagicCodeBeenSent) { + InteractionManager.runAfterInteractions(() => { + setCanSendHasMagicCodeBeenSent(true); + }); + } }, [isVisible, sendValidateCode, hasMagicCodeBeenSent, clearError]); if (isVisible) { @@ -66,7 +73,7 @@ function ValidateCodeActionForm({ clearError={clearError} buttonStyles={[themeStyles.justifyContentEnd, themeStyles.flex1]} ref={forwardedRef} - hasMagicCodeBeenSent={hasMagicCodeBeenSent} + hasMagicCodeBeenSent={canSendHasMagicCodeBeenSent} /> ); From e37d5648e6e130b8dd3da00cd922799d4f4bf95c Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Tue, 4 Feb 2025 19:09:50 +0900 Subject: [PATCH 24/39] fix: show remove contact method modal --- .../settings/Profile/Contacts/ContactMethodDetailsPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index 3a9bd26501a4..a98fcb93c716 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -262,7 +262,6 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { /> )} - {getDeleteConfirmationModal()} ); @@ -333,6 +332,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { /> {!isValidateCodeFormVisible && !!loginData.validatedDate && getMenuItems()} + {getDeleteConfirmationModal()} ); From 589f4441e23249410071a011c8444d218bdd5baa Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Tue, 4 Feb 2025 20:37:27 +0900 Subject: [PATCH 25/39] focusTrap not needed in mSafari --- .../settings/Profile/Contacts/ContactMethodDetailsPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index a98fcb93c716..d2c9cca1ec32 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -270,7 +270,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { onEntryTransitionEnd={() => validateCodeFormRef.current?.focus?.()} testID={ContactMethodDetailsPage.displayName} focusTrapSettings={{ - focusTrapOptions: !isMobileSafari() + focusTrapOptions: isMobileSafari() ? undefined : { // It is added because input form's focusing bothers transition animation: From 0e4b20f8c9234ae520735c70fea2931a0d23fc6a Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Wed, 5 Feb 2025 14:54:32 +0900 Subject: [PATCH 26/39] show/hide code form --- .../Contacts/ContactMethodDetailsPage.tsx | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index d2c9cca1ec32..8e4980679fad 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -318,18 +318,19 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { canDismissError /> )} - - validateSecondaryLogin(loginList, contactMethod, validateCode)} - validateError={!isEmptyObject(validateLoginError) ? validateLoginError : getLatestErrorField(loginData, 'validateCodeSent')} - clearError={() => clearContactMethodErrors(contactMethod, !isEmptyObject(validateLoginError) ? 'validateLogin' : 'validateCodeSent')} - sendValidateCode={() => requestContactMethodValidateCode(contactMethod)} - descriptionPrimary={translate('contacts.enterMagicCode', {contactMethod: formattedContactMethod})} - forwardedRef={validateCodeFormRef} - /> + {isValidateCodeFormVisible && !loginData.validatedDate && !!loginData && ( + validateSecondaryLogin(loginList, contactMethod, validateCode)} + validateError={!isEmptyObject(validateLoginError) ? validateLoginError : getLatestErrorField(loginData, 'validateCodeSent')} + clearError={() => clearContactMethodErrors(contactMethod, !isEmptyObject(validateLoginError) ? 'validateLogin' : 'validateCodeSent')} + sendValidateCode={() => requestContactMethodValidateCode(contactMethod)} + descriptionPrimary={translate('contacts.enterMagicCode', {contactMethod: formattedContactMethod})} + forwardedRef={validateCodeFormRef} + /> + )} {!isValidateCodeFormVisible && !!loginData.validatedDate && getMenuItems()} {getDeleteConfirmationModal()} From bc83a7b1101aadc6426c489c459db177c5682d4f Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Thu, 6 Feb 2025 22:07:10 +0900 Subject: [PATCH 27/39] fix: clear error runs on default contact method too --- src/components/ValidateCodeActionForm.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/components/ValidateCodeActionForm.tsx b/src/components/ValidateCodeActionForm.tsx index b50b2100d3d5..5f3907fc5437 100644 --- a/src/components/ValidateCodeActionForm.tsx +++ b/src/components/ValidateCodeActionForm.tsx @@ -31,6 +31,7 @@ function ValidateCodeActionForm({ }: ValidateCodeActionProps) { const themeStyles = useThemeStyles(); const firstRenderRef = useRef(true); + const isClosedRef = useRef(false); const [validateCodeAction] = useOnyx(ONYXKEYS.VALIDATE_ACTION_CODE); @@ -39,18 +40,24 @@ function ValidateCodeActionForm({ useEffect( () => () => { firstRenderRef.current = true; + isClosedRef.current = true; }, [], ); useEffect(() => { - if (!firstRenderRef.current || !isVisible || hasMagicCodeBeenSent) { + if (!firstRenderRef.current || hasMagicCodeBeenSent) { + // eslint-disable-next-line rulesdir/prefer-early-return return () => { - clearError(); + if (isClosedRef.current && isVisible) { + clearError(); + } }; } firstRenderRef.current = false; - sendValidateCode(); + if (isVisible) { + sendValidateCode(); + } if (hasMagicCodeBeenSent) { InteractionManager.runAfterInteractions(() => { setCanSendHasMagicCodeBeenSent(true); From 91e940d9045084863880dd1e4e66e94d623176b8 Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Fri, 7 Feb 2025 11:11:08 +0900 Subject: [PATCH 28/39] fix: has 2 isVisible --- src/components/ValidateCodeActionForm.tsx | 15 ++++++++++----- .../Profile/Contacts/ContactMethodDetailsPage.tsx | 1 + 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/components/ValidateCodeActionForm.tsx b/src/components/ValidateCodeActionForm.tsx index 5f3907fc5437..b5279786d6ff 100644 --- a/src/components/ValidateCodeActionForm.tsx +++ b/src/components/ValidateCodeActionForm.tsx @@ -12,12 +12,13 @@ import type {ValidateCodeFormHandle} from './ValidateCodeActionModal/ValidateCod type ValidateCodeActionFormProps = { /** Ref for validate code form */ forwardedRef: ForwardedRef; + isValidated: boolean; }; type ValidateCodeActionProps = ValidateCodeActionModalProps & ValidateCodeActionFormProps; function ValidateCodeActionForm({ - isVisible, + isValidated, descriptionPrimary, descriptionSecondary, validatePendingAction, @@ -36,6 +37,7 @@ function ValidateCodeActionForm({ const [validateCodeAction] = useOnyx(ONYXKEYS.VALIDATE_ACTION_CODE); const [canSendHasMagicCodeBeenSent, setCanSendHasMagicCodeBeenSent] = useState(false); + const [shouldValidate, setShouldValidate] = useState(!isValidated); useEffect( () => () => { @@ -49,13 +51,16 @@ function ValidateCodeActionForm({ if (!firstRenderRef.current || hasMagicCodeBeenSent) { // eslint-disable-next-line rulesdir/prefer-early-return return () => { - if (isClosedRef.current && isVisible) { + console.log('shouldValidate,: ', shouldValidate) + if (isClosedRef.current && shouldValidate) { + console.log('clearError/////////////////////////') clearError(); } }; } firstRenderRef.current = false; - if (isVisible) { + if (shouldValidate) { + console.log('sendValidateCode****************************') sendValidateCode(); } if (hasMagicCodeBeenSent) { @@ -63,9 +68,9 @@ function ValidateCodeActionForm({ setCanSendHasMagicCodeBeenSent(true); }); } - }, [isVisible, sendValidateCode, hasMagicCodeBeenSent, clearError]); + }, [sendValidateCode, hasMagicCodeBeenSent, clearError]); - if (isVisible) { + if (shouldValidate) { return ( {descriptionPrimary} diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index 8e4980679fad..04c3902f29a2 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -322,6 +322,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { validateSecondaryLogin(loginList, contactMethod, validateCode)} validateError={!isEmptyObject(validateLoginError) ? validateLoginError : getLatestErrorField(loginData, 'validateCodeSent')} From 943ce639a25855bfab664d490a0e055897d5713e Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Fri, 7 Feb 2025 11:54:04 +0900 Subject: [PATCH 29/39] not use setState for isValidated --- src/components/ValidateCodeActionForm.tsx | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/components/ValidateCodeActionForm.tsx b/src/components/ValidateCodeActionForm.tsx index b5279786d6ff..474ddc49c9c9 100644 --- a/src/components/ValidateCodeActionForm.tsx +++ b/src/components/ValidateCodeActionForm.tsx @@ -37,7 +37,6 @@ function ValidateCodeActionForm({ const [validateCodeAction] = useOnyx(ONYXKEYS.VALIDATE_ACTION_CODE); const [canSendHasMagicCodeBeenSent, setCanSendHasMagicCodeBeenSent] = useState(false); - const [shouldValidate, setShouldValidate] = useState(!isValidated); useEffect( () => () => { @@ -51,16 +50,13 @@ function ValidateCodeActionForm({ if (!firstRenderRef.current || hasMagicCodeBeenSent) { // eslint-disable-next-line rulesdir/prefer-early-return return () => { - console.log('shouldValidate,: ', shouldValidate) - if (isClosedRef.current && shouldValidate) { - console.log('clearError/////////////////////////') + if (isClosedRef.current && !isValidated) { clearError(); } }; } firstRenderRef.current = false; - if (shouldValidate) { - console.log('sendValidateCode****************************') + if (!isValidated) { sendValidateCode(); } if (hasMagicCodeBeenSent) { @@ -68,9 +64,9 @@ function ValidateCodeActionForm({ setCanSendHasMagicCodeBeenSent(true); }); } - }, [sendValidateCode, hasMagicCodeBeenSent, clearError]); + }, [isValidated, sendValidateCode, hasMagicCodeBeenSent, clearError]); - if (shouldValidate) { + if (!isValidated) { return ( {descriptionPrimary} From a2c3878e81fb7633e000586c003d4c1fc1bc9f7d Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Fri, 7 Feb 2025 21:19:39 +0900 Subject: [PATCH 30/39] created type for ValidateCodeActionForm --- .../index.tsx} | 59 ++++++++----------- src/components/ValidateCodeActionForm/type.ts | 41 +++++++++++++ .../ValidateCodeActionModal/type.ts | 2 +- .../Contacts/ContactMethodDetailsPage.tsx | 1 - 4 files changed, 66 insertions(+), 37 deletions(-) rename src/components/{ValidateCodeActionForm.tsx => ValidateCodeActionForm/index.tsx} (54%) create mode 100644 src/components/ValidateCodeActionForm/type.ts diff --git a/src/components/ValidateCodeActionForm.tsx b/src/components/ValidateCodeActionForm/index.tsx similarity index 54% rename from src/components/ValidateCodeActionForm.tsx rename to src/components/ValidateCodeActionForm/index.tsx index 474ddc49c9c9..f1fe3e2c1809 100644 --- a/src/components/ValidateCodeActionForm.tsx +++ b/src/components/ValidateCodeActionForm/index.tsx @@ -1,21 +1,12 @@ import React, {forwardRef, useEffect, useRef, useState} from 'react'; -import type {ForwardedRef} from 'react'; import {InteractionManager, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; +import Text from '@components/Text'; +import ValidateCodeForm from '@components/ValidateCodeActionModal/ValidateCodeForm'; +import type {ValidateCodeFormHandle} from '@components/ValidateCodeActionModal/ValidateCodeForm/BaseValidateCodeForm'; import useThemeStyles from '@hooks/useThemeStyles'; import ONYXKEYS from '@src/ONYXKEYS'; -import Text from './Text'; -import type {ValidateCodeActionModalProps} from './ValidateCodeActionModal/type'; -import ValidateCodeForm from './ValidateCodeActionModal/ValidateCodeForm'; -import type {ValidateCodeFormHandle} from './ValidateCodeActionModal/ValidateCodeForm/BaseValidateCodeForm'; - -type ValidateCodeActionFormProps = { - /** Ref for validate code form */ - forwardedRef: ForwardedRef; - isValidated: boolean; -}; - -type ValidateCodeActionProps = ValidateCodeActionModalProps & ValidateCodeActionFormProps; +import type {ValidateCodeActionFormProps} from './type'; function ValidateCodeActionForm({ isValidated, @@ -29,7 +20,7 @@ function ValidateCodeActionForm({ hasMagicCodeBeenSent, isLoading, forwardedRef, -}: ValidateCodeActionProps) { +}: ValidateCodeActionFormProps) { const themeStyles = useThemeStyles(); const firstRenderRef = useRef(true); const isClosedRef = useRef(false); @@ -66,31 +57,29 @@ function ValidateCodeActionForm({ } }, [isValidated, sendValidateCode, hasMagicCodeBeenSent, clearError]); - if (!isValidated) { - return ( - - {descriptionPrimary} - {!!descriptionSecondary && {descriptionSecondary}} - - - ); - } + return ( + + {descriptionPrimary} + {!!descriptionSecondary && {descriptionSecondary}} + + + ); } ValidateCodeActionForm.displayName = 'ValidateCodeActionForm'; -export default forwardRef((props, ref) => ( +export default forwardRef((props, ref) => ( void; + + /** Function to clear error of the form */ + clearError: () => void; + + /** Function is called when validate code modal is mounted and on magic code resend */ + sendValidateCode: () => void; + + /** If the magic code has been resent previously */ + hasMagicCodeBeenSent?: boolean; + + /** Whether the form is loading or not */ + isLoading?: boolean; + + /** Ref for validate code form */ + forwardedRef: ForwardedRef; +}; + +// eslint-disable-next-line import/prefer-default-export +export type {ValidateCodeActionFormProps}; diff --git a/src/components/ValidateCodeActionModal/type.ts b/src/components/ValidateCodeActionModal/type.ts index 81743304ff9c..4f70870ead3c 100644 --- a/src/components/ValidateCodeActionModal/type.ts +++ b/src/components/ValidateCodeActionModal/type.ts @@ -7,7 +7,7 @@ type ValidateCodeActionModalProps = { isVisible: boolean; /** Title of the modal */ - title?: string; + title: string; /** Primary description of the modal */ descriptionPrimary: string; diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index 04c3902f29a2..e14ed0e49cda 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -321,7 +321,6 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { {isValidateCodeFormVisible && !loginData.validatedDate && !!loginData && ( validateSecondaryLogin(loginList, contactMethod, validateCode)} From 600d0d56cff510675a4d4c4ac55c94d63d942f5f Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Fri, 7 Feb 2025 22:14:26 +0900 Subject: [PATCH 31/39] check isValidated not needed for sendValidateCode --- src/components/ValidateCodeActionForm/index.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/ValidateCodeActionForm/index.tsx b/src/components/ValidateCodeActionForm/index.tsx index f1fe3e2c1809..6239d2e202b9 100644 --- a/src/components/ValidateCodeActionForm/index.tsx +++ b/src/components/ValidateCodeActionForm/index.tsx @@ -47,9 +47,7 @@ function ValidateCodeActionForm({ }; } firstRenderRef.current = false; - if (!isValidated) { - sendValidateCode(); - } + sendValidateCode(); if (hasMagicCodeBeenSent) { InteractionManager.runAfterInteractions(() => { setCanSendHasMagicCodeBeenSent(true); From 3fc7ee4d85bf17b2784b1d0f75348afafb6e4a5b Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Fri, 7 Feb 2025 22:29:31 +0900 Subject: [PATCH 32/39] commeted for cleanup function --- src/components/ValidateCodeActionForm/index.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/ValidateCodeActionForm/index.tsx b/src/components/ValidateCodeActionForm/index.tsx index 6239d2e202b9..f3ce275a3757 100644 --- a/src/components/ValidateCodeActionForm/index.tsx +++ b/src/components/ValidateCodeActionForm/index.tsx @@ -41,6 +41,9 @@ function ValidateCodeActionForm({ if (!firstRenderRef.current || hasMagicCodeBeenSent) { // eslint-disable-next-line rulesdir/prefer-early-return return () => { + // We need to run clearError in cleanup function to use as onClose function. + // As 'useEffect cleanup function' runs when even the component is unmounted, we need to put clearError() in the if condition. + // So clearError() will not run when the form is unmounted. if (isClosedRef.current && !isValidated) { clearError(); } From c715494674fd5000c5ab2117bc75070b12f1b184 Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Tue, 11 Feb 2025 11:34:05 +0900 Subject: [PATCH 33/39] not use firstRenderRef --- src/components/ValidateCodeActionForm/index.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/ValidateCodeActionForm/index.tsx b/src/components/ValidateCodeActionForm/index.tsx index f3ce275a3757..a57ef629ace4 100644 --- a/src/components/ValidateCodeActionForm/index.tsx +++ b/src/components/ValidateCodeActionForm/index.tsx @@ -22,7 +22,7 @@ function ValidateCodeActionForm({ forwardedRef, }: ValidateCodeActionFormProps) { const themeStyles = useThemeStyles(); - const firstRenderRef = useRef(true); + const isInitialized = useRef(false); const isClosedRef = useRef(false); const [validateCodeAction] = useOnyx(ONYXKEYS.VALIDATE_ACTION_CODE); @@ -31,14 +31,14 @@ function ValidateCodeActionForm({ useEffect( () => () => { - firstRenderRef.current = true; + isInitialized.current = false; isClosedRef.current = true; }, [], ); useEffect(() => { - if (!firstRenderRef.current || hasMagicCodeBeenSent) { + if (hasMagicCodeBeenSent) { // eslint-disable-next-line rulesdir/prefer-early-return return () => { // We need to run clearError in cleanup function to use as onClose function. @@ -49,8 +49,10 @@ function ValidateCodeActionForm({ } }; } - firstRenderRef.current = false; - sendValidateCode(); + if (!isInitialized.current) { + isInitialized.current = true; + sendValidateCode(); + } if (hasMagicCodeBeenSent) { InteractionManager.runAfterInteractions(() => { setCanSendHasMagicCodeBeenSent(true); From 9b73217a2d9011e573cdfff289fafc14befe91e9 Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Tue, 11 Feb 2025 23:48:11 +0900 Subject: [PATCH 34/39] showing button on number pad poped up on iOS mWeb --- src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index 96baecd81b73..0dc7ad80c95e 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -270,6 +270,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { return ( validateCodeFormRef.current?.focus?.()} testID={ContactMethodDetailsPage.displayName} focusTrapSettings={{ From 08b8d76f8e126845f2fb8abbed1f0e39abc3b5e1 Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Wed, 12 Feb 2025 10:26:29 +0900 Subject: [PATCH 35/39] fix: keyboard not show on Android app, iOS app --- src/components/ValidateCodeActionForm/index.tsx | 13 +++---------- .../Profile/Contacts/ContactMethodDetailsPage.tsx | 6 +++++- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/components/ValidateCodeActionForm/index.tsx b/src/components/ValidateCodeActionForm/index.tsx index a57ef629ace4..cecee3aca981 100644 --- a/src/components/ValidateCodeActionForm/index.tsx +++ b/src/components/ValidateCodeActionForm/index.tsx @@ -1,5 +1,5 @@ -import React, {forwardRef, useEffect, useRef, useState} from 'react'; -import {InteractionManager, View} from 'react-native'; +import React, {forwardRef, useEffect, useRef} from 'react'; +import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import Text from '@components/Text'; import ValidateCodeForm from '@components/ValidateCodeActionModal/ValidateCodeForm'; @@ -27,8 +27,6 @@ function ValidateCodeActionForm({ const [validateCodeAction] = useOnyx(ONYXKEYS.VALIDATE_ACTION_CODE); - const [canSendHasMagicCodeBeenSent, setCanSendHasMagicCodeBeenSent] = useState(false); - useEffect( () => () => { isInitialized.current = false; @@ -53,11 +51,6 @@ function ValidateCodeActionForm({ isInitialized.current = true; sendValidateCode(); } - if (hasMagicCodeBeenSent) { - InteractionManager.runAfterInteractions(() => { - setCanSendHasMagicCodeBeenSent(true); - }); - } }, [isValidated, sendValidateCode, hasMagicCodeBeenSent, clearError]); return ( @@ -74,7 +67,7 @@ function ValidateCodeActionForm({ clearError={clearError} buttonStyles={[themeStyles.justifyContentEnd, themeStyles.flex1]} ref={forwardedRef} - hasMagicCodeBeenSent={canSendHasMagicCodeBeenSent} + hasMagicCodeBeenSent={hasMagicCodeBeenSent} /> ); diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index 0dc7ad80c95e..25ea18009bd5 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -271,7 +271,11 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { return ( validateCodeFormRef.current?.focus?.()} + onEntryTransitionEnd={() => { + InteractionManager.runAfterInteractions(() => { + validateCodeFormRef.current?.focus?.(); + }); + }} testID={ContactMethodDetailsPage.displayName} focusTrapSettings={{ focusTrapOptions: isMobileSafari() From aac99d395bcb8943ac3829f6b2e2d6b7f7eb156e Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Wed, 12 Feb 2025 11:48:10 +0900 Subject: [PATCH 36/39] deleted unneeded condition --- .../ValidateCodeActionForm/index.tsx | 22 ++++++++----------- src/components/ValidateCodeActionForm/type.ts | 3 --- .../Contacts/ContactMethodDetailsPage.tsx | 1 - 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/components/ValidateCodeActionForm/index.tsx b/src/components/ValidateCodeActionForm/index.tsx index cecee3aca981..bf30836d4ef9 100644 --- a/src/components/ValidateCodeActionForm/index.tsx +++ b/src/components/ValidateCodeActionForm/index.tsx @@ -9,7 +9,6 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {ValidateCodeActionFormProps} from './type'; function ValidateCodeActionForm({ - isValidated, descriptionPrimary, descriptionSecondary, validatePendingAction, @@ -36,22 +35,19 @@ function ValidateCodeActionForm({ ); useEffect(() => { - if (hasMagicCodeBeenSent) { - // eslint-disable-next-line rulesdir/prefer-early-return - return () => { - // We need to run clearError in cleanup function to use as onClose function. - // As 'useEffect cleanup function' runs when even the component is unmounted, we need to put clearError() in the if condition. - // So clearError() will not run when the form is unmounted. - if (isClosedRef.current && !isValidated) { - clearError(); - } - }; - } if (!isInitialized.current) { isInitialized.current = true; sendValidateCode(); } - }, [isValidated, sendValidateCode, hasMagicCodeBeenSent, clearError]); + return () => { + // We need to run clearError in cleanup function to use as onClose function. + // As 'useEffect cleanup function' runs whenever a dependency is called, we need to put clearError() in the if condition. + // So clearError() will not run when the form is unmounted. + if (isClosedRef.current) { + clearError(); + } + }; + }, [sendValidateCode, clearError]); return ( diff --git a/src/components/ValidateCodeActionForm/type.ts b/src/components/ValidateCodeActionForm/type.ts index 8c33050315ea..3d579e5fc4bc 100644 --- a/src/components/ValidateCodeActionForm/type.ts +++ b/src/components/ValidateCodeActionForm/type.ts @@ -3,9 +3,6 @@ import type {ValidateCodeFormHandle} from '@components/ValidateCodeActionModal/V import type {Errors, PendingAction} from '@src/types/onyx/OnyxCommon'; type ValidateCodeActionFormProps = { - /** Wheter code is validated */ - isValidated: boolean; - /** Primary description of the modal */ descriptionPrimary: string; diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index 25ea18009bd5..604793001390 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -329,7 +329,6 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { {isValidateCodeFormVisible && !loginData.validatedDate && !!loginData && ( validateSecondaryLogin(loginList, contactMethod, validateCode)} validateError={!isEmptyObject(validateLoginError) ? validateLoginError : getLatestErrorField(loginData, 'validateCodeSent')} From 35ab2c87f81dd63c8ec443b781d025bc3e88ea96 Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Wed, 12 Feb 2025 12:25:51 +0900 Subject: [PATCH 37/39] lint --- src/components/ValidateCodeActionForm/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/ValidateCodeActionForm/index.tsx b/src/components/ValidateCodeActionForm/index.tsx index bf30836d4ef9..93ea7554185c 100644 --- a/src/components/ValidateCodeActionForm/index.tsx +++ b/src/components/ValidateCodeActionForm/index.tsx @@ -39,6 +39,7 @@ function ValidateCodeActionForm({ isInitialized.current = true; sendValidateCode(); } + // eslint-disable-next-line rulesdir/prefer-early-return return () => { // We need to run clearError in cleanup function to use as onClose function. // As 'useEffect cleanup function' runs whenever a dependency is called, we need to put clearError() in the if condition. From f415985a55c9a996caaaa60ec55906767cd71a2f Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Wed, 12 Feb 2025 22:39:17 +0900 Subject: [PATCH 38/39] runs clearError() as call back when unmounted --- .../ValidateCodeActionForm/index.tsx | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/src/components/ValidateCodeActionForm/index.tsx b/src/components/ValidateCodeActionForm/index.tsx index 93ea7554185c..1764a87088d8 100644 --- a/src/components/ValidateCodeActionForm/index.tsx +++ b/src/components/ValidateCodeActionForm/index.tsx @@ -21,34 +21,28 @@ function ValidateCodeActionForm({ forwardedRef, }: ValidateCodeActionFormProps) { const themeStyles = useThemeStyles(); - const isInitialized = useRef(false); - const isClosedRef = useRef(false); const [validateCodeAction] = useOnyx(ONYXKEYS.VALIDATE_ACTION_CODE); - useEffect( - () => () => { - isInitialized.current = false; - isClosedRef.current = true; - }, - [], - ); + const isUnmounted = useRef(false); + + useEffect(() => { + sendValidateCode(); + + return () => { + isUnmounted.current = true; + }; + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps + }, []); useEffect(() => { - if (!isInitialized.current) { - isInitialized.current = true; - sendValidateCode(); - } - // eslint-disable-next-line rulesdir/prefer-early-return return () => { - // We need to run clearError in cleanup function to use as onClose function. - // As 'useEffect cleanup function' runs whenever a dependency is called, we need to put clearError() in the if condition. - // So clearError() will not run when the form is unmounted. - if (isClosedRef.current) { - clearError(); + if (!isUnmounted.current) { + return; } + clearError(); }; - }, [sendValidateCode, clearError]); + }, [clearError]); return ( From 09e4bc137bee72aaed19d4cfc4a5412cc501e0c6 Mon Sep 17 00:00:00 2001 From: jacobkim9881 Date: Fri, 14 Feb 2025 23:43:09 +0900 Subject: [PATCH 39/39] fix: when clicking contact method 2nd time, numpad not showing on Android app --- .../ValidateCodeForm/BaseValidateCodeForm.tsx | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/components/ValidateCodeActionModal/ValidateCodeForm/BaseValidateCodeForm.tsx b/src/components/ValidateCodeActionModal/ValidateCodeForm/BaseValidateCodeForm.tsx index cd1b35c21a44..e2738e97a5a9 100644 --- a/src/components/ValidateCodeActionModal/ValidateCodeForm/BaseValidateCodeForm.tsx +++ b/src/components/ValidateCodeActionModal/ValidateCodeForm/BaseValidateCodeForm.tsx @@ -100,6 +100,7 @@ function BaseValidateCodeForm({ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- nullish coalescing doesn't achieve the same result in this case const shouldDisableResendValidateCode = !!isOffline || account?.isLoading; const focusTimeoutRef = useRef(null); + const clearInputTimeout = useRef(null); const [timeRemaining, setTimeRemaining] = useState(CONST.REQUEST_CODE_DELAY as number); const [canShowError, setCanShowError] = useState(false); const latestActionVerifiedError = getLatestErrorField(validateCodeAction, 'actionVerified'); @@ -150,12 +151,27 @@ function BaseValidateCodeForm({ }, []), ); - useEffect(() => { - if (!hasMagicCodeBeenSent) { - return; - } - inputValidateCodeRef.current?.clear(); - }, [hasMagicCodeBeenSent]); + useFocusEffect( + useCallback(() => { + if (!inputValidateCodeRef.current) { + return; + } + if (clearInputTimeout.current) { + clearTimeout(clearInputTimeout.current); + } + if (hasMagicCodeBeenSent) { + clearInputTimeout.current = setTimeout(() => { + inputValidateCodeRef.current?.clear(); + }, CONST.ANIMATED_TRANSITION); + } + return () => { + if (!clearInputTimeout.current) { + return; + } + clearTimeout(clearInputTimeout.current); + }; + }, [hasMagicCodeBeenSent]), + ); useEffect(() => { if (timeRemaining > 0) {