Merge branch 'preview/email-pay-email' into 'develop'

Revert "fix: remove double image key and update filter of subscription plans"

See merge request witapp/aura-webapp!64
This commit is contained in:
Victor Ershov 2024-03-27 19:20:25 +00:00
commit ba8da9a188
7 changed files with 121 additions and 27 deletions

View File

@ -25,8 +25,8 @@ import {
AppleAuth, AppleAuth,
AIRequestsV2, AIRequestsV2,
Assistants, Assistants,
OpenAI OpenAI,
SinglePayment, SinglePayment
} from './resources' } from './resources'
const api = { const api = {

View File

@ -231,6 +231,7 @@ function App(): JSX.Element {
<Routes> <Routes>
<Route element={<Layout setIsSpecialOfferOpen={setIsSpecialOfferOpen} />}> <Route element={<Layout setIsSpecialOfferOpen={setIsSpecialOfferOpen} />}>
{/* Email - Pay - Email */} {/* Email - Pay - Email */}
<Route path={routes.client.epeGender()} element={<GenderPage />} />
<Route path={routes.client.epeBirthdate()} element={<BirthdayPage />} /> <Route path={routes.client.epeBirthdate()} element={<BirthdayPage />} />
<Route path={routes.client.epePayment()} element={<PaymentWithEmailPage />} /> <Route path={routes.client.epePayment()} element={<PaymentWithEmailPage />} />
<Route path={routes.client.epeSuccessPayment()} element={<SuccessPaymentPage />} /> <Route path={routes.client.epeSuccessPayment()} element={<SuccessPaymentPage />} />

View File

@ -71,7 +71,10 @@ export default function CheckoutForm({
onSubmit={handleSubmit} onSubmit={handleSubmit}
> >
{children ? children : null} {children ? children : null}
<PaymentElement onReady={() => setFormReady(true)} /> <PaymentElement
options={{ terms: { card: "never" } }}
onReady={() => setFormReady(true)}
/>
<MainButton <MainButton
color="blue" color="blue"
disabled={isProcessing || !formReady} disabled={isProcessing || !formReady}

View File

@ -1,6 +1,7 @@
import styles from "./styles.module.css"; import styles from "./styles.module.css";
import Title from "@/components/Title"; import Title from "@/components/Title";
import { Gender, genders } from "@/data"; import { Gender, genders } from "@/data";
import routes from "@/routes";
import { actions } from "@/store"; import { actions } from "@/store";
import { useEffect } from "react"; import { useEffect } from "react";
import { useDispatch } from "react-redux"; import { useDispatch } from "react-redux";
@ -10,6 +11,7 @@ function GenderPage(): JSX.Element {
const dispatch = useDispatch(); const dispatch = useDispatch();
const navigate = useNavigate(); const navigate = useNavigate();
const { targetId } = useParams(); const { targetId } = useParams();
const pathName = window.location.pathname;
useEffect(() => { useEffect(() => {
const isShowTryApp = targetId === "i"; const isShowTryApp = targetId === "i";
@ -18,6 +20,9 @@ function GenderPage(): JSX.Element {
const selectGender = (gender: Gender) => { const selectGender = (gender: Gender) => {
dispatch(actions.questionnaire.update({ gender: gender.id })); dispatch(actions.questionnaire.update({ gender: gender.id }));
if (pathName === "/epe/gender") {
return navigate(routes.client.epeBirthdate());
}
navigate(`/questionnaire/profile/flowChoice`); navigate(`/questionnaire/profile/flowChoice`);
}; };

View File

@ -1,6 +1,6 @@
import EmailInput from "@/components/EmailEnterPage/EmailInput"; import EmailInput from "@/components/EmailEnterPage/EmailInput";
import styles from "./styles.module.css"; import styles from "./styles.module.css";
import { useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { actions, selectors } from "@/store"; import { actions, selectors } from "@/store";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
@ -14,16 +14,20 @@ import Title from "@/components/Title";
import NameInput from "@/components/EmailEnterPage/NameInput"; import NameInput from "@/components/EmailEnterPage/NameInput";
import { getZodiacSignByDate } from "@/services/zodiac-sign"; import { getZodiacSignByDate } from "@/services/zodiac-sign";
import { import {
ResponseGet,
ResponsePost, ResponsePost,
ResponsePostExistPaymentData, ResponsePostExistPaymentData,
} from "@/api/resources/SinglePayment"; } from "@/api/resources/SinglePayment";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import routes from "@/routes"; import routes from "@/routes";
import PaymentForm from "./PaymentForm"; import PaymentForm from "./PaymentForm";
import { getPriceCentsToDollars } from "@/services/price";
import { User } from "@/api/resources/User";
function PaymentWithEmailPage() { function PaymentWithEmailPage() {
const { t, i18n } = useTranslation(); const { t, i18n } = useTranslation();
const { signUp } = useAuth(); const tokenFromStore = useSelector(selectors.selectToken);
const { signUp, user: userFromStore } = useAuth();
const api = useApi(); const api = useApi();
const navigate = useNavigate(); const navigate = useNavigate();
const timezone = getClientTimezone(); const timezone = getClientTimezone();
@ -36,12 +40,14 @@ function PaymentWithEmailPage() {
const [isValidName, setIsValidName] = useState(true); const [isValidName, setIsValidName] = useState(true);
const [isDisabled, setIsDisabled] = useState(true); const [isDisabled, setIsDisabled] = useState(true);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [isLoadingPage, setIsLoadingPage] = useState(false);
const [isAuth, setIsAuth] = useState(false); const [isAuth, setIsAuth] = useState(false);
const [apiError, setApiError] = useState<ApiError | null>(null); const [apiError, setApiError] = useState<ApiError | null>(null);
const [error, setError] = useState<boolean>(false); const [error, setError] = useState<boolean>(false);
const [paymentIntent, setPaymentIntent] = useState< const [paymentIntent, setPaymentIntent] = useState<
ResponsePost | ResponsePostExistPaymentData | null ResponsePost | ResponsePostExistPaymentData | null
>(null); >(null);
const [currentProduct, setCurrentProduct] = useState<ResponseGet>();
const returnUrl = `${window.location.protocol}//${window.location.host}/payment/result/?type=epe`; const returnUrl = `${window.location.protocol}//${window.location.host}/payment/result/?type=epe`;
useEffect(() => { useEffect(() => {
@ -108,25 +114,30 @@ function PaymentWithEmailPage() {
} }
}; };
const handleClick = async () => { const getCurrentProduct = async (token: string) => {
const authData = await authorization();
if (!authData) {
return;
}
const { user, token } = authData;
console.log(token);
const productsSinglePayment = await api.getSinglePaymentProducts({ const productsSinglePayment = await api.getSinglePaymentProducts({
token, token,
}); });
const { productId } = productsSinglePayment[0]; const currentProduct = productsSinglePayment.find(
const createSinglePayment = await api.createSinglePayment({ (product) => product.key === "compatibility.pdf"
);
return currentProduct;
};
const createSinglePayment = async (
user: User,
productId: string,
token: string,
email: string,
name: string | null
) => {
return await api.createSinglePayment({
token, token,
data: { data: {
user: { user: {
id: `${user?.id}`, id: `${user?.id}`,
email, email,
name, name: name || "",
sign: user?.profile?.sign?.sign || getZodiacSignByDate(birthday), sign: user?.profile?.sign?.sign || getZodiacSignByDate(birthday),
age: user?.profile?.age?.years || 1, age: user?.profile?.age?.years || 1,
}, },
@ -140,25 +151,94 @@ function PaymentWithEmailPage() {
return_url: returnUrl, return_url: returnUrl,
}, },
}); });
setPaymentIntent(createSinglePayment); };
const handleClick = async () => {
const authData = await authorization();
if (!authData) {
return;
}
const { user, token } = authData;
const currentProduct = await getCurrentProduct(token);
if (!currentProduct) {
setError(true);
return;
}
setCurrentProduct(currentProduct);
const { productId } = currentProduct;
const paymentIntent = await createSinglePayment(
user,
productId,
token,
email,
name
);
setPaymentIntent(paymentIntent);
setIsLoading(false); setIsLoading(false);
if ("payment" in createSinglePayment) { if ("payment" in paymentIntent) {
if (createSinglePayment.payment.status === "paid") if (paymentIntent.payment.status === "paid")
return navigate(routes.client.epeSuccessPayment()); return navigate(routes.client.epeSuccessPayment());
return navigate(routes.client.epeFailPayment()); return navigate(routes.client.epeFailPayment());
} }
}; };
const handleAuthUser = useCallback(async () => {
if (!tokenFromStore.length || !userFromStore) {
return;
}
setIsLoadingPage(true);
const currentProduct = await getCurrentProduct(tokenFromStore);
if (!currentProduct) {
setError(true);
return;
}
setCurrentProduct(currentProduct);
const { productId } = currentProduct;
const paymentIntent = await createSinglePayment(
userFromStore,
productId,
tokenFromStore,
userFromStore.email,
userFromStore.profile.full_name
);
setPaymentIntent(paymentIntent);
setIsLoadingPage(false);
setIsLoading(false);
if ("payment" in paymentIntent) {
if (paymentIntent.payment.status === "paid")
return navigate(routes.client.epeSuccessPayment());
return navigate(routes.client.epeFailPayment());
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
handleAuthUser();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return ( return (
<div className={`${styles.page} page`}> <div className={`${styles.page} page`}>
{paymentIntent && "paymentIntent" in paymentIntent && ( {isLoadingPage && <Loader color={LoaderColor.Black} />}
<PaymentForm {!isLoadingPage &&
stripePublicKey={paymentIntent.paymentIntent.data.public_key} paymentIntent &&
clientSecret={paymentIntent.paymentIntent.data.client_secret} "paymentIntent" in paymentIntent &&
returnUrl={returnUrl} !!tokenFromStore.length && (
/> <>
)} <Title variant="h1" className={styles.title}>
{!paymentIntent && ( {getPriceCentsToDollars(currentProduct?.amount || 0)}$
</Title>
<PaymentForm
stripePublicKey={paymentIntent.paymentIntent.data.public_key}
clientSecret={paymentIntent.paymentIntent.data.client_secret}
returnUrl={returnUrl}
/>
</>
)}
{(!tokenFromStore || !paymentIntent) && !isLoadingPage && (
<> <>
<NameInput <NameInput
value={name} value={name}

View File

@ -122,6 +122,7 @@ const routes = {
advisors: () => [host, "advisors"].join("/"), advisors: () => [host, "advisors"].join("/"),
advisorChat: (id: number) => [host, "advisors", id].join("/"), advisorChat: (id: number) => [host, "advisors", id].join("/"),
// Email - Pay - Email // Email - Pay - Email
epeGender: () => [host, "epe", "gender"].join("/"),
epeBirthdate: () => [host, "epe", "birthdate"].join("/"), epeBirthdate: () => [host, "epe", "birthdate"].join("/"),
epePayment: () => [host, "epe", "payment"].join("/"), epePayment: () => [host, "epe", "payment"].join("/"),
epeSuccessPayment: () => [host, "epe", "success-payment"].join("/"), epeSuccessPayment: () => [host, "epe", "success-payment"].join("/"),

View File

@ -22,3 +22,7 @@ export const getPriceFromTrial = (trial: ITrial | null) => {
} }
return (trial.price_cents === 100 ? 99 : trial.price_cents || 0) / 100; return (trial.price_cents === 100 ? 99 : trial.price_cents || 0) / 100;
}; };
export const getPriceCentsToDollars = (cents: number) => {
return (cents / 100).toFixed(2);
};