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 {
|
function PrivateSubscriptionOutlet(): JSX.Element {
|
||||||
const isProduction = import.meta.env.MODE === "production";
|
// const isProduction = import.meta.env.MODE === "production";
|
||||||
|
const isProduction = false;
|
||||||
console.log(isProduction);
|
console.log(isProduction);
|
||||||
const status = useSelector(selectors.selectStatus);
|
const status = useSelector(selectors.selectStatus);
|
||||||
return status === "subscribed" || !isProduction ? (
|
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,
|
birthDate: selectedDate,
|
||||||
},
|
},
|
||||||
categoryId: compatCategory,
|
categoryId: compatCategory,
|
||||||
|
selfName,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
dispatch(
|
||||||
|
actions.compatibilities.update({
|
||||||
|
name,
|
||||||
|
birthDate: getDateAsString(selectedDate),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
navigate(routes.client.compatibilityResult());
|
navigate(routes.client.compatibilityResult());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,8 @@ import { EPathsFromHome } from "@/store/siteConfig";
|
|||||||
import { buildFilename, saveFile } from "../WallpaperPage/utils";
|
import { buildFilename, saveFile } from "../WallpaperPage/utils";
|
||||||
import Onboarding from "../Onboarding";
|
import Onboarding from "../Onboarding";
|
||||||
import TextWithFinger from "../TextWithFinger";
|
import TextWithFinger from "../TextWithFinger";
|
||||||
|
import Slider from "../Slider";
|
||||||
|
import BestiesHoroscopeSlider from "../BestiesHoroscopeSlider";
|
||||||
|
|
||||||
const buttonTextFormatter = (text: string): JSX.Element => {
|
const buttonTextFormatter = (text: string): JSX.Element => {
|
||||||
const sentences = text.split(".");
|
const sentences = text.split(".");
|
||||||
@ -44,6 +46,8 @@ function HomePage(): JSX.Element {
|
|||||||
const isShowNavbar = homeConfig.isShowNavbar;
|
const isShowNavbar = homeConfig.isShowNavbar;
|
||||||
const onboardingConfigHome = useSelector(selectors.selectOnboardingHome);
|
const onboardingConfigHome = useSelector(selectors.selectOnboardingHome);
|
||||||
|
|
||||||
|
const bestiesHoroscopes = useSelector(selectors.selectCompatibilities);
|
||||||
|
|
||||||
const [isShowOnboardingHome, setIsShowOnboardingHome] = useState(
|
const [isShowOnboardingHome, setIsShowOnboardingHome] = useState(
|
||||||
!onboardingConfigHome?.isShown
|
!onboardingConfigHome?.isShown
|
||||||
);
|
);
|
||||||
@ -163,41 +167,60 @@ function HomePage(): JSX.Element {
|
|||||||
: "calc(100vh - 500px)",
|
: "calc(100vh - 500px)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{
|
<div
|
||||||
<div
|
ref={buttonsRef}
|
||||||
ref={buttonsRef}
|
className={`${styles["content__buttons"]} ${
|
||||||
className={`${styles["content__buttons"]} ${
|
isShowNavbar ? styles["content__buttons--hidden"] : ""
|
||||||
isShowNavbar ? styles["content__buttons--hidden"] : ""
|
}`}
|
||||||
}`}
|
>
|
||||||
|
<Onboarding
|
||||||
|
targetRef={buttonsRef.current as HTMLDivElement}
|
||||||
|
isShow={isShowOnboardingHome}
|
||||||
>
|
>
|
||||||
<Onboarding
|
<TextWithFinger
|
||||||
targetRef={buttonsRef.current as HTMLDivElement}
|
text={t("au.web_onbording.start")}
|
||||||
isShow={isShowOnboardingHome}
|
crossClickHandler={() => setIsShowOnboardingHome(false)}
|
||||||
>
|
/>
|
||||||
<TextWithFinger
|
</Onboarding>
|
||||||
text={t("au.web_onbording.start")}
|
<BlurringSubstrate
|
||||||
crossClickHandler={() => setIsShowOnboardingHome(false)}
|
style={{ color: "#fa71ea" }}
|
||||||
/>
|
className={styles["content__buttons-item"]}
|
||||||
</Onboarding>
|
clickHandler={handleCompatibility}
|
||||||
<BlurringSubstrate
|
>
|
||||||
style={{ color: "#fa71ea" }}
|
{buttonTextFormatter(t("aura-money_compatibility-button"))}
|
||||||
className={styles["content__buttons-item"]}
|
</BlurringSubstrate>
|
||||||
clickHandler={handleCompatibility}
|
<BlurringSubstrate
|
||||||
>
|
style={{ color: "#00f0ff" }}
|
||||||
{buttonTextFormatter(t("aura-money_compatibility-button"))}
|
className={styles["content__buttons-item"]}
|
||||||
</BlurringSubstrate>
|
clickHandler={handleBreath}
|
||||||
<BlurringSubstrate
|
>
|
||||||
style={{ color: "#00f0ff" }}
|
{buttonTextFormatter(t("aura-10_breath-button"))}
|
||||||
className={styles["content__buttons-item"]}
|
</BlurringSubstrate>
|
||||||
clickHandler={handleBreath}
|
</div>
|
||||||
>
|
<div className={`${styles["content__buttons"]}`}>
|
||||||
{buttonTextFormatter(t("aura-10_breath-button"))}
|
<div
|
||||||
</BlurringSubstrate>
|
className={`${styles["content__aura"]}`}
|
||||||
<div className={`${styles["content__aura"]}`} onClick={handleMagicBall}>
|
onClick={handleMagicBall}
|
||||||
<p className={styles["content__aura-text"]}>{"Get an answer"}</p>
|
>
|
||||||
</div>
|
<p className={styles["content__aura-text"]}>{"Get an answer"}</p>
|
||||||
</div>
|
</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"]}>
|
<div className={styles["content__daily-forecast"]}>
|
||||||
{dailyForecast &&
|
{dailyForecast &&
|
||||||
dailyForecast.forecasts.map((forecast, index) => (
|
dailyForecast.forecasts.map((forecast, index) => (
|
||||||
|
|||||||
@ -149,6 +149,7 @@
|
|||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center center;
|
background-position: center center;
|
||||||
animation: pulse 1s alternate infinite;
|
animation: pulse 1s alternate infinite;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content__aura-text {
|
.content__aura-text {
|
||||||
@ -157,6 +158,24 @@
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
margin: auto;
|
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 {
|
@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 (
|
return (
|
||||||
<div className={`${styles.page} page`}>
|
<div className={`${styles.page} page`}>
|
||||||
|
<img
|
||||||
|
className={`${styles.cross}`}
|
||||||
|
src="/cross.png"
|
||||||
|
alt="Cross"
|
||||||
|
onClick={() => navigate(routes.client.home())}
|
||||||
|
/>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div className={styles["payment-loader"]}>
|
<div className={styles["payment-loader"]}>
|
||||||
<Loader />
|
<Loader />
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
.page {
|
.page {
|
||||||
position: relative;
|
/* position: relative; */
|
||||||
|
position: static;
|
||||||
/* height: calc(100vh - 50px);
|
/* height: calc(100vh - 50px);
|
||||||
max-height: -webkit-fill-available; */
|
max-height: -webkit-fill-available; */
|
||||||
flex: auto;
|
flex: auto;
|
||||||
@ -14,3 +15,13 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: 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);
|
setIsRunning(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const canVibrate = !!window.navigator.vibrate;
|
|
||||||
if (canVibrate) window.navigator.vibrate(100);
|
|
||||||
setProcessState((prev) => prev + 1);
|
setProcessState((prev) => prev + 1);
|
||||||
},
|
},
|
||||||
isRunning ? 1000 : null
|
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";
|
} from "./subscriptionPlan";
|
||||||
import status, { actions as userStatusActions, selectStatus } from "./status";
|
import status, { actions as userStatusActions, selectStatus } from "./status";
|
||||||
import compatibility, {
|
import compatibility, {
|
||||||
actions as compatibilityActions, selectSelfName,
|
actions as compatibilityActions,
|
||||||
|
selectSelfName,
|
||||||
} from "./compatibility";
|
} from "./compatibility";
|
||||||
|
import compatibilities, {
|
||||||
|
actions as compatibilitiesActions,
|
||||||
|
selectCompatibilities,
|
||||||
|
} from "./compatibilities";
|
||||||
import userCallbacks, {
|
import userCallbacks, {
|
||||||
actions as userCallbacksActions,
|
actions as userCallbacksActions,
|
||||||
} from "./userCallbacks";
|
} from "./userCallbacks";
|
||||||
@ -57,6 +62,7 @@ export const actions = {
|
|||||||
aura: auraActions,
|
aura: auraActions,
|
||||||
siteConfig: siteConfigActions,
|
siteConfig: siteConfigActions,
|
||||||
compatibility: compatibilityActions,
|
compatibility: compatibilityActions,
|
||||||
|
compatibilities: compatibilitiesActions,
|
||||||
payment: paymentActions,
|
payment: paymentActions,
|
||||||
userCallbacks: userCallbacksActions,
|
userCallbacks: userCallbacksActions,
|
||||||
onboardingConfig: onboardingConfigActions,
|
onboardingConfig: onboardingConfigActions,
|
||||||
@ -82,6 +88,7 @@ export const selectors = {
|
|||||||
selectOnboardingCompatibility,
|
selectOnboardingCompatibility,
|
||||||
selectOnboardingBreath,
|
selectOnboardingBreath,
|
||||||
selectOnboardingNavbarFooter,
|
selectOnboardingNavbarFooter,
|
||||||
|
selectCompatibilities,
|
||||||
...formSelectors,
|
...formSelectors,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -94,6 +101,7 @@ export const reducer = combineReducers({
|
|||||||
aura,
|
aura,
|
||||||
payment,
|
payment,
|
||||||
compatibility,
|
compatibility,
|
||||||
|
compatibilities,
|
||||||
userCallbacks,
|
userCallbacks,
|
||||||
siteConfig,
|
siteConfig,
|
||||||
onboardingConfig,
|
onboardingConfig,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user