feat: add modal with required data

This commit is contained in:
Денис Катаев 2023-12-21 23:21:51 +00:00 committed by Victor Ershov
parent 35c2120ca2
commit e9e35f81d3
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 { import {
Routes, Routes,
Route, Route,
@ -16,6 +16,7 @@ import routes, {
hasNoFooter, hasNoFooter,
hasNoHeader, hasNoHeader,
hasNavbarFooter, hasNavbarFooter,
hasFullDataModal,
} from "@/routes"; } from "@/routes";
import BirthdayPage from "../BirthdayPage"; import BirthdayPage from "../BirthdayPage";
import BirthtimePage from "../BirthtimePage"; import BirthtimePage from "../BirthtimePage";
@ -59,6 +60,8 @@ import ThermalResult from "../pages/ThermalResult";
import MoonPhaseTrackerResult from "../pages/MoonPhaseTrackerResult"; import MoonPhaseTrackerResult from "../pages/MoonPhaseTrackerResult";
import EnergyVampirismResult from "../pages/EnergyVampirismResult"; import EnergyVampirismResult from "../pages/EnergyVampirismResult";
import NameHoroscopeResult from "../pages/NameHoroscopeResult"; import NameHoroscopeResult from "../pages/NameHoroscopeResult";
import Modal from "../Modal";
import FullDataModal from "../FullDataModal";
function App(): JSX.Element { function App(): JSX.Element {
const [isSpecialOfferOpen, setIsSpecialOfferOpen] = useState<boolean>(false); const [isSpecialOfferOpen, setIsSpecialOfferOpen] = useState<boolean>(false);
@ -282,11 +285,27 @@ function Layout({ setIsSpecialOfferOpen }: LayoutProps): JSX.Element {
const showNavbar = hasNavigation(location.pathname); const showNavbar = hasNavigation(location.pathname);
const showFooter = hasNoFooter(location.pathname); const showFooter = hasNoFooter(location.pathname);
const showHeader = hasNoHeader(location.pathname); const showHeader = hasNoHeader(location.pathname);
const isRouteFullDataModal = hasFullDataModal(location.pathname);
const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false); const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false);
const changeIsSpecialOfferOpen = () => setIsSpecialOfferOpen(true); const changeIsSpecialOfferOpen = () => setIsSpecialOfferOpen(true);
const homeConfig = useSelector(selectors.selectHome); const homeConfig = useSelector(selectors.selectHome);
const showNavbarFooter = homeConfig.isShowNavbar; 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 = () => { const handleCompatibility = () => {
dispatch( dispatch(
actions.siteConfig.update({ actions.siteConfig.update({
@ -353,6 +372,11 @@ function Layout({ setIsSpecialOfferOpen }: LayoutProps): JSX.Element {
clickCross={changeIsSpecialOfferOpen} clickCross={changeIsSpecialOfferOpen}
/> />
) : null} ) : null}
{isRouteFullDataModal && (
<Modal open={isShowFullDataModal} isCloseButtonVisible={false}>
<FullDataModal onClose={onCloseFullDataModal} />
</Modal>
)}
<main className="content"> <main className="content">
<Outlet /> <Outlet />
</main> </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 { function SkipStep(): JSX.Element {
const { user } = useAuth(); const { user } = useAuth();
return user ? ( 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(() => { useEffect(() => {
getMoonsImages(); getMoonsImages();
}, []); }, [api]);
const getMoonsImages = async () => { const getMoonsImages = async () => {
const assets = ( const assets = (
@ -288,22 +288,24 @@ function HomePage(): JSX.Element {
{/* SLIDERS */} {/* SLIDERS */}
<div className={styles.sliders}> <div className={styles.sliders}>
<div className={styles["slider"]}> {!!compatibilities.length && (
<Title variant="h2" className={styles["sliders__title"]}> <div className={styles["slider"]}>
{"Your Besties' Horoscope"} <Title variant="h2" className={styles["sliders__title"]}>
</Title> {"Your Besties' Horoscope"}
<Slider> </Title>
{compatibilities.map((item, index) => ( <Slider>
<BestiesHoroscopeSlider {compatibilities.map((item, index) => (
data={item} <BestiesHoroscopeSlider
key={index} data={item}
onClick={() => { key={index}
handleBestiesHoroscope(item); onClick={() => {
}} handleBestiesHoroscope(item);
/> }}
))} />
</Slider> ))}
</div> </Slider>
</div>
)}
<div className={styles["slider"]}> <div className={styles["slider"]}>
<Title variant="h2" className={styles["sliders__title"]}> <Title variant="h2" className={styles["sliders__title"]}>
{"Prediction Based on Your Moons"} {"Prediction Based on Your Moons"}
@ -357,22 +359,24 @@ function HomePage(): JSX.Element {
{/* SLIDERS */} {/* SLIDERS */}
<div className={styles.sliders}> <div className={styles.sliders}>
<div className={styles["slider"]}> {!!compatibilities.length && (
<Title variant="h2" className={styles["sliders__title"]}> <div className={styles["slider"]}>
{t("au.thermal_compatibility.result_title")} <Title variant="h2" className={styles["sliders__title"]}>
</Title> {t("au.thermal_compatibility.result_title")}
<Slider> </Title>
{compatibilities.map((item, index) => ( <Slider>
<ThermalSlider {compatibilities.map((item, index) => (
data={item} <ThermalSlider
key={index} data={item}
onClick={() => { key={index}
handleThermal(item); onClick={() => {
}} handleThermal(item);
/> }}
))} />
</Slider> ))}
</div> </Slider>
</div>
)}
</div> </div>
{/* END SLIDERS */} {/* END SLIDERS */}

View File

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

View File

@ -27,6 +27,10 @@
transform: translate(-50%,-50%); transform: translate(-50%,-50%);
} }
.modal-content::-webkit-scrollbar {
width: 0;
}
.modal-close-btn { .modal-close-btn {
display: flex; display: flex;
position: absolute; 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 styles from "./styles.module.css";
import { import {
getCategoryIdByZodiacSign, getCategoryIdByZodiacSign,
@ -28,7 +28,7 @@ function NameHoroscopeSlider({
const { i18n } = useTranslation(); const { i18n } = useTranslation();
const locale = i18n.language; const locale = i18n.language;
const birthDate = useSelector(selectors.selectBirthdate); const birthDate = useSelector(selectors.selectBirthdate);
const zodiacSign = getZodiacSignByDate(birthDate); const zodiacSign = useMemo(() => getZodiacSignByDate(birthDate), [birthDate]);
const [backgroundUrl, setBackgroundUrl] = useState(""); const [backgroundUrl, setBackgroundUrl] = useState("");
useEffect(() => { useEffect(() => {
@ -48,7 +48,7 @@ function NameHoroscopeSlider({
console.error("Error: ", error); console.error("Error: ", error);
} }
})(); })();
}, []); }, [api, locale, zodiacSign]);
return ( return (
<div <div

View File

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

View File

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

View File

@ -198,6 +198,11 @@ export const hasNoHeader = (path: string) => {
return !withoutHeaderRoutes.includes(`/${path.split("/")[1]}`); 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 => { export const getRouteBy = (status: UserStatus): string => {
switch (status) { switch (status) {
case "lead": case "lead":

View File

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