From 336b6abb2be1cc98b6c3205243637cbd66eae7fc Mon Sep 17 00:00:00 2001 From: thelullabyy Date: Wed, 8 Oct 2025 00:43:21 +0700 Subject: [PATCH 1/3] fix: Account - RBR is shown after remove secondary contact --- .../ValidateCodeActionForm/index.tsx | 9 ------- .../Contacts/ContactMethodDetailsPage.tsx | 27 +++++++++++++------ .../MergeAccounts/AccountValidatePage.tsx | 18 +++++++++++++ 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/src/components/ValidateCodeActionForm/index.tsx b/src/components/ValidateCodeActionForm/index.tsx index 88a5ba5d614d6..c5a551ef41b34 100644 --- a/src/components/ValidateCodeActionForm/index.tsx +++ b/src/components/ValidateCodeActionForm/index.tsx @@ -36,15 +36,6 @@ function ValidateCodeActionForm({ // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, [shouldSkipInitialValidation]); - useEffect(() => { - return () => { - if (!isUnmounted.current) { - return; - } - clearError(); - }; - }, [clearError]); - return ( {descriptionPrimary} diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index f897cdc68300f..a2e79b1f346f4 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -59,6 +59,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { const {isActingAsDelegate, showDelegateNoAccessModal} = useContext(DelegateNoAccessContext); const isLoadingOnyxValues = isLoadingOnyxValue(loginListResult, sessionResult, myDomainSecurityGroupsResult, securityGroupsResult, isLoadingReportDataResult); const {isAccountLocked, showLockedAccountModal} = useContext(LockedAccountContext); + const didClearError = useRef(false); const {formatPhoneNumber, translate} = useLocalize(); const themeStyles = useThemeStyles(); @@ -164,6 +165,23 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS.getRoute(backTo)); }, [prevValidatedDate, loginData?.validatedDate, isDefaultContactMethod, backTo]); + const clearError = useCallback(() => { + // When removing unverified contact methods, the ValidateCodeActionForm unmounts and triggers clearError. + // This causes loginData to become an object, which makes sendValidateCode trigger, so we add this check to prevent clearing the error. + if (!loginData?.partnerUserID) { + return; + } + clearContactMethodErrors(contactMethod, !isEmptyObject(validateLoginError) ? 'validateLogin' : 'validateCodeSent'); + }, [contactMethod, loginData?.partnerUserID, validateLoginError]); + + useEffect(() => { + if (isLoadingOnyxValues || didClearError.current) { + return; + } + didClearError.current = true; + clearError(); + }, [clearError, isLoadingOnyxValues]); + useEffect(() => { setIsValidateCodeFormVisible(!loginData?.validatedDate); }, [loginData?.validatedDate, loginData?.errorFields?.addedLogin]); @@ -343,14 +361,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { hasMagicCodeBeenSent={hasMagicCodeBeenSent} handleSubmitForm={(validateCode) => validateSecondaryLogin(loginList, contactMethod, validateCode, formatPhoneNumber)} validateError={!isEmptyObject(validateLoginError) ? validateLoginError : getLatestErrorField(loginData, 'validateCodeSent')} - clearError={() => { - // When removing unverified contact methods, the ValidateCodeActionForm unmounts and triggers clearError. - // This causes loginData to become an object, which makes sendValidateCode trigger, so we add this check to prevent clearing the error. - if (!loginData.partnerUserID) { - return; - } - clearContactMethodErrors(contactMethod, !isEmptyObject(validateLoginError) ? 'validateLogin' : 'validateCodeSent'); - }} + clearError={clearError} sendValidateCode={() => { if (!loginData.partnerUserID) { return; diff --git a/src/pages/settings/Security/MergeAccounts/AccountValidatePage.tsx b/src/pages/settings/Security/MergeAccounts/AccountValidatePage.tsx index 596126cf6217d..b472b6f03d809 100644 --- a/src/pages/settings/Security/MergeAccounts/AccountValidatePage.tsx +++ b/src/pages/settings/Security/MergeAccounts/AccountValidatePage.tsx @@ -30,6 +30,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type {Account} from '@src/types/onyx'; +import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; const getMergeErrorPage = (err: string): ValueOf | null => { if (err.includes('403')) { @@ -92,6 +93,13 @@ function AccountValidatePage() { const privateSubscription = usePrivateSubscription(); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); + const [, loginListResult] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); + const [, sessionResult] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true}); + const [, myDomainSecurityGroupsResult] = useOnyx(ONYXKEYS.MY_DOMAIN_SECURITY_GROUPS, {canBeMissing: true}); + const [, securityGroupsResult] = useOnyx(ONYXKEYS.COLLECTION.SECURITY_GROUP, {canBeMissing: true}); + const [, isLoadingReportDataResult] = useOnyx(ONYXKEYS.IS_LOADING_REPORT_DATA, {canBeMissing: true}); + const isLoadingOnyxValues = isLoadingOnyxValue(loginListResult, sessionResult, myDomainSecurityGroupsResult, securityGroupsResult, isLoadingReportDataResult); + const {params} = useRoute>(); const email = params.login ?? ''; @@ -151,6 +159,16 @@ function AccountValidatePage() { return unsubscribe; }, [navigation]); + const didClearError = useRef(false); + + useEffect(() => { + if (isLoadingOnyxValues || didClearError.current) { + return; + } + didClearError.current = true; + clearMergeWithValidateCode(); + }, [isLoadingOnyxValues]); + const authenticationErrorKey = getAuthenticationErrorKey(latestError); const validateCodeError = !errorPage && authenticationErrorKey ? {authError: translate(authenticationErrorKey)} : undefined; From 72c87e54cb96b5d93a9f30f43acb0eea8d866f80 Mon Sep 17 00:00:00 2001 From: thelullabyy Date: Tue, 28 Oct 2025 16:30:44 +0700 Subject: [PATCH 2/3] update code --- .../ValidateCodeActionForm/index.tsx | 9 +++++ .../Contacts/ContactMethodDetailsPage.tsx | 34 ++++++++----------- .../MergeAccounts/AccountValidatePage.tsx | 18 ---------- 3 files changed, 23 insertions(+), 38 deletions(-) diff --git a/src/components/ValidateCodeActionForm/index.tsx b/src/components/ValidateCodeActionForm/index.tsx index c5a551ef41b34..88a5ba5d614d6 100644 --- a/src/components/ValidateCodeActionForm/index.tsx +++ b/src/components/ValidateCodeActionForm/index.tsx @@ -36,6 +36,15 @@ function ValidateCodeActionForm({ // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, [shouldSkipInitialValidation]); + useEffect(() => { + return () => { + if (!isUnmounted.current) { + return; + } + clearError(); + }; + }, [clearError]); + return ( {descriptionPrimary} diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index 9a170b31c96c5..4b47e957fdb6d 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -41,6 +41,7 @@ import {close} from '@userActions/Modal'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; +import type {Login} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; import KeyboardUtils from '@src/utils/keyboard'; @@ -58,7 +59,6 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { const {isActingAsDelegate, showDelegateNoAccessModal} = useContext(DelegateNoAccessContext); const isLoadingOnyxValues = isLoadingOnyxValue(loginListResult, sessionResult, myDomainSecurityGroupsResult, securityGroupsResult, isLoadingReportDataResult); const {isAccountLocked, showLockedAccountModal} = useContext(LockedAccountContext); - const didClearError = useRef(false); const {formatPhoneNumber, translate} = useLocalize(); const themeStyles = useThemeStyles(); @@ -72,7 +72,11 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { */ const contactMethod: string = useMemo(() => getDecodedContactMethodFromUriParam(route.params.contactMethod), [route.params.contactMethod]); - const loginData = useMemo(() => loginList?.[contactMethod], [loginList, contactMethod]); + const loginDataRef = useRef(undefined); + const loginData = useMemo(() => { + loginDataRef.current = loginList?.[contactMethod]; + return loginList?.[contactMethod]; + }, [loginList, contactMethod]); const isDefaultContactMethod = useMemo(() => session?.email === loginData?.partnerUserID, [session?.email, loginData?.partnerUserID]); const validateLoginError = getEarliestErrorField(loginData, 'validateLogin'); @@ -148,23 +152,6 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS.getRoute(backTo)); }, [prevValidatedDate, loginData?.validatedDate, isDefaultContactMethod, backTo]); - const clearError = useCallback(() => { - // When removing unverified contact methods, the ValidateCodeActionForm unmounts and triggers clearError. - // This causes loginData to become an object, which makes sendValidateCode trigger, so we add this check to prevent clearing the error. - if (!loginData?.partnerUserID) { - return; - } - clearContactMethodErrors(contactMethod, !isEmptyObject(validateLoginError) ? 'validateLogin' : 'validateCodeSent'); - }, [contactMethod, loginData?.partnerUserID, validateLoginError]); - - useEffect(() => { - if (isLoadingOnyxValues || didClearError.current) { - return; - } - didClearError.current = true; - clearError(); - }, [clearError, isLoadingOnyxValues]); - useEffect(() => { setIsValidateCodeFormVisible(!loginData?.validatedDate); }, [loginData?.validatedDate, loginData?.errorFields?.addedLogin]); @@ -345,7 +332,14 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { hasMagicCodeBeenSent={hasMagicCodeBeenSent} handleSubmitForm={(validateCode) => validateSecondaryLogin(loginList, contactMethod, validateCode, formatPhoneNumber)} validateError={!isEmptyObject(validateLoginError) ? validateLoginError : getLatestErrorField(loginData, 'validateCodeSent')} - clearError={clearError} + clearError={() => { + // When removing unverified contact methods, the ValidateCodeActionForm unmounts and triggers clearError. + // This causes loginData to become an object, which makes sendValidateCode trigger, so we add this check to prevent clearing the error. + if (!loginDataRef.current?.partnerUserID) { + return; + } + clearContactMethodErrors(contactMethod, !isEmptyObject(validateLoginError) ? 'validateLogin' : 'validateCodeSent'); + }} sendValidateCode={() => { if (!loginData.partnerUserID) { return; diff --git a/src/pages/settings/Security/MergeAccounts/AccountValidatePage.tsx b/src/pages/settings/Security/MergeAccounts/AccountValidatePage.tsx index ee0d128681a3c..ddf653a7b0a27 100644 --- a/src/pages/settings/Security/MergeAccounts/AccountValidatePage.tsx +++ b/src/pages/settings/Security/MergeAccounts/AccountValidatePage.tsx @@ -30,7 +30,6 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type {Account} from '@src/types/onyx'; -import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; const getMergeErrorPage = (err: string): ValueOf | null => { if (err.includes('403')) { @@ -93,13 +92,6 @@ function AccountValidatePage() { const privateSubscription = usePrivateSubscription(); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); - const [, loginListResult] = useOnyx(ONYXKEYS.LOGIN_LIST, {canBeMissing: true}); - const [, sessionResult] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true}); - const [, myDomainSecurityGroupsResult] = useOnyx(ONYXKEYS.MY_DOMAIN_SECURITY_GROUPS, {canBeMissing: true}); - const [, securityGroupsResult] = useOnyx(ONYXKEYS.COLLECTION.SECURITY_GROUP, {canBeMissing: true}); - const [, isLoadingReportDataResult] = useOnyx(ONYXKEYS.IS_LOADING_REPORT_DATA, {canBeMissing: true}); - const isLoadingOnyxValues = isLoadingOnyxValue(loginListResult, sessionResult, myDomainSecurityGroupsResult, securityGroupsResult, isLoadingReportDataResult); - const {params} = useRoute>(); const email = params.login ?? ''; @@ -159,16 +151,6 @@ function AccountValidatePage() { return unsubscribe; }, [navigation]); - const didClearError = useRef(false); - - useEffect(() => { - if (isLoadingOnyxValues || didClearError.current) { - return; - } - didClearError.current = true; - clearMergeWithValidateCode(); - }, [isLoadingOnyxValues]); - const authenticationErrorKey = getAuthenticationErrorKey(latestError); const validateCodeError = !errorPage && authenticationErrorKey ? {authError: translate(authenticationErrorKey)} : undefined; From f8c7ec0d11a54040438cd1f1a802ccb05a13ef9c Mon Sep 17 00:00:00 2001 From: thelullabyy Date: Thu, 30 Oct 2025 18:07:29 +0800 Subject: [PATCH 3/3] fix: type err --- 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 4b47e957fdb6d..dd0d356e49faf 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -74,6 +74,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { const loginDataRef = useRef(undefined); const loginData = useMemo(() => { + // eslint-disable-next-line react-compiler/react-compiler loginDataRef.current = loginList?.[contactMethod]; return loginList?.[contactMethod]; }, [loginList, contactMethod]);