From d078648c2b527e3d1894a38d3104856a7304442f Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Mon, 24 Jun 2024 21:45:02 +0200 Subject: [PATCH 01/10] add gbp auth stripe --- ios/Podfile.lock | 72 +++++++++-------- src/CONST.ts | 3 + src/ONYXKEYS.ts | 8 ++ src/languages/en.ts | 1 + src/languages/es.ts | 1 + src/libs/API/types.ts | 4 + src/libs/actions/PaymentMethods.ts | 71 ++++++++++++++++- .../CardAuthenticationModal/index.native.tsx | 79 +++++++++++++++++++ .../CardAuthenticationModal/index.tsx | 77 ++++++++++++++++++ .../CardAuthenticationModal/types.ts | 7 ++ .../PaymentCard/AddPaymentCard.tsx | 4 +- src/types/onyx/PrivateStripeCustomer.ts | 11 +++ src/types/onyx/index.ts | 2 + 13 files changed, 305 insertions(+), 35 deletions(-) create mode 100644 src/pages/settings/Subscription/CardAuthenticationModal/index.native.tsx create mode 100644 src/pages/settings/Subscription/CardAuthenticationModal/index.tsx create mode 100644 src/pages/settings/Subscription/CardAuthenticationModal/types.ts create mode 100644 src/types/onyx/PrivateStripeCustomer.ts diff --git a/ios/Podfile.lock b/ios/Podfile.lock index ddab159714fc..79dc84fa1ad5 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1243,7 +1243,13 @@ PODS: - react-native-config (1.5.0): - react-native-config/App (= 1.5.0) - react-native-config/App (1.5.0): - - React-Core + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React + - React-Codegen + - React-RCTFabric + - ReactCommon/turbomodule/core - react-native-document-picker (9.1.1): - RCT-Folly - RCTRequired @@ -2502,7 +2508,7 @@ SPEC CHECKSUMS: FirebaseRemoteConfig: 2d6e2cfdb49af79535c8af8a80a4a5009038ec2b fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 FullStory: c95f74445f871bc344cdc4a4e4ece61b5554e55d - fullstory_react-native: 6cba8a2c054374a24a44dc4310407d9435459cae + fullstory_react-native: a56e2bb52753b69f01aab3ae876087db08488034 glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2 GoogleAppMeasurement: 5ba1164e3c844ba84272555e916d0a6d3d977e91 GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a @@ -2517,14 +2523,14 @@ SPEC CHECKSUMS: libvmaf: 27f523f1e63c694d14d534cd0fddd2fab0ae8711 libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009 lottie-ios: 3d98679b41fa6fd6aff2352b3953dbd3df8a397e - lottie-react-native: d0e530160e1a0116ab567343d843033c496d0d97 + lottie-react-native: 80bda323805fa62005afff0583d2927a89108f20 MapboxCommon: 768660d6fca8193529ecf82eb6f5f9ae7a5acdf9 MapboxCoreMaps: be412ff97b16aa7820922c818115a9a0d8211caa MapboxMaps: 87ef0003e6db46e45e7a16939f29ae87e38e7ce2 MapboxMobileEvents: de50b3a4de180dd129c326e09cd12c8adaaa46d6 nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 Onfido: 342cbecd7a4383e98dfe7f9c35e98aaece599062 - onfido-react-native-sdk: 3e3b0dd70afa97410fb318d54c6a415137968ef2 + onfido-react-native-sdk: 81e930e77236a0fc3da90e6a6eb834734d8ec2f5 Plaid: 7829e84db6d766a751c91a402702946d2977ddcb PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 RCT-Folly: 7169b2b1c44399c76a47b5deaaba715eeeb476c0 @@ -2549,27 +2555,27 @@ SPEC CHECKSUMS: React-jsitracing: e8a2dafb9878dbcad02b6b2b88e66267fb427b74 React-logger: 0a57b68dd2aec7ff738195f081f0520724b35dab React-Mapbuffer: 63913773ed7f96b814a2521e13e6d010282096ad - react-native-airship: 38e2596999242b68c933959d6145512e77937ac0 - react-native-blob-util: 1ddace5234c62e3e6e4e154d305ad07ef686599b - react-native-cameraroll: f373bebbe9f6b7c3fd2a6f97c5171cda574cf957 - react-native-config: 5330c8258265c1e5fdb8c009d2cabd6badd96727 + react-native-airship: 6ab7a7974d53f92b0c46548fc198f797fdbf371f + react-native-blob-util: a3ee23cfdde79c769c138d505670055de233b07a + react-native-cameraroll: 95ce0d1a7d2d1fe55bf627ab806b64de6c3e69e9 + react-native-config: 5ce986133b07fc258828b20b9506de0e683efc1c react-native-document-picker: 8532b8af7c2c930f9e202aac484ac785b0f4f809 - react-native-geolocation: f9e92eb774cb30ac1e099f34b3a94f03b4db7eb3 + react-native-geolocation: c1c21a8cda4abae6724a322458f64ac6889b8c2b react-native-image-picker: f8a13ff106bcc7eb00c71ce11fdc36aac2a44440 - react-native-key-command: 28ccfa09520e7d7e30739480dea4df003493bfe8 - react-native-keyboard-controller: 47c01b0741ae5fc84e53cf282e61cfa5c2edb19b + react-native-key-command: 74d18ad516037536c2f671ef0914bcce7739b2f5 + react-native-keyboard-controller: 6ce6dfa453730477605e889195e91eb170d5b626 react-native-launch-arguments: 5f41e0abf88a15e3c5309b8875d6fd5ac43df49d - react-native-netinfo: 02d31de0e08ab043d48f2a1a8baade109d7b6ca5 - react-native-pager-view: ccd4bbf9fc7effaf8f91f8dae43389844d9ef9fa - react-native-pdf: 762369633665ec02ac227aefe2f4558b92475c23 - react-native-performance: fb21ff0c9bd7a10789c69d948f25b0067d29f7a9 - react-native-plaid-link-sdk: 2a91ef7e257ae16d180a1ca14ba3041ae0836fbf - react-native-quick-sqlite: e3ab3e0a29d8c705f47a60aaa6ceaa42eb6a9ec1 - react-native-release-profiler: 14ccdc0eeb03bedf625cf68d53d80275a81b19dd + react-native-netinfo: 6479e7e2198f936e5abc14a3ec4d469ccbaf81e2 + react-native-pager-view: 9ac6bc0fb3fa31c6d403b253ee361e62ff7ccf7f + react-native-pdf: cd256a00b9d65cb1008dcca2792d7bfb8874838d + react-native-performance: 1aa5960d005159f4ab20be15b44714b53b44e075 + react-native-plaid-link-sdk: 93870f8cd1de8e0acca5cb5020188bdc94e15db6 + react-native-quick-sqlite: f7b9f578b8b3b608dc742240b0103faae5b61f63 + react-native-release-profiler: 42fc8e09b4f6f9b7d14cc5a15c72165e871c0918 react-native-render-html: 96c979fe7452a0a41559685d2f83b12b93edac8c - react-native-safe-area-context: 9d79895b60b8be151fdf6faef9d2d0591eeecc63 + react-native-safe-area-context: e8bdd57d9f8d34cc336f0ee6acb30712a8454446 react-native-view-shot: 6b7ed61d77d88580fed10954d45fad0eb2d47688 - react-native-webview: f8ab7a37905b2366a3e849ce5992b9724f6a528d + react-native-webview: a5f5f316527235f869992aaaf05050776198806d React-nativeconfig: d7af5bae6da70fa15ce44f045621cf99ed24087c React-NativeModulesApple: 0123905d5699853ac68519607555a9a4f5c7b3ac React-perflogger: 8a1e1af5733004bdd91258dcefbde21e0d1faccd @@ -2594,36 +2600,36 @@ SPEC CHECKSUMS: React-utils: 6e5ad394416482ae21831050928ae27348f83487 ReactCommon: 840a955d37b7f3358554d819446bffcf624b2522 RNAppleAuthentication: 0571c08da8c327ae2afc0261b48b4a515b0286a6 - RNCClipboard: 081418ae3b391b1012c3f41d045e5e39f1beed71 - RNCPicker: 106d11a1c159ce937009b2bd52db2bdb1577454f - RNDeviceInfo: 449272e9faf2afe94a3fe2896d169e92277fffa8 + RNCClipboard: c73bbc2e9012120161f1012578418827983bfd0c + RNCPicker: 68bb37e5d111a562139a87e35e7477c51ad0385a + RNDeviceInfo: cbf78fdb515ae73e641ee7c6b474f77a0299e7e6 RNDevMenu: 72807568fe4188bd4c40ce32675d82434b43c45d RNFBAnalytics: f76bfa164ac235b00505deb9fc1776634056898c RNFBApp: 729c0666395b1953198dc4a1ec6deb8fbe1c302e RNFBCrashlytics: 2061ca863e8e2fa1aae9b12477d7dfa8e88ca0f9 RNFBPerf: 389914cda4000fe0d996a752532a591132cbf3f9 - RNFlashList: 76c2fab003330924ab1a140d13aadf3834dc32e0 + RNFlashList: 5b0e8311e4cf1ad91e410fd7c8526a89fb5826d1 RNFS: 4ac0f0ea233904cb798630b3c077808c06931688 - RNGestureHandler: 74b7b3d06d667ba0bbf41da7718f2607ae0dfe8f + RNGestureHandler: 1190c218cdaaf029ee1437076a3fbbc3297d89fb RNGoogleSignin: ccaa4a81582cf713eea562c5dd9dc1961a715fd0 - RNLiveMarkdown: fff70dc755ed8199a449f61e76cbadec7cd20440 + RNLiveMarkdown: ec2d17221a5dda20b22fa70387443391c988c47b RNLocalize: d4b8af4e442d4bcca54e68fc687a2129b4d71a81 - rnmapbox-maps: df8fe93dbd251f25022f4023d31bc04160d4d65c - RNPermissions: 0b61d30d21acbeafe25baaa47d9bae40a0c65216 + rnmapbox-maps: 4640ca0850000159d9836aee83104b0c9a8c3bd1 + RNPermissions: 8990fc2c10da3640938e6db1647cb6416095b729 RNReactNativeHapticFeedback: 616c35bdec7d20d4c524a7949ca9829c09e35f37 - RNReanimated: 323436b1a5364dca3b5f8b1a13458455e0de9efe - RNScreens: 9ec969a95987a6caae170ef09313138abf3331e1 + RNReanimated: ce10cbc017bdab3079eb6d5b493a3a7256093cdf + RNScreens: 65a936f4e227b91e4a8e2a7d4c4607355bfefda0 RNShare: 2a4cdfc0626ad56b0ef583d424f2038f772afe58 RNSound: 6c156f925295bdc83e8e422e7d8b38d33bc71852 - RNSVG: 18f1381e046be2f1c30b4724db8d0c966238089f + RNSVG: db32cfcad0a221fd175e0882eff7bcba7690380a SDWebImage: 750adf017a315a280c60fde706ab1e552a3ae4e9 SDWebImageAVIFCoder: 8348fef6d0ec69e129c66c9fe4d74fbfbf366112 SDWebImageSVGCoder: 15a300a97ec1c8ac958f009c02220ac0402e936c SDWebImageWebPCoder: af09429398d99d524cae2fe00f6f0f6e491ed102 SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Turf: 13d1a92d969ca0311bbc26e8356cca178ce95da2 - VisionCamera: 1394a316c7add37e619c48d7aa40b38b954bf055 - Yoga: 64cd2a583ead952b0315d5135bf39e053ae9be70 + VisionCamera: 3033e0dd5272d46e97bcb406adea4ae0e6907abf + Yoga: 1b901a6d6eeba4e8a2e8f308f708691cdb5db312 PODFILE CHECKSUM: d5e281e5370cb0211a104efd90eb5fa7af936e14 diff --git a/src/CONST.ts b/src/CONST.ts index 71ef5e26f7ae..a1669d48d52d 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3512,6 +3512,9 @@ const CONST = { ENABLED: 'ENABLED', DISABLED: 'DISABLED', }, + STRIPE_GBP_AUTH_STATUSES: { + SUCCEEDED: 'succeeded', + }, TAB: { NEW_CHAT_TAB_ID: 'NewChatTab', NEW_CHAT: 'chat', diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 8a20032b4f91..d858a3e47e8d 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -178,6 +178,9 @@ const ONYXKEYS = { /** ID associated with the payment card added by the user. */ NVP_BILLING_FUND_ID: 'nvp_expensify_billingFundID', + /** The NVP with stripe information for user. */ + NVP_PRIVATE_STRIPE_CUSTOMER_ID: 'nvp_private_stripeCustomerID', + /** The amount owed by the workspace’s owner. */ NVP_PRIVATE_AMOUNT_OWNED: 'nvp_private_amountOwed', @@ -339,6 +342,9 @@ const ONYXKEYS = { /** Holds the checks used while transferring the ownership of the workspace */ POLICY_OWNERSHIP_CHANGE_CHECKS: 'policyOwnershipChangeChecks', + /** Stores iframe link to verify 3DS flow for subscription */ + VERIFY_3DS_SUBSCRIPTION: 'verify3dsSubscription', + /** Collection Keys */ COLLECTION: { DOWNLOAD: 'download_', @@ -671,6 +677,7 @@ type OnyxValuesMapping = { [ONYXKEYS.NVP_ACTIVE_POLICY_ID]: string; [ONYXKEYS.NVP_DISMISSED_REFERRAL_BANNERS]: OnyxTypes.DismissedReferralBanners; [ONYXKEYS.NVP_HAS_SEEN_TRACK_TRAINING]: boolean; + [ONYXKEYS.NVP_PRIVATE_STRIPE_CUSTOMER_ID]: OnyxTypes.PrivateStripeCustomer; [ONYXKEYS.NVP_PRIVATE_SUBSCRIPTION]: OnyxTypes.PrivateSubscription; [ONYXKEYS.USER_WALLET]: OnyxTypes.UserWallet; [ONYXKEYS.WALLET_ONFIDO]: OnyxTypes.WalletOnfido; @@ -710,6 +717,7 @@ type OnyxValuesMapping = { [ONYXKEYS.ONBOARDING_ADMINS_CHAT_REPORT_ID]: string; [ONYXKEYS.IS_SEARCHING_FOR_REPORTS]: boolean; [ONYXKEYS.LAST_VISITED_PATH]: string | undefined; + [ONYXKEYS.VERIFY_3DS_SUBSCRIPTION]: string; [ONYXKEYS.RECENTLY_USED_REPORT_FIELDS]: OnyxTypes.RecentlyUsedReportFields; [ONYXKEYS.UPDATE_REQUIRED]: boolean; [ONYXKEYS.RESET_REQUIRED]: boolean; diff --git a/src/languages/en.ts b/src/languages/en.ts index 6a9a6e7ccab9..42e7c7401a6b 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -3215,6 +3215,7 @@ export default { mergedWithCashTransaction: 'matched a receipt to this transaction.', }, subscription: { + authenticatePaymentCard: 'Authenticate payment card', mobileReducedFunctionalityMessage: 'You can’t make changes to your subscription in the mobile app.', billingBanner: { preTrial: { diff --git a/src/languages/es.ts b/src/languages/es.ts index f007c1211190..c34d7898fb97 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -3719,6 +3719,7 @@ export default { mergedWithCashTransaction: 'encontró un recibo para esta transacción.', }, subscription: { + authenticatePaymentCard: 'Autenticar tarjeta de pago', mobileReducedFunctionalityMessage: 'No puedes hacer cambios en tu suscripción en la aplicación móvil.', billingBanner: { preTrial: { diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 8f093ee827c3..a309a7e5622e 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -35,6 +35,7 @@ const WRITE_COMMANDS = { CHRONOS_REMOVE_OOO_EVENT: 'Chronos_RemoveOOOEvent', MAKE_DEFAULT_PAYMENT_METHOD: 'MakeDefaultPaymentMethod', ADD_PAYMENT_CARD: 'AddPaymentCard', + ADD_PAYMENT_CARD_GBP: 'AddPaymentCardGBP', TRANSFER_WALLET_BALANCE: 'TransferWalletBalance', DELETE_PAYMENT_CARD: 'DeletePaymentCard', UPDATE_PRONOUNS: 'UpdatePronouns', @@ -252,6 +253,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.ACTIVATE_PHYSICAL_EXPENSIFY_CARD]: Parameters.ActivatePhysicalExpensifyCardParams; [WRITE_COMMANDS.MAKE_DEFAULT_PAYMENT_METHOD]: Parameters.MakeDefaultPaymentMethodParams; [WRITE_COMMANDS.ADD_PAYMENT_CARD]: Parameters.AddPaymentCardParams; + [WRITE_COMMANDS.ADD_PAYMENT_CARD_GBP]: Parameters.AddPaymentCardParams; [WRITE_COMMANDS.DELETE_PAYMENT_CARD]: Parameters.DeletePaymentCardParams; [WRITE_COMMANDS.UPDATE_PRONOUNS]: Parameters.UpdatePronounsParams; [WRITE_COMMANDS.UPDATE_DISPLAY_NAME]: Parameters.UpdateDisplayNameParams; @@ -560,6 +562,7 @@ const SIDE_EFFECT_REQUEST_COMMANDS = { JOIN_POLICY_VIA_INVITE_LINK: 'JoinWorkspaceViaInviteLink', RECONNECT_APP: 'ReconnectApp', GENERATE_SPOTNANA_TOKEN: 'GenerateSpotnanaToken', + ADD_PAYMENT_CARD_GBP: 'AddPaymentCardGBP', } as const; type SideEffectRequestCommand = ValueOf; @@ -573,6 +576,7 @@ type SideEffectRequestCommandParameters = { [SIDE_EFFECT_REQUEST_COMMANDS.JOIN_POLICY_VIA_INVITE_LINK]: Parameters.JoinPolicyInviteLinkParams; [SIDE_EFFECT_REQUEST_COMMANDS.RECONNECT_APP]: Parameters.ReconnectAppParams; [SIDE_EFFECT_REQUEST_COMMANDS.GENERATE_SPOTNANA_TOKEN]: Parameters.GenerateSpotnanaTokenParams; + [SIDE_EFFECT_REQUEST_COMMANDS.ADD_PAYMENT_CARD_GBP]: Parameters.AddPaymentCardParams; }; type ApiRequestCommandParameters = WriteCommandParameters & ReadCommandParameters & SideEffectRequestCommandParameters; diff --git a/src/libs/actions/PaymentMethods.ts b/src/libs/actions/PaymentMethods.ts index c12f7a042659..c4dd9dbcc726 100644 --- a/src/libs/actions/PaymentMethods.ts +++ b/src/libs/actions/PaymentMethods.ts @@ -6,7 +6,7 @@ import Onyx from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import * as API from '@libs/API'; import type {AddPaymentCardParams, DeletePaymentCardParams, MakeDefaultPaymentMethodParams, PaymentCardParams, TransferWalletBalanceParams} from '@libs/API/parameters'; -import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; +import {READ_COMMANDS, SIDE_EFFECT_REQUEST_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; import * as CardUtils from '@libs/CardUtils'; import Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; @@ -257,6 +257,73 @@ function addSubscriptionPaymentCard(cardData: { }); } +/** + * Calls the API to add a new card for GBP currency with 3ds. + * + */ +function addPaymentCardGBP(cardData: { + cardNumber: string; + cardYear: string; + cardMonth: string; + cardCVV: string; + addressName: string; + addressZip: string; + currency: ValueOf; +}) { + const {cardNumber, cardYear, cardMonth, cardCVV, addressName, addressZip, currency} = cardData; + + const parameters: AddPaymentCardParams = { + cardNumber, + cardYear, + cardMonth, + cardCVV, + addressName, + addressZip, + currency, + isP2PDebitCard: false, + }; + + const optimisticData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.FORMS.ADD_DEBIT_CARD_FORM, + value: {isLoading: true}, + }, + ]; + + const successData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.FORMS.ADD_DEBIT_CARD_FORM, + value: {isLoading: false}, + }, + ]; + + const failureData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.FORMS.ADD_DEBIT_CARD_FORM, + value: {isLoading: false}, + }, + ]; + + // eslint-disable-next-line rulesdir/no-api-side-effects-method + API.makeRequestWithSideEffects(SIDE_EFFECT_REQUEST_COMMANDS.ADD_PAYMENT_CARD_GBP, parameters, {optimisticData, successData, failureData}).then((response) => { + if (response?.jsonCode !== CONST.JSON_CODE.SUCCESS) { + return; + } + Onyx.set(ONYXKEYS.VERIFY_3DS_SUBSCRIPTION, (response as {authenticationLink: string}).authenticationLink); + }); +} + +/** + * Clear 3ds flow - when verification will be finished + * + */ +function clearPaymentCard3dsVerification() { + Onyx.set(ONYXKEYS.VERIFY_3DS_SUBSCRIPTION, ''); +} + /** * Resets the values for the add debit card form back to their initial states */ @@ -433,6 +500,7 @@ export { kycWallRef, continueSetup, addSubscriptionPaymentCard, + addPaymentCardGBP, clearDebitCardFormErrorAndSubmit, dismissSuccessfulTransferBalancePage, transferWalletBalance, @@ -444,4 +512,5 @@ export { clearAddPaymentMethodError, clearWalletError, clearWalletTermsError, + clearPaymentCard3dsVerification, }; diff --git a/src/pages/settings/Subscription/CardAuthenticationModal/index.native.tsx b/src/pages/settings/Subscription/CardAuthenticationModal/index.native.tsx new file mode 100644 index 000000000000..abf22b1539e9 --- /dev/null +++ b/src/pages/settings/Subscription/CardAuthenticationModal/index.native.tsx @@ -0,0 +1,79 @@ +import React, {useEffect, useRef} from 'react'; +import {useOnyx} from 'react-native-onyx'; +import {WebView} from 'react-native-webview'; +import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import Modal from '@components/Modal'; +import ScreenWrapper from '@components/ScreenWrapper'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import * as PaymentMethods from '@userActions/PaymentMethods'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; + +type CardAuthenticationModalProps = { + /** Title shown in the header of the modal */ + headerTitle?: string; +}; +const renderLoading = () => ; + +function CardAuthenticationModal({headerTitle}: CardAuthenticationModalProps) { + const styles = useThemeStyles(); + const webViewRef = useRef(null); + const [authenticationLink = ''] = useOnyx(ONYXKEYS.VERIFY_3DS_SUBSCRIPTION); + const [session] = useOnyx(ONYXKEYS.SESSION); + const [privateStripeCustomerID] = useOnyx(ONYXKEYS.NVP_PRIVATE_STRIPE_CUSTOMER_ID); + const authToken = session?.authToken ?? null; + useEffect(() => { + if (privateStripeCustomerID?.status !== CONST.STRIPE_GBP_AUTH_STATUSES.SUCCEEDED) { + return; + } + PaymentMethods.clearPaymentCard3dsVerification(); + Navigation.navigate(ROUTES.SETTINGS_SUBSCRIPTION); + }, [privateStripeCustomerID]); + + const onModalClose = () => { + PaymentMethods.clearPaymentCard3dsVerification(); + }; + + return ( + + + + + + + ); +} + +CardAuthenticationModal.displayName = 'CardAuthenticationModal'; + +export default CardAuthenticationModal; diff --git a/src/pages/settings/Subscription/CardAuthenticationModal/index.tsx b/src/pages/settings/Subscription/CardAuthenticationModal/index.tsx new file mode 100644 index 000000000000..c2438d2c9dbe --- /dev/null +++ b/src/pages/settings/Subscription/CardAuthenticationModal/index.tsx @@ -0,0 +1,77 @@ +import React, {useEffect, useState} from 'react'; +import {View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; +import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import Modal from '@components/Modal'; +import ScreenWrapper from '@components/ScreenWrapper'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import * as PaymentMethods from '@userActions/PaymentMethods'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; + +type CardAuthenticationModalProps = { + /** Title shown in the header of the modal */ + headerTitle?: string; +}; +function CardAuthenticationModal({headerTitle}: CardAuthenticationModalProps) { + const styles = useThemeStyles(); + const [authenticationLink] = useOnyx(ONYXKEYS.VERIFY_3DS_SUBSCRIPTION); + const [privateStripeCustomerID] = useOnyx(ONYXKEYS.NVP_PRIVATE_STRIPE_CUSTOMER_ID); + const [isLoading, setIsLoading] = useState(true); + useEffect(() => { + if (privateStripeCustomerID?.status !== CONST.STRIPE_GBP_AUTH_STATUSES.SUCCEEDED) { + return; + } + PaymentMethods.clearPaymentCard3dsVerification(); + Navigation.navigate(ROUTES.SETTINGS_SUBSCRIPTION); + }, [privateStripeCustomerID]); + + const onModalClose = () => { + PaymentMethods.clearPaymentCard3dsVerification(); + }; + + return ( + + + + {isLoading && } + +