upd
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
import { isMobile } from "react-device-detect";
|
||||
import AuthDesktop from "./AuthDesktop";
|
||||
import AuthMobile from "./AuthMobile";
|
||||
|
||||
interface AuthProps {
|
||||
isAuth?: boolean;
|
||||
}
|
||||
|
||||
const Auth = ({ isAuth = false }: AuthProps) => {
|
||||
const userName = "Full Name";
|
||||
|
||||
return (
|
||||
<>
|
||||
{isMobile ? (
|
||||
<AuthMobile isAuth={isAuth} userName={userName} />
|
||||
) : (
|
||||
<AuthDesktop isAuth={isAuth} userName={userName} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Auth;
|
||||
@@ -0,0 +1,45 @@
|
||||
import useModal from "../../../store/useModal";
|
||||
import Button from "../../Button";
|
||||
import AuthIcon from "../../icons/AuthIcon";
|
||||
import LoginModal from "../../modals/auth/LoginModal";
|
||||
|
||||
interface AuthProps {
|
||||
isAuth: boolean;
|
||||
userName: string;
|
||||
}
|
||||
|
||||
const AuthDesktop = ({ isAuth, userName }: AuthProps) => {
|
||||
const { setModal } = useModal();
|
||||
|
||||
const handleOnLoginBtnClick = () => {
|
||||
setModal(<LoginModal />);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex gap-4 py-2 pr-6 text-black col-span-2 justify-end text-s">
|
||||
{isAuth ? (
|
||||
<>
|
||||
<div>
|
||||
<p className="">{userName}</p>
|
||||
<p className="text-[#0D192266] text-caption-m font-semibold">
|
||||
Company
|
||||
</p>
|
||||
</div>
|
||||
<div className="rounded-full w-10 h-10 bg-[#E2E2DC] overflow-clip flex items-center justify-center font-semibold">
|
||||
{/* <img src="" alt="avatar" className="bg-[#E2E2DC]" /> */}
|
||||
FN
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<Button
|
||||
buttonType="cta"
|
||||
text="Login"
|
||||
onClick={handleOnLoginBtnClick}
|
||||
icon={<AuthIcon />}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AuthDesktop;
|
||||
@@ -0,0 +1,33 @@
|
||||
import Button from "../../Button";
|
||||
import AuthIcon from "../../icons/AuthIcon";
|
||||
|
||||
interface AuthProps {
|
||||
isAuth: boolean;
|
||||
userName: string;
|
||||
}
|
||||
|
||||
const AuthMobile = ({ isAuth, userName }: AuthProps) => {
|
||||
return (
|
||||
<>
|
||||
{isAuth ? (
|
||||
<div className="flex gap-4 text-black justify-start w-full items-center px-4 py-2 bg-white rounded-lg">
|
||||
<p>{userName}</p>
|
||||
<div className="rounded-full w-10 h-10 bg-[#E2E2DC] overflow-clip">
|
||||
{/* <img src="" alt="avatar" className="bg-[#E2E2DC]" /> */}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex gap-4 text-black justify-center w-full items-center">
|
||||
<Button
|
||||
buttonType="cta"
|
||||
text="Login"
|
||||
icon={<AuthIcon />}
|
||||
className="w-full justify-center"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AuthMobile;
|
||||
@@ -0,0 +1,19 @@
|
||||
import Auth from "../Auth/Auth";
|
||||
import Logo from "../../Logo";
|
||||
import Navbar from "../Navbar/Navbar";
|
||||
import Location from "../Location";
|
||||
|
||||
const DesktopHeader = () => (
|
||||
<header className="bg-white fixed left-0 top-0 w-full z-[99999999] font-usual text-m select-none flex justify-between">
|
||||
<div className="flex gap-4 col-span-2">
|
||||
<Logo />
|
||||
<Location />
|
||||
</div>
|
||||
<Navbar />
|
||||
<div className="flex gap-5">
|
||||
<Auth isAuth={false} />
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
|
||||
export default DesktopHeader;
|
||||
@@ -0,0 +1,49 @@
|
||||
import { useState } from "react";
|
||||
import LogoIcon from "../../icons/LogoIcon";
|
||||
import Auth from "../Auth/Auth";
|
||||
import Navbar from "../Navbar/Navbar";
|
||||
import Location from "../Location";
|
||||
import BurgerMenuIcon from "../../icons/BurgerMenuIcon";
|
||||
|
||||
const MobileHeader = () => {
|
||||
const [isToggled, setIsToggled] = useState(false);
|
||||
const isAuth = false;
|
||||
|
||||
const handleOnToggleClick = () => {
|
||||
setIsToggled((prev) => !prev);
|
||||
};
|
||||
return (
|
||||
<header
|
||||
className={`bg-white w-full ${
|
||||
isToggled
|
||||
? "rounded-ee-lg rounded-es-lg shadow-[#00000026] shadow-md"
|
||||
: ""
|
||||
} text-white flex flex-col text-sm items-center transition-all duration-500 ease-in-out absolute top-0 left-0 z-[99999900] overflow-hidden font-usual ${
|
||||
isToggled ? "max-h-[472px]" : "max-h-14"
|
||||
}`}
|
||||
>
|
||||
<div className="flex justify-between w-full p-4">
|
||||
<div className={`text-[#0D1922] transition-opacity duration-500`}>
|
||||
<LogoIcon />
|
||||
</div>
|
||||
<div className="w-6 h-6 text-[#0D1922]" onClick={handleOnToggleClick}>
|
||||
<BurgerMenuIcon isToggled={isToggled} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col justify-between h-full items-end w-full p-4 bg-[#F3F3F2]">
|
||||
{isAuth && (
|
||||
<div className="pb-2 w-full">
|
||||
<Auth isAuth={isAuth} />
|
||||
</div>
|
||||
)}
|
||||
<Navbar />
|
||||
<div className="py-3">
|
||||
<Location />
|
||||
</div>
|
||||
{!isAuth && <Auth isAuth={isAuth} />}
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
export default MobileHeader;
|
||||
@@ -0,0 +1,12 @@
|
||||
import LocationIcon from "../icons/LocationIcon";
|
||||
|
||||
const Location = () => {
|
||||
return (
|
||||
<div className="text-[#73787C] flex gap-1 items-center justify-center">
|
||||
<LocationIcon />
|
||||
<p className="">Dubai</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Location;
|
||||
@@ -0,0 +1,67 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { useEffect, useState } from "react";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import { useNavigate, useLocation } from "react-router-dom";
|
||||
import { Tab } from "../../../types/tab";
|
||||
import NavbarDesktop from "./NavbarDesktop";
|
||||
import NavbarMobile from "./NavbarMobile";
|
||||
import { tabs as _tabs } from "../../../consts/tabs";
|
||||
import useFavorites from "../../../store/useFavorites";
|
||||
|
||||
const Navbar = () => {
|
||||
const [selectedTab, setSelectedTab] = useState<Tab | null>(null);
|
||||
const [tabs, setTabs] = useState(_tabs);
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const { favorites, setFavorites } = useFavorites();
|
||||
|
||||
const onTabClick = (tab: Tab) => {
|
||||
setSelectedTab(tab);
|
||||
navigate(tab.path);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const pathname = location.pathname;
|
||||
const tab = tabs.find((tab) => tab.path === pathname);
|
||||
const defaultTab = tabs[0];
|
||||
if (tab) {
|
||||
setSelectedTab(tab);
|
||||
} else {
|
||||
setSelectedTab(defaultTab);
|
||||
}
|
||||
}, [location.pathname]);
|
||||
|
||||
useEffect(() => {
|
||||
const _favorites = localStorage.getItem("Favorites");
|
||||
if (!_favorites) return;
|
||||
const convertedFavorute = JSON.parse(_favorites);
|
||||
setFavorites(convertedFavorute);
|
||||
}, [setFavorites]);
|
||||
|
||||
useEffect(() => {
|
||||
const updatedTabs = _tabs.map((tab) => {
|
||||
if (tab.value === "Favorites") {
|
||||
return { ...tab, count: favorites.length };
|
||||
}
|
||||
|
||||
return tab;
|
||||
});
|
||||
setTabs(updatedTabs);
|
||||
}, [favorites]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{isMobile ? (
|
||||
<NavbarMobile onTabClick={onTabClick} tabs={tabs} />
|
||||
) : (
|
||||
<NavbarDesktop
|
||||
selectedTab={selectedTab}
|
||||
onTabClick={onTabClick}
|
||||
tabs={tabs}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Navbar;
|
||||
@@ -0,0 +1,34 @@
|
||||
import { Tab } from "../../../types/tab";
|
||||
import NavbarTabDesktop from "./NavbarTabDesktop";
|
||||
import NavbarTabDesktopBrochure from "./NavbarTabDesktopBrochure";
|
||||
|
||||
interface NavbarProps {
|
||||
selectedTab: Tab | null;
|
||||
onTabClick: (tab: Tab) => void;
|
||||
tabs: Tab[];
|
||||
}
|
||||
|
||||
function NavbarDesktop({ selectedTab, onTabClick, tabs }: NavbarProps) {
|
||||
return (
|
||||
<nav
|
||||
className={`text-[#091118] self-center col-span-2 justify-center flex h-full`}
|
||||
>
|
||||
{tabs.map((tab) => {
|
||||
if (tab.value === "Brochures") {
|
||||
return <NavbarTabDesktopBrochure key={tab.id} tab={tab} />;
|
||||
} else {
|
||||
return (
|
||||
<NavbarTabDesktop
|
||||
key={tab.id}
|
||||
tab={tab}
|
||||
isSelected={selectedTab?.id === tab.id}
|
||||
onClick={onTabClick}
|
||||
/>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
||||
export default NavbarDesktop;
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Tab } from "../../../types/tab";
|
||||
import NavbarTabMobile from "./NavbarTabMobile";
|
||||
|
||||
interface NavbarProps {
|
||||
onTabClick: (tab: Tab) => void;
|
||||
tabs: Tab[];
|
||||
}
|
||||
|
||||
const NavbarMobile = ({ onTabClick, tabs }: NavbarProps) => (
|
||||
<nav
|
||||
className={`text-[#73787C] flex w-full flex-col bg-white rounded-lg px-4`}
|
||||
>
|
||||
{tabs.map((tab) => (
|
||||
<NavbarTabMobile key={tab.id} tab={tab} onClick={onTabClick} />
|
||||
))}
|
||||
</nav>
|
||||
);
|
||||
|
||||
export default NavbarMobile;
|
||||
@@ -0,0 +1,40 @@
|
||||
import useFavoritesStore from "../../../store/useFavoritesStore";
|
||||
import { Tab } from "../../../types/tab";
|
||||
|
||||
interface NavbarTabProps {
|
||||
tab: Tab;
|
||||
isSelected: boolean;
|
||||
onClick: (tab: Tab) => void;
|
||||
}
|
||||
|
||||
const NavbarTabDesktop = ({
|
||||
tab,
|
||||
onClick,
|
||||
isSelected = false,
|
||||
}: NavbarTabProps) => {
|
||||
const { favoriteUnits } = useFavoritesStore();
|
||||
|
||||
return (
|
||||
<button
|
||||
className="px-4 text-[#73787C] hover:text-black relative w-fit h-full"
|
||||
onClick={() => onClick(tab)}
|
||||
>
|
||||
<div
|
||||
className={`py-4 border-b-2 h-full flex items-center transition-all duration-300 ${
|
||||
isSelected
|
||||
? "border-b-[#00BED7]"
|
||||
: "border-b-transparent hover:border-b-[#E2E2DC] active:border-b-[#00BED7]"
|
||||
}`}
|
||||
>
|
||||
{tab.value}
|
||||
</div>
|
||||
{tab.value === "Favorites" && favoriteUnits.length > 0 && (
|
||||
<div className="absolute top-2 right-0 w-4 h-4 bg-[#00BED7] rounded-full text-white text-[10px] font-mono flex items-center justify-center">
|
||||
<span className="leading-none">{favoriteUnits.length}</span>
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default NavbarTabDesktop;
|
||||
@@ -0,0 +1,111 @@
|
||||
import { useState } from "react";
|
||||
import { Tab } from "../../../types/tab";
|
||||
import ChevronDownIcon from "../../icons/ChevronDownIcon";
|
||||
import DownloadIcon from "../../icons/DownloadIcon";
|
||||
import { useClickAway } from "@uidotdev/usehooks";
|
||||
|
||||
interface Props {
|
||||
tab: Tab;
|
||||
}
|
||||
|
||||
function NavbarTabDesktopBrochure({ tab }: Props) {
|
||||
const [isShowMenu, setIsShowMenu] = useState<boolean>(false);
|
||||
const ref = useClickAway<HTMLDivElement>(() => {
|
||||
setIsShowMenu(false);
|
||||
});
|
||||
|
||||
return (
|
||||
<div ref={ref} className="relative px-4 w-fit h-full text-[#73787C]">
|
||||
<button
|
||||
onClick={() => setIsShowMenu((prev) => !prev)}
|
||||
className={`py-4 border-b-2 h-full transition-all duration-300 border-b-transparent hover:text-[#0D1922] hover:border-b-[#E2E2DC] flex items-center gap-2`}
|
||||
>
|
||||
{tab.value} <ChevronDownIcon className="w-5 h-5" />
|
||||
</button>
|
||||
{isShowMenu && (
|
||||
<div className="absolute top-[calc(100%+16px)] left-0 bg-[#F3F3F2] rounded-2xl p-4 flex flex-col gap-3 shadow-lg">
|
||||
<div className="space-y-2">
|
||||
<div className="border-b pb-2">
|
||||
<p className="text-sm text-[#0D1922] text-left">
|
||||
Rove Home Marasi Drive
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<a
|
||||
href="/files/marasi-drive/ROVE_MAIN_BROCHURE.pdf"
|
||||
className="px-3 py-2 bg-white rounded-lg flex items-center justify-between bg-[#FFFFFFCC] w-72 hover:text-[#0D1922] transition-colors"
|
||||
download
|
||||
>
|
||||
<span className="text-xs font-semibold">
|
||||
Rove Main Brochure
|
||||
</span>
|
||||
<DownloadIcon className="min-w-5 min-h-5" />
|
||||
</a>
|
||||
<a
|
||||
href="/files/marasi-drive/ROVE_AMENITIES_BROCHURE.pdf"
|
||||
className="px-3 py-2 bg-white rounded-lg flex items-center justify-between bg-[#FFFFFFCC] w-72 hover:text-[#0D1922] transition-colors"
|
||||
download
|
||||
>
|
||||
<span className="text-xs font-semibold text-nowrap">
|
||||
Rove Amenties Brochure
|
||||
</span>
|
||||
<DownloadIcon className="min-w-5 min-h-5" />
|
||||
</a>
|
||||
<a
|
||||
href="/files/marasi-drive/ROVE_TECHNICAL_BROCHURE.pdf"
|
||||
className="px-3 py-2 bg-white rounded-lg flex items-center justify-between bg-[#FFFFFFCC] w-72 hover:text-[#0D1922] transition-colors"
|
||||
download
|
||||
>
|
||||
<span className="text-xs font-semibold">
|
||||
Rove Technical Brochure
|
||||
</span>
|
||||
<DownloadIcon className="min-w-5 min-h-5" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="border-b pb-2">
|
||||
<p className="text-sm text-[#0D1922] text-left">
|
||||
Rove Home Downtown
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<a
|
||||
href="/files/downtown/ROVE_MAIN_BROCHURE.pdf"
|
||||
className="px-3 py-2 bg-white rounded-lg flex items-center justify-between bg-[#FFFFFFCC] w-72 hover:text-[#0D1922] transition-colors"
|
||||
download
|
||||
>
|
||||
<span className="text-xs font-semibold">
|
||||
Rove Main Brochure
|
||||
</span>
|
||||
<DownloadIcon className="min-w-5 min-h-5" />
|
||||
</a>
|
||||
<a
|
||||
href="/files/downtown/ROVE_AMENITIES_BROCHURE.pdf"
|
||||
className="px-3 py-2 bg-white rounded-lg flex items-center justify-between bg-[#FFFFFFCC] w-72 hover:text-[#0D1922] transition-colors"
|
||||
download
|
||||
>
|
||||
<span className="text-xs font-semibold text-nowrap">
|
||||
Rove Amenties Brochure
|
||||
</span>
|
||||
<DownloadIcon className="min-w-5 min-h-5" />
|
||||
</a>
|
||||
<a
|
||||
href="/files/downtown/ROVE_PLANS_BROCHURE.pdf"
|
||||
className="px-3 py-2 bg-white rounded-lg flex items-center justify-between bg-[#FFFFFFCC] w-72 hover:text-[#0D1922] transition-colors"
|
||||
download
|
||||
>
|
||||
<span className="text-xs font-semibold">
|
||||
Rove Plans & Mood Board Brochure
|
||||
</span>
|
||||
<DownloadIcon className="min-w-5 min-h-5" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default NavbarTabDesktopBrochure;
|
||||
@@ -0,0 +1,30 @@
|
||||
import { Tab } from "../../../types/tab";
|
||||
import RightArrowIcon from "../../icons/RightArrowIcon";
|
||||
|
||||
interface NavbarTabProps {
|
||||
tab: Tab;
|
||||
onClick: (tab: Tab) => void;
|
||||
}
|
||||
|
||||
const NavbarTabMobile = ({ tab, onClick }: NavbarTabProps) => {
|
||||
return (
|
||||
<button className="w-full border-b last:border-b-0 flex justify-between py-4 ">
|
||||
<div
|
||||
className=" text-[#0D1922] relative w-fit"
|
||||
onClick={() => onClick(tab)}
|
||||
>
|
||||
<div className={` transition-all duration-300`}>{tab.value}</div>
|
||||
{tab.count !== 0 && (
|
||||
<div className="absolute top-0 -right-4 w-4 h-4 bg-[#00BED7] rounded-full text-white text-[10px] flex items-center justify-center">
|
||||
{tab.count}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-[#73787C]">
|
||||
<RightArrowIcon />
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default NavbarTabMobile;
|
||||
Reference in New Issue
Block a user