From c8084ffbc9476592e3f7203632e42ba36bed92f6 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Sun, 20 Oct 2024 00:44:43 +0200 Subject: [PATCH 001/278] Hide approve button if report has violations --- src/libs/actions/IOU.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index fb8cd014ec7b..047d081fbacb 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -6988,8 +6988,9 @@ function canApproveIOU(iouReport: OnyxTypes.OnyxInputOrEntry, const reportNameValuePairs = ReportUtils.getReportNameValuePairs(iouReport?.reportID); const isArchivedReport = ReportUtils.isArchivedRoom(iouReport, reportNameValuePairs); const unheldTotalIsZero = iouReport && iouReport.unheldTotal === 0; + const hasViolations = ReportUtils.hasViolations(iouReport?.reportID ?? '-1', allTransactionViolations); - return isCurrentUserManager && !isOpenExpenseReport && !isApproved && !iouSettled && !isArchivedReport && !unheldTotalIsZero; + return isCurrentUserManager && !isOpenExpenseReport && !isApproved && !iouSettled && !isArchivedReport && !unheldTotalIsZero && !hasViolations; } function canIOUBePaid( From f63804fda2685824aee85d1a1f9eba15d0bed65e Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Fri, 25 Oct 2024 19:24:52 +0800 Subject: [PATCH 002/278] 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 003/278] 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 004/278] 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 528d544a0b7f886c5c96269567b971298ed9e22b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= Date: Wed, 30 Oct 2024 16:04:46 -0600 Subject: [PATCH 005/278] Update transaction violations when the money request is paid --- src/libs/actions/IOU.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 7ce9b9dfb272..27bce6a61a7e 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -6956,6 +6956,26 @@ function getPayMoneyRequestParams( }, }); } + + const optimisticTransactionViolations: OnyxUpdate[] = reportTransactions.map(({transactionID}) => { + const violations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`] ?? []; + return { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, + value: null, + }; + }); + optimisticData.push(...optimisticTransactionViolations); + + const failureTransactionViolations: OnyxUpdate[] = reportTransactions.map(({transactionID}) => { + const violations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`] ?? []; + return { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, + value: violations, + }; + }); + failureData.push(...failureTransactionViolations); } let optimisticHoldReportID; From 234327d88fddb3801addf036ce02c52eb3527192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= Date: Wed, 30 Oct 2024 21:45:23 -0600 Subject: [PATCH 006/278] Remove unused value --- src/libs/actions/IOU.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 27bce6a61a7e..1f8464c47748 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -6958,7 +6958,6 @@ function getPayMoneyRequestParams( } const optimisticTransactionViolations: OnyxUpdate[] = reportTransactions.map(({transactionID}) => { - const violations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`] ?? []; return { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, From 3204148992ce2e3927608e2c6359439a17bd313f Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab <59809993+abzokhattab@users.noreply.github.com> Date: Sat, 2 Nov 2024 12:39:52 +0100 Subject: [PATCH 007/278] Disable the pay button if the report has violaitons --- src/libs/actions/IOU.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 047d081fbacb..f0461d03dd26 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -7042,8 +7042,9 @@ function canIOUBePaid( const {reimbursableSpend} = ReportUtils.getMoneyRequestSpendBreakdown(iouReport); const isAutoReimbursable = policy?.reimbursementChoice === CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_YES ? false : ReportUtils.canBeAutoReimbursed(iouReport, policy); const shouldBeApproved = canApproveIOU(iouReport, policy); - + const hasViolations = ReportUtils.hasViolations(iouReport?.reportID ?? '-1', allTransactionViolations); const isPayAtEndExpenseReport = ReportUtils.isPayAtEndExpenseReport(iouReport?.reportID, transactions); + return ( isPayer && !isOpenExpenseReport && @@ -7053,8 +7054,10 @@ function canIOUBePaid( !isChatReportArchived && !isAutoReimbursable && !shouldBeApproved && + !hasViolations && !isPayAtEndExpenseReport ); + } function getIOUReportActionToApproveOrPay(chatReport: OnyxEntry, excludedIOUReportID: string): OnyxEntry { From f760f272cdfd83f421fe929553a84c699d23a40a Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab <59809993+abzokhattab@users.noreply.github.com> Date: Sat, 2 Nov 2024 12:40:51 +0100 Subject: [PATCH 008/278] minor edit --- src/libs/actions/IOU.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index f0461d03dd26..575e14e36fd3 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -7057,7 +7057,6 @@ function canIOUBePaid( !hasViolations && !isPayAtEndExpenseReport ); - } function getIOUReportActionToApproveOrPay(chatReport: OnyxEntry, excludedIOUReportID: string): OnyxEntry { From 38a56502c4168ba86d0ae449b8aa1fe03b7d69fa Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab <59809993+abzokhattab@users.noreply.github.com> Date: Sat, 2 Nov 2024 12:45:12 +0100 Subject: [PATCH 009/278] minor edit --- src/libs/actions/IOU.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 575e14e36fd3..3a0ca373d3de 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -7043,6 +7043,7 @@ function canIOUBePaid( const isAutoReimbursable = policy?.reimbursementChoice === CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_YES ? false : ReportUtils.canBeAutoReimbursed(iouReport, policy); const shouldBeApproved = canApproveIOU(iouReport, policy); const hasViolations = ReportUtils.hasViolations(iouReport?.reportID ?? '-1', allTransactionViolations); + const hasViolations = ReportUtils.hasViolations(iouReport?.reportID ?? '-1', allTransactionViolations); const isPayAtEndExpenseReport = ReportUtils.isPayAtEndExpenseReport(iouReport?.reportID, transactions); return ( From 7af0e6a9cebac8ae5c2bc1c53ffd5b4833dc9193 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab <59809993+abzokhattab@users.noreply.github.com> Date: Sat, 2 Nov 2024 12:46:17 +0100 Subject: [PATCH 010/278] minor edit --- src/libs/actions/IOU.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 3a0ca373d3de..575e14e36fd3 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -7043,7 +7043,6 @@ function canIOUBePaid( const isAutoReimbursable = policy?.reimbursementChoice === CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_YES ? false : ReportUtils.canBeAutoReimbursed(iouReport, policy); const shouldBeApproved = canApproveIOU(iouReport, policy); const hasViolations = ReportUtils.hasViolations(iouReport?.reportID ?? '-1', allTransactionViolations); - const hasViolations = ReportUtils.hasViolations(iouReport?.reportID ?? '-1', allTransactionViolations); const isPayAtEndExpenseReport = ReportUtils.isPayAtEndExpenseReport(iouReport?.reportID, transactions); return ( From 6c716bb01bf104c444a4597c4cb140d9b99097bd Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab <59809993+abzokhattab@users.noreply.github.com> Date: Sat, 2 Nov 2024 12:49:51 +0100 Subject: [PATCH 011/278] minor edit --- src/libs/actions/IOU.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 575e14e36fd3..f911f17d0103 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -7044,7 +7044,7 @@ function canIOUBePaid( const shouldBeApproved = canApproveIOU(iouReport, policy); const hasViolations = ReportUtils.hasViolations(iouReport?.reportID ?? '-1', allTransactionViolations); const isPayAtEndExpenseReport = ReportUtils.isPayAtEndExpenseReport(iouReport?.reportID, transactions); - + return ( isPayer && !isOpenExpenseReport && From 7fb8e7585e2627f1b6df5ec52114cd2f5e2bc25e Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Mon, 11 Nov 2024 10:58:57 +0800 Subject: [PATCH 012/278] 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 013/278] 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 014/278] 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} + + + +