diff --git a/src/api/api.ts b/src/api/api.ts index 38c559b..9ba2ec0 100644 --- a/src/api/api.ts +++ b/src/api/api.ts @@ -24,7 +24,7 @@ import { SubscriptionPlans, AppleAuth, AIRequestsV2, - SinglePayment + SinglePayment, } from './resources' const api = { @@ -56,7 +56,6 @@ const api = { getZodiacs: createMethod(Zodiacs.createRequest), AIRequestsV2: createMethod(AIRequestsV2.createRequest), getAIRequestsV2: createMethod(AIRequestsV2.createRequestGet), - getSinglePaymentProducts: createMethod(SinglePayment.createRequestGet), createSinglePayment: createMethod(SinglePayment.createRequestPost), } diff --git a/src/components/StripePage/ApplePayButton/index.tsx b/src/components/StripePage/ApplePayButton/index.tsx index 201ec02..82ba844 100644 --- a/src/components/StripePage/ApplePayButton/index.tsx +++ b/src/components/StripePage/ApplePayButton/index.tsx @@ -15,12 +15,14 @@ interface ApplePayButtonProps { activeSubPlan: ISubscriptionPlan | null; client_secret: string; subscriptionReceiptId?: string; + returnUrl?: string; } function ApplePayButton({ activeSubPlan, client_secret, subscriptionReceiptId, + returnUrl, }: ApplePayButtonProps) { const stripe = useStripe(); const elements = useElements(); @@ -78,7 +80,7 @@ function ApplePayButton({ return e.complete("fail"); } navigate( - `${routes.client.paymentResult()}/${subscriptionReceiptId}/?redirect_status=succeeded` + returnUrl || `${routes.client.paymentResult()}/${subscriptionReceiptId}/?redirect_status=succeeded` ); e.complete("success"); // Show a success message to your customer diff --git a/src/components/pages/TrialPayment/components/PaymentModal/index.tsx b/src/components/pages/TrialPayment/components/PaymentModal/index.tsx index 1473ca0..43f70ef 100644 --- a/src/components/pages/TrialPayment/components/PaymentModal/index.tsx +++ b/src/components/pages/TrialPayment/components/PaymentModal/index.tsx @@ -22,12 +22,11 @@ import PayPalButton from "./components/PayPalButton"; interface IPaymentModalProps { activeSubscriptionPlan?: ISubscriptionPlan; - stripePublicKey?: string; - singlePayClientSecret?: string; - defaultPaymentMethod?: EPaymentMethod; + noTrial?: boolean; + returnUrl?: string; } -function PaymentModal({ activeSubscriptionPlan }: IPaymentModalProps) { +function PaymentModal({ activeSubscriptionPlan, noTrial, returnUrl }: IPaymentModalProps) { const { i18n } = useTranslation(); const locale = i18n.language; const api = useApi(); @@ -60,6 +59,9 @@ function PaymentModal({ activeSubscriptionPlan }: IPaymentModalProps) { useEffect(() => { (async () => { const siteConfig = await api.getAppConfig({ bundleId: "auraweb" }); + // const isProduction = import.meta.env.MODE === "production"; + // const stripePublicKey = isProduction ? siteConfig.data.stripe_public_key : "pk_test_51Ndqf4IlX4lgwUxrlLWqfYWpo0Ic0BV7DfiZxfMYy838IZP8NLrwwZ5i0HhhbOQBGoQZe4Rrel1ziEk8mhQ2TE3500ETWZPBva"; + // setStripePromise(loadStripe(stripePublicKey)); setStripePromise(loadStripe(siteConfig.data.stripe_public_key)); const { sub_plans } = await api.getSubscriptionPlans({ locale }); setSubPlans(sub_plans); @@ -173,22 +175,27 @@ function PaymentModal({ activeSubscriptionPlan }: IPaymentModalProps) { /> {activeSubPlan && (
-

- You will be charged only{" "} - - ${getPriceFromTrial(activeSubPlan?.trial)} for your 3-day trial. - -

-

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

+ {!noTrial && ( + <> +

+ You will be charged only{" "} + + ${getPriceFromTrial(activeSubPlan?.trial)} 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.

)}
- {stripePromise && clientSecret && subscriptionReceiptId && ( + {stripePromise && clientSecret && ( {selectedPaymentMethod === EPaymentMethod.PAYPAL_OR_APPLE_PAY && (
@@ -202,13 +209,14 @@ function PaymentModal({ activeSubscriptionPlan }: IPaymentModalProps) { activeSubPlan={activeSubPlan} client_secret={clientSecret} subscriptionReceiptId={subscriptionReceiptId} + returnUrl={window.location.href} /> {!!errors.length &&

{errors}

}
)} {selectedPaymentMethod === EPaymentMethod.CREDIT_CARD && ( - + )}
)} diff --git a/src/components/palmistry/discount-screen/discount-screen.css b/src/components/palmistry/discount-screen/discount-screen.css index e120a92..ffbf7c2 100644 --- a/src/components/palmistry/discount-screen/discount-screen.css +++ b/src/components/palmistry/discount-screen/discount-screen.css @@ -58,6 +58,11 @@ border: 2px solid #c7c7c7; } +.discount-screen__block:first-child .discount-screen__button { + background: #c7c7c7; + color: #000; +} + .discount-screen__block:last-child { padding-top: 0; border: 2px solid #066fde; @@ -111,3 +116,47 @@ width: calc(100% + 32px); justify-content: center; } + +.discount-screen__widget { + background: #fff; + bottom: 0; + box-shadow: 0 -2px 16px rgba(18, 22, 32, .1); + max-width: 428px; + width: 100%; + padding: 40px; + position: relative; +} + +.discount-screen__widget_success { + height: 400px; +} + +.discount-screen__success { + width: 100%; + height: 100%; + position: absolute; + left: 0; + top: 0; + background: #fff; + z-index: 99; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 30px; + padding: 40px; +} + +.discount-screen__success-icon { + width: 100px; + height: 100px; + max-width: 50%; + flex-shrink: 0; +} + +.discount-screen__success-text { + font-size: 24px; + line-height: 32px; + text-align: center; + color: #121620; +} diff --git a/src/components/palmistry/discount-screen/discount-screen.tsx b/src/components/palmistry/discount-screen/discount-screen.tsx index 19e2115..5906974 100644 --- a/src/components/palmistry/discount-screen/discount-screen.tsx +++ b/src/components/palmistry/discount-screen/discount-screen.tsx @@ -1,26 +1,98 @@ import React from "react"; import { useNavigate } from 'react-router-dom'; +import { useTranslation } from "react-i18next"; +import { Elements } from "@stripe/react-stripe-js"; +import { Stripe, loadStripe } from "@stripe/stripe-js"; import './discount-screen.css'; import routes from '@/routes'; +import { useApi } from "@/api"; +import { useAuth } from "@/auth"; import HeaderLogo from '@/components/palmistry/header-logo/header-logo'; +import CheckoutForm from "@/components/PaymentPage/methods/Stripe/CheckoutForm"; + +const currentProductId = "prod_PkXPacpzM8jSmE"; export default function DiscountScreen() { const navigate = useNavigate(); + const api = useApi(); + const { token, user } = useAuth(); + const { i18n } = useTranslation(); + const locale = i18n.language; - const userHasWeeklySubscription = false; + const [price, setPrice] = React.useState(''); + const [isSuccess] = React.useState(false); + const [stripePromise, setStripePromise] = React.useState | null>(null); + const [productId, setProductId] = React.useState(''); + const [clientSecret, setClientSecret] = React.useState(null); + const [stripePublicKey, setStripePublicKey] = React.useState(""); const goPremiumBundle = () => { navigate(routes.client.palmistryPremiumBundle()); }; React.useEffect(() => { - if (userHasWeeklySubscription) { + (async () => { + const { sub_plans } = await api.getSubscriptionPlans({ locale }); + const plan = sub_plans.find((plan) => plan.id === "stripe.40"); + + if (!plan?.price_cents) return; + + setPrice((plan?.price_cents / 100).toFixed(2)); + })(); + }, []); + + React.useEffect(() => { + (async () => { + const products = await api.getSinglePaymentProducts({ token }); + + const product = products.find((product) => product.productId === currentProductId); + + if (product) { + setProductId(product.productId); + } + })(); + }, []); + + React.useEffect(() => { + if (!stripePublicKey) return; + + setStripePromise(loadStripe(stripePublicKey)); + }, [stripePublicKey]); + + const buy = async () => { + if (!user?.id) return; + + const response = await api.createSinglePayment({ + token: token, + data: { + user: { + id: user.id, + email: user.email, + name: user.username || "", + sign: user.profile?.sign?.sign || "", + age: user.profile.age?.years || 0, + }, + partner: { + sign: "", + age: 0, + }, + paymentInfo: { + productId, + }, + return_url: `${window.location.host}/palmistry/premium-bundle`, + }, + }); + + if ('paymentIntent' in response && response.paymentIntent.status === "paid" || 'payment' in response && response.payment.status === "paid") { goPremiumBundle(); + } else if ('paymentIntent' in response) { + setClientSecret(response.paymentIntent.data.client_secret); + setStripePublicKey(response.paymentIntent.data.public_key); } - }, [userHasWeeklySubscription]); + }; return (
@@ -55,7 +127,7 @@ export default function DiscountScreen() {
save 33%
- €12.73 for
1-week plan
+ €{price} for
1-week plan
Total savings @@ -67,12 +139,39 @@ export default function DiscountScreen() { no
-
+ + {stripePromise && clientSecret && ( +
+ + + + + {isSuccess && ( +
+ + + + +
Payment success
+
+ )} +
+ )} ); } diff --git a/src/components/palmistry/payment-screen/payment-screen.tsx b/src/components/palmistry/payment-screen/payment-screen.tsx index d4912a4..2895207 100644 --- a/src/components/palmistry/payment-screen/payment-screen.tsx +++ b/src/components/palmistry/payment-screen/payment-screen.tsx @@ -1,11 +1,9 @@ import React from "react"; import { useSelector } from "react-redux"; -import { useNavigate } from 'react-router-dom'; import './payment-screen.css'; -import routes from '@/routes'; import useSteps, { Step } from '@/hooks/palmistry/use-steps'; import useTimer from '@/hooks/palmistry/use-timer'; import HeaderLogo from '@/components/palmistry/header-logo/header-logo'; @@ -17,18 +15,16 @@ const getFormattedPrice = (price: number) => { } export default function PaymentScreen() { - const navigate = useNavigate(); const time = useTimer(); const activeSubPlanFromStore = useSelector(selectors.selectActiveSubPlan); - // const subscriptionStatus = useSelector(selectors.selectStatus); - const subscriptionStatus = "subscribed"; + const subscriptionStatus = useSelector(selectors.selectStatus); const steps = useSteps(); React.useEffect(() => { if (subscriptionStatus === "subscribed") { setTimeout(() => { - navigate(routes.client.palmistryDiscount()); + steps.goNext(); }, 1500); } }, [subscriptionStatus]); @@ -242,7 +238,7 @@ export default function PaymentScreen() { {activeSubPlanFromStore && (
- {subscriptionStatus !== "subscribed" && } + {subscriptionStatus !== "subscribed" && } {subscriptionStatus === "subscribed" && (
diff --git a/src/components/palmistry/premium-bundle-screen/premium-bundle-screen.css b/src/components/palmistry/premium-bundle-screen/premium-bundle-screen.css index b015746..bbee099 100644 --- a/src/components/palmistry/premium-bundle-screen/premium-bundle-screen.css +++ b/src/components/palmistry/premium-bundle-screen/premium-bundle-screen.css @@ -137,3 +137,47 @@ fill: #fff; margin-right: 8px; } + +.premium-bundle-screen__widget { + background: #fff; + bottom: 0; + box-shadow: 0 -2px 16px rgba(18, 22, 32, .1); + max-width: 428px; + width: 100%; + padding: 40px; + position: relative; +} + +.premium-bundle-screen__widget_success { + height: 400px; +} + +.premium-bundle-screen__success { + width: 100%; + height: 100%; + position: absolute; + left: 0; + top: 0; + background: #fff; + z-index: 99; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 30px; + padding: 40px; +} + +.premium-bundle-screen__success-icon { + width: 100px; + height: 100px; + max-width: 50%; + flex-shrink: 0; +} + +.premium-bundle-screen__success-text { + font-size: 24px; + line-height: 32px; + text-align: center; + color: #121620; +} diff --git a/src/components/palmistry/premium-bundle-screen/premium-bundle-screen.tsx b/src/components/palmistry/premium-bundle-screen/premium-bundle-screen.tsx index bed1891..b2e85c6 100644 --- a/src/components/palmistry/premium-bundle-screen/premium-bundle-screen.tsx +++ b/src/components/palmistry/premium-bundle-screen/premium-bundle-screen.tsx @@ -1,22 +1,79 @@ import React from "react"; import { useNavigate } from 'react-router-dom'; +import { Elements } from "@stripe/react-stripe-js"; +import { Stripe, loadStripe } from "@stripe/stripe-js"; import './premium-bundle-screen.css'; import routes from '@/routes'; import HeaderLogo from '@/components/palmistry/header-logo/header-logo'; +import { useApi } from '@/api'; +import { useAuth } from "@/auth"; +import CheckoutForm from "@/components/PaymentPage/methods/Stripe/CheckoutForm"; + +const currentProductId = "prod_PkXPacpzM8jSmE"; export default function PremiumBundleScreen() { const navigate = useNavigate(); + const { token, user } = useAuth(); + const api = useApi(); - const userHasPremiumBundle = false; + const [stripePromise, setStripePromise] = React.useState | null>(null); + const [productId, setProductId] = React.useState(''); + const [isSuccess] = React.useState(false); + const [clientSecret, setClientSecret] = React.useState(null); + const [stripePublicKey, setStripePublicKey] = React.useState(""); React.useEffect(() => { - if (userHasPremiumBundle) { - navigate(routes.client.home()); + (async () => { + const products = await api.getSinglePaymentProducts({ token }); + + const product = products.find((product) => product.productId === currentProductId); + + if (product) { + setProductId(product.productId); + } + })(); + }, []); + + React.useEffect(() => { + if (!stripePublicKey) return; + + setStripePromise(loadStripe(stripePublicKey)); + }, [stripePublicKey]); + + const buy = async () => { + if (!user?.id) return; + + const response = await api.createSinglePayment({ + token: token, + data: { + user: { + id: user.id, + email: user.email, + name: user.username || "", + sign: user.profile?.sign?.sign || "", + age: user.profile.age?.years || 0, + }, + partner: { + sign: "", + age: 0, + }, + paymentInfo: { + productId, + }, + return_url: `${window.location.host}/palmistry/premium-bundle`, + }, + }); + + if ('paymentIntent' in response && response.paymentIntent.status === "paid" || 'payment' in response && response.payment.status === "paid") { + goHome(); + } else if ('paymentIntent' in response) { + setClientSecret(response.paymentIntent.data.client_secret); + setStripePublicKey(response.paymentIntent.data.public_key); } - }, [userHasPremiumBundle]); + }; const goHome = () => { navigate(routes.client.home()); @@ -134,7 +191,10 @@ export default function PremiumBundleScreen() {
-