Payment on palmistry/discount page
This commit is contained in:
parent
d22157cde1
commit
974453cb74
@ -24,7 +24,7 @@ import {
|
|||||||
SubscriptionPlans,
|
SubscriptionPlans,
|
||||||
AppleAuth,
|
AppleAuth,
|
||||||
AIRequestsV2,
|
AIRequestsV2,
|
||||||
SinglePayment
|
SinglePayment,
|
||||||
} from './resources'
|
} from './resources'
|
||||||
|
|
||||||
const api = {
|
const api = {
|
||||||
@ -56,7 +56,6 @@ const api = {
|
|||||||
getZodiacs: createMethod<Zodiacs.Payload, Zodiacs.Response>(Zodiacs.createRequest),
|
getZodiacs: createMethod<Zodiacs.Payload, Zodiacs.Response>(Zodiacs.createRequest),
|
||||||
AIRequestsV2: createMethod<AIRequestsV2.Payload, AIRequestsV2.Response>(AIRequestsV2.createRequest),
|
AIRequestsV2: createMethod<AIRequestsV2.Payload, AIRequestsV2.Response>(AIRequestsV2.createRequest),
|
||||||
getAIRequestsV2: createMethod<AIRequestsV2.PayloadGet, AIRequestsV2.IAiResponseGet>(AIRequestsV2.createRequestGet),
|
getAIRequestsV2: createMethod<AIRequestsV2.PayloadGet, AIRequestsV2.IAiResponseGet>(AIRequestsV2.createRequestGet),
|
||||||
|
|
||||||
getSinglePaymentProducts: createMethod<SinglePayment.PayloadGet, SinglePayment.ResponseGet[]>(SinglePayment.createRequestGet),
|
getSinglePaymentProducts: createMethod<SinglePayment.PayloadGet, SinglePayment.ResponseGet[]>(SinglePayment.createRequestGet),
|
||||||
createSinglePayment: createMethod<SinglePayment.PayloadPost, SinglePayment.ResponsePost | SinglePayment.ResponsePostExistPaymentData>(SinglePayment.createRequestPost),
|
createSinglePayment: createMethod<SinglePayment.PayloadPost, SinglePayment.ResponsePost | SinglePayment.ResponsePostExistPaymentData>(SinglePayment.createRequestPost),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,12 +15,14 @@ interface ApplePayButtonProps {
|
|||||||
activeSubPlan: ISubscriptionPlan | null;
|
activeSubPlan: ISubscriptionPlan | null;
|
||||||
client_secret: string;
|
client_secret: string;
|
||||||
subscriptionReceiptId?: string;
|
subscriptionReceiptId?: string;
|
||||||
|
returnUrl?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ApplePayButton({
|
function ApplePayButton({
|
||||||
activeSubPlan,
|
activeSubPlan,
|
||||||
client_secret,
|
client_secret,
|
||||||
subscriptionReceiptId,
|
subscriptionReceiptId,
|
||||||
|
returnUrl,
|
||||||
}: ApplePayButtonProps) {
|
}: ApplePayButtonProps) {
|
||||||
const stripe = useStripe();
|
const stripe = useStripe();
|
||||||
const elements = useElements();
|
const elements = useElements();
|
||||||
@ -78,7 +80,7 @@ function ApplePayButton({
|
|||||||
return e.complete("fail");
|
return e.complete("fail");
|
||||||
}
|
}
|
||||||
navigate(
|
navigate(
|
||||||
`${routes.client.paymentResult()}/${subscriptionReceiptId}/?redirect_status=succeeded`
|
returnUrl || `${routes.client.paymentResult()}/${subscriptionReceiptId}/?redirect_status=succeeded`
|
||||||
);
|
);
|
||||||
e.complete("success");
|
e.complete("success");
|
||||||
// Show a success message to your customer
|
// Show a success message to your customer
|
||||||
|
|||||||
@ -22,12 +22,11 @@ import PayPalButton from "./components/PayPalButton";
|
|||||||
|
|
||||||
interface IPaymentModalProps {
|
interface IPaymentModalProps {
|
||||||
activeSubscriptionPlan?: ISubscriptionPlan;
|
activeSubscriptionPlan?: ISubscriptionPlan;
|
||||||
stripePublicKey?: string;
|
noTrial?: boolean;
|
||||||
singlePayClientSecret?: string;
|
returnUrl?: string;
|
||||||
defaultPaymentMethod?: EPaymentMethod;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function PaymentModal({ activeSubscriptionPlan }: IPaymentModalProps) {
|
function PaymentModal({ activeSubscriptionPlan, noTrial, returnUrl }: IPaymentModalProps) {
|
||||||
const { i18n } = useTranslation();
|
const { i18n } = useTranslation();
|
||||||
const locale = i18n.language;
|
const locale = i18n.language;
|
||||||
const api = useApi();
|
const api = useApi();
|
||||||
@ -60,6 +59,9 @@ function PaymentModal({ activeSubscriptionPlan }: IPaymentModalProps) {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const siteConfig = await api.getAppConfig({ bundleId: "auraweb" });
|
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));
|
setStripePromise(loadStripe(siteConfig.data.stripe_public_key));
|
||||||
const { sub_plans } = await api.getSubscriptionPlans({ locale });
|
const { sub_plans } = await api.getSubscriptionPlans({ locale });
|
||||||
setSubPlans(sub_plans);
|
setSubPlans(sub_plans);
|
||||||
@ -173,22 +175,27 @@ function PaymentModal({ activeSubscriptionPlan }: IPaymentModalProps) {
|
|||||||
/>
|
/>
|
||||||
{activeSubPlan && (
|
{activeSubPlan && (
|
||||||
<div>
|
<div>
|
||||||
<p className={styles["sub-plan-description"]}>
|
{!noTrial && (
|
||||||
You will be charged only{" "}
|
<>
|
||||||
<b>
|
<p className={styles["sub-plan-description"]}>
|
||||||
${getPriceFromTrial(activeSubPlan?.trial)} for your 3-day trial.
|
You will be charged only{" "}
|
||||||
</b>
|
<b>
|
||||||
</p>
|
${getPriceFromTrial(activeSubPlan?.trial)} for your 3-day trial.
|
||||||
<p className={styles["sub-plan-description"]}>
|
</b>
|
||||||
We`ll <b>email you a reminder</b> before your trial period ends.
|
</p>
|
||||||
</p>
|
<p className={styles["sub-plan-description"]}>
|
||||||
|
We`ll <b>email you a reminder</b> before your trial period ends.
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
<p className={styles["sub-plan-description"]}>
|
<p className={styles["sub-plan-description"]}>
|
||||||
Cancel anytime. The charge will appear on your bill as witapps.
|
Cancel anytime. The charge will appear on your bill as witapps.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className={styles["payment-method-container"]}>
|
<div className={styles["payment-method-container"]}>
|
||||||
{stripePromise && clientSecret && subscriptionReceiptId && (
|
{stripePromise && clientSecret && (
|
||||||
<Elements stripe={stripePromise} options={{ clientSecret }}>
|
<Elements stripe={stripePromise} options={{ clientSecret }}>
|
||||||
{selectedPaymentMethod === EPaymentMethod.PAYPAL_OR_APPLE_PAY && (
|
{selectedPaymentMethod === EPaymentMethod.PAYPAL_OR_APPLE_PAY && (
|
||||||
<div className={styles["payment-method"]}>
|
<div className={styles["payment-method"]}>
|
||||||
@ -202,13 +209,14 @@ function PaymentModal({ activeSubscriptionPlan }: IPaymentModalProps) {
|
|||||||
activeSubPlan={activeSubPlan}
|
activeSubPlan={activeSubPlan}
|
||||||
client_secret={clientSecret}
|
client_secret={clientSecret}
|
||||||
subscriptionReceiptId={subscriptionReceiptId}
|
subscriptionReceiptId={subscriptionReceiptId}
|
||||||
|
returnUrl={window.location.href}
|
||||||
/>
|
/>
|
||||||
{!!errors.length && <p className={styles.errors}>{errors}</p>}
|
{!!errors.length && <p className={styles.errors}>{errors}</p>}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{selectedPaymentMethod === EPaymentMethod.CREDIT_CARD && (
|
{selectedPaymentMethod === EPaymentMethod.CREDIT_CARD && (
|
||||||
<CheckoutForm subscriptionReceiptId={subscriptionReceiptId} />
|
<CheckoutForm subscriptionReceiptId={subscriptionReceiptId} returnUrl={returnUrl} />
|
||||||
)}
|
)}
|
||||||
</Elements>
|
</Elements>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -58,6 +58,11 @@
|
|||||||
border: 2px solid #c7c7c7;
|
border: 2px solid #c7c7c7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.discount-screen__block:first-child .discount-screen__button {
|
||||||
|
background: #c7c7c7;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
.discount-screen__block:last-child {
|
.discount-screen__block:last-child {
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
border: 2px solid #066fde;
|
border: 2px solid #066fde;
|
||||||
@ -111,3 +116,47 @@
|
|||||||
width: calc(100% + 32px);
|
width: calc(100% + 32px);
|
||||||
justify-content: center;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,26 +1,98 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
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 './discount-screen.css';
|
||||||
|
|
||||||
import routes from '@/routes';
|
import routes from '@/routes';
|
||||||
|
import { useApi } from "@/api";
|
||||||
|
import { useAuth } from "@/auth";
|
||||||
import HeaderLogo from '@/components/palmistry/header-logo/header-logo';
|
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() {
|
export default function DiscountScreen() {
|
||||||
const navigate = useNavigate();
|
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<Promise<Stripe | null> | null>(null);
|
||||||
|
const [productId, setProductId] = React.useState('');
|
||||||
|
const [clientSecret, setClientSecret] = React.useState<string | null>(null);
|
||||||
|
const [stripePublicKey, setStripePublicKey] = React.useState<string>("");
|
||||||
|
|
||||||
const goPremiumBundle = () => {
|
const goPremiumBundle = () => {
|
||||||
navigate(routes.client.palmistryPremiumBundle());
|
navigate(routes.client.palmistryPremiumBundle());
|
||||||
};
|
};
|
||||||
|
|
||||||
React.useEffect(() => {
|
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();
|
goPremiumBundle();
|
||||||
|
} else if ('paymentIntent' in response) {
|
||||||
|
setClientSecret(response.paymentIntent.data.client_secret);
|
||||||
|
setStripePublicKey(response.paymentIntent.data.public_key);
|
||||||
}
|
}
|
||||||
}, [userHasWeeklySubscription]);
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="discount-screen">
|
<div className="discount-screen">
|
||||||
@ -55,7 +127,7 @@ export default function DiscountScreen() {
|
|||||||
<section className="discount-screen__block">
|
<section className="discount-screen__block">
|
||||||
<div className="discount-screen__header-block">save 33%</div>
|
<div className="discount-screen__header-block">save 33%</div>
|
||||||
|
|
||||||
<span className="discount-screen__price-block">€12.73 for <br /> 1-week plan</span>
|
<span className="discount-screen__price-block">€{price} for <br /> 1-week plan</span>
|
||||||
|
|
||||||
<div className="discount-screen__details">
|
<div className="discount-screen__details">
|
||||||
<span className="discount-screen__details-name">Total savings</span>
|
<span className="discount-screen__details-name">Total savings</span>
|
||||||
@ -67,12 +139,39 @@ export default function DiscountScreen() {
|
|||||||
<span className="discount-screen__details-value">no</span>
|
<span className="discount-screen__details-value">no</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button className="discount-screen__button">
|
<button className="discount-screen__button" onClick={buy}>
|
||||||
Pay now and <br /> skip trial
|
Pay now and <br /> skip trial
|
||||||
</button>
|
</button>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{stripePromise && clientSecret && (
|
||||||
|
<div className={`discount-screen__widget${isSuccess ? " discount-screen__widget_success" : ""}`}>
|
||||||
|
<Elements stripe={stripePromise} options={{ clientSecret }}>
|
||||||
|
<CheckoutForm returnUrl={`${window.location.host}/palmistry/premium-bundle`} />
|
||||||
|
</Elements>
|
||||||
|
|
||||||
|
{isSuccess && (
|
||||||
|
<div className="discount-screen__success">
|
||||||
|
<svg
|
||||||
|
className="discount-screen__success-icon"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="512"
|
||||||
|
height="512"
|
||||||
|
viewBox="0 0 52 52"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill="#4ec794"
|
||||||
|
d="M26 0C11.664 0 0 11.663 0 26s11.664 26 26 26 26-11.663 26-26S40.336 0 26 0zm14.495 17.329-16 18a1.997 1.997 0 0 1-2.745.233l-10-8a2 2 0 0 1 2.499-3.124l8.517 6.813L37.505 14.67a2.001 2.001 0 0 1 2.99 2.659z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<div className="discount-screen__success-text">Payment success</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
|
|
||||||
import './payment-screen.css';
|
import './payment-screen.css';
|
||||||
|
|
||||||
import routes from '@/routes';
|
|
||||||
import useSteps, { Step } from '@/hooks/palmistry/use-steps';
|
import useSteps, { Step } from '@/hooks/palmistry/use-steps';
|
||||||
import useTimer from '@/hooks/palmistry/use-timer';
|
import useTimer from '@/hooks/palmistry/use-timer';
|
||||||
import HeaderLogo from '@/components/palmistry/header-logo/header-logo';
|
import HeaderLogo from '@/components/palmistry/header-logo/header-logo';
|
||||||
@ -17,18 +15,16 @@ const getFormattedPrice = (price: number) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function PaymentScreen() {
|
export default function PaymentScreen() {
|
||||||
const navigate = useNavigate();
|
|
||||||
const time = useTimer();
|
const time = useTimer();
|
||||||
const activeSubPlanFromStore = useSelector(selectors.selectActiveSubPlan);
|
const activeSubPlanFromStore = useSelector(selectors.selectActiveSubPlan);
|
||||||
// const subscriptionStatus = useSelector(selectors.selectStatus);
|
const subscriptionStatus = useSelector(selectors.selectStatus);
|
||||||
const subscriptionStatus = "subscribed";
|
|
||||||
|
|
||||||
const steps = useSteps();
|
const steps = useSteps();
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (subscriptionStatus === "subscribed") {
|
if (subscriptionStatus === "subscribed") {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
navigate(routes.client.palmistryDiscount());
|
steps.goNext();
|
||||||
}, 1500);
|
}, 1500);
|
||||||
}
|
}
|
||||||
}, [subscriptionStatus]);
|
}, [subscriptionStatus]);
|
||||||
@ -242,7 +238,7 @@ export default function PaymentScreen() {
|
|||||||
|
|
||||||
{activeSubPlanFromStore && (
|
{activeSubPlanFromStore && (
|
||||||
<div className={`payment-screen__widget${subscriptionStatus === "subscribed" ? " payment-screen__widget_success" : ""}`}>
|
<div className={`payment-screen__widget${subscriptionStatus === "subscribed" ? " payment-screen__widget_success" : ""}`}>
|
||||||
{subscriptionStatus !== "subscribed" && <PaymentModal />}
|
{subscriptionStatus !== "subscribed" && <PaymentModal returnUrl={window.location.href}/>}
|
||||||
|
|
||||||
{subscriptionStatus === "subscribed" && (
|
{subscriptionStatus === "subscribed" && (
|
||||||
<div className="payment-screen__success">
|
<div className="payment-screen__success">
|
||||||
|
|||||||
@ -137,3 +137,47 @@
|
|||||||
fill: #fff;
|
fill: #fff;
|
||||||
margin-right: 8px;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,22 +1,79 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
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 './premium-bundle-screen.css';
|
||||||
|
|
||||||
import routes from '@/routes';
|
import routes from '@/routes';
|
||||||
import HeaderLogo from '@/components/palmistry/header-logo/header-logo';
|
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() {
|
export default function PremiumBundleScreen() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const { token, user } = useAuth();
|
||||||
|
const api = useApi();
|
||||||
|
|
||||||
const userHasPremiumBundle = false;
|
const [stripePromise, setStripePromise] = React.useState<Promise<Stripe | null> | null>(null);
|
||||||
|
const [productId, setProductId] = React.useState('');
|
||||||
|
const [isSuccess] = React.useState(false);
|
||||||
|
const [clientSecret, setClientSecret] = React.useState<string | null>(null);
|
||||||
|
const [stripePublicKey, setStripePublicKey] = React.useState<string>("");
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (userHasPremiumBundle) {
|
(async () => {
|
||||||
navigate(routes.client.home());
|
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 = () => {
|
const goHome = () => {
|
||||||
navigate(routes.client.home());
|
navigate(routes.client.home());
|
||||||
@ -134,7 +191,10 @@ export default function PremiumBundleScreen() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button className="premium-bundle-screen__button premium-bundle-screen__button-active premium-bundle-screen__buy-button">
|
<button
|
||||||
|
className="premium-bundle-screen__button premium-bundle-screen__button-active premium-bundle-screen__buy-button"
|
||||||
|
onClick={buy}
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
width="13"
|
width="13"
|
||||||
height="16"
|
height="16"
|
||||||
@ -151,6 +211,33 @@ export default function PremiumBundleScreen() {
|
|||||||
Buy now
|
Buy now
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{stripePromise && clientSecret && (
|
||||||
|
<div className={`discount-screen__widget${isSuccess ? " discount-screen__widget_success" : ""}`}>
|
||||||
|
<Elements stripe={stripePromise} options={{ clientSecret }}>
|
||||||
|
<CheckoutForm returnUrl={window.location.host} />
|
||||||
|
</Elements>
|
||||||
|
|
||||||
|
{isSuccess && (
|
||||||
|
<div className="discount-screen__success">
|
||||||
|
<svg
|
||||||
|
className="discount-screen__success-icon"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="512"
|
||||||
|
height="512"
|
||||||
|
viewBox="0 0 52 52"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill="#4ec794"
|
||||||
|
d="M26 0C11.664 0 0 11.663 0 26s11.664 26 26 26 26-11.663 26-26S40.336 0 26 0zm14.495 17.329-16 18a1.997 1.997 0 0 1-2.745.233l-10-8a2 2 0 0 1 2.499-3.124l8.517 6.813L37.505 14.67a2.001 2.001 0 0 1 2.99 2.659z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<div className="discount-screen__success-text">Payment success</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import React from 'react';
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
|
|
||||||
|
import { PatchPayload } from "@/api/resources/User";
|
||||||
import { Step } from '@/hooks/palmistry/use-steps';
|
import { Step } from '@/hooks/palmistry/use-steps';
|
||||||
import { useAuth } from "@/auth";
|
import { useAuth } from "@/auth";
|
||||||
import { useApi, ApiError, extractErrorMessage } from "@/api";
|
import { useApi, ApiError, extractErrorMessage } from "@/api";
|
||||||
@ -55,18 +56,23 @@ export default function StepEmail() {
|
|||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
const auth = await api.auth({ email, timezone, locale });
|
const auth = await api.auth({ email, timezone, locale });
|
||||||
const { auth: { token, user } } = auth;
|
const { auth: { token, user } } = auth;
|
||||||
|
|
||||||
signUp(token, user);
|
signUp(token, user);
|
||||||
const payload = {
|
const payload: PatchPayload = {
|
||||||
user: {
|
user: {
|
||||||
profile_attributes: {
|
profile_attributes: {
|
||||||
birthday: steps.getStoredValue(Step.Birthdate),
|
birthday: steps.getStoredValue(Step.Birthdate),
|
||||||
gender: steps.getStoredValue(Step.Gender),
|
gender: steps.getStoredValue(Step.Gender),
|
||||||
relationship_status: steps.getStoredValue(Step.RelationshipStatus),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
token,
|
token,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const relationshipStatus = steps.getStoredValue(Step.RelationshipStatus);
|
||||||
|
if (relationshipStatus) {
|
||||||
|
payload.user.profile_attributes!.relationship_status = relationshipStatus;
|
||||||
|
}
|
||||||
|
|
||||||
const updatedUser = await api.updateUser(payload).catch((error) => console.log("Error: ", error));
|
const updatedUser = await api.updateUser(payload).catch((error) => console.log("Error: ", error));
|
||||||
|
|
||||||
if (updatedUser?.user) dispatch(actions.user.update(updatedUser.user));
|
if (updatedUser?.user) dispatch(actions.user.update(updatedUser.user));
|
||||||
|
|||||||
@ -1,13 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
|
|
||||||
import { Step } from '@/hooks/palmistry/use-steps';
|
import { Step } from '@/hooks/palmistry/use-steps';
|
||||||
import useSteps from '@/hooks/palmistry/use-steps';
|
import useSteps from '@/hooks/palmistry/use-steps';
|
||||||
import Paywall from '@/components/palmistry/paywall/paywall';
|
import Paywall from '@/components/palmistry/paywall/paywall';
|
||||||
|
|
||||||
export default function StepPaywall() {
|
export default function StepPaywall() {
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const steps = useSteps();
|
const steps = useSteps();
|
||||||
const storedEmail = steps.getStoredValue(Step.Email);
|
const storedEmail = steps.getStoredValue(Step.Email);
|
||||||
|
|
||||||
@ -18,7 +15,7 @@ export default function StepPaywall() {
|
|||||||
}, [storedEmail]);
|
}, [storedEmail]);
|
||||||
|
|
||||||
const onNext = () => {
|
const onNext = () => {
|
||||||
navigate('/palmistry/payment');
|
steps.goNext();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,13 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { AnimatePresence, motion } from 'framer-motion';
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import { useSelector } from "react-redux";
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
|
|
||||||
import './steps-manager.css';
|
import './steps-manager.css';
|
||||||
|
|
||||||
import routes from '@/routes';
|
|
||||||
import { selectors } from "@/store";
|
|
||||||
import Progressbar from '@/components/palmistry/progress-bar/progress-bar';
|
import Progressbar from '@/components/palmistry/progress-bar/progress-bar';
|
||||||
import PalmistryContainer from '@/components/palmistry/palmistry-container/palmistry-container';
|
import PalmistryContainer from '@/components/palmistry/palmistry-container/palmistry-container';
|
||||||
import useSteps, { Step } from '@/hooks/palmistry/use-steps';
|
import useSteps, { Step } from '@/hooks/palmistry/use-steps';
|
||||||
@ -52,8 +48,6 @@ const animationDuration = 0.2;
|
|||||||
export default function StepsManager() {
|
export default function StepsManager() {
|
||||||
const steps = useSteps();
|
const steps = useSteps();
|
||||||
const { pathname } = useLocation();
|
const { pathname } = useLocation();
|
||||||
const subscriptionStatus = useSelector(selectors.selectStatus);
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const [modalIsOpen, setModalIsOpen] = React.useState(false);
|
const [modalIsOpen, setModalIsOpen] = React.useState(false);
|
||||||
|
|
||||||
@ -62,12 +56,6 @@ export default function StepsManager() {
|
|||||||
|
|
||||||
steps.goFirstUnpassedStep();
|
steps.goFirstUnpassedStep();
|
||||||
}, [steps.isInited]);
|
}, [steps.isInited]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (subscriptionStatus === "subscribed" && steps.current !== Step.Payment) {
|
|
||||||
navigate(routes.client.home());
|
|
||||||
}
|
|
||||||
}, [subscriptionStatus]);
|
|
||||||
|
|
||||||
const motionDivClassName = [
|
const motionDivClassName = [
|
||||||
'steps-manager__motion-div',
|
'steps-manager__motion-div',
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
import type { UserStatus } from "./types";
|
import type { UserStatus } from "./types";
|
||||||
|
|
||||||
|
const isProduction = import.meta.env.MODE === "production";
|
||||||
|
|
||||||
const host = "";
|
const host = "";
|
||||||
export const apiHost = "https://api-web.aura.wit.life";
|
export const apiHost = "https://api-web.aura.wit.life";
|
||||||
|
const dApiHost = isProduction ? "https://d.api.witapps.us" : "https://dev.api.witapps.us"
|
||||||
const siteHost = "https://aura.wit.life";
|
const siteHost = "https://aura.wit.life";
|
||||||
const prefix = "api/v1";
|
const prefix = "api/v1";
|
||||||
const dApiHost = "https://dev.api.witapps.us";
|
const dApiHost = "https://dev.api.witapps.us";
|
||||||
@ -176,7 +179,6 @@ const routes = {
|
|||||||
),
|
),
|
||||||
getAiRequestsV2: (id: string) =>
|
getAiRequestsV2: (id: string) =>
|
||||||
[apiHost, "api/v2", "ai", "requests", `${id}.json`].join("/"),
|
[apiHost, "api/v2", "ai", "requests", `${id}.json`].join("/"),
|
||||||
|
|
||||||
dApiTestPaymentProducts: () =>
|
dApiTestPaymentProducts: () =>
|
||||||
[dApiHost, "payment", "test", "products"].join("/"),
|
[dApiHost, "payment", "test", "products"].join("/"),
|
||||||
dApiPaymentCheckout: () => [dApiHost, "payment", "checkout"].join("/"),
|
dApiPaymentCheckout: () => [dApiHost, "payment", "checkout"].join("/"),
|
||||||
@ -276,6 +278,7 @@ export const withoutFooterRoutes = [
|
|||||||
routes.client.trialPaymentWithDiscount(),
|
routes.client.trialPaymentWithDiscount(),
|
||||||
routes.client.palmistryPaywall(),
|
routes.client.palmistryPaywall(),
|
||||||
routes.client.palmistryPayment(),
|
routes.client.palmistryPayment(),
|
||||||
|
routes.client.palmistryDiscount(),
|
||||||
routes.client.email("marketing-landing"),
|
routes.client.email("marketing-landing"),
|
||||||
routes.client.email("marketing-trial-payment"),
|
routes.client.email("marketing-trial-payment"),
|
||||||
routes.client.tryApp(),
|
routes.client.tryApp(),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user