Revert "fix: remove double image key and update filter of subscription plans"
This commit is contained in:
parent
5bd1896465
commit
6fbc1c3a21
@ -23,7 +23,8 @@ import {
|
||||
GoogleAuth,
|
||||
SubscriptionPlans,
|
||||
AppleAuth,
|
||||
AIRequestsV2
|
||||
AIRequestsV2,
|
||||
SinglePayment
|
||||
} from './resources'
|
||||
|
||||
const api = {
|
||||
@ -55,6 +56,9 @@ const api = {
|
||||
getZodiacs: createMethod<Zodiacs.Payload, Zodiacs.Response>(Zodiacs.createRequest),
|
||||
AIRequestsV2: createMethod<AIRequestsV2.Payload, AIRequestsV2.Response>(AIRequestsV2.createRequest),
|
||||
getAIRequestsV2: createMethod<AIRequestsV2.PayloadGet, AIRequestsV2.IAiResponseGet>(AIRequestsV2.createRequestGet),
|
||||
|
||||
getSinglePaymentProducts: createMethod<SinglePayment.PayloadGet, SinglePayment.ResponseGet[]>(SinglePayment.createRequestGet),
|
||||
createSinglePayment: createMethod<SinglePayment.PayloadPost, SinglePayment.ResponsePost | SinglePayment.ResponsePostExistPaymentData>(SinglePayment.createRequestPost),
|
||||
}
|
||||
|
||||
export type ApiContextValue = typeof api
|
||||
|
||||
82
src/api/resources/SinglePayment.ts
Normal file
82
src/api/resources/SinglePayment.ts
Normal file
@ -0,0 +1,82 @@
|
||||
import routes from "@/routes";
|
||||
import { getAuthHeaders } from "../utils";
|
||||
|
||||
interface Payload {
|
||||
token: string;
|
||||
}
|
||||
|
||||
export interface PayloadGet extends Payload {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface PayloadPost extends Payload {
|
||||
data: {
|
||||
user: {
|
||||
id: string;
|
||||
email: string;
|
||||
name: string;
|
||||
sign: string;
|
||||
age: number;
|
||||
};
|
||||
partner: {
|
||||
sign: string | null;
|
||||
age: number | null;
|
||||
};
|
||||
paymentInfo: {
|
||||
productId: string;
|
||||
};
|
||||
return_url: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ResponseGet {
|
||||
key: string;
|
||||
productId: string;
|
||||
amount: number;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export interface ResponsePost {
|
||||
paymentIntent: {
|
||||
status: string;
|
||||
data: {
|
||||
client_secret: string;
|
||||
paymentIntentId: string;
|
||||
return_url?: string;
|
||||
public_key: string;
|
||||
product: {
|
||||
id: string;
|
||||
name: string;
|
||||
description: null | string;
|
||||
price: {
|
||||
id: string;
|
||||
unit_amount: number;
|
||||
currency: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface ResponsePostExistPaymentData {
|
||||
payment: {
|
||||
status: string;
|
||||
invoiceId: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const createRequestPost = ({ data, token }: PayloadPost): Request => {
|
||||
const url = new URL(routes.server.dApiPaymentCheckout());
|
||||
const body = JSON.stringify(data);
|
||||
return new Request(url, {
|
||||
method: "POST",
|
||||
headers: getAuthHeaders(token),
|
||||
body,
|
||||
});
|
||||
};
|
||||
|
||||
export const createRequestGet = ({ id, token }: PayloadGet): Request => {
|
||||
id;
|
||||
const url = new URL(routes.server.dApiTestPaymentProducts());
|
||||
return new Request(url, { method: "GET", headers: getAuthHeaders(token) });
|
||||
};
|
||||
@ -22,3 +22,4 @@ export * as GoogleAuth from "./GoogleAuth";
|
||||
export * as SubscriptionPlans from "./SubscriptionPlans";
|
||||
export * as AppleAuth from "./AppleAuth";
|
||||
export * as AIRequestsV2 from "./AIRequestsV2";
|
||||
export * as SinglePayment from "./SinglePayment";
|
||||
|
||||
@ -104,6 +104,9 @@ import AddReportPage from "../pages/AdditionalPurchases/pages/AddReport";
|
||||
import UnlimitedReadingsPage from "../pages/AdditionalPurchases/pages/UnlimitedReadings";
|
||||
import AddConsultationPage from "../pages/AdditionalPurchases/pages/AddConsultation";
|
||||
import StepsManager from "@/components/palmistry/steps-manager/steps-manager";
|
||||
import PaymentWithEmailPage from "../pages/PaymentWithEmailPage";
|
||||
import SuccessPaymentPage from "../pages/PaymentWithEmailPage/ResultPayment/SuccessPaymentPage";
|
||||
import FailPaymentPage from "../pages/PaymentWithEmailPage/ResultPayment/FailPaymentPage";
|
||||
|
||||
const isProduction = import.meta.env.MODE === "production";
|
||||
|
||||
@ -216,6 +219,13 @@ function App(): JSX.Element {
|
||||
return (
|
||||
<Routes>
|
||||
<Route element={<Layout setIsSpecialOfferOpen={setIsSpecialOfferOpen} />}>
|
||||
{/* Email - Pay - Email */}
|
||||
<Route path={routes.client.epeBirthdate()} element={<BirthdayPage />} />
|
||||
<Route path={routes.client.epePayment()} element={<PaymentWithEmailPage />} />
|
||||
<Route path={routes.client.epeSuccessPayment()} element={<SuccessPaymentPage />} />
|
||||
<Route path={routes.client.epeFailPayment()} element={<FailPaymentPage />} />
|
||||
{/* Email - Pay - Email */}
|
||||
|
||||
{/* Test Routes Start */}
|
||||
<Route path={routes.client.notFound()} element={<NotFoundPage />} />
|
||||
<Route path={routes.client.gender()} element={<GenderPage />}>
|
||||
@ -331,8 +341,14 @@ function App(): JSX.Element {
|
||||
{/* Additional Purchases */}
|
||||
<Route element={<AdditionalPurchases />}>
|
||||
<Route path={routes.client.addReport()} element={<AddReportPage />} />
|
||||
<Route path={routes.client.unlimitedReadings()} element={<UnlimitedReadingsPage />} />
|
||||
<Route path={routes.client.addConsultation()} element={<AddConsultationPage />} />
|
||||
<Route
|
||||
path={routes.client.unlimitedReadings()}
|
||||
element={<UnlimitedReadingsPage />}
|
||||
/>
|
||||
<Route
|
||||
path={routes.client.addConsultation()}
|
||||
element={<AddConsultationPage />}
|
||||
/>
|
||||
</Route>
|
||||
{/* Additional Purchases End */}
|
||||
|
||||
@ -472,15 +488,9 @@ function App(): JSX.Element {
|
||||
</Route>
|
||||
</Route>
|
||||
|
||||
<Route
|
||||
path="/palmistry"
|
||||
element={<StepsManager/>}
|
||||
/>
|
||||
<Route path="/palmistry" element={<StepsManager />} />
|
||||
|
||||
<Route
|
||||
path="/palmistry/:step"
|
||||
element={<StepsManager/>}
|
||||
/>
|
||||
<Route path="/palmistry/:step" element={<StepsManager />} />
|
||||
|
||||
<Route path="*" element={<NotFoundPage />} />
|
||||
</Route>
|
||||
|
||||
@ -1,54 +1,83 @@
|
||||
import { useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import { actions, selectors } from '@/store'
|
||||
import { DatePicker } from '../DateTimePicker'
|
||||
import MainButton from '../MainButton'
|
||||
import Policy from '../Policy'
|
||||
import Purposes from '../Purposes'
|
||||
import Title from '../Title'
|
||||
import routes from '@/routes'
|
||||
import './styles.css'
|
||||
import { useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { actions, selectors } from "@/store";
|
||||
import { DatePicker } from "../DateTimePicker";
|
||||
import MainButton from "../MainButton";
|
||||
import Policy from "../Policy";
|
||||
import Purposes from "../Purposes";
|
||||
import Title from "../Title";
|
||||
import routes from "@/routes";
|
||||
import "./styles.css";
|
||||
|
||||
function BirthdayPage(): JSX.Element {
|
||||
const { t } = useTranslation()
|
||||
const dispatch = useDispatch()
|
||||
const navigate = useNavigate()
|
||||
const birthdate = useSelector(selectors.selectBirthdate)
|
||||
const [isDisabled, setIsDisabled] = useState(true)
|
||||
const handleNext = () => navigate(routes.client.didYouKnow())
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
const birthdate = useSelector(selectors.selectBirthdate);
|
||||
const [isDisabled, setIsDisabled] = useState(true);
|
||||
const nextRoute = window.location.href.includes("/epe/")
|
||||
? routes.client.epePayment()
|
||||
: routes.client.didYouKnow();
|
||||
const handleNext = () => navigate(nextRoute);
|
||||
const handleValid = (birthdate: string) => {
|
||||
dispatch(actions.form.addDate(birthdate))
|
||||
setIsDisabled(birthdate === '')
|
||||
}
|
||||
dispatch(actions.form.addDate(birthdate));
|
||||
setIsDisabled(birthdate === "");
|
||||
};
|
||||
|
||||
return (
|
||||
<section className='page'>
|
||||
<Title variant='h3' className='mt-24'>{t('lets_start')}</Title>
|
||||
<Title variant='h2'>{t('date_of_birth')}</Title>
|
||||
<section className="page">
|
||||
<Title variant="h3" className="mt-24">
|
||||
{t("lets_start")}
|
||||
</Title>
|
||||
<Title variant="h2">{t("date_of_birth")}</Title>
|
||||
<DatePicker
|
||||
name='birthdate'
|
||||
name="birthdate"
|
||||
value={birthdate}
|
||||
onValid={handleValid}
|
||||
onInvalid={() => setIsDisabled(true)}
|
||||
inputClassName='date-picker-input'
|
||||
inputClassName="date-picker-input"
|
||||
/>
|
||||
<MainButton onClick={handleNext} disabled={isDisabled}>
|
||||
{t('next')}
|
||||
{t("next")}
|
||||
</MainButton>
|
||||
<footer className='footer'>
|
||||
<footer className="footer">
|
||||
<Policy>
|
||||
{t('privacy_text', {
|
||||
eulaLink: <a href='https://aura.wit.life/terms' target='_blank' rel='noopener noreferrer'>{t('eula')}</a>,
|
||||
privacyLink: <a href='https://aura.wit.life/privacy' target='_blank' rel='noopener noreferrer'>{t('privacy_notice')}</a>,
|
||||
clickHere: <a href='https://aura.wit.life/' target='_blank' rel='noopener noreferrer'>{t('here')}</a>,
|
||||
{t("privacy_text", {
|
||||
eulaLink: (
|
||||
<a
|
||||
href="https://aura.wit.life/terms"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{t("eula")}
|
||||
</a>
|
||||
),
|
||||
privacyLink: (
|
||||
<a
|
||||
href="https://aura.wit.life/privacy"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{t("privacy_notice")}
|
||||
</a>
|
||||
),
|
||||
clickHere: (
|
||||
<a
|
||||
href="https://aura.wit.life/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{t("here")}
|
||||
</a>
|
||||
),
|
||||
})}
|
||||
</Policy>
|
||||
<Purposes />
|
||||
</footer>
|
||||
</section>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default BirthdayPage
|
||||
export default BirthdayPage;
|
||||
|
||||
@ -15,11 +15,13 @@ import styles from "./styles.module.css";
|
||||
interface ICheckoutFormProps {
|
||||
children?: JSX.Element | null;
|
||||
subscriptionReceiptId?: string;
|
||||
returnUrl?: string;
|
||||
}
|
||||
|
||||
export default function CheckoutForm({
|
||||
children,
|
||||
subscriptionReceiptId,
|
||||
returnUrl,
|
||||
}: ICheckoutFormProps) {
|
||||
const stripe = useStripe();
|
||||
const elements = useElements();
|
||||
@ -43,7 +45,9 @@ export default function CheckoutForm({
|
||||
const { error } = await stripe.confirmPayment({
|
||||
elements,
|
||||
confirmParams: {
|
||||
return_url: `https://${window.location.host}/payment/result/${subscriptionReceiptId}/`,
|
||||
return_url: returnUrl
|
||||
? returnUrl
|
||||
: `https://${window.location.host}/payment/result/${subscriptionReceiptId}/`,
|
||||
},
|
||||
});
|
||||
if (error) {
|
||||
@ -75,9 +79,7 @@ export default function CheckoutForm({
|
||||
className={styles.button}
|
||||
>
|
||||
<img src="/lock.svg" alt="Secure" />
|
||||
<span id="button-text">
|
||||
{isProcessing ? "Processing..." : "Start"}
|
||||
</span>
|
||||
<span id="button-text">{isProcessing ? "Processing..." : "Start"}</span>
|
||||
</MainButton>
|
||||
{!!message.length && (
|
||||
<Title variant="h5" style={{ color: "red" }}>
|
||||
|
||||
@ -16,6 +16,7 @@ function PaymentResultPage(): JSX.Element {
|
||||
const dispatch = useDispatch();
|
||||
const [searchParams] = useSearchParams();
|
||||
const status = searchParams.get("redirect_status");
|
||||
const type = searchParams.get("type");
|
||||
// const { id } = useParams();
|
||||
// const requestTimeOutRef = useRef<NodeJS.Timeout>();
|
||||
const [isLoading] = useState(true);
|
||||
@ -89,9 +90,17 @@ function PaymentResultPage(): JSX.Element {
|
||||
useEffect(() => {
|
||||
if (status === "succeeded") {
|
||||
dispatch(actions.status.update("subscribed"));
|
||||
return navigate(routes.client.paymentSuccess());
|
||||
let successPaymentRoute = routes.client.paymentSuccess();
|
||||
if (type === "epe") {
|
||||
successPaymentRoute = routes.client.epeSuccessPayment();
|
||||
}
|
||||
return navigate(successPaymentRoute);
|
||||
}
|
||||
return navigate(routes.client.paymentFail());
|
||||
let failPaymentRoute = routes.client.paymentFail();
|
||||
if (type === "epe") {
|
||||
failPaymentRoute = routes.client.epeFailPayment();
|
||||
}
|
||||
return navigate(failPaymentRoute);
|
||||
}, [navigate, status, dispatch]);
|
||||
|
||||
return <div className={styles.page}>{isLoading && <Loader />}</div>;
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
import { Elements } from "@stripe/react-stripe-js";
|
||||
import styles from "./styles.module.css";
|
||||
import CheckoutForm from "@/components/PaymentPage/methods/Stripe/CheckoutForm";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Stripe, loadStripe } from "@stripe/stripe-js";
|
||||
import SecurityPayments from "../../TrialPayment/components/SecurityPayments";
|
||||
|
||||
interface IPaymentFormProps {
|
||||
stripePublicKey: string;
|
||||
clientSecret: string;
|
||||
returnUrl: string;
|
||||
}
|
||||
|
||||
function PaymentForm({ stripePublicKey, clientSecret, returnUrl }: IPaymentFormProps) {
|
||||
const [stripePromise, setStripePromise] =
|
||||
useState<Promise<Stripe | null> | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setStripePromise(loadStripe(stripePublicKey));
|
||||
}, [stripePublicKey]);
|
||||
return (
|
||||
<div className={styles["payment-modal"]}>
|
||||
<div className={styles["payment-method-container"]}>
|
||||
{stripePromise && clientSecret && (
|
||||
<Elements stripe={stripePromise} options={{ clientSecret }}>
|
||||
<CheckoutForm returnUrl={returnUrl} />
|
||||
</Elements>
|
||||
)}
|
||||
</div>
|
||||
<SecurityPayments />
|
||||
<p className={styles.address}>500 N RAINBOW BLVD LAS VEGAS, NV 89107</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PaymentForm;
|
||||
@ -0,0 +1,44 @@
|
||||
.payment-modal {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 250px;
|
||||
gap: 25px;
|
||||
color: #2f2e37;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: 700;
|
||||
font-size: 20px;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sub-plan-description {
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
line-height: 150%;
|
||||
}
|
||||
|
||||
.payment-method-container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.address {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.payment-method {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.address {
|
||||
color: gray;
|
||||
font-size: 10px;
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import routes from "@/routes";
|
||||
import styles from "./styles.module.css";
|
||||
import Title from "@/components/Title";
|
||||
import MainButton from "@/components/MainButton";
|
||||
|
||||
function FailPaymentPage(): JSX.Element {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const handleNext = () => navigate(routes.client.epePayment());
|
||||
|
||||
return (
|
||||
<section className={`${styles.page} page`}>
|
||||
<img
|
||||
src="/ExclamationIcon.png"
|
||||
alt="Exclamation Icon"
|
||||
style={{ minHeight: "180px" }}
|
||||
/>
|
||||
<div className={styles.text}>
|
||||
<Title variant="h1">{t("auweb.pay_bad.title")}</Title>
|
||||
<p className={styles.list}>{t("auweb.pay_bad.text1")}</p>
|
||||
</div>
|
||||
<div className={styles.bottom}>
|
||||
<p className={styles.description}>{t("auweb.pay_bad.text2")}</p>
|
||||
<MainButton className={styles.button} onClick={handleNext}>
|
||||
{t("auweb.pay_bad.button")}
|
||||
</MainButton>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default FailPaymentPage;
|
||||
@ -0,0 +1,38 @@
|
||||
.page {
|
||||
position: relative;
|
||||
height: calc(100vh - 50px);
|
||||
/* max-height: -webkit-fill-available; */
|
||||
overflow-y: scroll;
|
||||
justify-content: center;
|
||||
gap: 80px;
|
||||
}
|
||||
|
||||
.text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.list {
|
||||
font-weight: 500;
|
||||
white-space: pre-wrap;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.button {
|
||||
width: 100%;
|
||||
max-width: 260px;
|
||||
border-radius: 50px;
|
||||
background-color: #fe2b57;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import styles from "./styles.module.css";
|
||||
import Title from "@/components/Title";
|
||||
|
||||
function SuccessPaymentPage(): JSX.Element {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<section className={`${styles.page} page`}>
|
||||
<img
|
||||
src="/SuccessIcon.png"
|
||||
alt="Success Icon"
|
||||
style={{ minHeight: "98px" }}
|
||||
/>
|
||||
<div className={styles.text}>
|
||||
<Title variant="h1">The information has been sent to your e-mail</Title>
|
||||
<p>{t("auweb.pay_good.text1")}</p>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default SuccessPaymentPage;
|
||||
@ -0,0 +1,25 @@
|
||||
.page {
|
||||
position: relative;
|
||||
flex: auto;
|
||||
height: calc(100vh - 50px);
|
||||
max-height: -webkit-fill-available;
|
||||
justify-content: center;
|
||||
gap: 80px;
|
||||
}
|
||||
|
||||
.text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.text > p {
|
||||
text-align: center;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.button {
|
||||
width: 100%;
|
||||
max-width: 260px;
|
||||
border-radius: 50px;
|
||||
background-color: #fe2b57;
|
||||
}
|
||||
213
src/components/pages/PaymentWithEmailPage/index.tsx
Normal file
213
src/components/pages/PaymentWithEmailPage/index.tsx
Normal file
@ -0,0 +1,213 @@
|
||||
import EmailInput from "@/components/EmailEnterPage/EmailInput";
|
||||
import styles from "./styles.module.css";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { actions, selectors } from "@/store";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import MainButton from "@/components/MainButton";
|
||||
import Loader, { LoaderColor } from "@/components/Loader";
|
||||
import { useAuth } from "@/auth";
|
||||
import { ApiError, extractErrorMessage, useApi } from "@/api";
|
||||
import { getClientTimezone } from "@/locales";
|
||||
import ErrorText from "@/components/ErrorText";
|
||||
import Title from "@/components/Title";
|
||||
import NameInput from "@/components/EmailEnterPage/NameInput";
|
||||
import { getZodiacSignByDate } from "@/services/zodiac-sign";
|
||||
import {
|
||||
ResponsePost,
|
||||
ResponsePostExistPaymentData,
|
||||
} from "@/api/resources/SinglePayment";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import routes from "@/routes";
|
||||
import PaymentForm from "./PaymentForm";
|
||||
|
||||
function PaymentWithEmailPage() {
|
||||
const { t, i18n } = useTranslation();
|
||||
const { signUp } = useAuth();
|
||||
const api = useApi();
|
||||
const navigate = useNavigate();
|
||||
const timezone = getClientTimezone();
|
||||
const dispatch = useDispatch();
|
||||
const birthday = useSelector(selectors.selectBirthday);
|
||||
const locale = i18n.language;
|
||||
const [email, setEmail] = useState("");
|
||||
const [name, setName] = useState("");
|
||||
const [isValidEmail, setIsValidEmail] = useState(false);
|
||||
const [isValidName, setIsValidName] = useState(true);
|
||||
const [isDisabled, setIsDisabled] = useState(true);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [isAuth, setIsAuth] = useState(false);
|
||||
const [apiError, setApiError] = useState<ApiError | null>(null);
|
||||
const [error, setError] = useState<boolean>(false);
|
||||
const [paymentIntent, setPaymentIntent] = useState<
|
||||
ResponsePost | ResponsePostExistPaymentData | null
|
||||
>(null);
|
||||
const returnUrl = `${window.location.protocol}//${window.location.host}/payment/result/?type=epe`;
|
||||
|
||||
useEffect(() => {
|
||||
if (isValidName && isValidEmail) {
|
||||
setIsDisabled(false);
|
||||
} else {
|
||||
setIsDisabled(true);
|
||||
}
|
||||
}, [isValidEmail, email, isValidName, name]);
|
||||
|
||||
const handleValidEmail = (email: string) => {
|
||||
dispatch(actions.form.addEmail(email));
|
||||
setEmail(email);
|
||||
setIsValidEmail(true);
|
||||
};
|
||||
|
||||
const handleValidName = (name: string) => {
|
||||
setName(name);
|
||||
setIsValidName(true);
|
||||
};
|
||||
|
||||
const authorization = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const auth = await api.auth({ email, timezone, locale });
|
||||
const {
|
||||
auth: { token, user },
|
||||
} = auth;
|
||||
signUp(token, user);
|
||||
const payload = {
|
||||
user: {
|
||||
profile_attributes: {
|
||||
birthday,
|
||||
full_name: name,
|
||||
},
|
||||
},
|
||||
token,
|
||||
};
|
||||
const updatedUser = await api.updateUser(payload).catch((error) => {
|
||||
console.log("Error: ", error);
|
||||
});
|
||||
|
||||
if (updatedUser?.user) {
|
||||
dispatch(actions.user.update(updatedUser.user));
|
||||
}
|
||||
if (name) {
|
||||
dispatch(
|
||||
actions.user.update({
|
||||
username: name,
|
||||
})
|
||||
);
|
||||
}
|
||||
dispatch(actions.status.update("registred"));
|
||||
setIsAuth(true);
|
||||
const userUpdated = await api.getUser({ token });
|
||||
return { user: userUpdated?.user, token };
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
if (error instanceof ApiError) {
|
||||
setApiError(error as ApiError);
|
||||
} else {
|
||||
setError(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleClick = async () => {
|
||||
const authData = await authorization();
|
||||
if (!authData) {
|
||||
return;
|
||||
}
|
||||
const { user, token } = authData;
|
||||
console.log(token);
|
||||
|
||||
const productsSinglePayment = await api.getSinglePaymentProducts({
|
||||
id: "1",
|
||||
token,
|
||||
});
|
||||
const { productId } = productsSinglePayment[0];
|
||||
const createSinglePayment = await api.createSinglePayment({
|
||||
token,
|
||||
data: {
|
||||
user: {
|
||||
id: `${user?.id}`,
|
||||
email,
|
||||
name,
|
||||
sign: user?.profile?.sign?.sign || getZodiacSignByDate(birthday),
|
||||
age: user?.profile?.age?.years || 1,
|
||||
},
|
||||
partner: {
|
||||
sign: "partner_cancer",
|
||||
age: 26,
|
||||
},
|
||||
paymentInfo: {
|
||||
productId,
|
||||
},
|
||||
return_url: returnUrl,
|
||||
},
|
||||
});
|
||||
setPaymentIntent(createSinglePayment);
|
||||
setIsLoading(false);
|
||||
if ("payment" in createSinglePayment) {
|
||||
if (createSinglePayment.payment.status === "paid")
|
||||
return navigate(routes.client.epeSuccessPayment());
|
||||
return navigate(routes.client.epeFailPayment());
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`${styles.page} page`}>
|
||||
{paymentIntent && "paymentIntent" in paymentIntent && (
|
||||
<PaymentForm
|
||||
stripePublicKey={paymentIntent.paymentIntent.data.public_key}
|
||||
clientSecret={paymentIntent.paymentIntent.data.client_secret}
|
||||
returnUrl={returnUrl}
|
||||
/>
|
||||
)}
|
||||
{!paymentIntent && (
|
||||
<>
|
||||
<NameInput
|
||||
value={name}
|
||||
placeholder="Your name"
|
||||
onValid={handleValidName}
|
||||
onInvalid={() => setIsValidName(true)}
|
||||
/>
|
||||
<EmailInput
|
||||
name="email"
|
||||
value={email}
|
||||
placeholder={t("your_email")}
|
||||
onValid={handleValidEmail}
|
||||
onInvalid={() => setIsValidEmail(false)}
|
||||
/>
|
||||
|
||||
<MainButton
|
||||
className={styles.button}
|
||||
onClick={handleClick}
|
||||
disabled={isDisabled}
|
||||
>
|
||||
{isLoading && <Loader color={LoaderColor.White} />}
|
||||
{!isLoading &&
|
||||
!(!apiError && !error && !isLoading && isAuth) &&
|
||||
t("_continue")}
|
||||
{!apiError && !error && !isLoading && isAuth && (
|
||||
<img
|
||||
className={styles["success-icon"]}
|
||||
src="/SuccessIcon.png"
|
||||
alt="Success Icon"
|
||||
/>
|
||||
)}
|
||||
</MainButton>
|
||||
</>
|
||||
)}
|
||||
{(error || apiError) && (
|
||||
<Title variant="h3" style={{ color: "red", margin: 0 }}>
|
||||
Something went wrong
|
||||
</Title>
|
||||
)}
|
||||
{apiError && (
|
||||
<ErrorText
|
||||
size="medium"
|
||||
isShown={Boolean(apiError)}
|
||||
message={apiError ? extractErrorMessage(apiError) : null}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PaymentWithEmailPage;
|
||||
61
src/components/pages/PaymentWithEmailPage/styles.module.css
Normal file
61
src/components/pages/PaymentWithEmailPage/styles.module.css
Normal file
@ -0,0 +1,61 @@
|
||||
.page {
|
||||
/* position: relative; */
|
||||
position: static;
|
||||
height: fit-content;
|
||||
min-height: calc(100dvh - 103px);
|
||||
/* max-height: -webkit-fill-available; */
|
||||
display: flex;
|
||||
justify-items: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
/* gap: 16px; */
|
||||
}
|
||||
|
||||
.button {
|
||||
border-radius: 12px;
|
||||
margin-top: 0;
|
||||
box-shadow: rgba(0, 0, 0, 0.25) 0px 4px 4px 0px;
|
||||
height: 50px;
|
||||
min-height: 0;
|
||||
background: linear-gradient(
|
||||
165.54deg,
|
||||
rgb(20, 19, 51) -33.39%,
|
||||
rgb(32, 34, 97) 15.89%,
|
||||
rgb(84, 60, 151) 55.84%,
|
||||
rgb(105, 57, 162) 74.96%
|
||||
);
|
||||
font-size: 18px;
|
||||
line-height: 21px;
|
||||
}
|
||||
|
||||
.payment-loader {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.cross {
|
||||
position: absolute;
|
||||
top: -36px;
|
||||
right: 28px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
cursor: pointer;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 27px;
|
||||
font-weight: 700;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.email {
|
||||
font-size: 17px;
|
||||
font-weight: 500;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.success-icon {
|
||||
height: 100%;
|
||||
}
|
||||
@ -22,6 +22,9 @@ import PayPalButton from "./components/PayPalButton";
|
||||
|
||||
interface IPaymentModalProps {
|
||||
activeSubscriptionPlan?: ISubscriptionPlan;
|
||||
stripePublicKey?: string;
|
||||
singlePayClientSecret?: string;
|
||||
defaultPaymentMethod?: EPaymentMethod;
|
||||
}
|
||||
|
||||
function PaymentModal({ activeSubscriptionPlan }: IPaymentModalProps) {
|
||||
|
||||
@ -4,6 +4,7 @@ const host = "";
|
||||
export const apiHost = "https://api-web.aura.wit.life";
|
||||
const siteHost = "https://aura.wit.life";
|
||||
const prefix = "api/v1";
|
||||
const dApiHost = "https://dev.api.witapps.us";
|
||||
|
||||
const routes = {
|
||||
client: {
|
||||
@ -14,17 +15,22 @@ const routes = {
|
||||
palmistryBirthdate: () => [host, "palmistry", "birthdate"].join("/"),
|
||||
palmistryPalmsHold: () => [host, "palmistry", "palms-hold"].join("/"),
|
||||
palmistryWish: () => [host, "palmistry", "wish"].join("/"),
|
||||
palmistryRelationship: () => [host, "palmistry", "relationship-status"].join("/"),
|
||||
palmistryResonatedElement: () => [host, "palmistry", "resonated-element"].join("/"),
|
||||
palmistryColorYouLike: () => [host, "palmistry", "color-you-like"].join("/"),
|
||||
palmistryRelationship: () =>
|
||||
[host, "palmistry", "relationship-status"].join("/"),
|
||||
palmistryResonatedElement: () =>
|
||||
[host, "palmistry", "resonated-element"].join("/"),
|
||||
palmistryColorYouLike: () =>
|
||||
[host, "palmistry", "color-you-like"].join("/"),
|
||||
palmistryDecisions: () => [host, "palmistry", "decisions"].join("/"),
|
||||
palmistryGuidancePlan: () => [host, "palmistry", "guidance-plan"].join("/"),
|
||||
palmistryPersonalStatement: () => [host, "palmistry", "personal-statement"].join("/"),
|
||||
palmistryPersonalStatement: () =>
|
||||
[host, "palmistry", "personal-statement"].join("/"),
|
||||
palmistryScanInfo: () => [host, "palmistry", "scan-info"].join("/"),
|
||||
palmistryUpload: () => [host, "palmistry", "upload"].join("/"),
|
||||
palmistryScanPhoto: () => [host, "palmistry", "scan-photo"].join("/"),
|
||||
palmistryEmail: () => [host, "palmistry", "email"].join("/"),
|
||||
palmistrySubscriptionPlan: () => [host, "palmistry", "subscription-plan"].join("/"),
|
||||
palmistrySubscriptionPlan: () =>
|
||||
[host, "palmistry", "subscription-plan"].join("/"),
|
||||
palmistryPaywall: () => [host, "palmistry", "paywall"].join("/"),
|
||||
palmistryPayment: () => [host, "palmistry", "payment"].join("/"),
|
||||
palmistryDiscount: () => [host, "palmistry", "discount"].join("/"),
|
||||
@ -108,6 +114,12 @@ const routes = {
|
||||
unlimitedReadings: () => [host, "unlimited-readings"].join("/"),
|
||||
addConsultation: () => [host, "add-consultation"].join("/"),
|
||||
|
||||
// Email - Pay - Email
|
||||
epeBirthdate: () => [host, "epe", "birthdate"].join("/"),
|
||||
epePayment: () => [host, "epe", "payment"].join("/"),
|
||||
epeSuccessPayment: () => [host, "epe", "success-payment"].join("/"),
|
||||
epeFailPayment: () => [host, "epe", "fail-payment"].join("/"),
|
||||
|
||||
notFound: () => [host, "404"].join("/"),
|
||||
},
|
||||
server: {
|
||||
@ -164,6 +176,10 @@ const routes = {
|
||||
),
|
||||
getAiRequestsV2: (id: string) =>
|
||||
[apiHost, "api/v2", "ai", "requests", `${id}.json`].join("/"),
|
||||
|
||||
dApiTestPaymentProducts: () =>
|
||||
[dApiHost, "payment", "test", "products"].join("/"),
|
||||
dApiPaymentCheckout: () => [dApiHost, "payment", "checkout"].join("/"),
|
||||
},
|
||||
};
|
||||
|
||||
@ -266,6 +282,7 @@ export const withoutFooterRoutes = [
|
||||
routes.client.addReport(),
|
||||
routes.client.unlimitedReadings(),
|
||||
routes.client.addConsultation(),
|
||||
routes.client.epeSuccessPayment(),
|
||||
];
|
||||
|
||||
export const withoutFooterPartOfRoutes = [routes.client.questionnaire()];
|
||||
@ -334,14 +351,15 @@ export const withoutHeaderRoutes = [
|
||||
routes.client.email("marketing-landing"),
|
||||
routes.client.email("marketing-trial-payment"),
|
||||
routes.client.tryApp(),
|
||||
routes.client.epeSuccessPayment(),
|
||||
];
|
||||
export const hasNoHeader = (path: string) => {
|
||||
let result = true;
|
||||
|
||||
withoutHeaderRoutes.forEach((route) => {
|
||||
if (
|
||||
!path.includes("palmistry") && path.includes(route) ||
|
||||
path.includes("palmistry") && path === route
|
||||
(!path.includes("palmistry") && path.includes(route)) ||
|
||||
(path.includes("palmistry") && path === route)
|
||||
) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user