diff --git a/src/assets/icons/IconCart.svg b/src/assets/icons/IconCart.svg index 19ba73fa..094fee80 100644 --- a/src/assets/icons/IconCart.svg +++ b/src/assets/icons/IconCart.svg @@ -1,3 +1,3 @@ - - + + diff --git a/src/assets/icons/IconHeaderMenuArrow.svg b/src/assets/icons/IconHeaderMenuArrow.svg new file mode 100644 index 00000000..83967014 --- /dev/null +++ b/src/assets/icons/IconHeaderMenuArrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/IconHeart.svg b/src/assets/icons/IconHeart.svg new file mode 100644 index 00000000..c253ef84 --- /dev/null +++ b/src/assets/icons/IconHeart.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/shared/icons/person.svg b/src/assets/icons/IconPerson.svg similarity index 96% rename from src/shared/icons/person.svg rename to src/assets/icons/IconPerson.svg index d9236bfc..cbd0d566 100644 --- a/src/shared/icons/person.svg +++ b/src/assets/icons/IconPerson.svg @@ -1,3 +1,3 @@ - + diff --git a/src/shared/icons/person_auth.svg b/src/assets/icons/IconPersonAuth.svg similarity index 98% rename from src/shared/icons/person_auth.svg rename to src/assets/icons/IconPersonAuth.svg index 0f045e0c..2bd9baeb 100644 --- a/src/shared/icons/person_auth.svg +++ b/src/assets/icons/IconPersonAuth.svg @@ -1,3 +1,3 @@ - + diff --git a/src/assets/icons/IconPhone.svg b/src/assets/icons/IconPhone.svg new file mode 100644 index 00000000..5af1cbab --- /dev/null +++ b/src/assets/icons/IconPhone.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/shared/icons/scales.svg b/src/assets/icons/IconScales.svg similarity index 98% rename from src/shared/icons/scales.svg rename to src/assets/icons/IconScales.svg index d770e784..19675179 100644 --- a/src/shared/icons/scales.svg +++ b/src/assets/icons/IconScales.svg @@ -1,3 +1,3 @@ - + diff --git a/src/assets/icons/iconHeaderMenuClose.svg b/src/assets/icons/iconHeaderMenuClose.svg new file mode 100644 index 00000000..7e327aaa --- /dev/null +++ b/src/assets/icons/iconHeaderMenuClose.svg @@ -0,0 +1,4 @@ + + + diff --git a/src/assets/icons/iconMenu.svg b/src/assets/icons/iconMenu.svg index c1fc5fb6..5685a635 100644 --- a/src/assets/icons/iconMenu.svg +++ b/src/assets/icons/iconMenu.svg @@ -1,6 +1,6 @@ - - - - + + + + diff --git a/src/assets/icons/iconSearch.svg b/src/assets/icons/iconSearch.svg index ac0c10a9..21c1538d 100644 --- a/src/assets/icons/iconSearch.svg +++ b/src/assets/icons/iconSearch.svg @@ -1,4 +1,4 @@ - - + + diff --git a/src/entities/ContactCard/ContactCard.tsx b/src/entities/ContactCard/ContactCard.tsx index 1f048598..6ee5b9e4 100644 --- a/src/entities/ContactCard/ContactCard.tsx +++ b/src/entities/ContactCard/ContactCard.tsx @@ -7,6 +7,7 @@ import Paragraph from '@/shared/ui/Paragraph/Paragraph' import styles from './contactCard.module.scss' export type PropsContactCard = { + isMenuModalOpen?: boolean messenger: TMessenger Icon: string } @@ -15,17 +16,25 @@ export type PropsContactCard = { * Компонент карточки контакта. Заполнение карточки происходит с применением метода map * по массиву мессенджеров с использованием из него ссылки (link) на мессенджер, его названием (title) и иконку(Icon). * Причем иконка(Icon) в массиве мессенджеров импортируется как svg компонент + * @param {boolean} isMenuModalOpen - состояние открытия модального окна; * @param {TMessenger} messenger - массив для наполнения карточки контакта; * @param {string} Icon - компонент-ссылка на svg-компонент из массива messenger (messenger.icon); */ -const ContactCard: FC = ({ messenger, Icon }) => { +const ContactCard: FC = ({ isMenuModalOpen, messenger, Icon }) => { return ( -
  • - -
    +
  • + +
    - {messenger.title} + {!isMenuModalOpen && {messenger.title}}
  • ) diff --git a/src/entities/ContactCard/contactCard.module.scss b/src/entities/ContactCard/contactCard.module.scss index 62e8a2ea..54d1e4cd 100644 --- a/src/entities/ContactCard/contactCard.module.scss +++ b/src/entities/ContactCard/contactCard.module.scss @@ -4,19 +4,30 @@ background-color: var.$white; border-radius: 5px; margin: 0 1.5px 3px; -} -.link { - height: 160px; - width: 163px; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; -} + &__link { + height: 160px; + width: 163px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + } + + &__icon { + width: 60px; + height: 60px; + margin-bottom: 12px; + } -.icon { - width: 60px; - height: 60px; - margin-bottom: 12px; + &__iconHeaderMenuModal { + width: 40px; + height: 40px; + } } + + + + + + diff --git a/src/entities/HeaderAccount/HeaderAccount.tsx b/src/entities/HeaderAccount/HeaderAccount.tsx index d09938cb..ca67f516 100644 --- a/src/entities/HeaderAccount/HeaderAccount.tsx +++ b/src/entities/HeaderAccount/HeaderAccount.tsx @@ -1,16 +1,16 @@ import { FC, lazy, useState, Suspense, useEffect } from 'react' import { useSelector } from 'react-redux' -import SearchIcon from '@/assets/icons/iconSearch.svg' +import CartIcon from '@/assets/icons/IconCart.svg' +import HeartIcon from '@/assets/icons/IconHeart.svg' +import PersonIcon from '@/assets/icons/IconPerson.svg' +import PersonAuthIcon from '@/assets/icons/IconPersonAuth.svg' +import ScalesIcon from '@/assets/icons/IconScales.svg' +import SearchIcon from '@/assets/icons/IconSearch.svg' import { getUserAuthStatus } from '@/features/login/model/selectors/getUserAuthStatus' import { logout } from '@/features/login/model/services/logout/logout' import { loginActions } from '@/features/login/model/slice/loginSlice' import { Routes } from '@/shared/config/routerConfig/routes' -import CartIcon from '@/shared/icons/cart.svg' -import HeartIcon from '@/shared/icons/heart.svg' -import PersonIcon from '@/shared/icons/person.svg' -import PersonAuthIcon from '@/shared/icons/person_auth.svg' -import ScalesIcon from '@/shared/icons/scales.svg' import { useAppDispatch } from '@/shared/libs/hooks/store' import { useResize } from '@/shared/libs/hooks/useResize' import { Button } from '@/shared/ui/Button/Button' @@ -22,6 +22,8 @@ import Spinner from '@/shared/ui/Spinner/Spinner' import styles from './headerAccount.module.scss' export type HeaderAccountProps = { + isMenuModalOpen?: boolean + handleClose?: () => void counter: number total: string } @@ -29,10 +31,12 @@ export type HeaderAccountProps = { const LazyLoginForm = lazy(() => import('@/features/login/index')) /** + * Компонент хедера, показывающий блок аккаунта + * @param {boolean} isMenuModalOpen - состояние открытия модального окна * @param {string} counter - счетчик количества товаров в корзине * @param {string} total - полная стоимость */ -const HeaderAccount: FC = ({ counter, total }) => { +const HeaderAccount: FC = ({ isMenuModalOpen, handleClose, counter, total }) => { const [isModalOpen, setIsModalOpen] = useState(false) const [isModalClosing, setIsModalClosing] = useState(false) @@ -73,47 +77,110 @@ const HeaderAccount: FC = ({ counter, total }) => { )} -
      - {!isScreenLg && } +
        + {isScreenLg || isMenuModalOpen ? null : }
      • {/* Временная реализация TODO заменить на дропдаун на ховер в контекстном меню добавить пункт-кнопку для разлогина пока висит на иконке */}
      • - {isScreenLg && ( + {isScreenLg || isMenuModalOpen ? (
      • - - + +
      • - )} + ) : null} - {isScreenLg && ( + {isScreenLg || isMenuModalOpen ? (
      • - - + +
      • - )} + ) : null}
      • - - {isScreenLg && ( -
        -
        - Корзина - {counter} + className={ + isScreenLg || isMenuModalOpen + ? `${styles.headerAccount__cart}` + : `${styles.headerAccount__cartMobile}` + }> + {isScreenLg || isMenuModalOpen ? ( + <> + +
        +
        + Корзина + {counter} +
        + + {total} +
        - {total} -
        + + ) : ( + )}
      • diff --git a/src/entities/HeaderAccount/headerAccount.module.scss b/src/entities/HeaderAccount/headerAccount.module.scss index cc479828..38751182 100644 --- a/src/entities/HeaderAccount/headerAccount.module.scss +++ b/src/entities/HeaderAccount/headerAccount.module.scss @@ -1,4 +1,4 @@ -@use '../../shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/variables' as var; .headerAccount { grid-area: account; @@ -12,14 +12,6 @@ gap: 24px; } - &__search { - cursor: pointer; - - &:active { - transform: scale(0.9); - } - } - &__cart { display: flex; justify-content: center; @@ -31,7 +23,7 @@ transition: border 0.25s; &:hover { - border: 1px solid var.$white; + border: 1px solid var.$link-border; } } @@ -47,6 +39,24 @@ } } + &__icon { + fill: var.$white; + cursor: pointer; + transition: 0.25s; + + &:hover { + fill: var.$header-color; + } + + &:active { + transform: scale(0.9); + } + + &_active { + fill: var.$footer-form-color; + } + } + &__cartContainer { display: flex; flex-direction: column; @@ -66,6 +76,10 @@ font-size: 13px; font-weight: 600; color: var.$white; + + &_dark { + color: var.$body-color; + } } &__cartTotalText { diff --git a/src/features/HeaderMenuModal/HeaderMenuModalCatalog/HeaderMenuModalCatalog.module.scss b/src/features/HeaderMenuModal/HeaderMenuModalCatalog/HeaderMenuModalCatalog.module.scss new file mode 100644 index 00000000..c6d7a317 --- /dev/null +++ b/src/features/HeaderMenuModal/HeaderMenuModalCatalog/HeaderMenuModalCatalog.module.scss @@ -0,0 +1,27 @@ +@use '@/shared/styles/utils/variables' as var; + +.headerMenuModalCatalog { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + + &__route { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + min-height: 57px; + border-bottom: 1px solid var.$bg-subscribe; + font-size: 15px; + color: var.$body-color; + margin: 0; + padding: 10px 30px; + cursor: pointer; + transition: 0.25s; + + &:active { + color: var.$header-color; + } + } +} diff --git a/src/features/HeaderMenuModal/HeaderMenuModalCatalog/HeaderMenuModalCatalog.tsx b/src/features/HeaderMenuModal/HeaderMenuModalCatalog/HeaderMenuModalCatalog.tsx new file mode 100644 index 00000000..3c1df450 --- /dev/null +++ b/src/features/HeaderMenuModal/HeaderMenuModalCatalog/HeaderMenuModalCatalog.tsx @@ -0,0 +1,56 @@ +import { FC } from 'react' + +import { Routes } from '@/shared/config/routerConfig/routes' +import Link from '@/shared/ui/Link/Link' + +import HeaderMenuModalHeading from '../HeaderMenuModalHeading/HeaderMenuModalHeading' +import { ICategory } from '../model/types/types' + +import styles from './HeaderMenuModalCatalog.module.scss' + +export interface IHeaderMenuModalCatalog { + categories?: ICategory[] + handleCategory?: () => void + isCatalog?: boolean + handleClose?: () => void +} + +/** + * Компонент для отрисовки категорий в HeaderMenuModal; + * @param {boolean} isCatalog - стейт позволяющий показывать данный компонент; + * @param {array} categories - массив категорий полученный из редакса; + * @param {function} handleCategory - функция переключения активности; + * @param {function} handleClose - функция закрытия модальго окна; + */ + +const HeaderMenuModalCatalog: FC = ({ + isCatalog, + categories, + handleCategory, + handleClose +}) => { + return ( + <> + {isCatalog && ( +
        + + +
          + {categories?.map(item => ( +
        • + + {item.name} + +
        • + ))} +
        +
        + )} + + ) +} + +export default HeaderMenuModalCatalog diff --git a/src/features/HeaderMenuModal/HeaderMenuModalHeading/HeaderMenuModalHeading.module.scss b/src/features/HeaderMenuModal/HeaderMenuModalHeading/HeaderMenuModalHeading.module.scss new file mode 100644 index 00000000..000ddbfb --- /dev/null +++ b/src/features/HeaderMenuModal/HeaderMenuModalHeading/HeaderMenuModalHeading.module.scss @@ -0,0 +1,33 @@ +@use '@/shared/styles/utils/variables' as var; + +.headerMenuModalHeading { + display: flex; + justify-content: flex-start; + align-items: center; + gap: 14px; + width: 100%; + height: 75px; + background: var.$theme-primary-color; + font-size: 17px; + color: var.$white; + fill: var.$white; + border-bottom: 1px solid var.$bg-subscribe; + margin: 0; + padding: 20px 30px 20px 20px; + cursor: pointer; + transition: 0.25s; + + &:active { + color: var.$header-color; + } + + &__arrow { + fill: var.$white; + transform: rotate(90deg); + transition: 0.25s; + + &:active { + fill: var.$header-color; + } + } +} diff --git a/src/features/HeaderMenuModal/HeaderMenuModalHeading/HeaderMenuModalHeading.tsx b/src/features/HeaderMenuModal/HeaderMenuModalHeading/HeaderMenuModalHeading.tsx new file mode 100644 index 00000000..278f120c --- /dev/null +++ b/src/features/HeaderMenuModal/HeaderMenuModalHeading/HeaderMenuModalHeading.tsx @@ -0,0 +1,26 @@ +import { FC } from 'react' + +import ArrowIcon from '@/assets/icons/IconHeaderMenuArrow.svg' +import { Button } from '@/shared/ui/Button/Button' + +import styles from './HeaderMenuModalHeading.module.scss' + +interface IHeaderMenuModalHeading { + handleCategory?: () => void +} + +/** + * Компонент для отрисовки верхнего болка "Меню" со стрелкой "Назад" в HeaderMenuModal + * @param {function} handleCategory - функция переключения активности + */ + +const HeaderMenuModalHeading: FC = ({ handleCategory }) => { + return ( + + ) +} + +export default HeaderMenuModalHeading diff --git a/src/features/HeaderMenuModal/HeaderMenuModalLink/HeaderMenuModalLink.module.scss b/src/features/HeaderMenuModal/HeaderMenuModalLink/HeaderMenuModalLink.module.scss new file mode 100644 index 00000000..029a77ac --- /dev/null +++ b/src/features/HeaderMenuModal/HeaderMenuModalLink/HeaderMenuModalLink.module.scss @@ -0,0 +1,27 @@ +@use '@/shared/styles/utils/variables' as var; + +.headerMenuModalLink { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + height: 57px; + border-bottom: 1px solid var.$bg-subscribe; + padding: 10px 30px; + font-size: 15px; + color: var.$body-color; + cursor: pointer; + transition: 0.25s; + + &:hover { + color: var.$header-color; + } + + &:active { + color: var.$header-color; + } + + &__arrow { + transform: rotate(270deg); + } +} diff --git a/src/features/HeaderMenuModal/HeaderMenuModalLink/HeaderMenuModalLink.tsx b/src/features/HeaderMenuModal/HeaderMenuModalLink/HeaderMenuModalLink.tsx new file mode 100644 index 00000000..db7258d9 --- /dev/null +++ b/src/features/HeaderMenuModal/HeaderMenuModalLink/HeaderMenuModalLink.tsx @@ -0,0 +1,30 @@ +import { FC } from 'react' + +import ArrowIcon from '@/assets/images/sideBarMenu/IconArrowDown.svg' +import { Button } from '@/shared/ui/Button/Button' + +import styles from './HeaderMenuModalLink.module.scss' + +interface IHeaderMenuModalLink { + title?: string + isVisible?: boolean + onClick?: () => void +} + +/** + * Компонент модального окна HeaderMenuModal, отвечающий за развертывание кнопок с именами обьектов массива; + * @param {string} title - название линка; + * @param {boolean} isVisible - значение позволяющее показывать иконку стрелки; + * @param {function} onClick - - функция переключения активности; + */ + +const HeaderMenuModalLink: FC = ({ title, isVisible, onClick }) => { + return ( + + ) +} + +export default HeaderMenuModalLink diff --git a/src/features/HeaderMenuModal/HeaderMenuModalSublinks/HeaderMenuModalSublinks.module.scss b/src/features/HeaderMenuModal/HeaderMenuModalSublinks/HeaderMenuModalSublinks.module.scss new file mode 100644 index 00000000..879c8cd1 --- /dev/null +++ b/src/features/HeaderMenuModal/HeaderMenuModalSublinks/HeaderMenuModalSublinks.module.scss @@ -0,0 +1,25 @@ +@use '@/shared/styles/utils/variables' as var; + +.headerMenuModalSublinks { + display: flex; + flex-direction: column; + width: 100%; + + &__route { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + min-height: 57px; + border-bottom: 1px solid var.$bg-subscribe; + padding: 10px 30px; + font-size: 15px; + color: var.$body-color; + cursor: pointer; + transition: 0.25s; + + &:active { + color: var.$header-color; + } + } +} diff --git a/src/features/HeaderMenuModal/HeaderMenuModalSublinks/HeaderMenuModalSublinks.tsx b/src/features/HeaderMenuModal/HeaderMenuModalSublinks/HeaderMenuModalSublinks.tsx new file mode 100644 index 00000000..601076e1 --- /dev/null +++ b/src/features/HeaderMenuModal/HeaderMenuModalSublinks/HeaderMenuModalSublinks.tsx @@ -0,0 +1,59 @@ +import { FC } from 'react' + +import Link from '@/shared/ui/Link/Link' + +import HeaderMenuModalHeading from '../HeaderMenuModalHeading/HeaderMenuModalHeading' +import { IData } from '../model/types/types' + +import styles from './HeaderMenuModalSublinks.module.scss' + +export interface IHeaderMenuModalSublinks { + isActive?: boolean + choice?: number + index?: number + item?: IData + handleClose?: () => void +} + +/** + * Компонент модального окна HeaderMenuModal, отвечающий за развертывание роутов и их названий + * @param {boolean} isActive - булево значение; + * @param {number} choice - изменяемое состояние индекса; + * @param {number} index - индекс выбранной кнопки; + * @param {object} item - обьект массива; + * @param {function} handleClose - функция закрытия модального окна; + */ + +const HeaderMenuModalSublinks: FC = ({ + isActive, + choice, + index, + item, + handleClose +}) => { + return ( + <> + {choice === index && ( +
        + +
          + {isActive && + choice === index && + item?.routes?.map((el, i) => ( +
        • + + {el.subtitle} + +
        • + ))} +
        +
        + )} + + ) +} + +export default HeaderMenuModalSublinks diff --git a/src/features/HeaderMenuModal/index.tsx b/src/features/HeaderMenuModal/index.tsx new file mode 100644 index 00000000..850f4bcf --- /dev/null +++ b/src/features/HeaderMenuModal/index.tsx @@ -0,0 +1,2 @@ +import HeaderMenuModal from './ui/HeaderMenuModal' +export default HeaderMenuModal diff --git a/src/features/HeaderMenuModal/model/types/types.ts b/src/features/HeaderMenuModal/model/types/types.ts new file mode 100644 index 00000000..561986c1 --- /dev/null +++ b/src/features/HeaderMenuModal/model/types/types.ts @@ -0,0 +1,16 @@ +export interface IData { + routes?: IRoute[] + subtitle?: string + route?: string | null +} + +export interface IRoute { + subtitle?: string + route?: string | null +} + +export interface ICategory { + id?: number + name?: string + slug?: string +} diff --git a/src/features/HeaderMenuModal/ui/HeaderMenuModal.module.scss b/src/features/HeaderMenuModal/ui/HeaderMenuModal.module.scss new file mode 100644 index 00000000..2f1f5ec7 --- /dev/null +++ b/src/features/HeaderMenuModal/ui/HeaderMenuModal.module.scss @@ -0,0 +1,112 @@ +@use '@/shared/styles/utils/variables' as var; + +.headerMenuModal { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + background: var.$white; + overflow: auto; + + &__heading { + position: relative; + display: flex; + align-items: center; + width: 100%; + height: 75px; + background: var.$theme-primary-color; + color: var.$white; + fill: var.$white; + border-bottom: 1px solid var.$bg-subscribe; + padding: 20px 30px; + } + + &__closeButton { + margin: 0; + padding: 0; + } + + &__closeIcon { + fill: var.$white; + cursor: pointer; + transition: 0.25s; + + &:hover { + fill: var.$header-color; + } + + &:active { + transform: scale(0.8); + } + } + + &__title { + position: absolute; + left: 45%; + color: var.$white; + letter-spacing: 1px; + } + + &__account { + display: flex; + justify-content: center; + align-items: center; + padding: 20px 30px; + } + + &__catalog { + display: flex; + align-items: center; + width: 100%; + height: 57px; + font-size: 15px; + color: var.$body-color; + border-bottom: 1px solid var.$bg-subscribe; + padding: 10px 30px; + cursor: pointer; + transition: 0.25s; + } + + &__container { + width: 100%; + margin-top: 57px; + padding: 0 30px; + } + + &__support { + display: flex; + align-items: center; + height: 57px; + background: var.$promo-color; + border-radius: 10px; + font-size: 15px; + font-weight: 700; + color: var.$white; + padding: 10px 30px; + cursor: pointer; + opacity: 1; + transition: 0.25s; + + &:hover { + opacity: 0.9; + } + + &:active { + opacity: 0.9; + } + } + + &__workHours { + padding: 0 30px; + font-size: 13px; + color: var.$footer-form-color; + } + + &__contactList { + display: flex; + justify-content: center; + align-items: center; + gap: 20px; + padding-top: 30px; + } +} diff --git a/src/features/HeaderMenuModal/ui/HeaderMenuModal.tsx b/src/features/HeaderMenuModal/ui/HeaderMenuModal.tsx new file mode 100644 index 00000000..54ca39b7 --- /dev/null +++ b/src/features/HeaderMenuModal/ui/HeaderMenuModal.tsx @@ -0,0 +1,144 @@ +import { FC, useState } from 'react' +import Skeleton from 'react-loading-skeleton' +import 'react-loading-skeleton/dist/skeleton.css' +import { useNavigate } from 'react-router' + +import CloseIcon from '@/assets/icons/iconHeaderMenuClose.svg' +import PhoneIcon from '@/assets/icons/IconPhone.svg' +import ContactCard from '@/entities/ContactCard/ContactCard' +import HeaderAccount from '@/entities/HeaderAccount/HeaderAccount' +import { headerMenuData } from '@/mockData/headerMenuData' +import { headerAccountData } from '@/shared/mockData/headerAccountData' +import { messengerArray } from '@/shared/model/types/messengerArray' +import { Button } from '@/shared/ui/Button/Button' +import Heading, { HeadingType } from '@/shared/ui/Heading/Heading' +import Link from '@/shared/ui/Link/Link' +import Paragraph from '@/shared/ui/Paragraph/Paragraph' + +import HeaderMenuModalCatalog from '../HeaderMenuModalCatalog/HeaderMenuModalCatalog' +import HeaderMenuModalLink from '../HeaderMenuModalLink/HeaderMenuModalLink' +import HeaderMenuModalSublinks from '../HeaderMenuModalSublinks/HeaderMenuModalSublinks' +import { ICategory } from '../model/types/types' + +import styles from './HeaderMenuModal.module.scss' + +interface IHeaderMenuModal { + categories?: ICategory[] + phoneNumber?: string + isMenuModalOpen?: boolean + handleClose?: () => void +} + +/** + * Модальное окно HeaderMenuModal + * @param {array} categories - массив категорий полученный из редакса; + * @param {string} phoneNumber - телефон полученный из редакса; + * @param {boolean} isMenuModalOpen - состояние открытия модального окна; + * @param {function} handleClose - функция закрытия модального окна; + */ + +const HeaderMenuModal: FC = ({ categories, phoneNumber, isMenuModalOpen, handleClose }) => { + const [isActive, setIsActive] = useState(false) + const [isCatalog, setIsCatalog] = useState(false) + const [choice, setChoice] = useState(0) + const navigate = useNavigate() + + const handleClick = (index: number) => { + setChoice(index) + setIsActive(!isActive) + } + + const handleLink = (route: string) => { + navigate(route) + handleClose + } + + const handleCategory = () => { + setIsActive(!isActive) + setIsCatalog(!isCatalog) + } + + return ( +
        + {!isActive && !isCatalog && ( + <> +
        + + + + Меню + +
        + +
        + +
        + + )} + + {!isCatalog ? ( + !isActive && + ) : ( + + )} + + {!isCatalog && ( +
          + {headerMenuData && + headerMenuData.map((item, index) => ( +
        • (item.link === null ? handleClick(index) : handleLink(item.link))}> + {!isActive ? ( + + ) : ( + + )} +
        • + ))} +
        + )} + + {!isActive && !isCatalog && ( +
        + + Поддержка:  + +   + {phoneNumber || } + + Будни, с 10.00 до 20.00 +
          + {messengerArray.map(item => ( + + ))} +
        +
        + )} +
        + ) +} + +export default HeaderMenuModal diff --git a/src/mockData/headerMenuData.ts b/src/mockData/headerMenuData.ts new file mode 100644 index 00000000..dafcda69 --- /dev/null +++ b/src/mockData/headerMenuData.ts @@ -0,0 +1,39 @@ +import { Routes } from '@/shared/config/routerConfig/routes' + +export const headerMenuData = [ + { + title: 'О нас', + link: null, + routes: [ + { subtitle: 'О нас', route: Routes.ABOUT }, + { subtitle: 'Политика безопасности', route: Routes.HOME }, + { subtitle: 'Обзоры', route: Routes.HOME }, + { subtitle: 'Условия соглашения', route: Routes.HOME } + ] + }, + { + title: 'Блог', + link: Routes.BLOG + }, + { + title: 'Новости', + link: Routes.NEWS + }, + { + title: 'Отзывы о магазине', + link: Routes.REVIEWS + }, + { + title: 'Контакты', + link: Routes.CONTACTS + }, + { + title: 'Помощь', + link: null, + routes: [ + { subtitle: 'Информация о доставке', route: Routes.DELIVERY }, + { subtitle: 'Возвраты', route: Routes.ADD_RETURN }, + { subtitle: 'Подарочные сертификаты', route: Routes.VOUCHERS } + ] + } +] diff --git a/src/pages/FormReturnPage/FormReturnPage.module.scss b/src/pages/FormReturnPage/FormReturnPage.module.scss index e0ea4a2a..32ea7f6b 100644 --- a/src/pages/FormReturnPage/FormReturnPage.module.scss +++ b/src/pages/FormReturnPage/FormReturnPage.module.scss @@ -1,4 +1,4 @@ -@use '../../shared/styles/utils/mixins' as media; +@use '@/shared/styles/utils/mixins' as media; .formReturn { display: flex; @@ -23,7 +23,7 @@ align-items: flex-start; gap: 20px; - @include media.respond-to('middle') { + @include media.respond-to('large') { flex-direction: column; gap: 10px; } @@ -46,5 +46,3 @@ } } } - - diff --git a/src/pages/FormReturnPage/FormReturnPage.tsx b/src/pages/FormReturnPage/FormReturnPage.tsx index 3b8ccb32..e85c384e 100644 --- a/src/pages/FormReturnPage/FormReturnPage.tsx +++ b/src/pages/FormReturnPage/FormReturnPage.tsx @@ -26,7 +26,7 @@ const FormReturnPage: FC = () => { const [isModalClosing, setIsModalClosing] = useState(false) const [user, setUser] = useState('Elon Musk') // позже юзера будем получать из редакса - const { isScreenMd } = useResize() + const { isScreenLg } = useResize() const changeModalState = () => { setIsModalOpen(!isModalOpen) @@ -74,7 +74,7 @@ const FormReturnPage: FC = () => {
        - {isScreenMd ? ( + {isScreenLg ? ( ) : ( diff --git a/src/shared/icons/cart.svg b/src/shared/icons/cart.svg deleted file mode 100644 index 5f2a943c..00000000 --- a/src/shared/icons/cart.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/shared/icons/heart.svg b/src/shared/icons/heart.svg deleted file mode 100644 index 9b3bd37c..00000000 --- a/src/shared/icons/heart.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/src/widgets/Header/Header.tsx b/src/widgets/Header/Header.tsx index f3b6cb66..e9ee027e 100644 --- a/src/widgets/Header/Header.tsx +++ b/src/widgets/Header/Header.tsx @@ -1,9 +1,9 @@ import classNames from 'classnames' -import { useEffect, useMemo, useState } from 'react' +import { lazy, Suspense, useEffect, useMemo, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { AppDispatch } from '@/app/providers/StoreProvider/config/store' -import MenuIcon from '@/assets/icons/iconMenu.svg' +import MenuIcon from '@/assets/icons/IconMenu.svg' import { getLoading, selectCategories, @@ -19,6 +19,7 @@ import IconCategories from '@/shared/icons/IconCategories.svg' import { useResize } from '@/shared/libs/hooks/useResize' import { linkItems } from '@/shared/mockData/catalogListData' import { headerAccountData } from '@/shared/mockData/headerAccountData' +import { Button } from '@/shared/ui/Button/Button' import CatalogLink from '@/shared/ui/CatalogLink/CatalogLink' import CatalogLinkSkeleton from '@/shared/ui/CatalogLink/ui/skeleton/CatalogLinkSkeleton' import ContextMenuElement from '@/shared/ui/ContextMenuElement/ContextMenuElement' @@ -27,6 +28,7 @@ import Logo from '@/shared/ui/logo/Logo' import LogoSkeleton from '@/shared/ui/logo/model/skeleton/LogoSkeleton' import Modal from '@/shared/ui/Modal/Modal' import Paragraph from '@/shared/ui/Paragraph/Paragraph' +import Spinner from '@/shared/ui/Spinner/Spinner' import CatalogNodeItem from '@/widgets/CatalogNodeItem/CatalogNodeItem' import NavigationLink from '@/widgets/NavigationLink/NavigationLink' @@ -37,6 +39,12 @@ import { getCoreBaseHeader } from './model/services/getCoreBaseHeader' import ListItemButton from './ui/ListItemButton' import ListItemLink from './ui/ListItemLink' +const HeaderMenuModal = lazy(() => import('@/features/HeaderMenuModal')) + +/** + * Компонент шапки сайта + */ + function Header() { const dispatch = useDispatch() const categories = useSelector(selectCategories) @@ -44,6 +52,7 @@ function Header() { const displayedCategories = useSelector(selectDisplayedCategories) const [isModalOpen, setIsModalOpen] = useState(false) const [isModalClosing, setIsModalClosing] = useState(false) + const [isMenuModalOpen, setIsMenuModalOpen] = useState(false) const phoneNumber = coreBaseData.header.support.phone_number const logo = coreBaseData.header.main_logo.image const isCategoriesLoading = useSelector(getLoading) @@ -54,6 +63,10 @@ function Header() { setIsModalOpen(!isModalOpen) } + const changeMenuModalState = () => { + setIsMenuModalOpen(!isMenuModalOpen) + } + const aboutUsNode = useMemo( () => (
          @@ -129,7 +142,25 @@ function Header() { )} -
          + + {isMenuModalOpen && ( + + }> + + + + )} + +
          {isScreenLg && (