From d8da6d9de6fd90e033cd2aee39c61192f176927c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B5=D0=BD=D0=B8=D1=81=20=D0=9A=D0=B0=D1=82=D0=B0?= =?UTF-8?q?=D0=B5=D0=B2?= Date: Wed, 12 Jun 2024 23:15:41 +0000 Subject: [PATCH] AW-104-express-checkout --- public/amazon-pay-mark.png | Bin 0 -> 14520 bytes .../methods/ExpressCheckoutStripe/index.tsx | 116 ++++++++++++ .../ExpressCheckoutStripe/styles.module.css | 16 ++ .../components/PaymentModal/index.tsx | 153 +++++++++------- .../components/PaymentModal/styles.module.css | 6 + .../components/PaymentModal/index.tsx | 167 ++++++++++-------- .../components/PaymentModal/styles.module.css | 6 + .../PaymentButtons/index.tsx | 32 ++-- 8 files changed, 345 insertions(+), 151 deletions(-) create mode 100644 public/amazon-pay-mark.png create mode 100644 src/components/PaymentPage/methods/ExpressCheckoutStripe/index.tsx create mode 100644 src/components/PaymentPage/methods/ExpressCheckoutStripe/styles.module.css diff --git a/public/amazon-pay-mark.png b/public/amazon-pay-mark.png new file mode 100644 index 0000000000000000000000000000000000000000..602efb79465d18f99d928b4237336466638e9a97 GIT binary patch literal 14520 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 literal 0 HcmV?d00001 diff --git a/src/components/PaymentPage/methods/ExpressCheckoutStripe/index.tsx b/src/components/PaymentPage/methods/ExpressCheckoutStripe/index.tsx new file mode 100644 index 0000000..ef717bf --- /dev/null +++ b/src/components/PaymentPage/methods/ExpressCheckoutStripe/index.tsx @@ -0,0 +1,116 @@ +import { useMemo, useState } from "react"; +import styles from "./styles.module.css"; + +import { + useStripe, + useElements, + ExpressCheckoutElement, +} from "@stripe/react-stripe-js"; +import { + AvailablePaymentMethods, + StripeExpressCheckoutElementReadyEvent, +} from "@stripe/stripe-js"; + +interface IExpressCheckoutStripeProps { + clientSecret: string; + returnUrl?: string; + isHide?: boolean; + onAvailable?: ( + isAvailable: boolean, + availableMethods: AvailablePaymentMethods | undefined + ) => void; + onChangeLoading?: (isLoading: boolean) => void; +} + +const checkFormAvailable = ( + availablePaymentMethods: undefined | AvailablePaymentMethods +) => { + if (!availablePaymentMethods) return false; + let result = false; + for (const key in availablePaymentMethods) { + if (availablePaymentMethods[key as keyof AvailablePaymentMethods]) { + result = true; + break; + } + } + return result; +}; + +function ExpressCheckoutStripe({ + clientSecret, + returnUrl = "https://${window.location.host}/payment/result/", + isHide = false, + onAvailable, + onChangeLoading, +}: IExpressCheckoutStripeProps) { + const stripe = useStripe(); + const elements = useElements(); + const [errorMessage, setErrorMessage] = useState(); + const [isAvailable, setIsAvailable] = useState(false); + const isHideForm = useMemo( + () => isHide || !isAvailable, + [isAvailable, isHide] + ); + + const onConfirm = async () => + // event: StripeExpressCheckoutElementConfirmEvent + { + if (!stripe || !elements) { + // Stripe.js hasn't loaded yet. + // Make sure to disable form submission until Stripe.js has loaded. + return; + } + + const { error: submitError } = await elements.submit(); + if (submitError) { + setErrorMessage(submitError.message); + return; + } + + // // Create the PaymentIntent and obtain clientSecret + // const res = await fetch("/create-intent", { + // method: "POST", + // }); + // const { client_secret: clientSecret } = await res.json(); + + // Confirm the PaymentIntent using the details collected by the Express Checkout Element + const { error } = await stripe.confirmPayment({ + // `elements` instance used to create the Express Checkout Element + elements, + // `clientSecret` from the created PaymentIntent + clientSecret, + confirmParams: { + return_url: returnUrl, + }, + }); + + if (error) { + // This point is only reached if there's an immediate error when + // confirming the payment. Show the error to your customer (for example, payment details incomplete) + setErrorMessage(error.message); + } else { + // The payment UI automatically closes with a success animation. + // Your customer is redirected to your `return_url`. + } + }; + + const onReady = (event: StripeExpressCheckoutElementReadyEvent) => { + const _isAvailable = checkFormAvailable(event.availablePaymentMethods); + setIsAvailable(_isAvailable); + onAvailable && onAvailable(_isAvailable, event.availablePaymentMethods); + onChangeLoading && onChangeLoading(false); + }; + + return ( +
+ onChangeLoading && onChangeLoading(false)} + onConfirm={onConfirm} + /> + {errorMessage &&

{errorMessage}

} +
+ ); +} + +export default ExpressCheckoutStripe; diff --git a/src/components/PaymentPage/methods/ExpressCheckoutStripe/styles.module.css b/src/components/PaymentPage/methods/ExpressCheckoutStripe/styles.module.css new file mode 100644 index 0000000..68a9185 --- /dev/null +++ b/src/components/PaymentPage/methods/ExpressCheckoutStripe/styles.module.css @@ -0,0 +1,16 @@ +.container { + width: 100%; +} + +.hide { + height: 0; + visibility: hidden; +} + +.error { + width: 100%; + color: #FF5758; + text-align: center; + font-size: 14px; + margin-top: 8px; +} \ No newline at end of file diff --git a/src/components/pages/ABDesign/v1/pages/TrialPayment/components/PaymentModal/index.tsx b/src/components/pages/ABDesign/v1/pages/TrialPayment/components/PaymentModal/index.tsx index 4b4412d..6d65711 100644 --- a/src/components/pages/ABDesign/v1/pages/TrialPayment/components/PaymentModal/index.tsx +++ b/src/components/pages/ABDesign/v1/pages/TrialPayment/components/PaymentModal/index.tsx @@ -5,7 +5,7 @@ import { useEffect, useMemo, useState } from "react"; import { EPaymentMethod, paymentMethods } from "@/data/paymentMethods"; import { Elements } from "@stripe/react-stripe-js"; import CheckoutForm from "@/components/PaymentPage/methods/CheckoutForm"; -import { Stripe, loadStripe } from "@stripe/stripe-js"; +import { AvailablePaymentMethods, Stripe, loadStripe } from "@stripe/stripe-js"; import { useSelector } from "react-redux"; import { selectors } from "@/store"; import { useNavigate } from "react-router-dom"; @@ -15,8 +15,7 @@ import SecurityPayments from "../SecurityPayments"; import { EPlacementKeys, IPaywallProduct } from "@/api/resources/Paywall"; import { usePaywall } from "@/hooks/paywall/usePaywall"; import { useMakePayment } from "@/hooks/payment/useMakePayment"; -import StripeButton from "@/components/PaymentPage/methods/StripeButton"; -import CheckAvailableStripeButton from "@/components/PaymentPage/methods/StripeButton/CheckAvailableStripeButton"; +import ExpressCheckoutStripe from "@/components/PaymentPage/methods/ExpressCheckoutStripe"; interface IPaymentModalProps { activeProduct?: IPaywallProduct; @@ -49,7 +48,7 @@ function PaymentModal({ returnUrl: checkoutUrl, paymentType, publicKey, - isLoading, + isLoading: isLoadingPayment, error, } = useMakePayment({ productId: _activeProduct?._id || "", @@ -58,17 +57,23 @@ function PaymentModal({ returnPaidUrl: returnUrl, }); - const stripeButton = useSelector(selectors.selectStripeButton); + const [availableMethods, setAvailableMethods] = useState< + AvailablePaymentMethods | undefined + >(); - const paymentRequest = stripeButton?.paymentRequest; - const availableMethods = stripeButton?.availableMethods; + const [isLoadingExpressCheckout, setIsLoadingExpressCheckout] = + useState(true); + + const isLoading = useMemo(() => { + return isLoadingPayment || isLoadingExpressCheckout; + }, [isLoadingPayment, isLoadingExpressCheckout]); if (checkoutUrl?.length) { window.location.href = checkoutUrl; } const paymentMethodsButtons = useMemo(() => { - return paymentMethods(availableMethods); + return paymentMethods(availableMethods || null); }, [availableMethods]); const [selectedPaymentMethod, setSelectedPaymentMethod] = useState( @@ -92,15 +97,16 @@ function PaymentModal({ })(); }, [_activeProduct, navigate, products, publicKey]); - if (isLoading) { - return ( -
-
- -
-
- ); - } + const onAvailableExpressCheckout = ( + isAvailable: boolean, + availableMethods: AvailablePaymentMethods | undefined + ) => { + if (isAvailable && availableMethods) { + setAvailableMethods(availableMethods); + return setSelectedPaymentMethod(EPaymentMethod.PAYMENT_BUTTONS); + } + return setAvailableMethods(undefined); + }; if (error?.length) { return ( @@ -113,62 +119,75 @@ function PaymentModal({ } return ( -
- - Choose payment method - - - {_activeProduct && ( -
- {!noTrial && ( - <> -

- You will be charged only{" "} - ${getPrice(_activeProduct)} for your 3-day trial. -

-

- We`ll email you a reminder before your trial period ends. -

- - )} - -

- Cancel anytime. The charge will appear on your bill as witapps. -

+ <> + {isLoading && ( +
+
+ +
)} -
- {stripePromise && clientSecret && ( - - - {selectedPaymentMethod === EPaymentMethod.PAYMENT_BUTTONS && ( -
- {paymentRequest && ( - - )} -
+
+ + Choose payment method + + + {_activeProduct && ( +
+ {!noTrial && ( + <> +

+ You will be charged only{" "} + ${getPrice(_activeProduct)} for your 3-day trial. +

+

+ We`ll email you a reminder before your trial period + ends. +

+ )} - {selectedPaymentMethod === EPaymentMethod.CREDIT_CARD && ( - - )} - +

+ Cancel anytime. The charge will appear on your bill as witapps. +

+
)} +
+ {stripePromise && clientSecret && ( + + + onAvailableExpressCheckout(_isAvailable, _availableMethods) + } + onChangeLoading={(isLoading) => + setIsLoadingExpressCheckout(isLoading) + } + /> + {selectedPaymentMethod === EPaymentMethod.CREDIT_CARD && ( + + )} + + )} +
+ +

500 N RAINBOW BLVD LAS VEGAS, NV 89107

- -

500 N RAINBOW BLVD LAS VEGAS, NV 89107

-
+ ); } diff --git a/src/components/pages/ABDesign/v1/pages/TrialPayment/components/PaymentModal/styles.module.css b/src/components/pages/ABDesign/v1/pages/TrialPayment/components/PaymentModal/styles.module.css index db76c7b..113d87d 100644 --- a/src/components/pages/ABDesign/v1/pages/TrialPayment/components/PaymentModal/styles.module.css +++ b/src/components/pages/ABDesign/v1/pages/TrialPayment/components/PaymentModal/styles.module.css @@ -8,6 +8,12 @@ color: #2f2e37; } +.payment-modal.hide { + min-height: 0; + height: 0; + opacity: 0; +} + .title { font-weight: 700; font-size: 20px; diff --git a/src/components/pages/TrialPayment/components/PaymentModal/index.tsx b/src/components/pages/TrialPayment/components/PaymentModal/index.tsx index 8f11bdd..c178efc 100644 --- a/src/components/pages/TrialPayment/components/PaymentModal/index.tsx +++ b/src/components/pages/TrialPayment/components/PaymentModal/index.tsx @@ -5,7 +5,7 @@ import { useEffect, useMemo, useState } from "react"; import { EPaymentMethod, paymentMethods } from "@/data/paymentMethods"; import { Elements } from "@stripe/react-stripe-js"; import CheckoutForm from "@/components/PaymentPage/methods/CheckoutForm"; -import { Stripe, loadStripe } from "@stripe/stripe-js"; +import { AvailablePaymentMethods, Stripe, loadStripe } from "@stripe/stripe-js"; import { useSelector } from "react-redux"; import { selectors } from "@/store"; import Loader from "@/components/Loader"; @@ -13,8 +13,9 @@ import SecurityPayments from "../SecurityPayments"; import { EPlacementKeys, IPaywallProduct } from "@/api/resources/Paywall"; import { usePaywall } from "@/hooks/paywall/usePaywall"; import { useMakePayment } from "@/hooks/payment/useMakePayment"; -import StripeButton from "@/components/PaymentPage/methods/StripeButton"; -import CheckAvailableStripeButton from "@/components/PaymentPage/methods/StripeButton/CheckAvailableStripeButton"; +import ExpressCheckoutStripe from "@/components/PaymentPage/methods/ExpressCheckoutStripe"; +import routes from "@/routes"; +import { useNavigate } from "react-router-dom"; interface IPaymentModalProps { activeProduct?: IPaywallProduct; @@ -36,6 +37,7 @@ function PaymentModal({ returnUrl, placementKey = EPlacementKeys["aura.placement.main"], }: IPaymentModalProps) { + const navigate = useNavigate(); const [stripePromise, setStripePromise] = useState | null>(null); @@ -51,7 +53,7 @@ function PaymentModal({ returnUrl: checkoutUrl, paymentType, publicKey, - isLoading, + isLoading: isLoadingPayment, error, } = useMakePayment({ productId: _activeProduct?._id || "", @@ -60,20 +62,27 @@ function PaymentModal({ returnPaidUrl: returnUrl, }); - const { paymentRequest, availableMethods } = useSelector( - selectors.selectStripeButton - ); + const [availableMethods, setAvailableMethods] = useState< + AvailablePaymentMethods | undefined + >(); + + const [isLoadingExpressCheckout, setIsLoadingExpressCheckout] = + useState(true); + + const isLoading = useMemo(() => { + return isLoadingPayment || isLoadingExpressCheckout; + }, [isLoadingPayment, isLoadingExpressCheckout]); if (checkoutUrl?.length) { window.location.href = checkoutUrl; } const paymentMethodsButtons = useMemo(() => { - return paymentMethods(availableMethods); + return paymentMethods(availableMethods || null); }, [availableMethods]); const [selectedPaymentMethod, setSelectedPaymentMethod] = useState( - EPaymentMethod.PAYMENT_BUTTONS + paymentMethodsButtons[0].id ); const onSelectPaymentMethod = (method: EPaymentMethod) => { @@ -84,18 +93,25 @@ function PaymentModal({ (async () => { if (!products?.length || !publicKey) return; setStripePromise(loadStripe(publicKey)); + const isActiveProduct = products.find( + (product) => product._id === _activeProduct?._id + ); + if (!_activeProduct || !isActiveProduct) { + navigate(routes.client.trialChoice()); + } })(); - }, [products, publicKey]); + }, [_activeProduct, navigate, products, publicKey]); - if (isLoading) { - return ( -
-
- -
-
- ); - } + const onAvailableExpressCheckout = ( + isAvailable: boolean, + availableMethods: AvailablePaymentMethods | undefined + ) => { + if (isAvailable && availableMethods) { + setAvailableMethods(availableMethods); + return setSelectedPaymentMethod(EPaymentMethod.PAYMENT_BUTTONS); + } + return setAvailableMethods(undefined); + }; if (error?.length) { return ( @@ -108,62 +124,75 @@ function PaymentModal({ } return ( -
- - Choose payment method - - - {_activeProduct && ( -
- {!noTrial && ( - <> -

- You will be charged only{" "} - ${getPrice(_activeProduct)} for your 3-day trial. -

-

- We`ll email you a reminder before your trial period ends. -

- - )} - -

- Cancel anytime. The charge will appear on your bill as witapps. -

+ <> + {isLoading && ( +
+
+ +
)} -
- {stripePromise && clientSecret && ( - - - {selectedPaymentMethod === EPaymentMethod.PAYMENT_BUTTONS && ( -
- {paymentRequest && ( - - )} -
+
+ + Choose payment method + + + {_activeProduct && ( +
+ {!noTrial && ( + <> +

+ You will be charged only{" "} + ${getPrice(_activeProduct)} for your 3-day trial. +

+

+ We`ll email you a reminder before your trial period + ends. +

+ )} - {selectedPaymentMethod === EPaymentMethod.CREDIT_CARD && ( - - )} - +

+ Cancel anytime. The charge will appear on your bill as witapps. +

+
)} +
+ {stripePromise && clientSecret && ( + + + onAvailableExpressCheckout(_isAvailable, _availableMethods) + } + onChangeLoading={(isLoading) => + setIsLoadingExpressCheckout(isLoading) + } + /> + {selectedPaymentMethod === EPaymentMethod.CREDIT_CARD && ( + + )} + + )} +
+ +

500 N RAINBOW BLVD LAS VEGAS, NV 89107

- -

500 N RAINBOW BLVD LAS VEGAS, NV 89107

-
+ ); } diff --git a/src/components/pages/TrialPayment/components/PaymentModal/styles.module.css b/src/components/pages/TrialPayment/components/PaymentModal/styles.module.css index db76c7b..113d87d 100644 --- a/src/components/pages/TrialPayment/components/PaymentModal/styles.module.css +++ b/src/components/pages/TrialPayment/components/PaymentModal/styles.module.css @@ -8,6 +8,12 @@ color: #2f2e37; } +.payment-modal.hide { + min-height: 0; + height: 0; + opacity: 0; +} + .title { font-weight: 700; font-size: 20px; diff --git a/src/components/ui/PaymentMethodsButtons/PaymentButtons/index.tsx b/src/components/ui/PaymentMethodsButtons/PaymentButtons/index.tsx index 1faf69c..b78586b 100644 --- a/src/components/ui/PaymentMethodsButtons/PaymentButtons/index.tsx +++ b/src/components/ui/PaymentMethodsButtons/PaymentButtons/index.tsx @@ -4,26 +4,28 @@ import { TCanMakePaymentResult } from "@/components/PaymentPage/methods/StripeBu interface IPaymentButtonsProps { availableMethods: TCanMakePaymentResult; } +const Image = ({ availableMethods }: IPaymentButtonsProps) => { + if (!availableMethods) return <>; + if (availableMethods["applePay"]) { + return ApplePay; + } + if (availableMethods["googlePay"]) { + return google; + } + if (availableMethods["amazon"]) { + return AmazonPay; + } + if (availableMethods["link"]) { + return LinkPay; + } + return <>; +}; function PaymentButtons({ availableMethods }: IPaymentButtonsProps) { if (!availableMethods) return <>; return (
- {availableMethods["applePay"] && ( - ApplePay - )} - {availableMethods["googlePay"] && ( - google - )} - {availableMethods["link"] && ( - LinkPay - )} +
); }