feat: add magic ball page and home button, add besties horoscope slider
This commit is contained in:
parent
f90d66f3ba
commit
0f6f8f7e72
@ -344,7 +344,8 @@ function PrivateOutlet(): JSX.Element {
|
||||
}
|
||||
|
||||
function PrivateSubscriptionOutlet(): JSX.Element {
|
||||
const isProduction = import.meta.env.MODE === "production";
|
||||
// const isProduction = import.meta.env.MODE === "production";
|
||||
const isProduction = false;
|
||||
console.log(isProduction);
|
||||
const status = useSelector(selectors.selectStatus);
|
||||
return status === "subscribed" || !isProduction ? (
|
||||
|
||||
66
src/components/BestiesHoroscopeSlider/index.tsx
Normal file
66
src/components/BestiesHoroscopeSlider/index.tsx
Normal file
@ -0,0 +1,66 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import styles from "./styles.module.css";
|
||||
import {
|
||||
getCategoryIdByZodiacSign,
|
||||
getZodiacSignByDate,
|
||||
} from "@/services/zodiac-sign";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useApi } from "@/api";
|
||||
import { getRandomArbitrary } from "@/services/random-value";
|
||||
|
||||
interface BestiesHoroscopeSliderProps {
|
||||
data: Horoscope;
|
||||
}
|
||||
|
||||
export interface Horoscope {
|
||||
name: string;
|
||||
birthDate: string;
|
||||
}
|
||||
|
||||
function BestiesHoroscopeSlider({
|
||||
data,
|
||||
}: BestiesHoroscopeSliderProps): JSX.Element {
|
||||
const api = useApi();
|
||||
const { i18n, t } = useTranslation();
|
||||
const locale = i18n.language;
|
||||
const zodiacSign = getZodiacSignByDate(data.birthDate);
|
||||
const [backgroundUrl, setBackgroundUrl] = useState("");
|
||||
|
||||
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);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={styles.container}
|
||||
style={{
|
||||
background: `url(${backgroundUrl})`,
|
||||
}}
|
||||
onLoad={() => {
|
||||
console.log("start");
|
||||
}}
|
||||
>
|
||||
<p className={styles.text}>
|
||||
{t("au.besties.result")}
|
||||
<b> {data.name}</b>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default BestiesHoroscopeSlider;
|
||||
28
src/components/BestiesHoroscopeSlider/styles.module.css
Normal file
28
src/components/BestiesHoroscopeSlider/styles.module.css
Normal file
@ -0,0 +1,28 @@
|
||||
.container {
|
||||
width: max-content;
|
||||
max-width: 280px;
|
||||
height: 160px;
|
||||
border-radius: 17px;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
padding: 8px 12px;
|
||||
background-repeat: no-repeat !important;
|
||||
background-size: cover !important;
|
||||
background-position: center !important;
|
||||
background-color: #000 !important;
|
||||
}
|
||||
|
||||
.text {
|
||||
color: #b1b0b0;
|
||||
font-weight: 400;
|
||||
font-size: 17px;
|
||||
line-height: 20px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.text > b {
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
}
|
||||
@ -90,8 +90,16 @@ function CompatibilityPage(): JSX.Element {
|
||||
birthDate: selectedDate,
|
||||
},
|
||||
categoryId: compatCategory,
|
||||
selfName,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
actions.compatibilities.update({
|
||||
name,
|
||||
birthDate: getDateAsString(selectedDate),
|
||||
})
|
||||
);
|
||||
|
||||
navigate(routes.client.compatibilityResult());
|
||||
};
|
||||
|
||||
|
||||
@ -21,6 +21,8 @@ import { EPathsFromHome } from "@/store/siteConfig";
|
||||
import { buildFilename, saveFile } from "../WallpaperPage/utils";
|
||||
import Onboarding from "../Onboarding";
|
||||
import TextWithFinger from "../TextWithFinger";
|
||||
import Slider from "../Slider";
|
||||
import BestiesHoroscopeSlider from "../BestiesHoroscopeSlider";
|
||||
|
||||
const buttonTextFormatter = (text: string): JSX.Element => {
|
||||
const sentences = text.split(".");
|
||||
@ -44,6 +46,8 @@ function HomePage(): JSX.Element {
|
||||
const isShowNavbar = homeConfig.isShowNavbar;
|
||||
const onboardingConfigHome = useSelector(selectors.selectOnboardingHome);
|
||||
|
||||
const bestiesHoroscopes = useSelector(selectors.selectCompatibilities);
|
||||
|
||||
const [isShowOnboardingHome, setIsShowOnboardingHome] = useState(
|
||||
!onboardingConfigHome?.isShown
|
||||
);
|
||||
@ -163,41 +167,60 @@ function HomePage(): JSX.Element {
|
||||
: "calc(100vh - 500px)",
|
||||
}}
|
||||
>
|
||||
{
|
||||
<div
|
||||
ref={buttonsRef}
|
||||
className={`${styles["content__buttons"]} ${
|
||||
isShowNavbar ? styles["content__buttons--hidden"] : ""
|
||||
}`}
|
||||
<div
|
||||
ref={buttonsRef}
|
||||
className={`${styles["content__buttons"]} ${
|
||||
isShowNavbar ? styles["content__buttons--hidden"] : ""
|
||||
}`}
|
||||
>
|
||||
<Onboarding
|
||||
targetRef={buttonsRef.current as HTMLDivElement}
|
||||
isShow={isShowOnboardingHome}
|
||||
>
|
||||
<Onboarding
|
||||
targetRef={buttonsRef.current as HTMLDivElement}
|
||||
isShow={isShowOnboardingHome}
|
||||
>
|
||||
<TextWithFinger
|
||||
text={t("au.web_onbording.start")}
|
||||
crossClickHandler={() => setIsShowOnboardingHome(false)}
|
||||
/>
|
||||
</Onboarding>
|
||||
<BlurringSubstrate
|
||||
style={{ color: "#fa71ea" }}
|
||||
className={styles["content__buttons-item"]}
|
||||
clickHandler={handleCompatibility}
|
||||
>
|
||||
{buttonTextFormatter(t("aura-money_compatibility-button"))}
|
||||
</BlurringSubstrate>
|
||||
<BlurringSubstrate
|
||||
style={{ color: "#00f0ff" }}
|
||||
className={styles["content__buttons-item"]}
|
||||
clickHandler={handleBreath}
|
||||
>
|
||||
{buttonTextFormatter(t("aura-10_breath-button"))}
|
||||
</BlurringSubstrate>
|
||||
<div className={`${styles["content__aura"]}`} onClick={handleMagicBall}>
|
||||
<p className={styles["content__aura-text"]}>{"Get an answer"}</p>
|
||||
</div>
|
||||
<TextWithFinger
|
||||
text={t("au.web_onbording.start")}
|
||||
crossClickHandler={() => setIsShowOnboardingHome(false)}
|
||||
/>
|
||||
</Onboarding>
|
||||
<BlurringSubstrate
|
||||
style={{ color: "#fa71ea" }}
|
||||
className={styles["content__buttons-item"]}
|
||||
clickHandler={handleCompatibility}
|
||||
>
|
||||
{buttonTextFormatter(t("aura-money_compatibility-button"))}
|
||||
</BlurringSubstrate>
|
||||
<BlurringSubstrate
|
||||
style={{ color: "#00f0ff" }}
|
||||
className={styles["content__buttons-item"]}
|
||||
clickHandler={handleBreath}
|
||||
>
|
||||
{buttonTextFormatter(t("aura-10_breath-button"))}
|
||||
</BlurringSubstrate>
|
||||
</div>
|
||||
<div className={`${styles["content__buttons"]}`}>
|
||||
<div
|
||||
className={`${styles["content__aura"]}`}
|
||||
onClick={handleMagicBall}
|
||||
>
|
||||
<p className={styles["content__aura-text"]}>{"Get an answer"}</p>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
{/* SLIDERS */}
|
||||
<div className={styles.sliders}>
|
||||
<div>
|
||||
<Title variant="h2" className={styles["sliders__title"]}>
|
||||
{"Your Besties' Horoscope"}
|
||||
</Title>
|
||||
<Slider>
|
||||
{bestiesHoroscopes.map((item, index) => (
|
||||
<BestiesHoroscopeSlider data={item} key={index} />
|
||||
))}
|
||||
</Slider>
|
||||
</div>
|
||||
</div>
|
||||
{/* END SLIDERS */}
|
||||
|
||||
<div className={styles["content__daily-forecast"]}>
|
||||
{dailyForecast &&
|
||||
dailyForecast.forecasts.map((forecast, index) => (
|
||||
|
||||
@ -149,6 +149,7 @@
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
animation: pulse 1s alternate infinite;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.content__aura-text {
|
||||
@ -157,6 +158,24 @@
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
margin: auto;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.sliders {
|
||||
width: 100vw;
|
||||
max-width: 560px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 42px;
|
||||
}
|
||||
|
||||
.sliders__title {
|
||||
font-weight: 700;
|
||||
font-size: 23px;
|
||||
color: #FD433F;
|
||||
text-align: left;
|
||||
padding: 0 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
|
||||
16
src/components/Slider/index.tsx
Normal file
16
src/components/Slider/index.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
interface ISliderProps {
|
||||
children: JSX.Element[];
|
||||
className?: string;
|
||||
}
|
||||
|
||||
function Slider({ children, className }: ISliderProps): JSX.Element {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={`${styles.slider} ${className || ""}`}>{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Slider;
|
||||
17
src/components/Slider/styles.module.css
Normal file
17
src/components/Slider/styles.module.css
Normal file
@ -0,0 +1,17 @@
|
||||
.slider {
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 16px;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
|
||||
.container::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
@ -49,6 +49,12 @@ export function StripePage(): JSX.Element {
|
||||
|
||||
return (
|
||||
<div className={`${styles.page} page`}>
|
||||
<img
|
||||
className={`${styles.cross}`}
|
||||
src="/cross.png"
|
||||
alt="Cross"
|
||||
onClick={() => navigate(routes.client.home())}
|
||||
/>
|
||||
{isLoading ? (
|
||||
<div className={styles["payment-loader"]}>
|
||||
<Loader />
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
.page {
|
||||
position: relative;
|
||||
/* position: relative; */
|
||||
position: static;
|
||||
/* height: calc(100vh - 50px);
|
||||
max-height: -webkit-fill-available; */
|
||||
flex: auto;
|
||||
@ -14,3 +15,13 @@
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.cross {
|
||||
position: absolute;
|
||||
top: -36px;
|
||||
right: 28px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
cursor: pointer;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
@ -63,8 +63,6 @@ function MagicBallPage(): JSX.Element {
|
||||
setIsRunning(false);
|
||||
return;
|
||||
}
|
||||
const canVibrate = !!window.navigator.vibrate;
|
||||
if (canVibrate) window.navigator.vibrate(100);
|
||||
setProcessState((prev) => prev + 1);
|
||||
},
|
||||
isRunning ? 1000 : null
|
||||
|
||||
23
src/store/compatibilities.ts
Normal file
23
src/store/compatibilities.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { Horoscope } from "@/components/BestiesHoroscopeSlider";
|
||||
import { createSlice, createSelector } from "@reduxjs/toolkit";
|
||||
import type { PayloadAction } from "@reduxjs/toolkit";
|
||||
|
||||
const initialState: Horoscope[] = []
|
||||
|
||||
const compatibilitiesSlice = createSlice({
|
||||
name: "compatibilities",
|
||||
initialState,
|
||||
reducers: {
|
||||
update(state, action: PayloadAction<Horoscope>) {
|
||||
return [ ...initialState, ...state, action.payload ];
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => builder.addCase("reset", () => initialState),
|
||||
});
|
||||
|
||||
export const { actions } = compatibilitiesSlice;
|
||||
export const selectCompatibilities = createSelector(
|
||||
(state: { compatibilities: Horoscope[] }) => state.compatibilities,
|
||||
(compatibilities) => compatibilities
|
||||
);
|
||||
export default compatibilitiesSlice.reducer;
|
||||
@ -33,8 +33,13 @@ import subscriptionPlans, {
|
||||
} from "./subscriptionPlan";
|
||||
import status, { actions as userStatusActions, selectStatus } from "./status";
|
||||
import compatibility, {
|
||||
actions as compatibilityActions, selectSelfName,
|
||||
actions as compatibilityActions,
|
||||
selectSelfName,
|
||||
} from "./compatibility";
|
||||
import compatibilities, {
|
||||
actions as compatibilitiesActions,
|
||||
selectCompatibilities,
|
||||
} from "./compatibilities";
|
||||
import userCallbacks, {
|
||||
actions as userCallbacksActions,
|
||||
} from "./userCallbacks";
|
||||
@ -57,6 +62,7 @@ export const actions = {
|
||||
aura: auraActions,
|
||||
siteConfig: siteConfigActions,
|
||||
compatibility: compatibilityActions,
|
||||
compatibilities: compatibilitiesActions,
|
||||
payment: paymentActions,
|
||||
userCallbacks: userCallbacksActions,
|
||||
onboardingConfig: onboardingConfigActions,
|
||||
@ -82,6 +88,7 @@ export const selectors = {
|
||||
selectOnboardingCompatibility,
|
||||
selectOnboardingBreath,
|
||||
selectOnboardingNavbarFooter,
|
||||
selectCompatibilities,
|
||||
...formSelectors,
|
||||
};
|
||||
|
||||
@ -94,6 +101,7 @@ export const reducer = combineReducers({
|
||||
aura,
|
||||
payment,
|
||||
compatibility,
|
||||
compatibilities,
|
||||
userCallbacks,
|
||||
siteConfig,
|
||||
onboardingConfig,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user