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:
gofnnp 2023-10-06 00:34:38 +04:00
parent 2fc26aceb0
commit 844d5d1295
16 changed files with 183 additions and 47 deletions

17
public/finger.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -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>

View File

@ -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>

View File

@ -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}

View File

@ -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>
);

View File

@ -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 {

View File

@ -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)}

View File

@ -6,7 +6,7 @@
}
.navbar.navbar--open {
z-index: 5;
z-index: 99;
}
.navbar.navbar--open .navbar__panel {

View File

@ -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}

View File

@ -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;
}

View File

@ -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}

View File

@ -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;

View File

@ -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 {

View File

@ -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);

View File

@ -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>;

View File

@ -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,