Merge branch 'edits' into 'develop'

edits

See merge request witapp/aura-webapp!153
This commit is contained in:
Daniil Chemerkin 2024-06-01 22:39:58 +00:00
commit 8dac39a275
16 changed files with 188 additions and 137 deletions

View File

@ -69,7 +69,7 @@
</head> </head>
<body> <body>
<!-- Yandex.Metrika counter --> <!-- Yandex.Metrika counter -->
<script type="text/javascript" async="async"> <script type="text/javascript">
(function (m, e, t, r, i, k, a) { (function (m, e, t, r, i, k, a) {
m[i] = m[i] =
m[i] || m[i] ||

View File

@ -49,6 +49,8 @@ const api = {
getSubscriptionPlans: createMethod<SubscriptionPlans.Payload, SubscriptionPlans.Response>(SubscriptionPlans.createRequest), getSubscriptionPlans: createMethod<SubscriptionPlans.Payload, SubscriptionPlans.Response>(SubscriptionPlans.createRequest),
getSubscriptionCheckout: createMethod<SubscriptionCheckout.Payload, SubscriptionCheckout.Response>(SubscriptionCheckout.createRequest), getSubscriptionCheckout: createMethod<SubscriptionCheckout.Payload, SubscriptionCheckout.Response>(SubscriptionCheckout.createRequest),
getSubscriptionStatus: createMethod<SubscriptionStatus.Payload, SubscriptionStatus.Response>(SubscriptionStatus.createRequest), getSubscriptionStatus: createMethod<SubscriptionStatus.Payload, SubscriptionStatus.Response>(SubscriptionStatus.createRequest),
// new get subscription status
getSubscriptionStatusNew: createMethod<SubscriptionStatus.Payload, SubscriptionStatus.ResponseNew>(SubscriptionStatus.createRequestNew),
getAiCompatCategories: createMethod<AICompatCategories.Payload, AICompatCategories.Response>(AICompatCategories.createRequest), getAiCompatCategories: createMethod<AICompatCategories.Payload, AICompatCategories.Response>(AICompatCategories.createRequest),
getAiCompat: createMethod<AICompats.Payload, AICompats.Response>(AICompats.createRequest), getAiCompat: createMethod<AICompats.Payload, AICompats.Response>(AICompats.createRequest),
getAiRequest: createMethod<AIRequests.Payload, AIRequests.Response>(AIRequests.createRequest), getAiRequest: createMethod<AIRequests.Payload, AIRequests.Response>(AIRequests.createRequest),

View File

@ -14,3 +14,12 @@ export const createRequest = ({ token }: Payload): Request => {
const url = new URL(routes.server.subscriptionStatus()) const url = new URL(routes.server.subscriptionStatus())
return new Request(url, { method: 'GET', headers: getAuthHeaders(token) }) return new Request(url, { method: 'GET', headers: getAuthHeaders(token) })
} }
export interface ResponseNew {
subscription: boolean;
}
export const createRequestNew = ({ token }: Payload): Request => {
const url = new URL(routes.server.subscriptionStatusNew())
return new Request(url, { method: 'GET', headers: getAuthHeaders(token) })
}

View File

@ -222,10 +222,13 @@ function App(): JSX.Element {
token, token,
}); });
if (has_subscription && user) { const { subscription: subscriptionStatusNew } =
await api.getSubscriptionStatusNew({ token });
if ((has_subscription || subscriptionStatusNew) && user) {
return dispatch(actions.status.update("subscribed")); return dispatch(actions.status.update("subscribed"));
} }
if (!has_subscription && user) { if (!has_subscription && !subscriptionStatusNew && user) {
return dispatch(actions.status.update("unsubscribed")); return dispatch(actions.status.update("unsubscribed"));
} }
if (!user) { if (!user) {

View File

@ -15,4 +15,5 @@
.image { .image {
position: absolute; position: absolute;
bottom: 8px; bottom: 8px;
z-index: -1;
} }

View File

@ -1,6 +1,5 @@
import { IAnswer } from "@/data"; import { IAnswer } from "@/data";
import styles from "./styles.module.css"; import styles from "./styles.module.css";
import { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { actions, selectors } from "@/store"; import { actions, selectors } from "@/store";
@ -20,34 +19,36 @@ function MultiplyAnswers({ answers }: IMultiplyAnswersProps) {
const { currentlyAffecting, gender } = useSelector( const { currentlyAffecting, gender } = useSelector(
selectors.selectQuestionnaire selectors.selectQuestionnaire
); );
const [selectedAnswers, setSelectedAnswers] = useState<string[]>(
currentlyAffecting?.split("$") || []
);
const handleClick = (answer: IAnswer) => { const handleClick = (answer: IAnswer) => {
if (selectedAnswers.includes(answer.id)) { if (currentlyAffecting.includes(`$${answer.id}`)) {
return setSelectedAnswers((prevState) => return dispatch(
prevState.filter((item) => item !== answer.id) actions.questionnaire.update({
currentlyAffecting: currentlyAffecting.replace(`$${answer.id}`, ""),
})
); );
} }
if (answer.id === "none_of_these") { if (answer.id === "none_of_these") {
return setSelectedAnswers([answer.id]); return dispatch(
actions.questionnaire.update({
currentlyAffecting: `$${answer.id}`,
})
);
} }
if ( if (
selectedAnswers.includes("none_of_these") && currentlyAffecting.includes("$none_of_these") &&
answer.id !== "none_of_these" answer.id !== "none_of_these"
) { ) {
return; return;
} }
return setSelectedAnswers((prevState) => [...prevState, answer.id]); return dispatch(
actions.questionnaire.update({
currentlyAffecting: `${currentlyAffecting}$${answer.id}`,
})
);
}; };
const handleNext = () => { const handleNext = () => {
dispatch(
actions.questionnaire.update({
currentlyAffecting: selectedAnswers.join("$"),
})
);
navigate( navigate(
`${routes.client.questionnaireV1()}/relationships/partnerPriority` `${routes.client.questionnaireV1()}/relationships/partnerPriority`
); );
@ -55,30 +56,35 @@ function MultiplyAnswers({ answers }: IMultiplyAnswersProps) {
return ( return (
<> <>
{answers.map((answer, index) => ( <div className={styles["multiply-answers"]}>
<Answer {answers.map((answer, index) => (
key={index} <Answer
answer={answer} key={index}
disabled={ answer={answer}
selectedAnswers.includes("none_of_these") && disabled={
answer.id !== "none_of_these" currentlyAffecting.includes("$none_of_these") &&
} answer.id !== "none_of_these"
classNameContainer={ }
selectedAnswers.includes(answer.id) ? styles["answer-active"] : "" classNameContainer={
} currentlyAffecting.includes(`${answer.id}`)
type="multiply" ? styles["answer-active"]
active={selectedAnswers.includes(answer.id)} : ""
gender={gender} }
onClick={() => handleClick(answer)} type="multiply"
/> active={currentlyAffecting.includes(`${answer.id}`)}
))} gender={gender}
<QuestionnaireGreenButton onClick={() => handleClick(answer)}
className={styles.button} />
onClick={handleNext} ))}
disabled={!selectedAnswers.length} </div>
> {!!currentlyAffecting.length && (
{t("next")} <QuestionnaireGreenButton
</QuestionnaireGreenButton> className={styles.button}
onClick={handleNext}
>
{t("next")}
</QuestionnaireGreenButton>
)}
</> </>
); );
} }

View File

@ -1,4 +1,19 @@
.multiply-answers {
display: flex;
flex-direction: column;
align-items: center;
gap: 11px;
z-index: 0;
padding-bottom: 116px;
width: 100%;
}
.button { .button {
position: fixed;
bottom: calc(0dvh + 16px);
width: calc(100% - 64px);
max-width: 396px;
margin-top: 8px; margin-top: 8px;
} }

View File

@ -49,6 +49,7 @@
align-items: center; align-items: center;
gap: 11px; gap: 11px;
margin-top: 28px; margin-top: 28px;
z-index: 0;
} }
.description { .description {

View File

@ -54,7 +54,11 @@ function OnboardingPage() {
return ( return (
<section className={`${styles.page} page`}> <section className={`${styles.page} page`}>
<img className={styles.image} src="/leo.png" alt="Leo" /> <img
className={`${styles.image} ${styles[periodClassName]}`}
src="/leo.png"
alt="Leo"
/>
{onboardingTitles[activeIndexTitle] && ( {onboardingTitles[activeIndexTitle] && (
<Title className={`${styles.title} ${styles[periodClassName]}`}> <Title className={`${styles.title} ${styles[periodClassName]}`}>
{onboardingTitles[activeIndexTitle]} {onboardingTitles[activeIndexTitle]}

View File

@ -16,6 +16,7 @@
margin-top: 100px; margin-top: 100px;
width: 100%; width: 100%;
max-width: 273px; max-width: 273px;
transition: opacity 1s;
} }
.title { .title {

View File

@ -20,15 +20,17 @@
} }
.image-container { .image-container {
display: flex; display: grid;
justify-content: center;
align-items: center; align-items: center;
justify-items: center;
grid-template-columns: calc(50% - 30px) min-content calc(50% - 30px);
width: 100%; width: 100%;
gap: 32px; gap: 6px;
} }
.image-container > img { .image-container > img {
max-width: 118px; /* max-width: 118px; */
max-height: 196px;
} }
.compatibility-description-container { .compatibility-description-container {

View File

@ -18,7 +18,7 @@
border-top-left-radius: 15px; border-top-left-radius: 15px;
border-top-right-radius: 15px; border-top-right-radius: 15px;
display: grid; display: grid;
grid-template-columns: 1fr min-content 1fr; grid-template-columns: calc(50% - 28px) min-content calc(50% - 28px);
align-items: center; align-items: center;
gap: 4px; gap: 4px;
padding-top: 10px; padding-top: 10px;
@ -35,6 +35,8 @@
.image-container > img { .image-container > img {
height: 196px; height: 196px;
width: 100%;
object-fit: contain;
} }
.image-container > p { .image-container > p {

View File

@ -10,9 +10,7 @@ import { SinglePayment, useApi, useApiCall } from "@/api";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { selectors } from "@/store"; import { selectors } from "@/store";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { import { ResponsePost } from "@/api/resources/SinglePayment";
ResponsePost,
} from "@/api/resources/SinglePayment";
import { createSinglePayment } from "@/services/singlePayment"; import { createSinglePayment } from "@/services/singlePayment";
import Modal from "@/components/Modal"; import Modal from "@/components/Modal";
import PaymentForm from "@/components/pages/SinglePaymentPage/PaymentForm"; import PaymentForm from "@/components/pages/SinglePaymentPage/PaymentForm";
@ -25,9 +23,7 @@ function AddConsultationPage() {
const api = useApi(); const api = useApi();
const tokenFromStore = useSelector(selectors.selectToken); const tokenFromStore = useSelector(selectors.selectToken);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [paymentIntent, setPaymentIntent] = useState< const [paymentIntent, setPaymentIntent] = useState<ResponsePost | null>(null);
ResponsePost | null
>(null);
const [isError, setIsError] = useState(false); const [isError, setIsError] = useState(false);
const returnUrl = `${window.location.protocol}//${ const returnUrl = `${window.location.protocol}//${
window.location.host window.location.host
@ -45,29 +41,34 @@ function AddConsultationPage() {
); );
const handleClick = async () => { const handleClick = async () => {
if (!userFromStore || !currentProduct) return; try {
setIsLoading(true); if (!userFromStore || !currentProduct) return;
const { _id, key } = currentProduct; setIsLoading(true);
const paymentInfo = { const { _id, key } = currentProduct;
productId: _id, const paymentInfo = {
key, productId: _id,
}; key,
const paymentIntent = await createSinglePayment( };
userFromStore, const paymentIntent = await createSinglePayment(
paymentInfo, userFromStore,
tokenFromStore, paymentInfo,
userFromStore.email, tokenFromStore,
userFromStore.profile.full_name, userFromStore.email,
userFromStore.profile.birthday, userFromStore.profile.full_name,
returnUrl, userFromStore.profile.birthday,
api returnUrl,
); api
setPaymentIntent(paymentIntent); );
setIsLoading(false); setPaymentIntent(paymentIntent);
if ("payment" in paymentIntent) { if ("payment" in paymentIntent) {
if (paymentIntent.payment.status === "paid") if (paymentIntent.payment.status === "paid")
return navigate(routes.client.getInformationPartner()); return navigate(routes.client.getInformationPartner());
return setIsError(true); return setIsError(true);
}
} catch (error) {
setIsError(true);
} finally {
setIsLoading(false);
} }
}; };

View File

@ -9,9 +9,7 @@ import FooterButton from "../../components/FooterButton";
import routes from "@/routes"; import routes from "@/routes";
import PaymentAddress from "../../components/PaymentAddress"; import PaymentAddress from "../../components/PaymentAddress";
import { createSinglePayment } from "@/services/singlePayment"; import { createSinglePayment } from "@/services/singlePayment";
import { import { ResponsePost } from "@/api/resources/SinglePayment";
ResponsePost,
} from "@/api/resources/SinglePayment";
import { useAuth } from "@/auth"; import { useAuth } from "@/auth";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { selectors } from "@/store"; import { selectors } from "@/store";
@ -26,9 +24,7 @@ function AddReportPage() {
const { user: userFromStore } = useAuth(); const { user: userFromStore } = useAuth();
const api = useApi(); const api = useApi();
const tokenFromStore = useSelector(selectors.selectToken); const tokenFromStore = useSelector(selectors.selectToken);
const [paymentIntent, setPaymentIntent] = useState< const [paymentIntent, setPaymentIntent] = useState<ResponsePost | null>(null);
ResponsePost | null
>(null);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [isError, setIsError] = useState(false); const [isError, setIsError] = useState(false);
const [activeOffer, setActiveOffer] = useState(signUpOffers[0]); const [activeOffer, setActiveOffer] = useState(signUpOffers[0]);
@ -48,31 +44,36 @@ function AddReportPage() {
}; };
const handleClick = async () => { const handleClick = async () => {
if (!userFromStore || !activeOffer) return; try {
const currentProduct = getCurrentProduct(activeOffer?.productKey); if (!userFromStore || !activeOffer) return;
if (!currentProduct) return; const currentProduct = getCurrentProduct(activeOffer?.productKey);
setIsLoading(true); if (!currentProduct) return;
const { _id, key } = currentProduct; setIsLoading(true);
const paymentInfo = { const { _id, key } = currentProduct;
productId: _id, const paymentInfo = {
key, productId: _id,
}; key,
const paymentIntent = await createSinglePayment( };
userFromStore, const paymentIntent = await createSinglePayment(
paymentInfo, userFromStore,
tokenFromStore, paymentInfo,
userFromStore.email, tokenFromStore,
userFromStore.profile.full_name, userFromStore.email,
userFromStore.profile.birthday, userFromStore.profile.full_name,
returnUrl, userFromStore.profile.birthday,
api returnUrl,
); api
setPaymentIntent(paymentIntent); );
setIsLoading(false); setPaymentIntent(paymentIntent);
if ("payment" in paymentIntent) { if ("payment" in paymentIntent) {
if (paymentIntent.payment.status === "paid") if (paymentIntent.payment.status === "paid")
return navigate(routes.client.unlimitedReadings()); return navigate(routes.client.unlimitedReadings());
return setIsError(true); return setIsError(true);
}
} catch (error) {
setIsError(true);
} finally {
setIsLoading(false);
} }
}; };

View File

@ -16,9 +16,7 @@ import { selectors } from "@/store";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { createSinglePayment } from "@/services/singlePayment"; import { createSinglePayment } from "@/services/singlePayment";
import Loader, { LoaderColor } from "@/components/Loader"; import Loader, { LoaderColor } from "@/components/Loader";
import { import { ResponsePost } from "@/api/resources/SinglePayment";
ResponsePost,
} from "@/api/resources/SinglePayment";
import Modal from "@/components/Modal"; import Modal from "@/components/Modal";
import { getPriceCentsToDollars } from "@/services/price"; import { getPriceCentsToDollars } from "@/services/price";
import PaymentForm from "@/components/pages/SinglePaymentPage/PaymentForm"; import PaymentForm from "@/components/pages/SinglePaymentPage/PaymentForm";
@ -40,9 +38,7 @@ function UnlimitedReadingsPage() {
const api = useApi(); const api = useApi();
const tokenFromStore = useSelector(selectors.selectToken); const tokenFromStore = useSelector(selectors.selectToken);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [paymentIntent, setPaymentIntent] = useState< const [paymentIntent, setPaymentIntent] = useState<ResponsePost | null>(null);
ResponsePost | null
>(null);
const [isError, setIsError] = useState(false); const [isError, setIsError] = useState(false);
const returnUrl = `${window.location.protocol}//${ const returnUrl = `${window.location.protocol}//${
window.location.host window.location.host
@ -60,29 +56,34 @@ function UnlimitedReadingsPage() {
); );
const handleClick = async () => { const handleClick = async () => {
if (!userFromStore || !currentProduct) return; try {
setIsLoading(true); if (!userFromStore || !currentProduct) return;
const { _id, key } = currentProduct; setIsLoading(true);
const paymentInfo = { const { _id, key } = currentProduct;
productId: _id, const paymentInfo = {
key, productId: _id,
}; key,
const paymentIntent = await createSinglePayment( };
userFromStore, const paymentIntent = await createSinglePayment(
paymentInfo, userFromStore,
tokenFromStore, paymentInfo,
userFromStore.email, tokenFromStore,
userFromStore.profile.full_name, userFromStore.email,
userFromStore.profile.birthday, userFromStore.profile.full_name,
returnUrl, userFromStore.profile.birthday,
api returnUrl,
); api
setPaymentIntent(paymentIntent); );
setIsLoading(false); setPaymentIntent(paymentIntent);
if ("payment" in paymentIntent) { if ("payment" in paymentIntent) {
if (paymentIntent.payment.status === "paid") if (paymentIntent.payment.status === "paid")
return navigate(routes.client.addConsultation()); return navigate(routes.client.addConsultation());
return setIsError(true); return setIsError(true);
}
} catch (error) {
setIsError(true);
} finally {
setIsLoading(false);
} }
}; };

View File

@ -225,6 +225,8 @@ const routes = {
[apiHost, prefix, "user", "subscription_receipts", "status.json"].join( [apiHost, prefix, "user", "subscription_receipts", "status.json"].join(
"/" "/"
), ),
subscriptionStatusNew: () =>
[dApiHost, "users", "subscription", "status"].join("/"),
subscriptionReceipts: () => subscriptionReceipts: () =>
[apiHost, prefix, "user", "subscription_receipts.json"].join("/"), [apiHost, prefix, "user", "subscription_receipts.json"].join("/"),
subscriptionReceipt: (id: string) => subscriptionReceipt: (id: string) =>