Merge branch 'clone' into 'main'

feat: add modal with required data

See merge request witapp/aura-webapp!18
This commit is contained in:
Victor Ershov 2023-12-21 23:21:51 +00:00
commit 64ee5a0c79
11 changed files with 161 additions and 64 deletions

View File

@ -1,4 +1,4 @@
import { useCallback, useEffect, useState } from "react";
import { useCallback, useEffect, useMemo, useState } from "react";
import {
Routes,
Route,
@ -16,6 +16,7 @@ import routes, {
hasNoFooter,
hasNoHeader,
hasNavbarFooter,
hasFullDataModal,
} from "@/routes";
import BirthdayPage from "../BirthdayPage";
import BirthtimePage from "../BirthtimePage";
@ -59,6 +60,8 @@ import ThermalResult from "../pages/ThermalResult";
import MoonPhaseTrackerResult from "../pages/MoonPhaseTrackerResult";
import EnergyVampirismResult from "../pages/EnergyVampirismResult";
import NameHoroscopeResult from "../pages/NameHoroscopeResult";
import Modal from "../Modal";
import FullDataModal from "../FullDataModal";
function App(): JSX.Element {
const [isSpecialOfferOpen, setIsSpecialOfferOpen] = useState<boolean>(false);
@ -282,11 +285,27 @@ function Layout({ setIsSpecialOfferOpen }: LayoutProps): JSX.Element {
const showNavbar = hasNavigation(location.pathname);
const showFooter = hasNoFooter(location.pathname);
const showHeader = hasNoHeader(location.pathname);
const isRouteFullDataModal = hasFullDataModal(location.pathname);
const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false);
const changeIsSpecialOfferOpen = () => setIsSpecialOfferOpen(true);
const homeConfig = useSelector(selectors.selectHome);
const showNavbarFooter = homeConfig.isShowNavbar;
const birthdate = useSelector(selectors.selectBirthdate);
const dataItems = useMemo(() => [birthdate], [birthdate]);
const [isShowFullDataModal, setIsShowFullDataModal] =
useState<boolean>(false);
useEffect(() => {
setIsShowFullDataModal(getIsShowFullDataModal(dataItems));
}, [dataItems]);
const onCloseFullDataModal = (_birthDate: string) => {
console.log("onCloseFullDataModal", _birthDate);
dispatch(actions.form.addDate(_birthDate));
setIsShowFullDataModal(getIsShowFullDataModal(dataItems));
};
const handleCompatibility = () => {
dispatch(
actions.siteConfig.update({
@ -353,6 +372,11 @@ function Layout({ setIsSpecialOfferOpen }: LayoutProps): JSX.Element {
clickCross={changeIsSpecialOfferOpen}
/>
) : null}
{isRouteFullDataModal && (
<Modal open={isShowFullDataModal} isCloseButtonVisible={false}>
<FullDataModal onClose={onCloseFullDataModal} />
</Modal>
)}
<main className="content">
<Outlet />
</main>
@ -397,6 +421,19 @@ function PrivateSubscriptionOutlet(): JSX.Element {
);
}
function getIsShowFullDataModal(dataItems: Array<unknown> = []): boolean {
let hasNoDataItem = false;
for (const item of dataItems) {
if (!item) {
hasNoDataItem = true;
break;
}
}
return hasNoDataItem;
}
function SkipStep(): JSX.Element {
const { user } = useAuth();
return user ? (

View File

@ -0,0 +1,42 @@
import { useSelector } from "react-redux";
import { DatePicker } from "../DateTimePicker";
import Title from "../Title";
import styles from "./styles.module.css";
import { selectors } from "@/store";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import MainButton from "../MainButton";
interface IFullDataModalProps {
onClose: (birthDate: string) => void;
}
function FullDataModal({ onClose }: IFullDataModalProps) {
const { t } = useTranslation();
const birthDateFromStore = useSelector(selectors.selectBirthdate);
const [birthDate, setBirthDate] = useState(birthDateFromStore);
const [isDisabled, setIsDisabled] = useState(true);
const handleValid = (_birthDate: string) => {
setBirthDate(_birthDate);
setIsDisabled(_birthDate === "");
};
return (
<div className={styles.container}>
<Title variant="h2">{t("date_of_birth")}</Title>
<DatePicker
name="birthDate"
value={birthDate}
onValid={handleValid}
onInvalid={() => setIsDisabled(true)}
inputClassName="date-picker-input"
/>
<MainButton disabled={isDisabled} onClick={() => onClose(birthDate)}>
Save
</MainButton>
</div>
);
}
export default FullDataModal;

View File

@ -148,7 +148,7 @@ function HomePage(): JSX.Element {
useEffect(() => {
getMoonsImages();
}, []);
}, [api]);
const getMoonsImages = async () => {
const assets = (
@ -288,22 +288,24 @@ function HomePage(): JSX.Element {
{/* SLIDERS */}
<div className={styles.sliders}>
<div className={styles["slider"]}>
<Title variant="h2" className={styles["sliders__title"]}>
{"Your Besties' Horoscope"}
</Title>
<Slider>
{compatibilities.map((item, index) => (
<BestiesHoroscopeSlider
data={item}
key={index}
onClick={() => {
handleBestiesHoroscope(item);
}}
/>
))}
</Slider>
</div>
{!!compatibilities.length && (
<div className={styles["slider"]}>
<Title variant="h2" className={styles["sliders__title"]}>
{"Your Besties' Horoscope"}
</Title>
<Slider>
{compatibilities.map((item, index) => (
<BestiesHoroscopeSlider
data={item}
key={index}
onClick={() => {
handleBestiesHoroscope(item);
}}
/>
))}
</Slider>
</div>
)}
<div className={styles["slider"]}>
<Title variant="h2" className={styles["sliders__title"]}>
{"Prediction Based on Your Moons"}
@ -357,22 +359,24 @@ function HomePage(): JSX.Element {
{/* SLIDERS */}
<div className={styles.sliders}>
<div className={styles["slider"]}>
<Title variant="h2" className={styles["sliders__title"]}>
{t("au.thermal_compatibility.result_title")}
</Title>
<Slider>
{compatibilities.map((item, index) => (
<ThermalSlider
data={item}
key={index}
onClick={() => {
handleThermal(item);
}}
/>
))}
</Slider>
</div>
{!!compatibilities.length && (
<div className={styles["slider"]}>
<Title variant="h2" className={styles["sliders__title"]}>
{t("au.thermal_compatibility.result_title")}
</Title>
<Slider>
{compatibilities.map((item, index) => (
<ThermalSlider
data={item}
key={index}
onClick={() => {
handleThermal(item);
}}
/>
))}
</Slider>
</div>
)}
</div>
{/* END SLIDERS */}

View File

@ -1,26 +1,34 @@
import { ReactNode } from 'react'
import './styles.css'
import { ReactNode } from "react";
import styles from "./styles.module.css";
interface ModalProps {
children: ReactNode
open?: boolean
onClose?: () => void
children: ReactNode;
open?: boolean;
isCloseButtonVisible?: boolean;
onClose?: () => void;
}
function Modal({ open, children, onClose }: ModalProps): JSX.Element {
function Modal({
open,
children,
isCloseButtonVisible = true,
onClose,
}: ModalProps): JSX.Element {
const handleClose = (event: React.MouseEvent) => {
if (event.target !== event.currentTarget) return
onClose?.()
}
if (!open) return <></>
if (event.target !== event.currentTarget) return;
onClose?.();
};
if (!open) return <></>;
return (
<div className='modal' onClick={handleClose}>
<div className='modal-content'>
<button className='modal-close-btn' onClick={handleClose} />
<div className={styles.modal} onClick={handleClose}>
<div className={styles["modal-content"]}>
{isCloseButtonVisible && (
<button className={styles["modal-close-btn"]} onClick={handleClose} />
)}
{children}
</div>
</div>
)
);
}
export default Modal
export default Modal;

View File

@ -27,6 +27,10 @@
transform: translate(-50%,-50%);
}
.modal-content::-webkit-scrollbar {
width: 0;
}
.modal-close-btn {
display: flex;
position: absolute;

View File

@ -1,4 +1,4 @@
import { useEffect, useState } from "react";
import { useEffect, useMemo, useState } from "react";
import styles from "./styles.module.css";
import {
getCategoryIdByZodiacSign,
@ -28,7 +28,7 @@ function NameHoroscopeSlider({
const { i18n } = useTranslation();
const locale = i18n.language;
const birthDate = useSelector(selectors.selectBirthdate);
const zodiacSign = getZodiacSignByDate(birthDate);
const zodiacSign = useMemo(() => getZodiacSignByDate(birthDate), [birthDate]);
const [backgroundUrl, setBackgroundUrl] = useState("");
useEffect(() => {
@ -48,7 +48,7 @@ function NameHoroscopeSlider({
console.error("Error: ", error);
}
})();
}, []);
}, [api, locale, zodiacSign]);
return (
<div

View File

@ -42,7 +42,7 @@ function ThermalSlider({ data, onClick }: ThermalProps): JSX.Element {
console.error("Error: ", error);
}
})();
}, []);
}, [api, locale, zodiacSign]);
return (
<div

View File

@ -1,6 +1,5 @@
import { useEffect, useState } from "react";
import { useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { useAuth } from "@/auth";
import { useApi, Assets } from "@/api";
import { saveFile, buildFilename } from "../WallpaperPage/utils";
import styles from "./styles.module.css";
@ -18,13 +17,8 @@ function WallpapersZodiacSign(): JSX.Element {
const locale = i18n.language;
const [asset, setAsset] = useState<Assets.Asset>();
const {
user,
// token
} = useAuth();
const birthdate = useSelector(selectors.selectBirthdate);
const zodiacSign = getZodiacSignByDate(birthdate);
const category = user?.profile.sign?.sign || "";
const zodiacSign = useMemo(() => getZodiacSignByDate(birthdate), [birthdate]);
const getZodiacWallpaper = async () => {
const { asset_categories } = await api.getAssetCategories({ locale });
@ -38,11 +32,14 @@ function WallpapersZodiacSign(): JSX.Element {
useEffect(() => {
getZodiacWallpaper();
}, []);
}, [api, locale, zodiacSign]);
const saveImage = () =>
asset &&
saveFile(asset.url.replace("http://", "https://"), buildFilename(category));
saveFile(
asset.url.replace("http://", "https://"),
buildFilename(zodiacSign)
);
return (
<div

View File

@ -198,6 +198,11 @@ export const hasNoHeader = (path: string) => {
return !withoutHeaderRoutes.includes(`/${path.split("/")[1]}`);
};
export const withFullDataModalRoutes = [routes.client.home()];
export const hasFullDataModal = (path: string) => {
return withFullDataModalRoutes.includes(`/${path.split("/")[1]}`);
};
export const getRouteBy = (status: UserStatus): string => {
switch (status) {
case "lead":

View File

@ -28,7 +28,7 @@ export const getCategoryIdByZodiacSign = (
categories: AssetCategory[]
) => {
const categoryId = categories.find(
(category) => category.slug === zodiacSign.toLowerCase()
(category) => category.slug === zodiacSign?.toLowerCase()
)?.id;
return categoryId;
};