feat: navbar onboarding, add blur name input from done button on compatibility page, fix cross button on compatibility page, add menu button to home page, replace download button moon page, fix percents
This commit is contained in:
parent
2fc26aceb0
commit
844d5d1295
17
public/finger.svg
Normal file
17
public/finger.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 10 KiB |
@ -225,7 +225,9 @@ function Layout({ setIsSpecialOfferOpen }: LayoutProps): JSX.Element {
|
||||
{showNavbar ? (
|
||||
<Navbar isOpen={isMenuOpen} closeMenu={() => setIsMenuOpen(false)} />
|
||||
) : null}
|
||||
{showNavbarFooter && hasNavbarFooter(location.pathname) ? (
|
||||
{
|
||||
// showNavbarFooter &&
|
||||
hasNavbarFooter(location.pathname) ? (
|
||||
<NavbarFooter items={navbarItems} />
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
@ -40,9 +40,10 @@ function CompatResultPage(): JSX.Element {
|
||||
if (homeConfig.pathFromHome === EPathsFromHome.compatibility) {
|
||||
return navigate(routes.client.breath());
|
||||
}
|
||||
return navigate(routes.client.compatibility());
|
||||
};
|
||||
|
||||
const handleCompatibility = () => navigate(routes.client.compatibility());
|
||||
// const handleCompatibility = () => navigate(routes.client.compatibility());
|
||||
|
||||
const loadData = useCallback(async () => {
|
||||
const right_bday =
|
||||
@ -119,7 +120,7 @@ function CompatResultPage(): JSX.Element {
|
||||
}}
|
||||
/>
|
||||
</FullScreenModal>
|
||||
<div className={styles.cross} onClick={handleCompatibility}></div>
|
||||
<div className={styles.cross} onClick={handleNext}></div>
|
||||
<div className={styles["title-container"]}>
|
||||
<Title variant="h2">{t("you_and", { user: rightUser.name })}</Title>
|
||||
</div>
|
||||
|
||||
@ -169,7 +169,7 @@ function CompatibilityPage(): JSX.Element {
|
||||
{!onboardingCompatibility.isShown && <>
|
||||
{currentOnboarding === 0 && (
|
||||
<Onboarding
|
||||
targetRef={inputRef}
|
||||
targetRef={inputRef.current as HTMLDivElement}
|
||||
isShow={currentOnboarding === 0}
|
||||
direction={EDirectionOnboarding.BOTTOM}
|
||||
showBackground={true}
|
||||
@ -183,7 +183,7 @@ function CompatibilityPage(): JSX.Element {
|
||||
)}
|
||||
{currentOnboarding === 1 && (
|
||||
<Onboarding
|
||||
targetRef={dateRef}
|
||||
targetRef={dateRef.current as HTMLDivElement}
|
||||
isShow={currentOnboarding === 1}
|
||||
direction={EDirectionOnboarding.BOTTOM}
|
||||
showBackground={true}
|
||||
@ -206,7 +206,7 @@ function CompatibilityPage(): JSX.Element {
|
||||
)}
|
||||
{currentOnboarding === 3 && (
|
||||
<Onboarding
|
||||
targetRef={mainButtonRef}
|
||||
targetRef={mainButtonRef.current as HTMLDivElement}
|
||||
isShow={currentOnboarding === 3}
|
||||
direction={EDirectionOnboarding.TOP}
|
||||
showBackground={true}
|
||||
@ -231,13 +231,16 @@ function CompatibilityPage(): JSX.Element {
|
||||
onKeyDown={(e) => {
|
||||
if (!name.length) return;
|
||||
if (e.key === "Enter") {
|
||||
setCurrentOnboarding(1);
|
||||
(e.target as HTMLInputElement).blur();
|
||||
dateRef.current?.scrollIntoView({ behavior: "smooth" });
|
||||
}
|
||||
}}
|
||||
onValid={handleValidName}
|
||||
onInvalid={() => setIsDisabledName(true)}
|
||||
onBlur={() => {
|
||||
if (!name.length) return;
|
||||
setCurrentOnboarding(1);
|
||||
dateRef.current?.scrollIntoView({ behavior: "smooth" });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
@ -250,7 +253,7 @@ function CompatibilityPage(): JSX.Element {
|
||||
</div>
|
||||
{currentOnboarding === 2 && !onboardingCompatibility.isShown && (
|
||||
<Onboarding
|
||||
targetRef={categoriesRef}
|
||||
targetRef={categoriesRef.current as HTMLDivElement}
|
||||
isShow={currentOnboarding === 2}
|
||||
direction={EDirectionOnboarding.TOP}
|
||||
showBackground={true}
|
||||
|
||||
@ -10,6 +10,7 @@ interface INameInput<T> {
|
||||
onKeyDown: (event: React.KeyboardEvent<HTMLInputElement>) => void;
|
||||
onValid: (value: string) => void;
|
||||
onInvalid: () => void;
|
||||
onBlur: () => void;
|
||||
}
|
||||
|
||||
const isValidName = (name: string) => {
|
||||
@ -17,7 +18,8 @@ const isValidName = (name: string) => {
|
||||
};
|
||||
|
||||
function NameInput(props: INameInput<string>): JSX.Element {
|
||||
const { name, value, placeholder, onValid, onInvalid, onKeyDown } = props;
|
||||
const { name, value, placeholder, onValid, onInvalid, onKeyDown, onBlur } =
|
||||
props;
|
||||
const [userName, setUserName] = useState(value);
|
||||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setUserName(event.target.value);
|
||||
@ -40,6 +42,7 @@ function NameInput(props: INameInput<string>): JSX.Element {
|
||||
onChange={handleChange}
|
||||
onKeyDown={onKeyDown}
|
||||
placeholder={placeholder ?? " "}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -14,7 +14,7 @@ const colors: Record<string, string> = {
|
||||
}
|
||||
|
||||
const valueFormatter = (value: number) => {
|
||||
return `${(value * 10).toFixed(1)}%`
|
||||
return `${(value * 100).toFixed(1)}%`
|
||||
}
|
||||
|
||||
function EnergyValues({ className, values }: IEnergyValues): JSX.Element {
|
||||
|
||||
@ -166,7 +166,7 @@ function HomePage(): JSX.Element {
|
||||
isShowNavbar ? styles["content__buttons--hidden"] : ""
|
||||
}`}
|
||||
>
|
||||
<Onboarding targetRef={buttonsRef} isShow={isShowOnboardingHome}>
|
||||
<Onboarding targetRef={buttonsRef.current as HTMLDivElement} isShow={isShowOnboardingHome}>
|
||||
<TextWithFinger
|
||||
text={t("au.web_onbording.start")}
|
||||
crossClickHandler={() => setIsShowOnboardingHome(false)}
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
}
|
||||
|
||||
.navbar.navbar--open {
|
||||
z-index: 5;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.navbar.navbar--open .navbar__panel {
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
import { Link } from "react-router-dom";
|
||||
import styles from "./styles.module.css";
|
||||
import Onboarding from "../Onboarding";
|
||||
import { useRef, useState } from "react";
|
||||
import TextWithFinger from "../TextWithFinger";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { actions, selectors } from "@/store";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export interface INavbarHomeItems {
|
||||
title: string;
|
||||
@ -15,6 +21,58 @@ interface INavbarHomeProps {
|
||||
}
|
||||
|
||||
function NavbarFooter({ items }: INavbarHomeProps): JSX.Element {
|
||||
const dispatch = useDispatch();
|
||||
const { t } = useTranslation();
|
||||
const onboardingConfigNavbarFooter = useSelector(
|
||||
selectors.selectOnboardingNavbarFooter
|
||||
);
|
||||
|
||||
const [isShowOnboardingNavbarFooter, setIsShowOnboardingNavbarFooter] =
|
||||
useState(!onboardingConfigNavbarFooter.isShown);
|
||||
const [selectedOnboarding, setSelectedOnboarding] = useState(3);
|
||||
|
||||
const buttonsRef = useRef([] as HTMLDivElement[]);
|
||||
|
||||
const setShownOnboarding = () => {
|
||||
setIsShowOnboardingNavbarFooter(false);
|
||||
dispatch(
|
||||
actions.onboardingConfig.update({
|
||||
navbarFooter: {
|
||||
isShown: true,
|
||||
},
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const onboardingsSettings = [
|
||||
{
|
||||
text: t("au.web_onbording.breathing"),
|
||||
onClick: () => setSelectedOnboarding(2),
|
||||
classNameText: `${styles["breathing-onboarding__text"]} ${styles.onboarding}`,
|
||||
},
|
||||
{
|
||||
text: t("au.web_onbording.onboarding_2"),
|
||||
onClick: () => setSelectedOnboarding(2),
|
||||
},
|
||||
{
|
||||
text: t("au.web_onbording.compatibility"),
|
||||
onClick: () => setShownOnboarding(),
|
||||
classNameText: `${styles["compatibility-onboarding__text"]} ${styles.onboarding}`,
|
||||
},
|
||||
{
|
||||
text: t("au.web_onbording.moon"),
|
||||
onClick: () => setSelectedOnboarding(0),
|
||||
classNameText: `${styles["moon-onboarding__text"]} ${styles.onboarding}`,
|
||||
},
|
||||
];
|
||||
|
||||
const handleClick = (item: INavbarHomeItems) => {
|
||||
onboardingsSettings[selectedOnboarding].onClick();
|
||||
if (item.onClick) {
|
||||
item.onClick();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`${styles["container"]}`}>
|
||||
{items.map((item, index) => (
|
||||
@ -23,17 +81,33 @@ function NavbarFooter({ items }: INavbarHomeProps): JSX.Element {
|
||||
item.active ? styles["navbar-item--active"] : ""
|
||||
}`}
|
||||
key={index}
|
||||
ref={(el) => (buttonsRef.current[index] = el as HTMLDivElement)}
|
||||
>
|
||||
{isShowOnboardingNavbarFooter && (
|
||||
<Onboarding
|
||||
targetRef={buttonsRef.current[index]}
|
||||
isShow={index === selectedOnboarding}
|
||||
>
|
||||
<TextWithFinger
|
||||
text={onboardingsSettings[index].text}
|
||||
crossClickHandler={() => onboardingsSettings[index].onClick()}
|
||||
classNameText={onboardingsSettings[index].classNameText}
|
||||
/>
|
||||
</Onboarding>
|
||||
)}
|
||||
<Link
|
||||
className={styles["navbar-item__link"]}
|
||||
to={item.path}
|
||||
onClick={item.onClick}
|
||||
onClick={() => {
|
||||
handleClick(item);
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={styles["navbar-item__image-container"]}
|
||||
style={{
|
||||
backgroundColor:
|
||||
item.paths.includes(location.pathname) ? "#ff2c57" : "#fff",
|
||||
backgroundColor: item.paths.includes(location.pathname)
|
||||
? "#ff2c57"
|
||||
: "#fff",
|
||||
mask: `url('/navbar-icons/${item.image}')`,
|
||||
WebkitMask: `url('/navbar-icons/${item.image}')`,
|
||||
WebkitMaskSize: "contain",
|
||||
@ -50,7 +124,9 @@ function NavbarFooter({ items }: INavbarHomeProps): JSX.Element {
|
||||
</div>
|
||||
<p
|
||||
style={{
|
||||
color: item.paths.includes(location.pathname) ? "#ff2c57" : "#fff",
|
||||
color: item.paths.includes(location.pathname)
|
||||
? "#ff2c57"
|
||||
: "#fff",
|
||||
}}
|
||||
>
|
||||
{item.title}
|
||||
|
||||
@ -44,3 +44,16 @@
|
||||
.navbar-item__image {
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.onboarding {
|
||||
width: 188px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.moon-onboarding__text {
|
||||
margin-right: 108px;
|
||||
}
|
||||
|
||||
.breathing-onboarding__text {
|
||||
margin-left: 108px;
|
||||
}
|
||||
|
||||
@ -9,11 +9,12 @@ export enum EDirectionOnboarding {
|
||||
}
|
||||
|
||||
interface OnboardingProps {
|
||||
targetRef: React.RefObject<HTMLElement>;
|
||||
targetRef: HTMLElement;
|
||||
isShow: boolean;
|
||||
direction?: EDirectionOnboarding;
|
||||
showBackground?: boolean;
|
||||
children: JSX.Element;
|
||||
classNameContainer?: string;
|
||||
}
|
||||
interface IBoardingCoordinates {
|
||||
top: number;
|
||||
@ -21,43 +22,43 @@ interface IBoardingCoordinates {
|
||||
}
|
||||
|
||||
const getCoordinates = (
|
||||
targetRef: React.RefObject<HTMLElement>,
|
||||
targetRef: HTMLElement,
|
||||
direction: EDirectionOnboarding,
|
||||
onboardingRef: React.RefObject<HTMLDivElement>
|
||||
): IBoardingCoordinates => {
|
||||
if (targetRef.current && onboardingRef.current) {
|
||||
if (targetRef && onboardingRef.current) {
|
||||
switch (direction) {
|
||||
case EDirectionOnboarding.LEFT:
|
||||
return {
|
||||
top:
|
||||
targetRef.current.offsetTop +
|
||||
targetRef.current.offsetHeight / 2 -
|
||||
targetRef.offsetTop +
|
||||
targetRef.offsetHeight / 2 -
|
||||
onboardingRef.current.offsetHeight / 2,
|
||||
left:
|
||||
targetRef.current.offsetLeft - onboardingRef.current.offsetWidth,
|
||||
targetRef.offsetLeft - onboardingRef.current.offsetWidth,
|
||||
};
|
||||
case EDirectionOnboarding.RIGHT:
|
||||
return {
|
||||
top:
|
||||
targetRef.current.offsetTop +
|
||||
targetRef.current.offsetHeight / 2 -
|
||||
targetRef.offsetTop +
|
||||
targetRef.offsetHeight / 2 -
|
||||
onboardingRef.current.offsetHeight / 2,
|
||||
left: targetRef.current.offsetLeft + targetRef.current.offsetWidth,
|
||||
left: targetRef.offsetLeft + targetRef.offsetWidth,
|
||||
};
|
||||
case EDirectionOnboarding.TOP:
|
||||
return {
|
||||
top: targetRef.current.offsetTop - onboardingRef.current.offsetHeight,
|
||||
top: targetRef.offsetTop - onboardingRef.current.offsetHeight,
|
||||
left:
|
||||
targetRef.current.offsetLeft +
|
||||
targetRef.current.offsetWidth / 2 -
|
||||
targetRef.offsetLeft +
|
||||
targetRef.offsetWidth / 2 -
|
||||
onboardingRef.current.offsetWidth / 2,
|
||||
};
|
||||
case EDirectionOnboarding.BOTTOM:
|
||||
return {
|
||||
top: targetRef.current.offsetTop + targetRef.current.offsetHeight,
|
||||
top: targetRef.offsetTop + targetRef.offsetHeight,
|
||||
left:
|
||||
targetRef.current.offsetLeft +
|
||||
targetRef.current.offsetWidth / 2 -
|
||||
targetRef.offsetLeft +
|
||||
targetRef.offsetWidth / 2 -
|
||||
onboardingRef.current.offsetWidth / 2,
|
||||
};
|
||||
}
|
||||
@ -70,11 +71,12 @@ const getCoordinates = (
|
||||
|
||||
const getClassNameContainer = (
|
||||
direction: EDirectionOnboarding,
|
||||
showBackground: boolean
|
||||
showBackground: boolean,
|
||||
classNameContainer?: string
|
||||
) => {
|
||||
return `${styles["onboarding-container"]} ${
|
||||
styles[`direction-${direction}`]
|
||||
} ${showBackground ? styles["background"] : ""}`;
|
||||
} ${showBackground ? styles["background"] : ""} ${classNameContainer}`;
|
||||
};
|
||||
|
||||
function Onboarding({
|
||||
@ -82,6 +84,7 @@ function Onboarding({
|
||||
isShow,
|
||||
direction = EDirectionOnboarding.TOP,
|
||||
showBackground = false,
|
||||
classNameContainer = '',
|
||||
children,
|
||||
}: OnboardingProps): JSX.Element {
|
||||
const onboardingRef = useRef<HTMLDivElement>(null);
|
||||
@ -99,10 +102,10 @@ function Onboarding({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={getClassNameContainer(direction, showBackground)}>
|
||||
<div className={getClassNameContainer(direction, showBackground, classNameContainer)}>
|
||||
<div
|
||||
className={`${styles["onboarding"]} ${
|
||||
!targetRef.current || !onboardingRef.current ? styles["hide"] : ""
|
||||
!targetRef || !onboardingRef.current ? styles["hide"] : ""
|
||||
}`}
|
||||
style={{ top: `${top}px`, left: `${left}px` }}
|
||||
ref={onboardingRef}
|
||||
|
||||
@ -1,23 +1,25 @@
|
||||
import { EDirectionOnboarding } from "../Onboarding";
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
interface OnboardingProps {
|
||||
interface TextWithFingerProps {
|
||||
text: string;
|
||||
showCross?: boolean;
|
||||
direction?: EDirectionOnboarding;
|
||||
classNameText?: string;
|
||||
crossClickHandler?: () => void;
|
||||
}
|
||||
|
||||
function Onboarding({
|
||||
function TextWithFinger({
|
||||
text,
|
||||
showCross = true,
|
||||
direction = EDirectionOnboarding.TOP,
|
||||
classNameText = "",
|
||||
crossClickHandler,
|
||||
}: OnboardingProps): JSX.Element {
|
||||
}: TextWithFingerProps): JSX.Element {
|
||||
return (
|
||||
<>
|
||||
{text.length && (
|
||||
<div className={styles["onboarding-text"]}>
|
||||
<div className={`${styles["onboarding-text"]} ${classNameText}`}>
|
||||
{showCross && (
|
||||
<div className={styles["cross"]} onClick={crossClickHandler}></div>
|
||||
)}
|
||||
@ -26,11 +28,11 @@ function Onboarding({
|
||||
)}
|
||||
<img
|
||||
className={`${styles["finger"]} ${styles[`direction-${direction}`]}`}
|
||||
src="/finger.png"
|
||||
src="/finger.svg"
|
||||
alt="finger"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Onboarding;
|
||||
export default TextWithFinger;
|
||||
|
||||
@ -60,15 +60,19 @@
|
||||
|
||||
.btn-download {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 28px;
|
||||
right: 32px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
background-image: url(./Dowload.png);
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
background-size: 70%;
|
||||
background-image: url("/Save-icon.png");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
-webkit-backdrop-filter: blur(14px);
|
||||
background-color: #696969;
|
||||
backdrop-filter: blur(14px);
|
||||
border-radius: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.zodiac-metas {
|
||||
|
||||
@ -89,7 +89,7 @@ export const isEntrypoint = (path: string) => entrypoints.includes(path);
|
||||
export const isNotEntrypoint = (path: string) => !isEntrypoint(path);
|
||||
export const withNavigationRoutes = [
|
||||
routes.client.wallpaper(),
|
||||
// routes.client.home(),
|
||||
routes.client.home(),
|
||||
];
|
||||
export const hasNavigation = (path: string) =>
|
||||
withNavigationRoutes.includes(path);
|
||||
|
||||
@ -19,6 +19,7 @@ import onboardingConfig, {
|
||||
selectOnboardingBreath,
|
||||
selectOnboardingCompatibility,
|
||||
selectOnboardingHome,
|
||||
selectOnboardingNavbarFooter,
|
||||
actions as onboardingConfigActions,
|
||||
} from "./onboarding";
|
||||
import payment, {
|
||||
@ -90,6 +91,7 @@ export const selectors = {
|
||||
selectOnboardingHome,
|
||||
selectOnboardingCompatibility,
|
||||
selectOnboardingBreath,
|
||||
selectOnboardingNavbarFooter,
|
||||
...formSelectors,
|
||||
};
|
||||
export type RootState = ReturnType<typeof reducer>;
|
||||
|
||||
@ -11,6 +11,9 @@ interface IOnboardingConfig {
|
||||
breath: {
|
||||
isShown: boolean;
|
||||
};
|
||||
navbarFooter: {
|
||||
isShown: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
const initialState: IOnboardingConfig = {
|
||||
@ -23,6 +26,9 @@ const initialState: IOnboardingConfig = {
|
||||
breath: {
|
||||
isShown: false,
|
||||
},
|
||||
navbarFooter: {
|
||||
isShown: false
|
||||
}
|
||||
};
|
||||
|
||||
const onboardingConfigSlice = createSlice({
|
||||
@ -45,6 +51,10 @@ export const selectOnboardingHome = createSelector(
|
||||
(state: { onboardingConfig: IOnboardingConfig }) => state.onboardingConfig.home,
|
||||
(onboardingConfig) => onboardingConfig
|
||||
);
|
||||
export const selectOnboardingNavbarFooter = createSelector(
|
||||
(state: { onboardingConfig: IOnboardingConfig }) => state.onboardingConfig.navbarFooter,
|
||||
(onboardingConfig) => onboardingConfig
|
||||
);
|
||||
export const selectOnboardingCompatibility = createSelector(
|
||||
(state: { onboardingConfig: IOnboardingConfig }) =>
|
||||
state.onboardingConfig.compatibility,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user