From 0843b661532c7e8e88fd105473ede37e4af848fd Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Sun, 25 Aug 2024 06:29:51 +0530 Subject: [PATCH 001/149] fix: Dupe detect - Tax field does not show the Default label on the confirmation page. Signed-off-by: krishna2323 --- src/libs/TransactionUtils/index.ts | 25 ++++++++++++++++--- .../ReviewDescription.tsx | 3 ++- src/types/onyx/ReviewDuplicates.ts | 4 +++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index e5bd5d9b0753..986435041fa6 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -959,9 +959,27 @@ function compareDuplicateTransactionFields(transactionID: string): {keep: Partia ]; } + const getTransactionCommentWithoutWaypointKeys = (firstTransaction: OnyxEntry) => { + // Remove keyForList from each waypoint + const updatedWaypoints = Object.fromEntries(Object.entries(firstTransaction?.waypoints ?? {}).map(([key, waypoint]) => [key, (({keyForList, ...rest}) => rest)(waypoint)])); + + // Create the new object + const updatedData = { + ...firstTransaction, + waypoints: updatedWaypoints, + }; + + return updatedData; + }; + // Helper function to check if all comments are equal function areAllCommentsEqual(items: Array>, firstTransaction: OnyxEntry) { - return items.every((item) => lodashIsEqual(item?.comment, firstTransaction?.comment)); + return items.every((item) => { + if (item?.comment?.waypoints) { + return lodashIsEqual(getTransactionCommentWithoutWaypointKeys(item.comment), getTransactionCommentWithoutWaypointKeys(firstTransaction?.comment)); + } + return lodashIsEqual(item?.comment, firstTransaction?.comment); + }); } // Helper function to check if all fields are equal for a given key @@ -986,10 +1004,11 @@ function compareDuplicateTransactionFields(transactionID: string): {keep: Partia if (fieldName === 'description') { const allCommentsAreEqual = areAllCommentsEqual(transactions, firstTransaction); - const allCommentsAreEmpty = isFirstTransactionCommentEmptyObject && transactions.every((item) => item?.comment === undefined); + const allCommentsAreEmpty = isFirstTransactionCommentEmptyObject && transactions.every((item) => !item?.comment); if (allCommentsAreEqual || allCommentsAreEmpty) { keep[fieldName] = firstTransaction?.comment?.comment ?? firstTransaction?.comment; + keep.comment = firstTransaction?.comment; } else { processChanges(fieldName, transactions, keys); } @@ -1027,7 +1046,7 @@ function buildNewTransactionAfterReviewingDuplicates(reviewDuplicateTransaction: ...restReviewDuplicateTransaction, modifiedMerchant: reviewDuplicateTransaction?.merchant, merchant: reviewDuplicateTransaction?.merchant, - comment: {comment: reviewDuplicateTransaction?.description}, + comment: {...reviewDuplicateTransaction?.comment, comment: reviewDuplicateTransaction?.description}, }; } diff --git a/src/pages/TransactionDuplicate/ReviewDescription.tsx b/src/pages/TransactionDuplicate/ReviewDescription.tsx index e6229afe48ac..be7bb7ca4b18 100644 --- a/src/pages/TransactionDuplicate/ReviewDescription.tsx +++ b/src/pages/TransactionDuplicate/ReviewDescription.tsx @@ -33,7 +33,8 @@ function ReviewDescription() { ); const setDescription = (data: FieldItemType<'description'>) => { if (data.value !== undefined) { - setReviewDuplicatesKey({description: data.value}); + const comment = compareResult.change.description?.find((d) => d?.comment === data.value); + setReviewDuplicatesKey({description: data.value, comment}); } navigateToNextScreen(); }; diff --git a/src/types/onyx/ReviewDuplicates.ts b/src/types/onyx/ReviewDuplicates.ts index 0682ed0a7f7c..e8944a9f56b0 100644 --- a/src/types/onyx/ReviewDuplicates.ts +++ b/src/types/onyx/ReviewDuplicates.ts @@ -1,3 +1,5 @@ +import type {Comment} from './Transaction'; + /** * Model of review duplicates request */ @@ -26,6 +28,8 @@ type ReviewDuplicates = { /** Description which user want to keep */ description: string; + /** Description which user want to keep */ + comment: Comment; /** Whether the transaction is reimbursable */ reimbursable: boolean; From ccfc7d86c09920aacf195b711a1b5c7cf43ab68a Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Fri, 11 Oct 2024 20:21:48 +0530 Subject: [PATCH 002/149] revert changes. Signed-off-by: krishna2323 --- src/libs/TransactionUtils/index.ts | 25 +++---------------- .../ReviewDescription.tsx | 3 +-- src/types/onyx/ReviewDuplicates.ts | 4 --- 3 files changed, 4 insertions(+), 28 deletions(-) diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index 986435041fa6..e5bd5d9b0753 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -959,27 +959,9 @@ function compareDuplicateTransactionFields(transactionID: string): {keep: Partia ]; } - const getTransactionCommentWithoutWaypointKeys = (firstTransaction: OnyxEntry) => { - // Remove keyForList from each waypoint - const updatedWaypoints = Object.fromEntries(Object.entries(firstTransaction?.waypoints ?? {}).map(([key, waypoint]) => [key, (({keyForList, ...rest}) => rest)(waypoint)])); - - // Create the new object - const updatedData = { - ...firstTransaction, - waypoints: updatedWaypoints, - }; - - return updatedData; - }; - // Helper function to check if all comments are equal function areAllCommentsEqual(items: Array>, firstTransaction: OnyxEntry) { - return items.every((item) => { - if (item?.comment?.waypoints) { - return lodashIsEqual(getTransactionCommentWithoutWaypointKeys(item.comment), getTransactionCommentWithoutWaypointKeys(firstTransaction?.comment)); - } - return lodashIsEqual(item?.comment, firstTransaction?.comment); - }); + return items.every((item) => lodashIsEqual(item?.comment, firstTransaction?.comment)); } // Helper function to check if all fields are equal for a given key @@ -1004,11 +986,10 @@ function compareDuplicateTransactionFields(transactionID: string): {keep: Partia if (fieldName === 'description') { const allCommentsAreEqual = areAllCommentsEqual(transactions, firstTransaction); - const allCommentsAreEmpty = isFirstTransactionCommentEmptyObject && transactions.every((item) => !item?.comment); + const allCommentsAreEmpty = isFirstTransactionCommentEmptyObject && transactions.every((item) => item?.comment === undefined); if (allCommentsAreEqual || allCommentsAreEmpty) { keep[fieldName] = firstTransaction?.comment?.comment ?? firstTransaction?.comment; - keep.comment = firstTransaction?.comment; } else { processChanges(fieldName, transactions, keys); } @@ -1046,7 +1027,7 @@ function buildNewTransactionAfterReviewingDuplicates(reviewDuplicateTransaction: ...restReviewDuplicateTransaction, modifiedMerchant: reviewDuplicateTransaction?.merchant, merchant: reviewDuplicateTransaction?.merchant, - comment: {...reviewDuplicateTransaction?.comment, comment: reviewDuplicateTransaction?.description}, + comment: {comment: reviewDuplicateTransaction?.description}, }; } diff --git a/src/pages/TransactionDuplicate/ReviewDescription.tsx b/src/pages/TransactionDuplicate/ReviewDescription.tsx index be7bb7ca4b18..e6229afe48ac 100644 --- a/src/pages/TransactionDuplicate/ReviewDescription.tsx +++ b/src/pages/TransactionDuplicate/ReviewDescription.tsx @@ -33,8 +33,7 @@ function ReviewDescription() { ); const setDescription = (data: FieldItemType<'description'>) => { if (data.value !== undefined) { - const comment = compareResult.change.description?.find((d) => d?.comment === data.value); - setReviewDuplicatesKey({description: data.value, comment}); + setReviewDuplicatesKey({description: data.value}); } navigateToNextScreen(); }; diff --git a/src/types/onyx/ReviewDuplicates.ts b/src/types/onyx/ReviewDuplicates.ts index e8944a9f56b0..0682ed0a7f7c 100644 --- a/src/types/onyx/ReviewDuplicates.ts +++ b/src/types/onyx/ReviewDuplicates.ts @@ -1,5 +1,3 @@ -import type {Comment} from './Transaction'; - /** * Model of review duplicates request */ @@ -28,8 +26,6 @@ type ReviewDuplicates = { /** Description which user want to keep */ description: string; - /** Description which user want to keep */ - comment: Comment; /** Whether the transaction is reimbursable */ reimbursable: boolean; From 76ab756af59c94d9f9ff35bcb74a26e0ccb80330 Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Thu, 17 Oct 2024 19:07:11 +0530 Subject: [PATCH 003/149] update main branch. Signed-off-by: krishna2323 --- src/libs/TransactionUtils/index.ts | 3 ++- src/pages/TransactionDuplicate/ReviewDescription.tsx | 4 +++- src/types/onyx/ReviewDuplicates.ts | 5 +++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index bd0db668fe2c..1630d74835cb 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -1045,6 +1045,7 @@ function compareDuplicateTransactionFields(transactionID: string): {keep: Partia const allCommentsAreEmpty = isFirstTransactionCommentEmptyObject && transactions.every((item) => getDescription(item) === ''); if (allCommentsAreEqual || allCommentsAreEmpty) { keep[fieldName] = firstTransaction?.comment?.comment ?? firstTransaction?.comment; + keep.comment = firstTransaction?.comment; } else { processChanges(fieldName, transactions, keys); } @@ -1082,7 +1083,7 @@ function buildNewTransactionAfterReviewingDuplicates(reviewDuplicateTransaction: ...restReviewDuplicateTransaction, modifiedMerchant: reviewDuplicateTransaction?.merchant, merchant: reviewDuplicateTransaction?.merchant, - comment: {comment: reviewDuplicateTransaction?.description}, + comment: {...reviewDuplicateTransaction?.comment, comment: reviewDuplicateTransaction?.description}, }; } diff --git a/src/pages/TransactionDuplicate/ReviewDescription.tsx b/src/pages/TransactionDuplicate/ReviewDescription.tsx index 3d74d8cc36e1..108a39d654ce 100644 --- a/src/pages/TransactionDuplicate/ReviewDescription.tsx +++ b/src/pages/TransactionDuplicate/ReviewDescription.tsx @@ -38,7 +38,9 @@ function ReviewDescription() { ); const setDescription = (data: FieldItemType<'description'>) => { if (data.value !== undefined) { - setReviewDuplicatesKey({description: data.value}); + // setReviewDuplicatesKey({description: data.value}); + const comment = compareResult.change.description?.find((d) => d?.comment === data.value); + setReviewDuplicatesKey({comment, description: data.value}); } navigateToNextScreen(); }; diff --git a/src/types/onyx/ReviewDuplicates.ts b/src/types/onyx/ReviewDuplicates.ts index 0682ed0a7f7c..f436b50b1679 100644 --- a/src/types/onyx/ReviewDuplicates.ts +++ b/src/types/onyx/ReviewDuplicates.ts @@ -1,3 +1,5 @@ +import type {Comment} from './Transaction'; + /** * Model of review duplicates request */ @@ -26,6 +28,9 @@ type ReviewDuplicates = { /** Description which user want to keep */ description: string; + /** Description which user want to keep */ + comment: Comment; + /** Whether the transaction is reimbursable */ reimbursable: boolean; From f63804fda2685824aee85d1a1f9eba15d0bed65e Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Fri, 25 Oct 2024 19:24:52 +0800 Subject: [PATCH 004/149] fix hidden shows briefly when mentioning unknown user --- .../HTMLRenderers/MentionUserRenderer.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.tsx index 36586b09e514..96bdf8e9e1e8 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.tsx @@ -4,9 +4,9 @@ import isEmpty from 'lodash/isEmpty'; import React from 'react'; import {StyleSheet} from 'react-native'; import type {TextStyle} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; import type {CustomRendererProps, TPhrasing, TText} from 'react-native-render-html'; import {TNodeChildrenRenderer} from 'react-native-render-html'; -import {usePersonalDetails} from '@components/OnyxProvider'; import {ShowContextMenuContext, showContextMenuForReport} from '@components/ShowContextMenuContext'; import Text from '@components/Text'; import UserDetailsTooltip from '@components/UserDetailsTooltip'; @@ -20,6 +20,7 @@ import Navigation from '@libs/Navigation/Navigation'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Route} from '@src/ROUTES'; import asMutable from '@src/types/utils/asMutable'; @@ -31,7 +32,7 @@ function MentionUserRenderer({style, tnode, TDefaultRenderer, currentUserPersona const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const htmlAttribAccountID = tnode.attributes.accountid; - const personalDetails = usePersonalDetails() || CONST.EMPTY_OBJECT; + const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST); const htmlAttributeAccountID = tnode.attributes.accountid; let accountID: number; @@ -56,7 +57,7 @@ function MentionUserRenderer({style, tnode, TDefaultRenderer, currentUserPersona return displayText.split('@').at(0); }; - if (!isEmpty(htmlAttribAccountID)) { + if (!isEmpty(htmlAttribAccountID) && personalDetails?.[htmlAttribAccountID]) { const user = personalDetails[htmlAttribAccountID]; accountID = parseInt(htmlAttribAccountID, 10); mentionDisplayText = LocalePhoneNumber.formatPhoneNumber(user?.login ?? '') || PersonalDetailsUtils.getDisplayNameOrDefault(user); From dd9c2d426f05a146d6f89bd35089eafc8aa7a4de Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Tue, 29 Oct 2024 13:58:47 +0800 Subject: [PATCH 005/149] fix wrong backTo --- src/ROUTES.ts | 6 +++++- src/libs/Navigation/types.ts | 3 ++- src/libs/actions/BankAccounts.ts | 2 +- src/pages/settings/Wallet/PaymentMethodList.tsx | 2 +- src/pages/settings/Wallet/VerifyAccountPage.tsx | 8 ++++---- src/pages/settings/Wallet/WalletPage/WalletPage.tsx | 4 +++- 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 2e895537eaac..09f8fad58ff0 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -156,7 +156,11 @@ const ROUTES = { SETTINGS_ABOUT: 'settings/about', SETTINGS_APP_DOWNLOAD_LINKS: 'settings/about/app-download-links', SETTINGS_WALLET: 'settings/wallet', - SETTINGS_WALLET_VERIFY_ACCOUNT: {route: 'settings/wallet/verify', getRoute: (backTo?: string) => getUrlWithBackToParam('settings/wallet/verify', backTo)}, + SETTINGS_WALLET_VERIFY_ACCOUNT: { + route: 'settings/wallet/verify', + getRoute: (backTo?: string, forwardTo?: string) => + getUrlWithBackToParam(forwardTo ? `settings/wallet/verify?forwardTo=${encodeURIComponent(forwardTo)}` : 'settings/wallet/verify', backTo), + }, SETTINGS_WALLET_DOMAINCARD: { route: 'settings/wallet/card/:cardID?', getRoute: (cardID: string) => `settings/wallet/card/${cardID}` as const, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 3de07f2c801f..138e723345a3 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -108,7 +108,8 @@ type SettingsNavigatorParamList = { backTo?: Routes; }; [SCREENS.SETTINGS.PROFILE.NEW_CONTACT_METHOD]: { - backTo: Routes; + backTo?: Routes; + forwardTo?: Routes; }; [SCREENS.SETTINGS.PREFERENCES.ROOT]: undefined; [SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: undefined; diff --git a/src/libs/actions/BankAccounts.ts b/src/libs/actions/BankAccounts.ts index 6679a6e4b9ea..4795c1524d0e 100644 --- a/src/libs/actions/BankAccounts.ts +++ b/src/libs/actions/BankAccounts.ts @@ -79,7 +79,7 @@ function openPersonalBankAccountSetupView(exitReportID?: string, isUserValidated Onyx.merge(ONYXKEYS.PERSONAL_BANK_ACCOUNT, {exitReportID}); } if (!isUserValidated) { - Navigation.navigate(ROUTES.SETTINGS_WALLET_VERIFY_ACCOUNT.getRoute(ROUTES.SETTINGS_ADD_BANK_ACCOUNT)); + Navigation.navigate(ROUTES.SETTINGS_WALLET_VERIFY_ACCOUNT.getRoute(ROUTES.SETTINGS_WALLET, ROUTES.SETTINGS_ADD_BANK_ACCOUNT)); } Navigation.navigate(ROUTES.SETTINGS_ADD_BANK_ACCOUNT); }); diff --git a/src/pages/settings/Wallet/PaymentMethodList.tsx b/src/pages/settings/Wallet/PaymentMethodList.tsx index 23d0b5ab6550..9525c54f84f1 100644 --- a/src/pages/settings/Wallet/PaymentMethodList.tsx +++ b/src/pages/settings/Wallet/PaymentMethodList.tsx @@ -347,7 +347,7 @@ function PaymentMethodList({ const onPressItem = useCallback(() => { if (!isUserValidated) { - Navigation.navigate(ROUTES.SETTINGS_WALLET_VERIFY_ACCOUNT.getRoute(ROUTES.SETTINGS_ADD_BANK_ACCOUNT)); + Navigation.navigate(ROUTES.SETTINGS_WALLET_VERIFY_ACCOUNT.getRoute(ROUTES.SETTINGS_WALLET, ROUTES.SETTINGS_ADD_BANK_ACCOUNT)); return; } onPress(); diff --git a/src/pages/settings/Wallet/VerifyAccountPage.tsx b/src/pages/settings/Wallet/VerifyAccountPage.tsx index a3b51ef0de17..3275cea40495 100644 --- a/src/pages/settings/Wallet/VerifyAccountPage.tsx +++ b/src/pages/settings/Wallet/VerifyAccountPage.tsx @@ -8,7 +8,6 @@ import Navigation from '@libs/Navigation/Navigation'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; import * as User from '@userActions/User'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; type VerifyAccountPageProps = StackScreenProps; @@ -23,6 +22,7 @@ function VerifyAccountPage({route}: VerifyAccountPageProps) { const [isUserValidated] = useOnyx(ONYXKEYS.USER, {selector: (user) => !!user?.validated}); const [isValidateCodeActionModalVisible, setIsValidateCodeActionModalVisible] = useState(true); + const navigateForwardTo = route.params?.forwardTo; const navigateBackTo = route?.params?.backTo; useEffect(() => () => User.clearUnvalidatedNewContactMethodAction(), []); @@ -49,8 +49,8 @@ function VerifyAccountPage({route}: VerifyAccountPageProps) { return; } - Navigation.navigate(navigateBackTo); - }, [isUserValidated, navigateBackTo]); + Navigation.navigate(navigateForwardTo); + }, [isUserValidated, navigateForwardTo]); useEffect(() => { if (isValidateCodeActionModalVisible) { @@ -58,7 +58,7 @@ function VerifyAccountPage({route}: VerifyAccountPageProps) { } if (!isUserValidated && navigateBackTo) { - Navigation.navigate(ROUTES.SETTINGS_WALLET); + Navigation.goBack(navigateBackTo); } else if (!navigateBackTo) { Navigation.goBack(); } diff --git a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx index 7b9366370349..3e3030c86d4f 100644 --- a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx +++ b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx @@ -500,7 +500,9 @@ function WalletPage({shouldListenForResize = false}: WalletPageProps) { ref={buttonRef as ForwardedRef} onPress={() => { if (!isUserValidated) { - Navigation.navigate(ROUTES.SETTINGS_WALLET_VERIFY_ACCOUNT.getRoute(ROUTES.SETTINGS_ENABLE_PAYMENTS)); + Navigation.navigate( + ROUTES.SETTINGS_WALLET_VERIFY_ACCOUNT.getRoute(ROUTES.SETTINGS_WALLET, ROUTES.SETTINGS_ENABLE_PAYMENTS), + ); return; } Navigation.navigate(ROUTES.SETTINGS_ENABLE_PAYMENTS); From 774851deb0e68c408e3f51c893f2f0ec05cc51b8 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Tue, 29 Oct 2024 14:35:01 +0800 Subject: [PATCH 006/149] fix wrong variable being checked --- src/pages/settings/Wallet/VerifyAccountPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/Wallet/VerifyAccountPage.tsx b/src/pages/settings/Wallet/VerifyAccountPage.tsx index 3275cea40495..302f73f09144 100644 --- a/src/pages/settings/Wallet/VerifyAccountPage.tsx +++ b/src/pages/settings/Wallet/VerifyAccountPage.tsx @@ -45,7 +45,7 @@ function VerifyAccountPage({route}: VerifyAccountPageProps) { setIsValidateCodeActionModalVisible(false); - if (!navigateBackTo) { + if (!navigateForwardTo) { return; } From 7fb8e7585e2627f1b6df5ec52114cd2f5e2bc25e Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Mon, 11 Nov 2024 10:58:57 +0800 Subject: [PATCH 007/149] add backTo when going to wallet verify page --- src/components/SettlementButton/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/SettlementButton/index.tsx b/src/components/SettlementButton/index.tsx index 53b09bfcbf31..caf13b7e6997 100644 --- a/src/components/SettlementButton/index.tsx +++ b/src/components/SettlementButton/index.tsx @@ -191,7 +191,7 @@ function SettlementButton({ if (iouPaymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY || iouPaymentType === CONST.IOU.PAYMENT_TYPE.VBBA) { if (!isUserValidated) { - Navigation.navigate(ROUTES.SETTINGS_WALLET_VERIFY_ACCOUNT.route); + Navigation.navigate(ROUTES.SETTINGS_WALLET_VERIFY_ACCOUNT.getRoute(Navigation.getActiveRoute())); return; } triggerKYCFlow(event, iouPaymentType); From bc5c10c9b36f1f9eb8e8b01cc822540543d5d7ab Mon Sep 17 00:00:00 2001 From: I Nyoman Jyotisa Date: Mon, 11 Nov 2024 19:07:43 +0800 Subject: [PATCH 008/149] Create SMS delivery failure sign in flow in homepage --- src/languages/en.ts | 7 ++ src/languages/es.ts | 8 +++ src/pages/signin/SMSDeliveryFailurePage.tsx | 75 +++++++++++++++++++++ src/pages/signin/SignInPage.tsx | 18 +++-- src/types/onyx/Account.ts | 1 + 5 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 src/pages/signin/SMSDeliveryFailurePage.tsx diff --git a/src/languages/en.ts b/src/languages/en.ts index 0fdf0b8fdee4..43cbc8aaa865 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -472,6 +472,7 @@ const translations = { links: 'Links', days: 'days', rename: 'Rename', + validate: 'Validate', }, location: { useCurrent: 'Use current location', @@ -1816,6 +1817,12 @@ const translations = { onceTheAbove: 'Once the above steps are completed, please reach out to ', toUnblock: ' to unblock your login.', }, + smsDeliveryFailurePage: { + smsDeliveryFailureMessage: ({login}: OurEmailProviderParams) => + `We have temporarily suspended sending SMS to ${login} because we were unable to deliver SMS messages to your phone number. To try again, please click the button:`, + validateFailed: ({time}: UntilTimeParams) => `Reset failed because it hasn’t been 24 hours since our last attempt. Please wait ${time} before trying again.`, + validateSuccess: 'Your number has been cleared successfully and we can send you a new magic code to sign in', + }, welcomeSignUpForm: { join: 'Join', }, diff --git a/src/languages/es.ts b/src/languages/es.ts index 712423cf0776..a4fa00364a6e 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -462,6 +462,7 @@ const translations = { sent: 'Enviado', links: 'Enlaces', days: 'días', + validate: 'Validar', }, connectionComplete: { title: 'Conexión completa', @@ -1819,6 +1820,13 @@ const translations = { onceTheAbove: 'Una vez completados los pasos anteriores, ponte en contacto con ', toUnblock: ' para desbloquear el inicio de sesión.', }, + smsDeliveryFailurePage: { + smsDeliveryFailureMessage: ({login}: OurEmailProviderParams) => + `Hemos suspendido temporalmente el envío de SMS a ${login} porque no pudimos entregar los mensajes SMS a tu número de teléfono. Para intentarlo de nuevo, por favor haz clic en el botón:`, + validateFailed: ({time}: UntilTimeParams) => + `El restablecimiento falló porque no han pasado 24 horas desde nuestro último intento. Por favor espera ${time} antes de intentarlo nuevamente.`, + validateSuccess: 'Tu número ha sido restablecido exitosamente y podemos enviarte un nuevo código mágico para iniciar sesión', + }, welcomeSignUpForm: { join: 'Unirse', }, diff --git a/src/pages/signin/SMSDeliveryFailurePage.tsx b/src/pages/signin/SMSDeliveryFailurePage.tsx new file mode 100644 index 000000000000..f068500163f8 --- /dev/null +++ b/src/pages/signin/SMSDeliveryFailurePage.tsx @@ -0,0 +1,75 @@ +import {Str} from 'expensify-common'; +import React, {useEffect, useMemo} from 'react'; +import {Keyboard, View} from 'react-native'; +import {withOnyx} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; +import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; +import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; +import Text from '@components/Text'; +import useKeyboardState from '@hooks/useKeyboardState'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as Session from '@userActions/Session'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {Credentials} from '@src/types/onyx'; + +type SMSDeliveryFailurePageOnyxProps = { + /** The credentials of the logged in person */ + credentials: OnyxEntry; +}; +type SMSDeliveryFailurePageProps = SMSDeliveryFailurePageOnyxProps; +function SMSDeliveryFailurePage({credentials}: SMSDeliveryFailurePageProps) { + const styles = useThemeStyles(); + const {isKeyboardShown} = useKeyboardState(); + const {translate} = useLocalize(); + const login = useMemo(() => { + if (!credentials?.login) { + return ''; + } + return Str.isSMSLogin(credentials.login) ? Str.removeSMSDomain(credentials.login) : credentials.login; + }, [credentials?.login]); + // This view doesn't have a field for user input, so dismiss the device keyboard if shown + useEffect(() => { + if (!isKeyboardShown) { + return; + } + Keyboard.dismiss(); + }, [isKeyboardShown]); + return ( + <> + + + {translate('smsDeliveryFailurePage.smsDeliveryFailureMessage', {login})} + + + + {}} + message={''} + isAlertVisible={false} + buttonStyles={styles.mt3} + containerStyles={[styles.mh0]} + /> + + + Session.clearSignInData()} + role="button" + accessibilityLabel={translate('common.back')} + // disable hover dim for switch + hoverDimmingValue={1} + pressDimmingValue={0.2} + > + {translate('common.back')} + + + + ); +} +SMSDeliveryFailurePage.displayName = 'SMSDeliveryFailurePage'; +export default withOnyx({ + credentials: {key: ONYXKEYS.CREDENTIALS}, +})(SMSDeliveryFailurePage); diff --git a/src/pages/signin/SignInPage.tsx b/src/pages/signin/SignInPage.tsx index 1068cf97197e..64a052e6a3ef 100644 --- a/src/pages/signin/SignInPage.tsx +++ b/src/pages/signin/SignInPage.tsx @@ -33,6 +33,7 @@ import type {InputHandle} from './LoginForm/types'; import SignInPageLayout from './SignInPageLayout'; import type {SignInPageLayoutRef} from './SignInPageLayout/types'; import SignUpWelcomeForm from './SignUpWelcomeForm'; +import SMSDeliveryFailurePage from './SMSDeliveryFailurePage'; import UnlinkLoginForm from './UnlinkLoginForm'; import ValidateCodeForm from './ValidateCodeForm'; import type {BaseValidateCodeFormRef} from './ValidateCodeForm/BaseValidateCodeForm'; @@ -62,6 +63,7 @@ type SignInPageRef = { type RenderOption = { shouldShowLoginForm: boolean; shouldShowEmailDeliveryFailurePage: boolean; + shouldShowSMSDeliveryFailurePage: boolean; shouldShowUnlinkLoginForm: boolean; shouldShowValidateCodeForm: boolean; shouldShowChooseSSOOrMagicCode: boolean; @@ -90,6 +92,7 @@ type GetRenderOptionsParams = { * @param isUsingMagicCode * @param hasInitiatedSAMLLogin * @param hasEmailDeliveryFailure + * @param hasSMSDeliveryFailure */ function getRenderOptions({ hasLogin, @@ -105,6 +108,7 @@ function getRenderOptions({ const isSAMLEnabled = !!account?.isSAMLEnabled; const isSAMLRequired = !!account?.isSAMLRequired; const hasEmailDeliveryFailure = !!account?.hasEmailDeliveryFailure; + const hasSMSDeliveryFailure = !!account?.hasSMSDeliveryFailure; // True, if the user has SAML required, and we haven't yet initiated SAML for their account const shouldInitiateSAMLLogin = hasAccount && hasLogin && isSAMLRequired && !hasInitiatedSAMLLogin && !!account.isLoading; @@ -121,13 +125,15 @@ function getRenderOptions({ const shouldShouldSignUpWelcomeForm = !!credentials?.login && !account?.validated && !account?.accountExists && !account?.domainControlled; const shouldShowLoginForm = !shouldShowAnotherLoginPageOpenedMessage && !hasLogin && !hasValidateCode; const shouldShowEmailDeliveryFailurePage = hasLogin && hasEmailDeliveryFailure && !shouldShowChooseSSOOrMagicCode && !shouldInitiateSAMLLogin; - const isUnvalidatedSecondaryLogin = hasLogin && !isPrimaryLogin && !account?.validated && !hasEmailDeliveryFailure; + const shouldShowSMSDeliveryFailurePage = hasLogin && hasSMSDeliveryFailure && !shouldShowChooseSSOOrMagicCode && !shouldInitiateSAMLLogin; + const isUnvalidatedSecondaryLogin = hasLogin && !isPrimaryLogin && !account?.validated && !hasEmailDeliveryFailure && !hasSMSDeliveryFailure; const shouldShowValidateCodeForm = !shouldShouldSignUpWelcomeForm && hasAccount && (hasLogin || hasValidateCode) && !isUnvalidatedSecondaryLogin && !hasEmailDeliveryFailure && + !hasSMSDeliveryFailure && !shouldShowChooseSSOOrMagicCode && !isSAMLRequired; const shouldShowWelcomeHeader = shouldShowLoginForm || shouldShowValidateCodeForm || shouldShowChooseSSOOrMagicCode || isUnvalidatedSecondaryLogin || shouldShouldSignUpWelcomeForm; @@ -137,6 +143,7 @@ function getRenderOptions({ return { shouldShowLoginForm, shouldShowEmailDeliveryFailurePage, + shouldShowSMSDeliveryFailurePage, shouldShowUnlinkLoginForm: !shouldShouldSignUpWelcomeForm && isUnvalidatedSecondaryLogin, shouldShowValidateCodeForm, shouldShowChooseSSOOrMagicCode, @@ -200,6 +207,7 @@ function SignInPage({credentials, account, activeClients = [], preferredLocale, const { shouldShowLoginForm, shouldShowEmailDeliveryFailurePage, + shouldShowSMSDeliveryFailurePage, shouldShowUnlinkLoginForm, shouldShowValidateCodeForm, shouldShowChooseSSOOrMagicCode, @@ -249,11 +257,11 @@ function SignInPage({credentials, account, activeClients = [], preferredLocale, ? `${translate('welcomeText.welcome')} ${translate('welcomeText.welcomeEnterMagicCode', {login: userLoginToDisplay})}` : translate('welcomeText.welcomeEnterMagicCode', {login: userLoginToDisplay}); } - } else if (shouldShowUnlinkLoginForm || shouldShowEmailDeliveryFailurePage || shouldShowChooseSSOOrMagicCode) { + } else if (shouldShowUnlinkLoginForm || shouldShowEmailDeliveryFailurePage || shouldShowChooseSSOOrMagicCode || shouldShowSMSDeliveryFailurePage) { welcomeHeader = shouldUseNarrowLayout ? headerText : translate('welcomeText.welcome'); // Don't show any welcome text if we're showing the user the email delivery failed view - if (shouldShowEmailDeliveryFailurePage || shouldShowChooseSSOOrMagicCode) { + if (shouldShowEmailDeliveryFailurePage || shouldShowChooseSSOOrMagicCode || shouldShowSMSDeliveryFailurePage) { welcomeText = ''; } } else if (shouldShouldSignUpWelcomeForm) { @@ -273,7 +281,8 @@ function SignInPage({credentials, account, activeClients = [], preferredLocale, const navigateBack = () => { if ( shouldShouldSignUpWelcomeForm || - (!shouldShowAnotherLoginPageOpenedMessage && (shouldShowEmailDeliveryFailurePage || shouldShowUnlinkLoginForm || shouldShowChooseSSOOrMagicCode)) + (!shouldShowAnotherLoginPageOpenedMessage && + (shouldShowEmailDeliveryFailurePage || shouldShowUnlinkLoginForm || shouldShowChooseSSOOrMagicCode || shouldShowSMSDeliveryFailurePage)) ) { Session.clearSignInData(); return; @@ -332,6 +341,7 @@ function SignInPage({credentials, account, activeClients = [], preferredLocale, {shouldShowUnlinkLoginForm && } {shouldShowChooseSSOOrMagicCode && } {shouldShowEmailDeliveryFailurePage && } + {shouldShowSMSDeliveryFailurePage && } )} diff --git a/src/types/onyx/Account.ts b/src/types/onyx/Account.ts index 3902d67882c4..d31c23b2e5a5 100644 --- a/src/types/onyx/Account.ts +++ b/src/types/onyx/Account.ts @@ -70,6 +70,7 @@ type Account = { /** Is this account having trouble receiving emails? */ hasEmailDeliveryFailure?: boolean; + hasSMSDeliveryFailure?: boolean; /** URL to the assigned guide's appointment booking calendar */ guideCalendarLink?: string; From 9710a7995ef09b67ed68ad0394209ae0ccd6b551 Mon Sep 17 00:00:00 2001 From: I Nyoman Jyotisa Date: Tue, 12 Nov 2024 13:56:00 +0800 Subject: [PATCH 009/149] SMS delivery failure flow --- src/languages/en.ts | 2 - src/languages/es.ts | 3 - .../ResetPhoneNumberFailureParams.ts | 5 + src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 2 + src/libs/actions/Session/index.ts | 14 +++ src/pages/signin/SMSDeliveryFailurePage.tsx | 95 +++++++++++++------ src/pages/signin/SignInPage.tsx | 4 +- src/types/onyx/Account.ts | 8 ++ 9 files changed, 100 insertions(+), 34 deletions(-) create mode 100644 src/libs/API/parameters/ResetPhoneNumberFailureParams.ts diff --git a/src/languages/en.ts b/src/languages/en.ts index 43cbc8aaa865..f86e20178dfb 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1820,8 +1820,6 @@ const translations = { smsDeliveryFailurePage: { smsDeliveryFailureMessage: ({login}: OurEmailProviderParams) => `We have temporarily suspended sending SMS to ${login} because we were unable to deliver SMS messages to your phone number. To try again, please click the button:`, - validateFailed: ({time}: UntilTimeParams) => `Reset failed because it hasn’t been 24 hours since our last attempt. Please wait ${time} before trying again.`, - validateSuccess: 'Your number has been cleared successfully and we can send you a new magic code to sign in', }, welcomeSignUpForm: { join: 'Join', diff --git a/src/languages/es.ts b/src/languages/es.ts index a4fa00364a6e..4552532dbc06 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1823,9 +1823,6 @@ const translations = { smsDeliveryFailurePage: { smsDeliveryFailureMessage: ({login}: OurEmailProviderParams) => `Hemos suspendido temporalmente el envío de SMS a ${login} porque no pudimos entregar los mensajes SMS a tu número de teléfono. Para intentarlo de nuevo, por favor haz clic en el botón:`, - validateFailed: ({time}: UntilTimeParams) => - `El restablecimiento falló porque no han pasado 24 horas desde nuestro último intento. Por favor espera ${time} antes de intentarlo nuevamente.`, - validateSuccess: 'Tu número ha sido restablecido exitosamente y podemos enviarte un nuevo código mágico para iniciar sesión', }, welcomeSignUpForm: { join: 'Unirse', diff --git a/src/libs/API/parameters/ResetPhoneNumberFailureParams.ts b/src/libs/API/parameters/ResetPhoneNumberFailureParams.ts new file mode 100644 index 000000000000..dfc4751510a2 --- /dev/null +++ b/src/libs/API/parameters/ResetPhoneNumberFailureParams.ts @@ -0,0 +1,5 @@ +type ResetPhoneNumberFailureParams = { + email: string; +}; + +export default ResetPhoneNumberFailureParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index fb5558fb0350..2d4bb7e97480 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -349,3 +349,4 @@ export type {default as UpdateQuickbooksDesktopCompanyCardExpenseAccountTypePara export type {default as TogglePolicyPerDiemParams} from './TogglePolicyPerDiemParams'; export type {default as OpenPolicyPerDiemRatesPageParams} from './OpenPolicyPerDiemRatesPageParams'; export type {default as TogglePlatformMuteParams} from './TogglePlatformMuteParams'; +export type {default as ResetPhoneNumberFailureParams} from './ResetPhoneNumberFailureParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index b8b4bb749701..c907ae5ecc91 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -438,6 +438,7 @@ const WRITE_COMMANDS = { SELF_TOUR_VIEWED: 'SelfTourViewed', UPDATE_INVOICE_COMPANY_NAME: 'UpdateInvoiceCompanyName', UPDATE_INVOICE_COMPANY_WEBSITE: 'UpdateInvoiceCompanyWebsite', + RESET_PHONE_NUMBER_FAILURE: 'ResetPhoneNumberFailure', } as const; type WriteCommand = ValueOf; @@ -762,6 +763,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.UPDATE_SUBSCRIPTION_ADD_NEW_USERS_AUTOMATICALLY]: Parameters.UpdateSubscriptionAddNewUsersAutomaticallyParams; [WRITE_COMMANDS.UPDATE_SUBSCRIPTION_SIZE]: Parameters.UpdateSubscriptionSizeParams; [WRITE_COMMANDS.REQUEST_TAX_EXEMPTION]: null; + [WRITE_COMMANDS.RESET_PHONE_NUMBER_FAILURE]: Parameters.ResetPhoneNumberFailureParams; [WRITE_COMMANDS.DELETE_MONEY_REQUEST_ON_SEARCH]: Parameters.DeleteMoneyRequestOnSearchParams; [WRITE_COMMANDS.HOLD_MONEY_REQUEST_ON_SEARCH]: Parameters.HoldMoneyRequestOnSearchParams; diff --git a/src/libs/actions/Session/index.ts b/src/libs/actions/Session/index.ts index d75c5064f93a..4c96824c2afd 100644 --- a/src/libs/actions/Session/index.ts +++ b/src/libs/actions/Session/index.ts @@ -16,6 +16,7 @@ import type { RequestAccountValidationLinkParams, RequestNewValidateCodeParams, RequestUnlinkValidationLinkParams, + ResetPhoneNumberFailureParams, SignInUserWithLinkParams, SignUpUserParams, UnlinkLoginParams, @@ -376,6 +377,9 @@ function signInAttemptState(): OnyxData { isLoading: true, message: null, loadingForm: CONST.FORMS.LOGIN_FORM, + hasSMSDeliveryFailure: null, + isResetPhoneNumberFailureSuccess: null, + resetPhoneNumberFailureMessage: null, }, }, ], @@ -1126,6 +1130,15 @@ const canAnonymousUserAccessRoute = (route: string) => { return false; }; +/** + * To reset SMS delivery failure + */ +function resetPhoneNumberFailure(email: string) { + const params: ResetPhoneNumberFailureParams = {email}; + + API.write(WRITE_COMMANDS.RESET_PHONE_NUMBER_FAILURE, params); +} + export { beginSignIn, beginAppleSignIn, @@ -1163,4 +1176,5 @@ export { hasStashedSession, signUpUser, signInAfterTransitionFromOldDot, + resetPhoneNumberFailure, }; diff --git a/src/pages/signin/SMSDeliveryFailurePage.tsx b/src/pages/signin/SMSDeliveryFailurePage.tsx index f068500163f8..57e3fc10608b 100644 --- a/src/pages/signin/SMSDeliveryFailurePage.tsx +++ b/src/pages/signin/SMSDeliveryFailurePage.tsx @@ -1,41 +1,83 @@ import {Str} from 'expensify-common'; import React, {useEffect, useMemo} from 'react'; import {Keyboard, View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; -import type {OnyxEntry} from 'react-native-onyx'; -import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; +import {useOnyx} from 'react-native-onyx'; import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; import Text from '@components/Text'; import useKeyboardState from '@hooks/useKeyboardState'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as Session from '@userActions/Session'; -import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Credentials} from '@src/types/onyx'; +import Button from '@components/Button'; -type SMSDeliveryFailurePageOnyxProps = { - /** The credentials of the logged in person */ - credentials: OnyxEntry; -}; -type SMSDeliveryFailurePageProps = SMSDeliveryFailurePageOnyxProps; -function SMSDeliveryFailurePage({credentials}: SMSDeliveryFailurePageProps) { +function SMSDeliveryFailurePage() { const styles = useThemeStyles(); const {isKeyboardShown} = useKeyboardState(); const {translate} = useLocalize(); + const [credentials] = useOnyx(ONYXKEYS.CREDENTIALS); + const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const login = useMemo(() => { if (!credentials?.login) { return ''; } return Str.isSMSLogin(credentials.login) ? Str.removeSMSDomain(credentials.login) : credentials.login; }, [credentials?.login]); - // This view doesn't have a field for user input, so dismiss the device keyboard if shown + + const isResetPhoneNumberFailureSuccess = account?.isResetPhoneNumberFailureSuccess; + const resetPhoneNumberFailureMessage = account?.resetPhoneNumberFailureMessage; + useEffect(() => { if (!isKeyboardShown) { return; } Keyboard.dismiss(); }, [isKeyboardShown]); + + if(isResetPhoneNumberFailureSuccess){ + return ( + <> + + + {resetPhoneNumberFailureMessage} + + + +