feat: add breath result page and fix numbers problem
This commit is contained in:
parent
0e430e472f
commit
f650878f3e
@ -16,7 +16,8 @@ import {
|
||||
PaymentIntents,
|
||||
AICompatCategories,
|
||||
AICompats,
|
||||
AIRequests
|
||||
AIRequests,
|
||||
UserCallbacks
|
||||
} from './resources'
|
||||
|
||||
const api = {
|
||||
@ -39,6 +40,8 @@ const api = {
|
||||
getAiCompatCategories: createMethod<AICompatCategories.Payload, AICompatCategories.Response>(AICompatCategories.createRequest),
|
||||
getAiCompat: createMethod<AICompats.Payload, AICompats.Response>(AICompats.createRequest),
|
||||
getAiRequest: createMethod<AIRequests.Payload, AIRequests.Response>(AIRequests.createRequest),
|
||||
createUserCallbacks: createMethod<UserCallbacks.PayloadPost, UserCallbacks.Response>(UserCallbacks.createRequestPost),
|
||||
getUserCallbacks: createMethod<UserCallbacks.PayloadGet, UserCallbacks.Response>(UserCallbacks.createRequestGet),
|
||||
}
|
||||
|
||||
export type ApiContextValue = typeof api
|
||||
|
||||
48
src/api/resources/UserCallbacks.ts
Normal file
48
src/api/resources/UserCallbacks.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import routes from "@/routes";
|
||||
import { getAuthHeaders } from "../utils";
|
||||
|
||||
export interface PayloadGet {
|
||||
id: string;
|
||||
token: string;
|
||||
}
|
||||
|
||||
export interface PayloadPost {
|
||||
data: {
|
||||
user_callback: {
|
||||
kind: string;
|
||||
};
|
||||
};
|
||||
token: string;
|
||||
}
|
||||
|
||||
export interface Response {
|
||||
user_callback: IUserCallbacks;
|
||||
}
|
||||
|
||||
export interface IUserCallbacks {
|
||||
id: string;
|
||||
user_id: number;
|
||||
kind: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
prev_stat_changes: IPrevStateChanges[];
|
||||
description: string;
|
||||
is_complete: boolean;
|
||||
}
|
||||
|
||||
export interface IPrevStateChanges {
|
||||
stat: string;
|
||||
value: number;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export const createRequestPost = ({ data, token }: PayloadPost): Request => {
|
||||
const url = new URL(routes.server.createUserCallbacks());
|
||||
const body = JSON.stringify(data);
|
||||
return new Request(url, { method: "POST", headers: getAuthHeaders(token), body });
|
||||
};
|
||||
|
||||
export const createRequestGet = ({ id, token }: PayloadGet): Request => {
|
||||
const url = new URL(routes.server.getUserCallbacks(id));
|
||||
return new Request(url, { method: "GET", headers: getAuthHeaders(token) });
|
||||
};
|
||||
@ -15,3 +15,4 @@ export * as PaymentIntents from './UserPaymentIntents'
|
||||
export * as AICompatCategories from './AICompatCategories'
|
||||
export * as AICompats from './AICompats'
|
||||
export * as AIRequests from './AIRequests'
|
||||
export * as UserCallbacks from './UserCallbacks'
|
||||
|
||||
@ -28,6 +28,7 @@ import BreathPage from '../BreathPage'
|
||||
import PriceListPage from '../PriceListPage'
|
||||
import CompatResultPage from '../CompatResultPage'
|
||||
import HomePage from '../HomePage'
|
||||
import UserCallbacksPage from '../UserCallbacksPage'
|
||||
|
||||
function App(): JSX.Element {
|
||||
const [isSpecialOfferOpen, setIsSpecialOfferOpen] = useState<boolean>(false)
|
||||
@ -56,6 +57,7 @@ function App(): JSX.Element {
|
||||
<Route path={routes.client.breath()} element={<BreathPage />} />
|
||||
<Route path={routes.client.priceList()} element={<PriceListPage />} />
|
||||
<Route path={routes.client.home()} element={<HomePage />} />
|
||||
<Route path={routes.client.breathResult()} element={<UserCallbacksPage />} />
|
||||
<Route element={<PrivateOutlet />}>
|
||||
<Route path={routes.client.subscription()} element={<SubscriptionPage />} />
|
||||
<Route path={routes.client.paymentMethod()} element={<PaymentPage />} />
|
||||
|
||||
@ -11,7 +11,7 @@ function BreathCircle(): JSX.Element {
|
||||
const navigate = useNavigate()
|
||||
const [text, setText] = useState(t(''))
|
||||
const [counter, setCounter] = useState(0)
|
||||
const handleNext = () => navigate(routes.client.compatibility())
|
||||
const handleNext = () => navigate(routes.client.breathResult())
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@ -14,7 +14,7 @@ const colors: Record<string, string> = {
|
||||
}
|
||||
|
||||
const valueFormatter = (value: number) => {
|
||||
return `${value * 100}%`
|
||||
return `${(value * 100).toFixed()}%`
|
||||
}
|
||||
|
||||
function EnergyValues({ className, values }: IEnergyValues): JSX.Element {
|
||||
|
||||
@ -8,7 +8,11 @@
|
||||
.energy-value {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 2px;
|
||||
gap: 4px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.energy-value__label {
|
||||
font-weight: 500;
|
||||
}
|
||||
@ -2,16 +2,9 @@ import { useNavigate } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import routes from "@/routes";
|
||||
import styles from "./styles.module.css";
|
||||
import { useSelector } from "react-redux";
|
||||
import { selectors } from "@/store";
|
||||
import {
|
||||
getCategoryIdByZodiacSign,
|
||||
getZodiacSignByDate,
|
||||
} from "@/services/zodiac-sign";
|
||||
import { useApi, useApiCall } from "@/api";
|
||||
import { Asset } from "@/api/resources/Assets";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { getRandomArbitrary } from "@/services/random-value";
|
||||
import BlurringSubstrate from "../BlurringSubstrate";
|
||||
import EnergyValues from "../EnergyValues";
|
||||
import { UserAura } from "@/api/resources/Auras";
|
||||
@ -39,19 +32,19 @@ function HomePage(): JSX.Element {
|
||||
navigate(routes.client.breath());
|
||||
};
|
||||
|
||||
const { i18n } = useTranslation();
|
||||
const locale = i18n.language;
|
||||
const birthdate = useSelector(selectors.selectBirthdate);
|
||||
const zodiacSign = getZodiacSignByDate(birthdate);
|
||||
// const { i18n } = useTranslation();
|
||||
// const locale = i18n.language;
|
||||
// const birthdate = useSelector(selectors.selectBirthdate);
|
||||
// const zodiacSign = getZodiacSignByDate(birthdate);
|
||||
const [asset, setAsset] = useState<Asset>();
|
||||
const api = useApi();
|
||||
|
||||
const assetsData = useCallback(async () => {
|
||||
const { asset_categories } = await api.getAssetCategories({ locale });
|
||||
const categoryId = getCategoryIdByZodiacSign(zodiacSign, asset_categories);
|
||||
// const { asset_categories } = await api.getAssetCategories({ locale });
|
||||
// const categoryId = getCategoryIdByZodiacSign(zodiacSign, asset_categories);
|
||||
const { assets } = await api.getAssets({ category: String("10" || "1") });
|
||||
return assets;
|
||||
}, [api, locale, zodiacSign]);
|
||||
}, [api]);
|
||||
|
||||
const {
|
||||
data: assets,
|
||||
@ -74,9 +67,6 @@ function HomePage(): JSX.Element {
|
||||
// isPending
|
||||
} = useApiCall<UserAura>(auraData);
|
||||
|
||||
console.log(aura);
|
||||
|
||||
|
||||
return (
|
||||
<section
|
||||
className={`${styles.page} page`}
|
||||
|
||||
@ -16,7 +16,7 @@ function PriceListPage(): JSX.Element {
|
||||
|
||||
const email = useSelector(selectors.selectEmail)
|
||||
const handleNext = () => {
|
||||
navigate(routes.client.breath())
|
||||
navigate(routes.client.home())
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
79
src/components/UserCallbacksPage/index.tsx
Normal file
79
src/components/UserCallbacksPage/index.tsx
Normal file
@ -0,0 +1,79 @@
|
||||
import Title from "../Title";
|
||||
import styles from "./styles.module.css";
|
||||
import { useCallback, useState } from "react";
|
||||
import { UserCallbacks, useApi, useApiCall } from "@/api";
|
||||
import { IPrevStateChanges } from "@/api/resources/UserCallbacks";
|
||||
|
||||
function UserCallbacksPage(): JSX.Element {
|
||||
const token =
|
||||
"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOjIzNjEyLCJpYXQiOjE2OTM0MTg5MTAsImV4cCI6MTcwMjA1ODkxMCwianRpIjoiNzg5MjkwYWItODg0YS00MGUyLTkyNjEtOWI2OGEyNjkwNmE0IiwiZW1haWwiOiJvdGhlckBleGFtcGxlLmNvbSIsInN0YXRlIjoicHJvdmVuIiwibG9jIjoiZW4iLCJ0eiI6LTI4ODAwLCJ0eXBlIjoiZW1haWwiLCJpc3MiOiJjb20ubGlmZS5hdXJhIn0.J2ocWIv5jKzuKMcwMgWMiNMyGg5qLlMAeln-bQm_9lw";
|
||||
const api = useApi();
|
||||
const [text, setText] = useState("Loading...");
|
||||
const [statChanges, setStatChanges] = useState([] as IPrevStateChanges[]);
|
||||
|
||||
const createCallback = useCallback(async () => {
|
||||
const data: UserCallbacks.PayloadPost = {
|
||||
data: {
|
||||
user_callback: {
|
||||
kind: "breathing_end",
|
||||
},
|
||||
},
|
||||
token,
|
||||
};
|
||||
const createCallbackRequest = await api.createUserCallbacks(data);
|
||||
setStatChanges(createCallbackRequest.user_callback.prev_stat_changes);
|
||||
if (!createCallbackRequest.user_callback.is_complete) {
|
||||
const getUserCallbacksRequest = async () => {
|
||||
const getCallback = await api.getUserCallbacks({
|
||||
id: createCallbackRequest.user_callback.id,
|
||||
token,
|
||||
});
|
||||
if (!getCallback.user_callback.is_complete) {
|
||||
setTimeout(getUserCallbacksRequest, 3000);
|
||||
}
|
||||
setText(getCallback.user_callback.description || "Loading...");
|
||||
return getCallback.user_callback;
|
||||
};
|
||||
return await getUserCallbacksRequest();
|
||||
}
|
||||
|
||||
return createCallbackRequest.user_callback;
|
||||
}, [api]);
|
||||
|
||||
useApiCall<UserCallbacks.IUserCallbacks>(createCallback);
|
||||
|
||||
return (
|
||||
<section className={`${styles.page} page`}>
|
||||
<div className={styles["title-container"]}>
|
||||
<Title variant="h3" className={styles.percent}>
|
||||
<>
|
||||
<p>Well done!</p>
|
||||
<p>Your results has changes...</p>
|
||||
</>
|
||||
</Title>
|
||||
{/* <Title variant="h2">{t("you_and", { user: rightUser.name })}</Title> */}
|
||||
</div>
|
||||
<div className={styles["result-container"]}>
|
||||
<div className={styles["result-container__values"]}>
|
||||
{statChanges.map((change, index) => (
|
||||
<div className={styles["result-container__value"]} key={index}>
|
||||
<span className={styles["result-container__value-label"]}>
|
||||
{change.label}
|
||||
</span>
|
||||
<span
|
||||
style={{ color: change.value > 0 ? "#00ea00" : "red" }}
|
||||
className={styles["result-container__value-value"]}
|
||||
>
|
||||
{change.value > 0 ? "+" : ""}
|
||||
{(change.value * 100).toFixed()}%
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<p className={styles["result-container__text"]}>{text}</p>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default UserCallbacksPage;
|
||||
37
src/components/UserCallbacksPage/styles.module.css
Normal file
37
src/components/UserCallbacksPage/styles.module.css
Normal file
@ -0,0 +1,37 @@
|
||||
.page {
|
||||
position: relative;
|
||||
height: calc(100vh - 50px);
|
||||
max-height: -webkit-fill-available;
|
||||
flex: auto;
|
||||
background-color: #000;
|
||||
color: #bababb;
|
||||
overflow-y: scroll;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.result-container__values {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
max-width: 250px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.result-container__value {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.result-container__value-label {
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.result-container__value-value {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.result-container__text {
|
||||
line-height: 1.2;
|
||||
margin-top: 32px;
|
||||
}
|
||||
@ -25,6 +25,7 @@ const routes = {
|
||||
breath: () => [host, 'breath'].join('/'),
|
||||
priceList: () => [host, 'price-list'].join('/'),
|
||||
home: () => [host, 'home'].join('/'),
|
||||
breathResult: () => [host, 'breath', 'result'].join('/'),
|
||||
},
|
||||
server: {
|
||||
user: () => [apiHost, prefix, 'user.json'].join('/'),
|
||||
@ -60,6 +61,7 @@ export const entrypoints = [
|
||||
routes.client.breath(),
|
||||
routes.client.compatibilityResult(),
|
||||
routes.client.home(),
|
||||
routes.client.breathResult(),
|
||||
]
|
||||
export const isEntrypoint = (path: string) => entrypoints.includes(path)
|
||||
export const isNotEntrypoint = (path: string) => !isEntrypoint(path)
|
||||
@ -81,6 +83,7 @@ export const withoutFooterRoutes = [
|
||||
routes.client.priceList(),
|
||||
routes.client.compatibilityResult(),
|
||||
routes.client.home(),
|
||||
routes.client.breathResult(),
|
||||
]
|
||||
export const hasNoFooter = (path: string) => !withoutFooterRoutes.includes(path)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user