feat: add besties horoscope result page
This commit is contained in:
parent
0f6f8f7e72
commit
16d79d3f3a
@ -22,7 +22,8 @@ import {
|
||||
Zodiacs,
|
||||
GoogleAuth,
|
||||
SubscriptionPlans,
|
||||
AppleAuth
|
||||
AppleAuth,
|
||||
AIRequestsV2
|
||||
} from './resources'
|
||||
|
||||
const api = {
|
||||
@ -52,6 +53,8 @@ const api = {
|
||||
getUserCallbacks: createMethod<UserCallbacks.PayloadGet, UserCallbacks.Response>(UserCallbacks.createRequestGet),
|
||||
getTranslations: createMethod<Translations.Payload, Translations.Response>(Translations.createRequest),
|
||||
getZodiacs: createMethod<Zodiacs.Payload, Zodiacs.Response>(Zodiacs.createRequest),
|
||||
AIRequestsV2: createMethod<AIRequestsV2.Payload, AIRequestsV2.Response>(AIRequestsV2.createRequest),
|
||||
getAIRequestsV2: createMethod<AIRequestsV2.PayloadGet, AIRequestsV2.IAiResponseGet>(AIRequestsV2.createRequestGet),
|
||||
}
|
||||
|
||||
export type ApiContextValue = typeof api
|
||||
|
||||
102
src/api/resources/AIRequestsV2.ts
Normal file
102
src/api/resources/AIRequestsV2.ts
Normal file
@ -0,0 +1,102 @@
|
||||
import routes from "@/routes";
|
||||
import { getAuthHeaders } from "../utils";
|
||||
|
||||
const dateFormatter = (date: string): string => {
|
||||
return date
|
||||
.split("-")
|
||||
.map((item) => item.padStart(2, "0"))
|
||||
.join("-");
|
||||
};
|
||||
|
||||
export interface Payload {
|
||||
promptKey: string;
|
||||
aiRequest: IAIRequestPayload;
|
||||
token: string;
|
||||
}
|
||||
|
||||
export interface PayloadGet {
|
||||
id: string;
|
||||
token: string;
|
||||
}
|
||||
|
||||
interface IAIRequestPayload {
|
||||
birthDate: string;
|
||||
sign: string;
|
||||
}
|
||||
|
||||
export interface Response {
|
||||
ai_request: IAiResponse;
|
||||
meta: IMeta;
|
||||
}
|
||||
|
||||
interface IMeta {
|
||||
links: {
|
||||
self: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IAiResponse {
|
||||
id: string;
|
||||
prompt_key: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
state: string;
|
||||
is_reused: boolean;
|
||||
finished_at: string;
|
||||
job_id: null;
|
||||
response: IAIRequest;
|
||||
}
|
||||
|
||||
export interface IAiResponseGet {
|
||||
ai_request: IAIRequest;
|
||||
}
|
||||
|
||||
export interface IAIRequest {
|
||||
id: string;
|
||||
prompt_key: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
state: string;
|
||||
is_reused: boolean;
|
||||
finished_at: string;
|
||||
job_id: unknown;
|
||||
response: {
|
||||
id: string;
|
||||
inputs: {
|
||||
sign: string;
|
||||
birth_date: string;
|
||||
};
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
body: string;
|
||||
has_vocal: boolean;
|
||||
speech: unknown;
|
||||
};
|
||||
}
|
||||
|
||||
export const createRequest = ({
|
||||
promptKey,
|
||||
aiRequest,
|
||||
token,
|
||||
}: Payload): Request => {
|
||||
const url = new URL(routes.server.aiRequestsV2(promptKey));
|
||||
const body = JSON.stringify({
|
||||
ai_request: {
|
||||
birth_date: dateFormatter(aiRequest.birthDate),
|
||||
sign: aiRequest.sign,
|
||||
},
|
||||
});
|
||||
return new Request(url, {
|
||||
method: "POST",
|
||||
headers: getAuthHeaders(token),
|
||||
body,
|
||||
});
|
||||
};
|
||||
|
||||
export const createRequestGet = ({ id, token }: PayloadGet): Request => {
|
||||
const url = new URL(routes.server.getAiRequestsV2(id));
|
||||
return new Request(url, {
|
||||
method: "GET",
|
||||
headers: getAuthHeaders(token),
|
||||
});
|
||||
};
|
||||
@ -21,3 +21,4 @@ export * as Zodiacs from "./Zodiacs";
|
||||
export * as GoogleAuth from "./GoogleAuth";
|
||||
export * as SubscriptionPlans from "./SubscriptionPlans";
|
||||
export * as AppleAuth from "./AppleAuth";
|
||||
export * as AIRequestsV2 from "./AIRequestsV2";
|
||||
|
||||
@ -52,6 +52,7 @@ import { StripePage } from "../StripePage";
|
||||
import AuthPage from "../AuthPage";
|
||||
import AuthResultPage from "../AuthResultPage";
|
||||
import MagicBallPage from "../pages/MagicBall";
|
||||
import BestiesHoroscopeResult from "../pages/BestiesHoroscopeResult";
|
||||
|
||||
function App(): JSX.Element {
|
||||
const [isSpecialOfferOpen, setIsSpecialOfferOpen] = useState<boolean>(false);
|
||||
@ -179,10 +180,6 @@ function App(): JSX.Element {
|
||||
element={<ProtectWallpaperPage />}
|
||||
/> */}
|
||||
</Route>
|
||||
<Route
|
||||
path={routes.client.magicBall()}
|
||||
element={<MagicBallPage />}
|
||||
/>
|
||||
<Route element={<PrivateOutlet />}>
|
||||
<Route element={<AuthorizedUserOutlet />}>
|
||||
<Route
|
||||
@ -220,6 +217,14 @@ function App(): JSX.Element {
|
||||
path={routes.client.wallpaper()}
|
||||
element={<WallpaperPage />}
|
||||
/>
|
||||
<Route
|
||||
path={routes.client.magicBall()}
|
||||
element={<MagicBallPage />}
|
||||
/>
|
||||
<Route
|
||||
path={routes.client.horoscopeBestiesResult()}
|
||||
element={<BestiesHoroscopeResult />}
|
||||
/>
|
||||
</Route>
|
||||
</Route>
|
||||
<Route path="*" element={<NotFoundPage />} />
|
||||
|
||||
@ -10,6 +10,7 @@ import { getRandomArbitrary } from "@/services/random-value";
|
||||
|
||||
interface BestiesHoroscopeSliderProps {
|
||||
data: Horoscope;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
export interface Horoscope {
|
||||
@ -19,6 +20,7 @@ export interface Horoscope {
|
||||
|
||||
function BestiesHoroscopeSlider({
|
||||
data,
|
||||
onClick
|
||||
}: BestiesHoroscopeSliderProps): JSX.Element {
|
||||
const api = useApi();
|
||||
const { i18n, t } = useTranslation();
|
||||
@ -51,9 +53,7 @@ function BestiesHoroscopeSlider({
|
||||
style={{
|
||||
background: `url(${backgroundUrl})`,
|
||||
}}
|
||||
onLoad={() => {
|
||||
console.log("start");
|
||||
}}
|
||||
onClick={onClick}
|
||||
>
|
||||
<p className={styles.text}>
|
||||
{t("au.besties.result")}
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
background-size: cover !important;
|
||||
background-position: center !important;
|
||||
background-color: #000 !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.text {
|
||||
|
||||
@ -22,7 +22,7 @@ import { buildFilename, saveFile } from "../WallpaperPage/utils";
|
||||
import Onboarding from "../Onboarding";
|
||||
import TextWithFinger from "../TextWithFinger";
|
||||
import Slider from "../Slider";
|
||||
import BestiesHoroscopeSlider from "../BestiesHoroscopeSlider";
|
||||
import BestiesHoroscopeSlider, { Horoscope } from "../BestiesHoroscopeSlider";
|
||||
|
||||
const buttonTextFormatter = (text: string): JSX.Element => {
|
||||
const sentences = text.split(".");
|
||||
@ -136,6 +136,13 @@ function HomePage(): JSX.Element {
|
||||
saveFile(asset.url.replace("http://", "https://"), buildFilename("1"));
|
||||
};
|
||||
|
||||
const handleBestiesHoroscope = (item: Horoscope) => {
|
||||
const { name, birthDate } = item;
|
||||
navigate(
|
||||
`${routes.client.horoscopeBestiesResult()}?name=${name}&birthDate=${birthDate}`
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<section
|
||||
className={`${styles.page} page`}
|
||||
@ -143,6 +150,12 @@ function HomePage(): JSX.Element {
|
||||
backgroundImage: `url(${asset?.url.replace("http://", "https://")})`,
|
||||
}}
|
||||
>
|
||||
{/* <div
|
||||
className={styles.background}
|
||||
style={{
|
||||
backgroundImage: `url(${asset?.url.replace("http://", "https://")})`,
|
||||
}}
|
||||
> */}
|
||||
<div className={styles.header}>
|
||||
<BlurringSubstrate>
|
||||
<div className={styles["header__energies"]}>
|
||||
@ -214,7 +227,13 @@ function HomePage(): JSX.Element {
|
||||
</Title>
|
||||
<Slider>
|
||||
{bestiesHoroscopes.map((item, index) => (
|
||||
<BestiesHoroscopeSlider data={item} key={index} />
|
||||
<BestiesHoroscopeSlider
|
||||
data={item}
|
||||
key={index}
|
||||
onClick={() => {
|
||||
handleBestiesHoroscope(item);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</Slider>
|
||||
</div>
|
||||
@ -242,6 +261,7 @@ function HomePage(): JSX.Element {
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{/* </div> */}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@ -14,6 +14,17 @@
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.background {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-size: calc(100% + 186px);
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.header {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
83
src/components/ProgressBarsModal/index.tsx
Normal file
83
src/components/ProgressBarsModal/index.tsx
Normal file
@ -0,0 +1,83 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import Title from "../Title";
|
||||
import ProgressBarLine from "../ui/ProgressBarLine";
|
||||
import styles from "./styles.module.css";
|
||||
import Spinner from "../ui/Spinner";
|
||||
import { useSelector } from "react-redux";
|
||||
import { selectors } from "@/store";
|
||||
|
||||
interface IProgressBarsModalProps {
|
||||
children: JSX.Element[];
|
||||
progressBars: ProgressBar[];
|
||||
className?: string;
|
||||
onEndLoading: () => void;
|
||||
}
|
||||
|
||||
export interface ProgressBar {
|
||||
label: string;
|
||||
}
|
||||
|
||||
const getProgressValue = (index: number, value: number) => {
|
||||
const integerDivision = Math.floor(value / 100);
|
||||
if (integerDivision > index) {
|
||||
return 100;
|
||||
}
|
||||
if (integerDivision === index) {
|
||||
return value % 100;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
function ProgressBarsModal({
|
||||
progressBars,
|
||||
className,
|
||||
onEndLoading,
|
||||
children,
|
||||
}: React.PropsWithChildren<IProgressBarsModalProps>): JSX.Element {
|
||||
const [progress, setProgress] = useState(0);
|
||||
const homeConfig = useSelector(selectors.selectHome);
|
||||
const showNavbarFooter = homeConfig.isShowNavbar;
|
||||
|
||||
useEffect(() => {
|
||||
if (progress >= progressBars.length * 100) {
|
||||
return onEndLoading();
|
||||
}
|
||||
const interval = setTimeout(() => {
|
||||
setProgress((prevProgress) => {
|
||||
return prevProgress + 1;
|
||||
});
|
||||
}, 50);
|
||||
return () => {
|
||||
clearTimeout(interval);
|
||||
};
|
||||
}, [progress, onEndLoading]);
|
||||
|
||||
return (
|
||||
<section
|
||||
className={`${styles.container} ${className || ""}`}
|
||||
style={{ paddingBottom: showNavbarFooter ? "48px" : "16px" }}
|
||||
>
|
||||
<div className={styles.title}>{children[0]}</div>
|
||||
{progressBars.map((progressBar, index) => (
|
||||
<div className={styles["progress-bar"]} key={index}>
|
||||
<Title variant="h4" className={styles["progress-bar__label"]}>
|
||||
{progressBar.label}
|
||||
</Title>
|
||||
<div className={styles["progress-bar__container"]}>
|
||||
<ProgressBarLine
|
||||
containerClassName={styles["progress-bar__line"]}
|
||||
value={getProgressValue(index, progress)}
|
||||
delay={50}
|
||||
/>
|
||||
<span className={styles["progress-bar__percentage"]}>
|
||||
{getProgressValue(index, progress)}%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<Spinner width="40px" strokeWidth={3} />
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default ProgressBarsModal;
|
||||
39
src/components/ProgressBarsModal/styles.module.css
Normal file
39
src/components/ProgressBarsModal/styles.module.css
Normal file
@ -0,0 +1,39 @@
|
||||
.container {
|
||||
padding: 16px 32px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: #fd3761;
|
||||
font-weight: 600;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.progress-bar__label {
|
||||
font-size: 16px;
|
||||
margin-bottom: 8px;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.progress-bar__container {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.progress-bar__line {
|
||||
width: calc(100% - 56px);
|
||||
}
|
||||
159
src/components/pages/BestiesHoroscopeResult/index.tsx
Normal file
159
src/components/pages/BestiesHoroscopeResult/index.tsx
Normal file
@ -0,0 +1,159 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Title from "@/components/Title";
|
||||
import styles from "./styles.module.css";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { selectors } from "@/store";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { AICompats, AIRequestsV2, useApi, useApiCall } from "@/api";
|
||||
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||
import routes from "@/routes";
|
||||
import FullScreenModal from "@/components/FullScreenModal";
|
||||
import ProgressBarsModal, { ProgressBar } from "@/components/ProgressBarsModal";
|
||||
import {
|
||||
getCategoryIdByZodiacSign,
|
||||
getZodiacSignByDate,
|
||||
} from "@/services/zodiac-sign";
|
||||
import { getRandomArbitrary } from "@/services/random-value";
|
||||
|
||||
function BestiesHoroscopeResult(): JSX.Element {
|
||||
const token = useSelector(selectors.selectToken);
|
||||
const { i18n, t } = useTranslation();
|
||||
const locale = i18n.language;
|
||||
const navigate = useNavigate();
|
||||
const api = useApi();
|
||||
const homeConfig = useSelector(selectors.selectHome);
|
||||
const showNavbarFooter = homeConfig.isShowNavbar;
|
||||
const [text, setText] = useState("Loading...");
|
||||
const [isOpenModal, setIsOpenModal] = useState(true);
|
||||
const [isVisualLoading, setIsVisualLoading] = useState(true);
|
||||
const [isDataLoading, setIsDataLoading] = useState(true);
|
||||
const [searchParams] = useSearchParams();
|
||||
const name = searchParams.get("name");
|
||||
const birthDate = searchParams.get("birthDate") || "";
|
||||
const zodiacSign = getZodiacSignByDate(birthDate);
|
||||
const [backgroundUrl, setBackgroundUrl] = useState("");
|
||||
|
||||
const progressBars: ProgressBar[] = [
|
||||
{
|
||||
label: t("au.besties.loading1"),
|
||||
},
|
||||
{
|
||||
label: t("au.besties.loading2"),
|
||||
},
|
||||
{
|
||||
label: t("au.besties.loading3"),
|
||||
},
|
||||
{
|
||||
label: t("au.besties.loading4"),
|
||||
},
|
||||
];
|
||||
|
||||
const handleNext = () => {
|
||||
return navigate(routes.client.home());
|
||||
};
|
||||
|
||||
const loadData = useCallback(async () => {
|
||||
const payload: AIRequestsV2.Payload = {
|
||||
aiRequest: {
|
||||
birthDate,
|
||||
sign: getZodiacSignByDate(birthDate).toLowerCase(),
|
||||
},
|
||||
promptKey: "horoscope_besties",
|
||||
token,
|
||||
};
|
||||
const aIRequest = await api.AIRequestsV2(payload);
|
||||
if (aIRequest.ai_request.state !== "ready") {
|
||||
const getAIRequest = async () => {
|
||||
const aIRequestById = await api.getAIRequestsV2({
|
||||
id: aIRequest.ai_request.id,
|
||||
token,
|
||||
});
|
||||
if (aIRequestById.ai_request.state !== "ready") {
|
||||
setTimeout(getAIRequest, 3000);
|
||||
}
|
||||
setText(aIRequestById?.ai_request?.response?.body || "Loading...");
|
||||
setIsDataLoading(false);
|
||||
checkLoading();
|
||||
return aIRequestById.ai_request;
|
||||
};
|
||||
return await getAIRequest();
|
||||
}
|
||||
setIsDataLoading(false);
|
||||
checkLoading();
|
||||
setText(aIRequest?.ai_request?.response?.response?.body || "Loading...");
|
||||
|
||||
return aIRequest?.ai_request?.response;
|
||||
}, [api, token, birthDate]);
|
||||
|
||||
useApiCall<AIRequestsV2.IAIRequest>(loadData);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
const { asset_categories } = await api.getAssetCategories({ locale });
|
||||
const categoryId = getCategoryIdByZodiacSign(
|
||||
zodiacSign,
|
||||
asset_categories
|
||||
);
|
||||
const assets = (
|
||||
await api.getAssets({ category: String(categoryId || "1") })
|
||||
).assets;
|
||||
const randomAsset = assets[getRandomArbitrary(0, assets.length - 1)];
|
||||
setBackgroundUrl(randomAsset.url);
|
||||
} catch (error) {
|
||||
console.error("Error: ", error);
|
||||
}
|
||||
})();
|
||||
}, [api, locale, zodiacSign]);
|
||||
|
||||
const getPaddingBottomPage = () => {
|
||||
if (showNavbarFooter) return "164px";
|
||||
return "108px";
|
||||
};
|
||||
|
||||
function checkLoading() {
|
||||
if (isVisualLoading || isDataLoading) {
|
||||
setIsOpenModal(true);
|
||||
} else {
|
||||
setIsOpenModal(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<section
|
||||
className={`${styles.page} page`}
|
||||
style={{ paddingBottom: getPaddingBottomPage() }}
|
||||
>
|
||||
<FullScreenModal isOpen={isOpenModal}>
|
||||
<ProgressBarsModal
|
||||
progressBars={progressBars}
|
||||
onEndLoading={() => {
|
||||
setIsVisualLoading(false);
|
||||
checkLoading();
|
||||
}}
|
||||
>
|
||||
<Title variant="h2">
|
||||
{t("au.besties.title")}{" "}
|
||||
<span className={styles["loading-name"]}>{name}</span>
|
||||
</Title>
|
||||
<></>
|
||||
</ProgressBarsModal>
|
||||
</FullScreenModal>
|
||||
<div className={styles["cross-container"]}>
|
||||
<div className={styles.cross} onClick={handleNext}></div>
|
||||
</div>
|
||||
<div
|
||||
className={styles["sign-image"]}
|
||||
style={{ backgroundImage: `url(${backgroundUrl})` }}
|
||||
>
|
||||
<Title variant="h2">
|
||||
{t("au.besties.result")}{" "}
|
||||
<span className={styles["loading-name"]}>{name}</span>
|
||||
</Title>
|
||||
</div>
|
||||
<p className={styles.text}>{text}</p>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default BestiesHoroscopeResult;
|
||||
@ -0,0 +1,79 @@
|
||||
.page {
|
||||
position: relative;
|
||||
height: fit-content;
|
||||
min-height: 100vh;
|
||||
flex: auto;
|
||||
/* max-height: -webkit-fill-available; */
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
overflow-y: scroll;
|
||||
padding-bottom: 180px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.loading-name {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.sign-image {
|
||||
width: 100%;
|
||||
height: 446px;
|
||||
color: #fd433f;
|
||||
border-radius: 17px;
|
||||
background-color: #000;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: 18px;
|
||||
line-height: 22px;
|
||||
font-weight: 400;
|
||||
padding: 0 8px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.cross-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.cross {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border: solid 2px #bdbdbd;
|
||||
border-radius: 100%;
|
||||
rotate: 45deg;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cross::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 10px;
|
||||
height: 2px;
|
||||
background-color: #bdbdbd;
|
||||
}
|
||||
|
||||
.cross::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 2px;
|
||||
height: 10px;
|
||||
background-color: #bdbdbd;
|
||||
}
|
||||
@ -34,6 +34,7 @@ const routes = {
|
||||
home: () => [host, "home"].join("/"),
|
||||
breathResult: () => [host, "breath", "result"].join("/"),
|
||||
magicBall: () => [host, "magic-ball"].join("/"),
|
||||
horoscopeBestiesResult: () => [host, "horoscope", "besties"].join("/"),
|
||||
},
|
||||
server: {
|
||||
appleAuth: (origin: string) => [apiHost, "auth", "apple", `gate?origin=${origin}`].join("/"),
|
||||
@ -81,6 +82,8 @@ const routes = {
|
||||
getUserCallbacks: (id: string) =>
|
||||
[apiHost, prefix, "user", "callbacks", `${id}.json`].join("/"),
|
||||
getTranslations: () => [siteHost, "api/v2", "t.json"].join("/"),
|
||||
aiRequestsV2: (promptKey: string) => [apiHost, "api/v2", "ai", "prompts", promptKey, "requests.json"].join("/"),
|
||||
getAiRequestsV2: (id: string) => [apiHost, "api/v2", "ai", "requests", `${id}.json`].join("/"),
|
||||
},
|
||||
};
|
||||
|
||||
@ -133,6 +136,7 @@ export const withoutFooterRoutes = [
|
||||
routes.client.paymentFail(),
|
||||
routes.client.paymentStripe(),
|
||||
routes.client.magicBall(),
|
||||
routes.client.horoscopeBestiesResult(),
|
||||
];
|
||||
export const hasNoFooter = (path: string) =>
|
||||
!withoutFooterRoutes.includes(path);
|
||||
@ -156,6 +160,7 @@ export const withoutHeaderRoutes = [
|
||||
routes.client.paymentSuccess(),
|
||||
routes.client.paymentFail(),
|
||||
routes.client.magicBall(),
|
||||
routes.client.horoscopeBestiesResult(),
|
||||
];
|
||||
export const hasNoHeader = (path: string) =>
|
||||
!withoutHeaderRoutes.includes(path);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user