Files
graff.estate-nextjs-updated/src/components/Layout/Header.tsx
T
2025-01-24 20:26:26 +05:00

236 lines
8.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import { api } from '@/api';
import { ClassNameWrapper } from '@/hocs/ClassNameWrapper';
import { useMediaQueries } from '@/hooks/useMediaQueries';
import { useScroll } from '@/hooks/useScroll';
import { useCheckAuthQuery } from '@/queries/checkAuth';
import { useModalStore } from '@/stores/useModalStore';
import { Button } from '@/ui/Button';
import { HeaderLink } from '@/ui/HeaderLink';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { AnimatePresence, motion } from 'framer-motion';
import Image from 'next/image';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { useRef, useState } from 'react';
import { useOnClickOutside } from 'usehooks-ts';
import { BurgerIcon } from '../icons/BurgerIcon';
import { CloseIcon } from '../icons/CloseIcon';
import { LogoIcon } from '../icons/LogoIcon';
import { LogoWithTextIcon } from '../icons/LogoWithTextIcon';
import { SkolkovoIcon } from '../icons/SkolkovoIcon';
import { ModalWithFeedbackForm } from '../modals/ModalWithFeedbackForm';
import { Products } from './Products';
export function Header() {
const { setModal } = useModalStore();
const queryClient = useQueryClient();
const { data: auth } = useCheckAuthQuery();
const { mutate: logout } = useMutation({
mutationKey: ['checkAuth'],
mutationFn: async () =>
await api.get('auth/logout').json<{ success: boolean }>(),
onSuccess() {
queryClient.invalidateQueries({ queryKey: ['checkAuth'] });
},
});
const [burgerOpened, setBurgerOpened] = useState(false);
const [productsOpened, setProductsOpened] = useState(false);
const { isLg, isXs, isSm, isMd } = useMediaQueries();
const pathname = usePathname();
const burgerRef = useRef<HTMLDivElement>(null);
const burgerBtnRef = useRef<HTMLDivElement>(null);
const productsRef = useRef<HTMLDivElement>(null);
const productsBtnRef = useRef<HTMLDivElement>(null);
const logoRef = useRef<HTMLAnchorElement>(null);
useOnClickOutside([productsRef, productsBtnRef], () => {
setProductsOpened(false);
});
useOnClickOutside([burgerRef, burgerBtnRef], () => {
setBurgerOpened(false);
});
const scroll = useScroll(logoRef);
return (
<header className="lg:mt-5 relative flex items-center px-5">
<Link href={'/'} ref={logoRef}>
<ClassNameWrapper className="max-lg:hidden">
<LogoWithTextIcon />
</ClassNameWrapper>
</Link>
<div className="relative flex justify-center flex-1 m-auto">
<AnimatePresence>
<motion.nav
animate={{
width:
burgerOpened && (isXs || isSm)
? 340
: productsOpened && !isXs && !isSm
? isLg
? 'calc(992 / 1440 * 100vw)'
: 'calc(100vw - 32px)'
: 'auto',
}}
className="fixed lg:top-5 top-4 p-1 rounded-[20px] bg-[#37393B99] backdrop-blur-2xl flex gap-1 z-[12]"
>
{((isLg && scroll < -logoRef.current?.clientHeight!) || !isLg) && (
<Link
href={'/'}
className="aspect-square p-4 alg:hidden hover:bg-[#37393B99] rounded-xl content-center"
>
<ClassNameWrapper className={'w-4 h-4'}>
<LogoIcon />
</ClassNameWrapper>
</Link>
)}
<div ref={productsBtnRef} className="max-md:hidden">
<button
className="px-6 py-4 font-medium btnm hover:bg-[#37393B99] rounded-2xl active:bg-white active:text-black"
onClick={() => {
setProductsOpened((prev) => !prev);
}}
>
Продукты
</button>
</div>
<HeaderLink
className="max-md:hidden btnm"
href={'/about'}
text={'О нас'}
/>
<HeaderLink
className="max-md:hidden btnm"
href={'/blog'}
text={'Блог'}
/>
<HeaderLink
className="max-md:hidden btnm"
href={'/projects'}
text={'Проекты'}
/>
<div className="md:justify-end flex justify-center flex-1">
<Button
className="btnm font-medium py-[17px] text-nowrap"
rounded="2xl"
onClick={() => setModal(<ModalWithFeedbackForm />, 'form')}
>
Оставить заявку
</Button>
</div>
<div className="md:hidden md:justify-end flex" ref={burgerBtnRef}>
<button
className="!border-none p-[18px] hover:bg-[#232425] rounded-2xl active:opacity-50 outline-none"
onClick={() => setBurgerOpened((prev) => !prev)}
>
<ClassNameWrapper className="w-4 h-4 text-white">
{burgerOpened ? <CloseIcon /> : <BurgerIcon />}
</ClassNameWrapper>
</button>
</div>
{auth && (
<div className="sm:max-md:absolute -right-1/4 sm:max-md:bg-[#37393B99] rounded-[20px] self-center">
<button
className="rounded-2xl btnm font-medium p-3 hover:bg-[#FF4517] transition-colors h-full hover:text-black outline-none"
onClick={() => logout()}
>
Выйти
</button>
</div>
)}
<AnimatePresence>
{burgerOpened && (isXs || isSm) && (
<>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 100 }}
exit={{ opacity: 0 }}
className="absolute w-full p-4 pt-2 top-16 rounded-2xl bg-[#232425] md:hidden space-y-6"
>
<div className="px-2 -mx-4 space-y-1">
<HeaderLink
href={'/about'}
text={'О нас'}
className="accent"
/>
<HeaderLink href={'/'} text={'Блог'} className="accent" />
<HeaderLink
href={'/projects'}
text={'Проекты'}
className="accent"
/>
</div>
<hr className="border-[#37393B]" />
<div className="space-y-[10px]">
<p className="btnm opacity-60">Продукты</p>
<Products />
</div>
<div>
<p className="btnm opacity-60 mb-1">Контакты:</p>
<Link
href={'tel:88007700067'}
className="accent font-medium outline-none"
>
8 800 770 00 67
</Link>
</div>
</motion.div>
<div className="fixed w-screen h-screen bg-[#0F101199] backdrop-blur-lg -top-4 -left-[calc((100vw-100%)/2)] -z-[1]" />
</>
)}
</AnimatePresence>
</motion.nav>
</AnimatePresence>
<AnimatePresence>
{productsOpened && (isMd || isLg) && (
<>
<motion.div
onClick={() => setProductsOpened(false)}
ref={productsRef}
animate={{
width: isLg
? 'calc(992 / 1440 * 100vw)'
: 'calc(100vw - 32px)',
}}
className="fixed max-md:hidden top-20 rounded-2xl bg-[#37393B99] backdrop-blur-2xl p-1 z-[13]"
>
<Products />
</motion.div>
<div className="fixed w-screen h-screen bg-[#0F101199] backdrop-blur-lg top-0 left-0 z-[11]" />
</>
)}
</AnimatePresence>
</div>
{pathname === '/projects' ? (
<Link
href={'https://dprofile.ru/graff.estate'}
className="max-xl:hidden rounded-[20px] bg-[#37393B99] backdrop-blur-[20px] hover:bg-[#232425] py-5 pl-[63px] pr-[33px] right-5 fixed z-[2] top-5 overflow-clip bg-[url(/img/components/header/dp.png)] bg-no-repeat bg-right-bottom"
>
<Image
src={'/img/components/header/show_case.png'}
width={53.77}
height={104.48}
alt="кейс dprofile"
className="absolute bottom-0 left-0 rotate-[2.56deg]"
/>
<p className="btnm font-medium">Смотреть кейс</p>
</Link>
) : (
<ClassNameWrapper className="max-lg:hidden">
<SkolkovoIcon />
</ClassNameWrapper>
)}
</header>
);
}