Merge branch 'clone' into 'main'
feat: add modal with required data See merge request witapp/aura-webapp!18
This commit is contained in:
commit
64ee5a0c79
@ -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 ? (
|
||||
|
||||
42
src/components/FullDataModal/index.tsx
Normal file
42
src/components/FullDataModal/index.tsx
Normal 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;
|
||||
0
src/components/FullDataModal/styles.module.css
Normal file
0
src/components/FullDataModal/styles.module.css
Normal 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 */}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -27,6 +27,10 @@
|
||||
transform: translate(-50%,-50%);
|
||||
}
|
||||
|
||||
.modal-content::-webkit-scrollbar {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.modal-close-btn {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
@ -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
|
||||
|
||||
@ -42,7 +42,7 @@ function ThermalSlider({ data, onClick }: ThermalProps): JSX.Element {
|
||||
console.error("Error: ", error);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
}, [api, locale, zodiacSign]);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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":
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user