upd
This commit is contained in:
@@ -49,8 +49,8 @@ function SkyGardenSlider() {
|
||||
}px + ${currentSlideIndex * 32}px))`,
|
||||
}}
|
||||
>
|
||||
{images.map((image) => (
|
||||
<img src={image} alt="" className="rounded-2xl" />
|
||||
{images.map((image, index) => (
|
||||
<img key={index} src={image} alt="" className="rounded-2xl" />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
+6
-18
@@ -5,18 +5,14 @@ import DefaultLayout from "./layouts/DefaultLayout";
|
||||
import MasterplanPage from "./pages/MasterplanPage";
|
||||
import ComplexPage from "./pages/ComplexPage";
|
||||
import ComplexWingPage from "./pages/ComplexWingPage";
|
||||
// import AboutProjectsPage from "./pages/AboutProjectsPage";
|
||||
import UnitTypesPage from "./pages/UnitTypesPage";
|
||||
import AboutPage from "./pages/AboutPage";
|
||||
// import ApartmentPage from "./pages/ApartmentPage";
|
||||
import VirtualTourPage from "./pages/VirtualTourPage";
|
||||
import UnitTypesItemPage from "./pages/UnitTypesItemPage";
|
||||
import SearchPage2 from "./pages/SearchPage2";
|
||||
import FavoritesPage2 from "./pages/FavoritesPage2";
|
||||
import WithFooterLayout from "./layouts/WithFooterLayout";
|
||||
// import AboutProjectsPage from "./pages/AboutProjectsPage";
|
||||
import AboutProjects2Page from "./pages/AboutProjects2Page";
|
||||
import TestPage from "./pages/TestPage";
|
||||
import AboutProjectsPage from "./pages/AboutProjectsPage";
|
||||
import SearchPage from "./pages/SearchPage";
|
||||
import FavoritesPage from "./pages/FavoritesPage";
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
@@ -43,10 +39,6 @@ const router = createBrowserRouter([
|
||||
path: "virtual-tour/:unitType",
|
||||
element: <VirtualTourPage />,
|
||||
},
|
||||
{
|
||||
path: "test",
|
||||
element: <TestPage />,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -55,7 +47,7 @@ const router = createBrowserRouter([
|
||||
children: [
|
||||
{
|
||||
path: "about-projects",
|
||||
element: <AboutProjects2Page />,
|
||||
element: <AboutProjectsPage />,
|
||||
},
|
||||
{
|
||||
path: "about",
|
||||
@@ -63,16 +55,12 @@ const router = createBrowserRouter([
|
||||
},
|
||||
{
|
||||
path: "favorites",
|
||||
element: <FavoritesPage2 />,
|
||||
element: <FavoritesPage />,
|
||||
},
|
||||
{
|
||||
path: "search",
|
||||
element: <SearchPage2 />,
|
||||
element: <SearchPage />,
|
||||
},
|
||||
// {
|
||||
// path: "search/:id",
|
||||
// element: <ApartmentPage />,
|
||||
// },
|
||||
{
|
||||
path: "unit-types",
|
||||
children: [
|
||||
|
||||
@@ -30,7 +30,7 @@ const AboutPage = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="grid grid-cols-2 gap-10 border-t border-b border-[#E2E2DC] py-6">
|
||||
<div className="flex flex-col justify-between gap-6">
|
||||
<div className="space-y-10 text-[#73787C] leading-[27px]">
|
||||
<p className="text-[56px] text-[#0D1922] font-mixcase leading-[56px] -tracking-[1.68px]">
|
||||
@@ -60,7 +60,11 @@ const AboutPage = () => {
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<img src="/images/pages/About/1.jpg" alt="" className="rounded-2xl pointer-events-none" />
|
||||
<img
|
||||
src="/images/pages/About/1.jpg"
|
||||
alt=""
|
||||
className="rounded-2xl pointer-events-none"
|
||||
/>
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="w-3 h-3 bg-[#00BED7] rounded-full"></div>
|
||||
|
||||
@@ -1,312 +0,0 @@
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import AdvantageCard from "../components/AboutProject/AdvantageCard";
|
||||
import PlaceCard from "../components/AboutProject/PlaceCard";
|
||||
import UnitCard from "../components/AboutProject/UnitCard";
|
||||
import Button2 from "../components/Button2";
|
||||
import ArrowLeftIcon from "../components/icons/ArrowLeftIcon";
|
||||
import Logo2Icon from "../components/icons/Logo2Icon";
|
||||
import ConsultantCard from "../components/AboutProject/ConsultantCard";
|
||||
import Slider from "../components/AboutProject/Slider";
|
||||
|
||||
function AboutProjects2Page() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<div className="mt-[58px] py-16 space-y-[100px] select-none">
|
||||
<div className="px-6 space-y-16">
|
||||
<p className="text-[56px] text-[#0D1922] font-mixcase -tracking-[1.68px] leading-none">
|
||||
Rove Home this residence a complete ecosystem that has everything
|
||||
you’ll ever need. This isn’t just where you’ll live.
|
||||
<br />
|
||||
It’s where you’ll thrive.
|
||||
</p>
|
||||
<div className="flex gap-6">
|
||||
<div className="min-w-[25%] w-[25%] flex flex-col justify-between gap-6">
|
||||
<div className="space-y-6">
|
||||
<p className="text-xs font-semibold text-[#73787C]">
|
||||
ABOUT ROVE HOME
|
||||
</p>
|
||||
<p className="text-2xl font-semibold">
|
||||
Embrace Rove’s forever-young spirit at Rove Home, where
|
||||
inspiring design and vibrant art installations converge with an
|
||||
exceptional location and an extended playlist of life-enhancing{" "}
|
||||
</p>
|
||||
</div>
|
||||
<Button2
|
||||
icon={<ArrowLeftIcon />}
|
||||
onClick={() => navigate("/masterplan/1/wing")}
|
||||
>
|
||||
Masterplan
|
||||
</Button2>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<img
|
||||
src="/images/pages/AboutProject/1.jpg"
|
||||
alt=""
|
||||
className="aspect-[21/9] h-full w-full rounded-2xl object-cover pointer-events-none"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mx-6 relative h-screen">
|
||||
<Slider />
|
||||
</div>
|
||||
|
||||
<div className="px-6 space-y-[140px]">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="space-y-6">
|
||||
<p className="text-xs text-[#73787C] font-semibold">
|
||||
ROVE AROUND THE CITY
|
||||
</p>
|
||||
<div className="grid grid-cols-2 gap-x-4 gap-y-2">
|
||||
<PlaceCard
|
||||
title="Burj Khalifa"
|
||||
desc="10 mins"
|
||||
image="/images/pages/AboutProject/places/1.jpg"
|
||||
/>
|
||||
<PlaceCard
|
||||
title="The Dubai Fountain"
|
||||
desc="10 mins"
|
||||
image="/images/pages/AboutProject/places/2.jpg"
|
||||
/>
|
||||
<PlaceCard
|
||||
title="Dubai Mall"
|
||||
desc="8 mins"
|
||||
image="/images/pages/AboutProject/places/3.jpg"
|
||||
/>
|
||||
<PlaceCard
|
||||
title="Dubai Opera"
|
||||
desc="11 mins"
|
||||
image="/images/pages/AboutProject/places/4.jpg"
|
||||
/>
|
||||
<PlaceCard
|
||||
title="Marasi Promenade"
|
||||
desc="4 mins"
|
||||
image="/images/pages/AboutProject/places/5.jpg"
|
||||
/>
|
||||
<PlaceCard
|
||||
title="Rove Downtown Hotel"
|
||||
desc="10 mins"
|
||||
image="/images/pages/AboutProject/places/6.jpg"
|
||||
/>
|
||||
<PlaceCard
|
||||
title="Rove City Walk Hotel"
|
||||
desc="12 mins"
|
||||
image="/images/pages/AboutProject/places/7.jpg"
|
||||
/>
|
||||
<PlaceCard
|
||||
title="City Walk"
|
||||
desc="12 mins"
|
||||
image="/images/pages/AboutProject/places/8.jpg"
|
||||
/>
|
||||
|
||||
<PlaceCard
|
||||
title="Coca Cola arena"
|
||||
desc="14 mins"
|
||||
image="/images/pages/AboutProject/places/9.jpg"
|
||||
/>
|
||||
|
||||
<PlaceCard
|
||||
title="Dubai International Airport"
|
||||
desc="10 mins"
|
||||
image="/images/pages/AboutProject/places/10.jpg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<img
|
||||
src="/images/pages/AboutProject/map.jpg"
|
||||
alt=""
|
||||
className="pointer-events-none"
|
||||
/>
|
||||
<div className="bg-gradient-to-r from-[#f3f3f2] to-transparent to-20% w-full h-full absolute top-0 left-0"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
<p className="text-xs text-[#73787C]">ADVANTAGES</p>
|
||||
<div className="grid grid-cols-2 gap-x-4 gap-y-14">
|
||||
<AdvantageCard
|
||||
title="Community"
|
||||
image="/images/pages/AboutProject/advantages/1.jpg"
|
||||
/>
|
||||
<AdvantageCard
|
||||
title="Rove-Inspired design"
|
||||
image="/images/pages/AboutProject/advantages/2.jpg"
|
||||
/>
|
||||
<AdvantageCard
|
||||
title="Fully loaded amenities"
|
||||
image="/images/pages/AboutProject/advantages/3.jpg"
|
||||
/>
|
||||
<AdvantageCard
|
||||
title="Add-on services"
|
||||
image="/images/pages/AboutProject/advantages/4.jpg"
|
||||
/>
|
||||
<AdvantageCard
|
||||
title="Central urban location"
|
||||
image="/images/pages/AboutProject/advantages/5.jpg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-16">
|
||||
<p className="text-[56px] text-[#0D1922] font-mixcase -tracking-[1.68px] leading-[56px]">
|
||||
Live in the future, today. Designed to embody Rove’s unique look and
|
||||
feel, the interiors will feature intelligent and modular living
|
||||
solutions by ORI, never seen before in UAE and the region.
|
||||
</p>
|
||||
<div className="space-y-6">
|
||||
<p className="text-2xl font-semibold w-[40%]">
|
||||
ORI introduces a revolutionary solution to apartment living, where
|
||||
space is not just a constraint but an opportunity.
|
||||
</p>
|
||||
<div className="flex gap-4">
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="w-3 h-3 bg-[#00BED7] rounded-full"></div>
|
||||
<p className="text-[#0D1922]">Simple</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="w-3 h-3 bg-[#00BED7] rounded-full"></div>
|
||||
<p className="text-[#0D1922]">Safe</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="w-3 h-3 bg-[#00BED7] rounded-full"></div>
|
||||
<p className="text-[#0D1922]">Effortless</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-4 -translate-x-6 pl-6 pr-2">
|
||||
<img
|
||||
src="/images/pages/AboutProject/interiors/1.jpg"
|
||||
alt=""
|
||||
className="w-[40%] object-cover rounded-2xl pointer-events-none"
|
||||
/>
|
||||
<img
|
||||
src="/images/pages/AboutProject/interiors/2.jpg"
|
||||
alt=""
|
||||
className="w-[20%] object-cover rounded-2xl pointer-events-none"
|
||||
/>
|
||||
<img
|
||||
src="/images/pages/AboutProject/interiors/3.jpg"
|
||||
alt=""
|
||||
className="w-[40%] object-cover rounded-2xl pointer-events-none"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<p className="text-xs text-[#73787C] font-semibold">
|
||||
UNITS DESCRIPTION
|
||||
</p>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<UnitCard
|
||||
title="Studio flex"
|
||||
desc1="Live in the future, today. In Studio Flex explore the ORI Cloud Bed, optimizing your living space with functionality and smart living."
|
||||
desc2="Every inch is designed to provide more space for comfort and convenience. This feature increase your unit size by 33%"
|
||||
square={341}
|
||||
price={1048888}
|
||||
image="/images/pages/AboutProject/units/1.jpg"
|
||||
/>
|
||||
<UnitCard
|
||||
title="Studio²"
|
||||
desc1="In Studio² experience the Flexibed, a smart innovation for modern living. When folded, it unveils a spacious living room creating a cohesive space that blends both style and functionality."
|
||||
desc2=""
|
||||
square={390}
|
||||
price={1138888}
|
||||
image="/images/pages/AboutProject/units/2.jpg"
|
||||
/>
|
||||
<UnitCard
|
||||
title="1 Bedroom"
|
||||
desc1="In 1 Bedroom² double up your space with next generation features that enhance smart living."
|
||||
desc2="With pocket walls that disappear and a Flexibed that seamlessly converts, you can transform your living room into an extra bedroom, anytime you want!"
|
||||
square={609}
|
||||
price={1668888}
|
||||
image="/images/pages/AboutProject/units/3.jpg"
|
||||
/>
|
||||
<UnitCard
|
||||
title="2 Bedroom²"
|
||||
desc1="In 2 Bedroom² discover extra functionality with added space and maximum value."
|
||||
desc2="Whether you want to add a multipurpose spare room or double up your living space as a bedroom - every inch of space feels larger and works exactly how you want."
|
||||
square={891}
|
||||
price={2408888}
|
||||
image="/images/pages/AboutProject/units/4.jpg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-16">
|
||||
<p className="text-[56px] text-[#0D1922] font-mixcase leading-[56px] -tracking-[1.68px]">
|
||||
Founded under Alshamsi family, IRTH is a real estate investment
|
||||
platform - based on the philosophy of value creation, innovation and
|
||||
building world-class living experiences.
|
||||
</p>
|
||||
<div className="space-y-6">
|
||||
<p className="text-xs text-[#73787C] font-semibold">
|
||||
ABOUT THE DEVELOPER
|
||||
</p>
|
||||
<div className="flex gap-4">
|
||||
<div className="min-w-[25%] w-[25%] p-10 bg-white flex flex-col gap-6 justify-between rounded-2xl">
|
||||
<div className="space-y-6">
|
||||
<Logo2Icon />
|
||||
<div className="space-y-4">
|
||||
<p>
|
||||
IRTH’s vision is long-term, supported with a proactive
|
||||
approach, swift actions, strong financial backing, and
|
||||
high-quality projects - bridging the gap between ambition
|
||||
and success. IRTH continues seeking new opportunities and
|
||||
broadening horizons – thriving in any market situation
|
||||
through an extensive land bank and strategic partnerships.
|
||||
</p>
|
||||
<p>
|
||||
At IRTH, we take pride in offering the best-inclass
|
||||
locations and properties for value-based investment
|
||||
opportunities - setting new standards in the real estate
|
||||
market in the region. We are IRTH – The Future of Real
|
||||
Estate.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Button2>Learn more</Button2>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<img
|
||||
src="/images/pages/AboutProject/3.jpg"
|
||||
alt=""
|
||||
className="rounded-2xl aspect-[21/9] object-cover object-bottom pointer-events-none"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
<p className="text-xs text-[#73787C] font-semibold">
|
||||
MAIN CONSULTANTS
|
||||
</p>
|
||||
<div className="grid grid-cols-4 gap-4">
|
||||
<ConsultantCard
|
||||
title="Architect"
|
||||
image="/images/pages/AboutProject/consultant-logos/archcorp.svg"
|
||||
/>
|
||||
<ConsultantCard
|
||||
title="Landscape architect"
|
||||
image="/images/pages/AboutProject/consultant-logos/scla.svg"
|
||||
/>
|
||||
<div className=""></div>
|
||||
<ConsultantCard
|
||||
title="Id team"
|
||||
image="/images/pages/AboutProject/consultant-logos/zebra.svg"
|
||||
/>
|
||||
<div className=""></div>
|
||||
<ConsultantCard
|
||||
title="Sales and marketing"
|
||||
image="/images/pages/AboutProject/consultant-logos/octa.svg"
|
||||
/>
|
||||
<ConsultantCard
|
||||
title="Art team"
|
||||
image="/images/pages/AboutProject/consultant-logos/studio-feel.svg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AboutProjects2Page;
|
||||
@@ -1,490 +1,310 @@
|
||||
import { isMobile } from "react-device-detect";
|
||||
import Button from "../components/Button";
|
||||
import LeftArrowIcon from "../components/icons/LeftArrowIcon";
|
||||
import LivingSolutionSlider from "../components/aboutComplex/LivingSolutionSlider";
|
||||
import RoveHomeSlider from "../components/aboutComplex/RoveHomeSlider";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
interface ICityItem {
|
||||
time: number;
|
||||
title: string;
|
||||
id: string;
|
||||
image: string;
|
||||
}
|
||||
|
||||
const roveAroundTheCity: ICityItem[] = [
|
||||
{
|
||||
id: "1",
|
||||
title: "Burj Khalifa",
|
||||
time: 10,
|
||||
image: "/images/aboutCompany/roveAroundTheCity/1.png",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
title: "The Dubai Fountain",
|
||||
time: 10,
|
||||
image: "/images/aboutCompany/roveAroundTheCity/2.png",
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
title: "Dubai Mall",
|
||||
time: 8,
|
||||
image: "/images/aboutCompany/roveAroundTheCity/3.png",
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
title: "Dubai Opera",
|
||||
time: 11,
|
||||
image: "/images/aboutCompany/roveAroundTheCity/4.png",
|
||||
},
|
||||
{
|
||||
id: "5",
|
||||
title: "Marasi Promenade",
|
||||
time: 4,
|
||||
image: "/images/aboutCompany/roveAroundTheCity/5.png",
|
||||
},
|
||||
{
|
||||
id: "6",
|
||||
title: "Rove Downtown Hotel",
|
||||
time: 10,
|
||||
image: "/images/aboutCompany/roveAroundTheCity/6.png",
|
||||
},
|
||||
{
|
||||
id: "7",
|
||||
title: "Rove City Walk Hotel",
|
||||
time: 12,
|
||||
image: "/images/aboutCompany/roveAroundTheCity/7.png",
|
||||
},
|
||||
{
|
||||
id: "8",
|
||||
title: "City Walk",
|
||||
time: 12,
|
||||
image: "/images/aboutCompany/roveAroundTheCity/8.png",
|
||||
},
|
||||
{
|
||||
id: "9",
|
||||
title: "Coca Cola arena",
|
||||
time: 14,
|
||||
image: "/images/aboutCompany/roveAroundTheCity/9.png",
|
||||
},
|
||||
{
|
||||
id: "10",
|
||||
title: " Dubai International Airport",
|
||||
time: 10,
|
||||
image: "/images/aboutCompany/roveAroundTheCity/10.png",
|
||||
},
|
||||
];
|
||||
|
||||
interface IAdvantages {
|
||||
title: string;
|
||||
image: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
const advantages: IAdvantages[] = [
|
||||
{
|
||||
title: "Community",
|
||||
image: "/images/aboutCompany/advantages/1.jpg",
|
||||
id: "1",
|
||||
},
|
||||
{
|
||||
title: "Rove-Inspired design",
|
||||
image: "/images/aboutCompany/advantages/2.jpg",
|
||||
id: "2",
|
||||
},
|
||||
{
|
||||
title: "Fully loaded amenities",
|
||||
image: "/images/aboutCompany/advantages/3.jpg",
|
||||
id: "3",
|
||||
},
|
||||
{
|
||||
title: "Add-on services",
|
||||
image: "/images/aboutCompany/advantages/4.jpg",
|
||||
id: "4",
|
||||
},
|
||||
{
|
||||
title: "Central urban location",
|
||||
image: "/images/aboutCompany/advantages/5.jpg",
|
||||
id: "5",
|
||||
},
|
||||
];
|
||||
|
||||
const advStyles = [
|
||||
"xl:col-start-3 xl:col-end-7",
|
||||
"xl:col-span-4",
|
||||
"xl:col-start-5 xl:col-end-9",
|
||||
"xl:col-span-4",
|
||||
"xl:col-start-3 xl:col-span-4",
|
||||
];
|
||||
import AdvantageCard from "../components/AboutProject/AdvantageCard";
|
||||
import PlaceCard from "../components/AboutProject/PlaceCard";
|
||||
import UnitCard from "../components/AboutProject/UnitCard";
|
||||
import Button2 from "../components/Button2";
|
||||
import ArrowLeftIcon from "../components/icons/ArrowLeftIcon";
|
||||
import Logo2Icon from "../components/icons/Logo2Icon";
|
||||
import ConsultantCard from "../components/AboutProject/ConsultantCard";
|
||||
import Slider from "../components/AboutProject/Slider";
|
||||
|
||||
function AboutProjectsPage() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleOnBackClick = () => {
|
||||
navigate(-1);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="overflow-x-hidden">
|
||||
<section
|
||||
className={`xl:pt-16 sm:pt-10 font-usual ${
|
||||
isMobile ? "pt-16" : ""
|
||||
} grid grid-cols-12 select-none`}
|
||||
>
|
||||
<div className="flex px-6 py-4 col-span-full h-16 relative">
|
||||
<div className="fixed z-[100]">
|
||||
<Button
|
||||
onClick={handleOnBackClick}
|
||||
text="Masterplan"
|
||||
icon={<LeftArrowIcon />}
|
||||
buttonType="cta"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/* About Rove Home */}
|
||||
<h1 className="uppercase xl:rubber-headline-indent text-headline-s xl:px-6 px-4 col-span-full pb-6">
|
||||
<div className="mt-[58px] py-16 space-y-[100px] select-none">
|
||||
<div className="px-6 space-y-16">
|
||||
<p className="text-[56px] text-[#0D1922] font-mixcase -tracking-[1.68px] leading-none">
|
||||
Rove Home this residence a complete ecosystem that has everything
|
||||
you’ll ever need. This isn’t just where you’ll live. It’s where you’ll
|
||||
thrive.
|
||||
</h1>
|
||||
|
||||
<div className="col-span-full px-6 grid grid-cols-12">
|
||||
<div className="text-caption-m font-semibold text-[#73787C] xl:col-span-1 uppercase col-span-full pb-3">
|
||||
About rove home
|
||||
you’ll ever need. This isn’t just where you’ll live.
|
||||
<br />
|
||||
It’s where you’ll thrive.
|
||||
</p>
|
||||
<div className="flex gap-6">
|
||||
<div className="min-w-[25%] w-[25%] flex flex-col justify-between gap-6">
|
||||
<div className="space-y-6">
|
||||
<p className="text-xs font-semibold text-[#73787C]">
|
||||
ABOUT ROVE HOME
|
||||
</p>
|
||||
<p className="text-2xl font-semibold">
|
||||
Embrace Rove’s forever-young spirit at Rove Home, where
|
||||
inspiring design and vibrant art installations converge with an
|
||||
exceptional location and an extended playlist of life-enhancing{" "}
|
||||
</p>
|
||||
</div>
|
||||
<Button2
|
||||
icon={<ArrowLeftIcon />}
|
||||
onClick={() => navigate("/masterplan/1/wing")}
|
||||
>
|
||||
Masterplan
|
||||
</Button2>
|
||||
</div>
|
||||
<div className="xl:col-start-3 col-span-full grid grid-cols-10 gap-6 xl:pb-[100px] sm:pb-16 pb-20">
|
||||
<div className="w-full">
|
||||
<img
|
||||
src="/images/aboutCompany/rovehome.png"
|
||||
src="/images/pages/AboutProject/1.jpg"
|
||||
alt=""
|
||||
className="col-span-full"
|
||||
className="aspect-[21/9] h-full w-full rounded-2xl object-cover pointer-events-none"
|
||||
/>
|
||||
<div className="xl:col-span-4 sm:col-span-6 col-span-full text-l text-[#73787C]">
|
||||
Embrace Rove’s forever-young spirit at Rove Home, where inspiring
|
||||
design and vibrant art installations converge with an exceptional
|
||||
location and an extended playlist of life-enhancing{" "}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* RoveHome roof */}
|
||||
<RoveHomeSlider />
|
||||
{/* Rove around the city */}
|
||||
<div className="col-span-full px-6 grid grid-cols-12 xl:pt-[100px] sm:pt-16 pt-14">
|
||||
<div className="text-caption-m font-semibold text-[#73787C] xl:col-span-1 col-span-full uppercase pb-3">
|
||||
ROVE AROUND THE CITY
|
||||
</div>
|
||||
<div className="xl:col-start-3 col-span-full grid grid-cols-10 gap-6">
|
||||
<div className="xl:col-span-4 xl:grid grid-cols-4 gap-4 order-2 xl:order-1 col-span-full flex flex-nowrap overflow-x-scroll">
|
||||
{roveAroundTheCity.map((item) => (
|
||||
<div
|
||||
key={item.id}
|
||||
className="xl:col-span-2 sm:col-span-1 col-span-2 bg-white rounded-lg flex flex-col p-3 xl:min-w-full sm:min-w-[calc(25vw-24px)] min-w-[calc(50vw-30px)]"
|
||||
>
|
||||
<div className="flex gap-1 items-center">
|
||||
<div className="bg-[#00BED7] w-3 h-3 rounded-full"></div>
|
||||
<div className="text-[#0D1922] text-m">{item.title}</div>
|
||||
</div>
|
||||
<p className="text-s text-[#73787C]">{item.time} mins</p>
|
||||
<img className="w-16 h-16 self-end" src={item.image} alt="" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="relative col-span-full xl:col-start-5 order-1 xl:order-2">
|
||||
<img
|
||||
src="/images/aboutCompany/Map.jpg"
|
||||
alt=""
|
||||
className="w-full"
|
||||
</div>
|
||||
|
||||
<div className="mx-6 relative h-screen">
|
||||
<Slider />
|
||||
</div>
|
||||
|
||||
<div className="px-6 space-y-[140px]">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="space-y-6">
|
||||
<p className="text-xs text-[#73787C] font-semibold">
|
||||
ROVE AROUND THE CITY
|
||||
</p>
|
||||
<div className="grid grid-cols-2 gap-x-4 gap-y-2">
|
||||
<PlaceCard
|
||||
title="Burj Khalifa"
|
||||
desc="10 mins"
|
||||
image="/images/pages/AboutProject/places/1.jpg"
|
||||
/>
|
||||
<PlaceCard
|
||||
title="The Dubai Fountain"
|
||||
desc="10 mins"
|
||||
image="/images/pages/AboutProject/places/2.jpg"
|
||||
/>
|
||||
<PlaceCard
|
||||
title="Dubai Mall"
|
||||
desc="8 mins"
|
||||
image="/images/pages/AboutProject/places/3.jpg"
|
||||
/>
|
||||
<PlaceCard
|
||||
title="Dubai Opera"
|
||||
desc="11 mins"
|
||||
image="/images/pages/AboutProject/places/4.jpg"
|
||||
/>
|
||||
<PlaceCard
|
||||
title="Marasi Promenade"
|
||||
desc="4 mins"
|
||||
image="/images/pages/AboutProject/places/5.jpg"
|
||||
/>
|
||||
<PlaceCard
|
||||
title="Rove Downtown Hotel"
|
||||
desc="10 mins"
|
||||
image="/images/pages/AboutProject/places/6.jpg"
|
||||
/>
|
||||
<PlaceCard
|
||||
title="Rove City Walk Hotel"
|
||||
desc="12 mins"
|
||||
image="/images/pages/AboutProject/places/7.jpg"
|
||||
/>
|
||||
<PlaceCard
|
||||
title="City Walk"
|
||||
desc="12 mins"
|
||||
image="/images/pages/AboutProject/places/8.jpg"
|
||||
/>
|
||||
|
||||
<PlaceCard
|
||||
title="Coca Cola arena"
|
||||
desc="14 mins"
|
||||
image="/images/pages/AboutProject/places/9.jpg"
|
||||
/>
|
||||
|
||||
<PlaceCard
|
||||
title="Dubai International Airport"
|
||||
desc="10 mins"
|
||||
image="/images/pages/AboutProject/places/10.jpg"
|
||||
/>
|
||||
<div className="bg-gradient-to-r from-[#f3f3f2] to-transparent to-20% w-full h-full absolute top-0 left-0"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Advantages */}
|
||||
<div className="col-span-full grid grid-cols-12 px-6 gap-x-4 xl:pt-[140px] sm:pt-16 pt-14">
|
||||
<div className="uppercase text-[#73787C] font-semibold xl:col-span-1 pb-3 text-caption-m col-span-full">
|
||||
ADVANTAGES
|
||||
<div className="relative">
|
||||
<img
|
||||
src="/images/pages/AboutProject/map.jpg"
|
||||
alt=""
|
||||
className="pointer-events-none"
|
||||
/>
|
||||
<div className="bg-gradient-to-r from-[#f3f3f2] to-transparent to-20% w-full h-full absolute top-0 left-0"></div>
|
||||
</div>
|
||||
<p className="text-subheadline-m font-semibold xl:col-start-3 col-span-full xl:pb-6 text-[#00BED7] pb-3">
|
||||
What makes a rove home?
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
<p className="text-xs text-[#73787C]">ADVANTAGES</p>
|
||||
<div className="grid grid-cols-2 gap-x-4 gap-y-14">
|
||||
<AdvantageCard
|
||||
title="Community"
|
||||
image="/images/pages/AboutProject/advantages/1.jpg"
|
||||
/>
|
||||
<AdvantageCard
|
||||
title="Rove-Inspired design"
|
||||
image="/images/pages/AboutProject/advantages/2.jpg"
|
||||
/>
|
||||
<AdvantageCard
|
||||
title="Fully loaded amenities"
|
||||
image="/images/pages/AboutProject/advantages/3.jpg"
|
||||
/>
|
||||
<AdvantageCard
|
||||
title="Add-on services"
|
||||
image="/images/pages/AboutProject/advantages/4.jpg"
|
||||
/>
|
||||
<AdvantageCard
|
||||
title="Central urban location"
|
||||
image="/images/pages/AboutProject/advantages/5.jpg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-16">
|
||||
<p className="text-[56px] text-[#0D1922] font-mixcase -tracking-[1.68px] leading-[56px]">
|
||||
Live in the future, today. Designed to embody Rove’s unique look and
|
||||
feel, the interiors will feature intelligent and modular living
|
||||
solutions by ORI, never seen before in UAE and the region.
|
||||
</p>
|
||||
{advantages.map((adv, index) => {
|
||||
const styles = `${advStyles[index]} ${
|
||||
index === advantages.length - 1 ? "" : "xl:pb-14 pb-6"
|
||||
}`;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={adv.id}
|
||||
className={`flex flex-col ${styles} xl:col-span-4 sm:col-span-6 col-span-full`}
|
||||
>
|
||||
<img
|
||||
src={adv.image}
|
||||
alt={adv.title}
|
||||
className="rounded-2xl object-cover aspect-[5/3]"
|
||||
/>
|
||||
<div className="flex gap-1 pt-3 items-center">
|
||||
<div className="rounded-full bg-[#00BED7] w-3 h-3"></div>
|
||||
<div className="text-m">{adv.title}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{/* EXPANDABLE LIVING SOLUTIONS */}
|
||||
<h1 className="uppercase xl:rubber-headline-indent text-headline-s xl:px-6 px-4 col-span-full pb-6 xl:pt-[140px] sm:pt-[100px] pt-20">
|
||||
Live in the future, today. Designed to embody Rove’s unique look and
|
||||
feel, the interiors will feature intelligent and modular living
|
||||
solutions by ORI, never seen before in UAE and the region.
|
||||
</h1>
|
||||
<div className="col-span-full grid grid-cols-12 px-6">
|
||||
<div className="text-caption-m font-semibold text-[#73787C] xl:col-span-2 uppercase col-start-1 col-span-full pb-3">
|
||||
EXPANDABLE LIVING SOLUTIONS
|
||||
</div>
|
||||
<div className="flex flex-col gap-6 xl:col-start-3 xl:col-span-4 col-span-full">
|
||||
<div className="text-[#00BED7] text-subheadline-m">
|
||||
<div className="space-y-6">
|
||||
<p className="text-2xl font-semibold w-[40%]">
|
||||
ORI introduces a revolutionary solution to apartment living, where
|
||||
space is not just a constraint but an opportunity.{" "}
|
||||
</div>
|
||||
<div className="flex gap-6">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="bg-[#00BED7] rounded-full w-3 h-3"></div>
|
||||
<p className="text-[#0D1922] text-m">Simple</p>
|
||||
space is not just a constraint but an opportunity.
|
||||
</p>
|
||||
<div className="flex gap-4">
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="w-3 h-3 bg-[#00BED7] rounded-full"></div>
|
||||
<p className="text-[#0D1922]">Simple</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="bg-[#00BED7] rounded-full w-3 h-3"></div>
|
||||
<p className="text-[#0D1922] text-m">Safe</p>
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="w-3 h-3 bg-[#00BED7] rounded-full"></div>
|
||||
<p className="text-[#0D1922]">Safe</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="bg-[#00BED7] rounded-full w-3 h-3"></div>
|
||||
<p className="text-[#0D1922] text-m">Effortless</p>
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="w-3 h-3 bg-[#00BED7] rounded-full"></div>
|
||||
<p className="text-[#0D1922]">Effortless</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-full pt-6">
|
||||
<LivingSolutionSlider />
|
||||
<div className="flex gap-4 -translate-x-6 pl-6 pr-2">
|
||||
<img
|
||||
src="/images/pages/AboutProject/interiors/1.jpg"
|
||||
alt=""
|
||||
className="w-[40%] object-cover rounded-2xl pointer-events-none"
|
||||
/>
|
||||
<img
|
||||
src="/images/pages/AboutProject/interiors/2.jpg"
|
||||
alt=""
|
||||
className="w-[20%] object-cover rounded-2xl pointer-events-none"
|
||||
/>
|
||||
<img
|
||||
src="/images/pages/AboutProject/interiors/3.jpg"
|
||||
alt=""
|
||||
className="w-[40%] object-cover rounded-2xl pointer-events-none"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Units description */}
|
||||
<div className="col-span-full px-6 grid grid-cols-12 xl:pt-[140px] xm:pt-[100px] pt-[80px]">
|
||||
<div className="text-caption-m font-semibold text-[#73787C] xl:col-span-1 col-span-full uppercase pb-3">
|
||||
<div className="space-y-4">
|
||||
<p className="text-xs text-[#73787C] font-semibold">
|
||||
UNITS DESCRIPTION
|
||||
</div>
|
||||
<div className="xl:col-start-3 col-span-full grid grid-cols-10 gap-6">
|
||||
<div className="lg:col-span-5 col-span-full grid relative grid-cols-5">
|
||||
<div className="sm:col-span-3 col-span-full h-full bg-white rounded-2xl flex flex-col justify-between p-8 sm:mr-[-32px] gap-6">
|
||||
<div>
|
||||
<h2 className="text-[#0D1922] font-bold text-subheadline-l">
|
||||
Studio flex
|
||||
</h2>
|
||||
<p className="text-m text-[#73787C] pt-4">
|
||||
Live in the future, today. In Studio Flex explore the ORI
|
||||
Cloud Bed, optimizing your living space with functionality
|
||||
and smart living.
|
||||
</p>
|
||||
<p className="text-m text-[#73787C] mt-[10px]">
|
||||
Every inch is designed to provide more space for comfort and
|
||||
convenience. This feature increase your unit size by 33%
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-s text-[#0D1922]">341 Sqft</p>
|
||||
<p className="font-bold text-m text-[#00BED7]">Unavailable</p>
|
||||
</div>
|
||||
</div>
|
||||
<img
|
||||
src="/images/aboutCompany/unitsDescription/1.jpg"
|
||||
alt=""
|
||||
className="sm:col-span-2 col-span-full -z-10 sm:h-full w-full object-cover rounded-2xl xl:aspect-auto sm:aspect-square aspect-[3.3/2] mt-[-32px] sm:mt-0"
|
||||
/>
|
||||
</div>
|
||||
<div className="lg:col-span-5 col-span-full grid relative grid-cols-5">
|
||||
<div className="sm:col-span-3 col-span-full h-full bg-white rounded-2xl flex flex-col justify-between p-8 sm:mr-[-32px] gap-6">
|
||||
<div>
|
||||
<h2 className="text-[#0D1922] font-bold text-subheadline-l">
|
||||
Studio<sup>2</sup>
|
||||
</h2>
|
||||
<p className="text-m text-[#73787C] pt-4">
|
||||
In Studio 2 experience the Flexibed, a smart innovation for
|
||||
modern living. When folded, it unveils a spacious living
|
||||
room creating a cohesive space that blends both style and
|
||||
functionality.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-s text-[#0D1922]">390 Sqft</p>
|
||||
<p className="font-bold text-m text-[#00BED7]">
|
||||
AED 1,138,888
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<img
|
||||
src="/images/aboutCompany/unitsDescription/2.jpg"
|
||||
alt=""
|
||||
className="sm:col-span-2 col-span-full -z-10 sm:h-full w-full object-cover rounded-2xl xl:aspect-auto sm:aspect-square aspect-[3.3/2] mt-[-32px] sm:mt-0"
|
||||
/>
|
||||
</div>
|
||||
<div className="lg:col-span-5 col-span-full grid relative grid-cols-5">
|
||||
<div className="sm:col-span-3 col-span-full h-full bg-white rounded-2xl flex flex-col justify-between p-8 sm:mr-[-32px] gap-6">
|
||||
<div>
|
||||
<h2 className="text-[#0D1922] font-bold text-subheadline-l">
|
||||
1 Bedroom<sup>2</sup>
|
||||
</h2>
|
||||
<p className="text-m text-[#73787C] pt-4">
|
||||
In 1 Bedroom 2 double up your space with next generation
|
||||
features that enhance smart living.
|
||||
</p>
|
||||
<p className="text-m text-[#73787C] mt-[10px]">
|
||||
With pocket walls that disappear and a Flexibed that
|
||||
seamlessly converts, you can transform your living room into
|
||||
an extra bedroom, anytime you want!
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-s text-[#0D1922]">609 Sqft</p>
|
||||
<p className="font-bold text-m text-[#00BED7]">Unvailiable</p>
|
||||
</div>
|
||||
</div>
|
||||
<img
|
||||
src="/images/aboutCompany/unitsDescription/3.jpg"
|
||||
alt=""
|
||||
className="sm:col-span-2 col-span-full -z-10 sm:h-full w-full object-cover rounded-2xl xl:aspect-auto sm:aspect-square aspect-[3.3/2] mt-[-32px] sm:mt-0"
|
||||
/>
|
||||
</div>
|
||||
<div className="lg:col-span-5 col-span-full grid relative grid-cols-5">
|
||||
<div className="sm:col-span-3 col-span-full h-full bg-white rounded-2xl flex flex-col justify-between p-8 sm:mr-[-32px] gap-6">
|
||||
<div>
|
||||
<h2 className="text-[#0D1922] font-bold text-subheadline-l">
|
||||
2 Bedroom<sup>2</sup>
|
||||
</h2>
|
||||
<p className="text-m text-[#73787C] pt-4">
|
||||
In 2 Bedroom 2 discover extra functionality with added space
|
||||
and maximum value.
|
||||
</p>
|
||||
<p className="text-m text-[#73787C] mt-[10px]">
|
||||
Whether you want to add a multipurpose spare room or double
|
||||
up your living space as a bedroom - every inch of space
|
||||
feels larger and works exactly how you want.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-s text-[#0D1922]">891 Sqft</p>
|
||||
<p className="font-bold text-m text-[#00BED7]">
|
||||
AED 2,408,888
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<img
|
||||
src="/images/aboutCompany/unitsDescription/4.jpg"
|
||||
alt=""
|
||||
className="sm:col-span-2 col-span-full -z-10 w-full object-cover rounded-2xl xl:aspect-auto sm:aspect-square aspect-[3.3/2] h-full mt-[-32px] sm:mt-0"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* About the developer */}
|
||||
<h1 className="uppercase xl:rubber-headline-indent text-headline-s xl:px-6 px-4 col-span-full xl:pb-16 sm:pb-10 pb-7 xl:pt-[140px] sm:pt-[100px] pt-20">
|
||||
Founded under Alshamsi family, IRTH is a real estate investment
|
||||
platform - based on the philosophy of value creation, innovation and
|
||||
building world-class living experiences.
|
||||
</h1>
|
||||
<div className="col-span-full grid xl:grid-cols-12 grid-cols-8 px-6 gap-6">
|
||||
<div className="text-caption-m font-semibold text-[#73787C] xl:col-span-1 col-span-full uppercase">
|
||||
ABOUT THE DEVELOPER
|
||||
</div>
|
||||
<div className="xl:col-start-3 xl:col-span-3 text-[#73787C] flex-col flex justify-between col-span-5 gap-6">
|
||||
<div>
|
||||
<p className="text-m">
|
||||
IRTH’s vision is long-term, supported with a proactive approach,
|
||||
swift actions, strong financial backing, and high-quality
|
||||
projects - bridging the gap between ambition and success. IRTH
|
||||
continues seeking new opportunities and broadening horizons –
|
||||
thriving in any market situation through an extensive land bank
|
||||
and strategic partnerships.
|
||||
</p>
|
||||
<p className="text-m pt-4">
|
||||
At IRTH, we take pride in offering the best-inclass locations
|
||||
and properties for value-based investment opportunities -
|
||||
setting new standards in the real estate market in the region.
|
||||
We are IRTH – The Future of Real Estate.
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
text="Learn more"
|
||||
buttonType="cta"
|
||||
className="justify-center w-fit px-[51px]"
|
||||
</p>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<UnitCard
|
||||
title="Studio flex"
|
||||
desc1="Live in the future, today. In Studio Flex explore the ORI Cloud Bed, optimizing your living space with functionality and smart living."
|
||||
desc2="Every inch is designed to provide more space for comfort and convenience. This feature increase your unit size by 33%"
|
||||
square={341}
|
||||
price={1048888}
|
||||
image="/images/pages/AboutProject/units/1.jpg"
|
||||
/>
|
||||
</div>
|
||||
<div className="xl:col-start-7 xl:col-span-7 col-span-full">
|
||||
<img
|
||||
src="/images/aboutCompany/about_the_developer.png"
|
||||
alt=""
|
||||
className="w-full"
|
||||
<UnitCard
|
||||
title="Studio²"
|
||||
desc1="In Studio² experience the Flexibed, a smart innovation for modern living. When folded, it unveils a spacious living room creating a cohesive space that blends both style and functionality."
|
||||
desc2=""
|
||||
square={390}
|
||||
price={1138888}
|
||||
image="/images/pages/AboutProject/units/2.jpg"
|
||||
/>
|
||||
<UnitCard
|
||||
title="1 Bedroom"
|
||||
desc1="In 1 Bedroom² double up your space with next generation features that enhance smart living."
|
||||
desc2="With pocket walls that disappear and a Flexibed that seamlessly converts, you can transform your living room into an extra bedroom, anytime you want!"
|
||||
square={609}
|
||||
price={1668888}
|
||||
image="/images/pages/AboutProject/units/3.jpg"
|
||||
/>
|
||||
<UnitCard
|
||||
title="2 Bedroom²"
|
||||
desc1="In 2 Bedroom² discover extra functionality with added space and maximum value."
|
||||
desc2="Whether you want to add a multipurpose spare room or double up your living space as a bedroom - every inch of space feels larger and works exactly how you want."
|
||||
square={891}
|
||||
price={2408888}
|
||||
image="/images/pages/AboutProject/units/4.jpg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/* MAIN CONSULTANTS */}
|
||||
<div className="col-span-full grid xl:grid-cols-12 grid-cols-8 px-6 xl:pt-[140px] xl:pb-[140px] sm:pt-[100px] pt-20 pb-10">
|
||||
<div className="text-caption-m font-semibold text-[#73787C] xl:col-span-2 uppercase pb-3 col-span-full">
|
||||
<div className="space-y-16">
|
||||
<p className="text-[56px] text-[#0D1922] font-mixcase leading-[56px] -tracking-[1.68px]">
|
||||
Founded under Alshamsi family, IRTH is a real estate investment
|
||||
platform - based on the philosophy of value creation, innovation and
|
||||
building world-class living experiences.
|
||||
</p>
|
||||
<div className="space-y-6">
|
||||
<p className="text-xs text-[#73787C] font-semibold">
|
||||
ABOUT THE DEVELOPER
|
||||
</p>
|
||||
<div className="flex gap-4">
|
||||
<div className="min-w-[25%] w-[25%] p-10 bg-white flex flex-col gap-6 justify-between rounded-2xl">
|
||||
<div className="space-y-6">
|
||||
<Logo2Icon />
|
||||
<div className="space-y-4">
|
||||
<p>
|
||||
IRTH’s vision is long-term, supported with a proactive
|
||||
approach, swift actions, strong financial backing, and
|
||||
high-quality projects - bridging the gap between ambition
|
||||
and success. IRTH continues seeking new opportunities and
|
||||
broadening horizons – thriving in any market situation
|
||||
through an extensive land bank and strategic partnerships.
|
||||
</p>
|
||||
<p>
|
||||
At IRTH, we take pride in offering the best-inclass
|
||||
locations and properties for value-based investment
|
||||
opportunities - setting new standards in the real estate
|
||||
market in the region. We are IRTH – The Future of Real
|
||||
Estate.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Button2>Learn more</Button2>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<img
|
||||
src="/images/pages/AboutProject/3.jpg"
|
||||
alt=""
|
||||
className="rounded-2xl aspect-[21/9] object-cover object-bottom pointer-events-none"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
<p className="text-xs text-[#73787C] font-semibold">
|
||||
MAIN CONSULTANTS
|
||||
</div>
|
||||
<div className="col-span-full grid xl:grid-cols-12 grid-cols-8 gap-4">
|
||||
<div className="xl:col-start-3 col-start-1 sm:col-span-2 col-span-4 bg-white rounded-2xl p-6 h-[280px] justify-between flex flex-col">
|
||||
<div className="flex gap-1 items-center">
|
||||
<div className="bg-[#00BED7] w-3 h-3 rounded-full"></div>
|
||||
<p className="text-m text-[#0D1922]">Architect</p>
|
||||
</div>
|
||||
<img
|
||||
src="/images/aboutCompany/mainConsultants/1.png"
|
||||
alt=""
|
||||
className="self-end"
|
||||
/>
|
||||
</div>
|
||||
<div className="sm:col-span-2 bg-white rounded-2xl col-span-4 p-6 h-[280px] justify-between flex flex-col">
|
||||
<div className="flex gap-1 items-center">
|
||||
<div className="bg-[#00BED7] w-3 h-3 rounded-full"></div>
|
||||
<p className="text-m text-[#0D1922]">Landscape architect</p>
|
||||
</div>
|
||||
<img
|
||||
src="/images/aboutCompany/mainConsultants/2.png"
|
||||
alt=""
|
||||
className="self-end"
|
||||
/>
|
||||
</div>
|
||||
<div className="sm:col-span-2 bg-white rounded-2xl col-span-full p-6 h-[280px] justify-between flex flex-col xl:col-start-9 sm:col-start-7">
|
||||
<div className="flex gap-1 items-center">
|
||||
<div className="bg-[#00BED7] w-3 h-3 rounded-full"></div>
|
||||
<p className="text-m text-[#0D1922]">Art team</p>
|
||||
</div>
|
||||
<img
|
||||
src="/images/aboutCompany/mainConsultants/3.png"
|
||||
alt=""
|
||||
className="self-end"
|
||||
/>
|
||||
</div>
|
||||
<div className="sm:col-span-2 bg-white rounded-2xl col-span-4 p-6 h-[280px] justify-between flex flex-col xl:col-start-5 sm:col-start-3">
|
||||
<div className="flex gap-1 items-center">
|
||||
<div className="bg-[#00BED7] w-3 h-3 rounded-full"></div>
|
||||
<p className="text-m text-[#0D1922]">Id team</p>
|
||||
</div>
|
||||
<img
|
||||
src="/images/aboutCompany/mainConsultants/4.png"
|
||||
alt=""
|
||||
className="self-end"
|
||||
/>
|
||||
</div>
|
||||
<div className="sm:col-span-2 bg-white rounded-2xl col-span-4 p-6 h-[280px] justify-between flex flex-col">
|
||||
<div className="flex gap-1 items-center">
|
||||
<div className="bg-[#00BED7] w-3 h-3 rounded-full"></div>
|
||||
<p className="text-m text-[#0D1922]">Sales and marketing</p>
|
||||
</div>
|
||||
<img
|
||||
src="/images/aboutCompany/mainConsultants/5.png"
|
||||
alt=""
|
||||
className="self-end"
|
||||
/>
|
||||
</div>
|
||||
</p>
|
||||
<div className="grid grid-cols-4 gap-4">
|
||||
<ConsultantCard
|
||||
title="Architect"
|
||||
image="/images/pages/AboutProject/consultant-logos/archcorp.svg"
|
||||
/>
|
||||
<ConsultantCard
|
||||
title="Landscape architect"
|
||||
image="/images/pages/AboutProject/consultant-logos/scla.svg"
|
||||
/>
|
||||
<div className=""></div>
|
||||
<ConsultantCard
|
||||
title="Id team"
|
||||
image="/images/pages/AboutProject/consultant-logos/zebra.svg"
|
||||
/>
|
||||
<div className=""></div>
|
||||
<ConsultantCard
|
||||
title="Sales and marketing"
|
||||
image="/images/pages/AboutProject/consultant-logos/octa.svg"
|
||||
/>
|
||||
<ConsultantCard
|
||||
title="Art team"
|
||||
image="/images/pages/AboutProject/consultant-logos/studio-feel.svg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
+311
-223
@@ -1,237 +1,325 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { sortCardBy } from "../calc/sortCard";
|
||||
// import { useState } from "react";
|
||||
// import ChevronDownIcon from "../components/icons/ChevronDownIcon";
|
||||
import useFavoritesStore from "../store/useFavoritesStore";
|
||||
import useModal from "../store/useModal";
|
||||
import HeartIcon from "../components/icons/HeartIcon";
|
||||
import UnitModalForSearchPage from "../components/modals/UnitModalForSearchPage";
|
||||
import unitTypes from "../data/unitTypes.json";
|
||||
import HeartFilledIcon from "../components/icons/HeartFilledIcon";
|
||||
import Button from "../components/Button";
|
||||
import Footer from "../components/Footer";
|
||||
import TrashIcon from "../components/icons/TrashIcon";
|
||||
import SortButton from "../components/searchPage/SortButton";
|
||||
import { initialSortList } from "../consts/initialMasterplanFilters";
|
||||
import Switch from "../components/Switch";
|
||||
import { ISwitcher } from "../types/switcher";
|
||||
import FavoritesSlider from "../components/favoritesPage/FavoriteSlider";
|
||||
import FavoriteCardList from "../components/favoritesPage/FavoriteCardList";
|
||||
import useFavorites from "../store/useFavorites";
|
||||
import BookingIcon from "../components/icons/BookingIcon";
|
||||
import IUnit from "../types/IUnit";
|
||||
|
||||
// const favoriteCards: ILayoutCard[] = [
|
||||
// {
|
||||
// id: "1",
|
||||
// roveHome: "Marasi Drive",
|
||||
// apartmentType: "Studio Flex",
|
||||
// wing: "East Wing",
|
||||
// floorStart: 11,
|
||||
// floorEnd: 35,
|
||||
// units: 234,
|
||||
// cost: 10488888,
|
||||
// square: 619,
|
||||
// },
|
||||
// {
|
||||
// id: "2",
|
||||
// roveHome: "Marasi Drive",
|
||||
// apartmentType: "1 Bedroom",
|
||||
// wing: "East Wing",
|
||||
// floorStart: 11,
|
||||
// floorEnd: 35,
|
||||
// units: 234,
|
||||
// cost: 1668888,
|
||||
// square: 619,
|
||||
// },
|
||||
// {
|
||||
// id: "3",
|
||||
// roveHome: "Marasi Drive",
|
||||
// apartmentType: "1 Bedroom",
|
||||
// wing: "East Wing",
|
||||
// floorStart: 11,
|
||||
// floorEnd: 35,
|
||||
// units: 234,
|
||||
// cost: 1668888,
|
||||
// square: 609,
|
||||
// },
|
||||
// {
|
||||
// id: "4",
|
||||
// roveHome: "Marasi Drive",
|
||||
// apartmentType: "1 Bedroom",
|
||||
// wing: "East Wing",
|
||||
// floorStart: 11,
|
||||
// floorEnd: 35,
|
||||
// units: 234,
|
||||
// cost: 1138888,
|
||||
// square: 609,
|
||||
// },
|
||||
// {
|
||||
// id: "5",
|
||||
// roveHome: "Marasi Drive",
|
||||
// apartmentType: "Studio Flex",
|
||||
// wing: "East Wing",
|
||||
// floorStart: 11,
|
||||
// floorEnd: 35,
|
||||
// units: 234,
|
||||
// cost: 10488888,
|
||||
// square: 609,
|
||||
// },
|
||||
// {
|
||||
// id: "6",
|
||||
// roveHome: "Marasi Drive",
|
||||
// apartmentType: "1 Bedroom",
|
||||
// wing: "East Wing",
|
||||
// floorStart: 11,
|
||||
// floorEnd: 35,
|
||||
// units: 234,
|
||||
// cost: 1668888,
|
||||
// square: 609,
|
||||
// },
|
||||
// {
|
||||
// id: "7",
|
||||
// roveHome: "Marasi Drive",
|
||||
// apartmentType: "1 Bedroom",
|
||||
// wing: "East Wing",
|
||||
// floorStart: 11,
|
||||
// floorEnd: 35,
|
||||
// units: 234,
|
||||
// cost: 1668888,
|
||||
// square: 609,
|
||||
// },
|
||||
// {
|
||||
// id: "8",
|
||||
// roveHome: "Marasi Drive",
|
||||
// apartmentType: "1 Bedroom",
|
||||
// wing: "East Wing",
|
||||
// floorStart: 11,
|
||||
// floorEnd: 35,
|
||||
// units: 234,
|
||||
// cost: 1138888,
|
||||
// square: 609,
|
||||
// },
|
||||
// {
|
||||
// id: "9",
|
||||
// roveHome: "Marasi Drive",
|
||||
// apartmentType: "Studio Flex",
|
||||
// wing: "East Wing",
|
||||
// floorStart: 11,
|
||||
// floorEnd: 35,
|
||||
// units: 234,
|
||||
// cost: 10488888,
|
||||
// square: 609,
|
||||
// },
|
||||
// {
|
||||
// id: "10",
|
||||
// roveHome: "Marasi Drive",
|
||||
// apartmentType: "1 Bedroom",
|
||||
// wing: "East Wing",
|
||||
// floorStart: 11,
|
||||
// floorEnd: 35,
|
||||
// units: 234,
|
||||
// cost: 1668888,
|
||||
// square: 609,
|
||||
// },
|
||||
// {
|
||||
// id: "11",
|
||||
// roveHome: "Marasi Drive",
|
||||
// apartmentType: "1 Bedroom",
|
||||
// wing: "East Wing",
|
||||
// floorStart: 11,
|
||||
// floorEnd: 35,
|
||||
// units: 234,
|
||||
// cost: 1668888,
|
||||
// square: 609,
|
||||
// },
|
||||
// {
|
||||
// id: "12",
|
||||
// roveHome: "Marasi Drive",
|
||||
// apartmentType: "1 Bedroom",
|
||||
// wing: "East Wing",
|
||||
// floorStart: 11,
|
||||
// floorEnd: 35,
|
||||
// units: 234,
|
||||
// cost: 1138888,
|
||||
// square: 609,
|
||||
// },
|
||||
// ];
|
||||
function FavoritesPage() {
|
||||
const { favoriteUnits, setFavoriteUnits } = useFavoritesStore();
|
||||
// const [isSortPriceAsc, setIsSortPriceAsc] = useState(false);
|
||||
const { setModal } = useModal();
|
||||
|
||||
const initialCollectionCompareSwitcher: ISwitcher = {
|
||||
id: "1",
|
||||
title: "collection/compare",
|
||||
isSwitched: false,
|
||||
};
|
||||
function getTypeByUnitNo(unitNo: string) {
|
||||
const side = unitNo[0] === "E" ? "East" : "West";
|
||||
const floor = Number(unitNo.split("-")[1].slice(0, -2));
|
||||
const number = Number(unitNo.split("-")[1].slice(-2));
|
||||
|
||||
const FavoritesPage = () => {
|
||||
const [sortList, setSortList] = useState(initialSortList);
|
||||
const [switcher, setSwitcher] = useState(initialCollectionCompareSwitcher);
|
||||
const { favorites, setFavorites } = useFavorites();
|
||||
console.log(side, floor, number);
|
||||
|
||||
const handleOnSortClick = (sortId: string) => {
|
||||
const updatedSortList = sortList.map((sort) => {
|
||||
const isSelected = sort.id === sortId;
|
||||
return { ...sort, isSelected: isSelected };
|
||||
});
|
||||
setSortList(updatedSortList);
|
||||
};
|
||||
|
||||
const handleOnSwitchClick = () => {
|
||||
setSwitcher((prev) => {
|
||||
return { ...prev, isSwitched: !prev.isSwitched };
|
||||
});
|
||||
};
|
||||
|
||||
const handleOnDeleteFavoriteClick = () => {
|
||||
localStorage.removeItem("Favorites");
|
||||
setFavorites([]);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const favoriteCards = localStorage.getItem("Favorites");
|
||||
if (favoriteCards) {
|
||||
const convertedCards = JSON.parse(favoriteCards);
|
||||
const sortedCards = sortCardBy(sortList, convertedCards);
|
||||
setFavorites(sortedCards);
|
||||
if (side === "East") {
|
||||
if ([1].includes(number)) {
|
||||
return "2br-type-a";
|
||||
} else if ([2, 4, 5, 11, 12, 13, 14].includes(number)) {
|
||||
return "studio-2";
|
||||
} else if ([3].includes(number)) {
|
||||
return "1br-type-d";
|
||||
} else if ([6, 7, 10, 15, 16].includes(number)) {
|
||||
return "1br-type-c";
|
||||
} else if ([8, 9].includes(number)) {
|
||||
return "1br-type-b";
|
||||
}
|
||||
} else if (side === "West") {
|
||||
if (floor <= 21) {
|
||||
// Floors 5-21
|
||||
if ([1].includes(number)) {
|
||||
return "2br-type-a";
|
||||
} else if ([2, 4, 5].includes(number)) {
|
||||
return "studio-2";
|
||||
} else if ([3, 6].includes(number)) {
|
||||
return "1br-type-d";
|
||||
} else if ([7, 8].includes(number)) {
|
||||
return "1br-type-a";
|
||||
} else if ([9, 10, 11, 12, 13, 14].includes(number)) {
|
||||
return "studio-flex";
|
||||
} else if ([15, 16].includes(number)) {
|
||||
return "1br-type-c";
|
||||
} else if ([17].includes(number)) {
|
||||
return "2br-type-b";
|
||||
}
|
||||
} else {
|
||||
// Floors 24-31
|
||||
if ([1].includes(number)) {
|
||||
return "2br-type-a";
|
||||
} else if ([2, 4, 5, 10, 11].includes(number)) {
|
||||
return "studio-2";
|
||||
} else if ([3, 6, 9, 12].includes(number)) {
|
||||
return "1br-type-d";
|
||||
} else if ([7, 8].includes(number)) {
|
||||
return "1br-type-a";
|
||||
} else if ([13, 14].includes(number)) {
|
||||
return "1br-type-c";
|
||||
} else if ([15].includes(number)) {
|
||||
return "2br-type-b";
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [setFavorites, sortList]);
|
||||
|
||||
// TODO Connect to DB
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function getImageSrc(unitNo: string): string {
|
||||
const side = unitNo[0];
|
||||
const floor = Number(unitNo.split("-")[1].slice(0, -2));
|
||||
const unitNumber = Number(unitNo.split("-")[1].slice(-2));
|
||||
|
||||
if (side === "W") {
|
||||
// Side "W"
|
||||
if (floor < 24) {
|
||||
switch (unitNumber) {
|
||||
case 1:
|
||||
return "/images/layouts/2br_a_left.png";
|
||||
case 2:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 3:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 4:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 5:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 6:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 7:
|
||||
return "/images/layouts/1br_a_left.png";
|
||||
case 8:
|
||||
return "/images/layouts/1br_a_left.png";
|
||||
case 9:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 10:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 11:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 12:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 13:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 14:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 15:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 16:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 17:
|
||||
return "/images/layouts/2br_b_left.png";
|
||||
}
|
||||
} else {
|
||||
switch (unitNumber) {
|
||||
case 1:
|
||||
return "/images/layouts/2br_a_left.png";
|
||||
case 2:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 3:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 4:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 5:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 6:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 7:
|
||||
return "/images/layouts/1br_a_left.png";
|
||||
case 8:
|
||||
return "/images/layouts/1br_a_left.png";
|
||||
case 9:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 10:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 11:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 12:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 13:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 14:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 15:
|
||||
return "/images/layouts/2br_b_left.png";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Side "E"
|
||||
switch (unitNumber) {
|
||||
case 1:
|
||||
return "/images/layouts/2br_a_left.png";
|
||||
case 2:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 3:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 4:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 5:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 6:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 7:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 8:
|
||||
return "/images/layouts/1br_b_left.png";
|
||||
case 9:
|
||||
return "/images/layouts/1br_b_left.png";
|
||||
case 10:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 11:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 12:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 13:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 14:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 15:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 16:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
}
|
||||
}
|
||||
|
||||
console.log(side, floor, unitNumber);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function addOrRemoveFromFavorites(unit: IUnit) {
|
||||
if (!favoriteUnits.some((favoriteUnit) => favoriteUnit.id === unit.id)) {
|
||||
setFavoriteUnits([...favoriteUnits, unit]);
|
||||
} else {
|
||||
setFavoriteUnits(
|
||||
favoriteUnits.filter((favoriteUnit) => favoriteUnit.id !== unit.id)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="overflow-scroll h-screen w-screen pt-14 select-none">
|
||||
<div className="p-6 pb-16">
|
||||
<div className="pb-6">
|
||||
<div className="flex justify-between w-full items-center border-b pb-[11px]">
|
||||
<div className="flex items-center gap-8">
|
||||
<div className="flex gap-4 font-semibold text-subheadline-s leading-7 py-[6px]">
|
||||
<h2 className="text-[#0D1922]">Units</h2>
|
||||
<p className="text-[#73787C]">{favorites.length}</p>
|
||||
</div>
|
||||
<SortButton sortList={sortList} onClick={handleOnSortClick} />
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
buttonType="tertiary"
|
||||
icon={<TrashIcon />}
|
||||
className="text-[#73787C]"
|
||||
text="Remove all"
|
||||
onClick={handleOnDeleteFavoriteClick}
|
||||
/>
|
||||
<div className="flex gap-2 items-center text-s">
|
||||
<p
|
||||
className={`transition-all duration-300 ease-in-out ${
|
||||
!switcher.isSwitched ? "text-[#0D1922]" : "text-[#73787C]"
|
||||
}`}
|
||||
>
|
||||
Collection
|
||||
</p>
|
||||
<Switch switcher={switcher} onClick={handleOnSwitchClick} />
|
||||
<p
|
||||
className={`transition-all duration-300 ease-in-out ${
|
||||
switcher.isSwitched ? "text-[#0D1922]" : "text-[#73787C]"
|
||||
}`}
|
||||
>
|
||||
Compare
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 pt-[58px]">
|
||||
<div className="p-6">
|
||||
<div className="pb-4 border-b border-[#E2E2DC] flex justify-between">
|
||||
<p className="text-2xl font-semibold">
|
||||
<span className="text-[#0D1922]">Favorites</span>{" "}
|
||||
{favoriteUnits.length}
|
||||
</p>
|
||||
{/* <button
|
||||
className="bg-white rounded-lg flex items-center gap-2 justify-center text-[#00BED7] px-4 py-2.5"
|
||||
onClick={() => setIsSortPriceAsc((prev) => !prev)}
|
||||
>
|
||||
<p className="text-sm">Sort by ascending price</p>
|
||||
<ChevronDownIcon
|
||||
className={`w-5 h-5 transition-transform ${
|
||||
isSortPriceAsc ? "" : "rotate-180"
|
||||
}`}
|
||||
/>
|
||||
</button> */}
|
||||
</div>
|
||||
<div className="pt-4 grid grid-cols-4 gap-4">
|
||||
{favoriteUnits.map((unit) => (
|
||||
<div
|
||||
key={unit.id}
|
||||
className="bg-white rounded-2xl p-4 space-y-4 flex flex-col justify-between"
|
||||
>
|
||||
<div className="flex justify-between">
|
||||
<div className="space-y-1">
|
||||
<p className="text-sm text-[#00BED7]">{unit.projectName}</p>
|
||||
<div className="flex items-center gap-2 text-xs font-semibold">
|
||||
<p className="">
|
||||
{unit.unitNo[0] === "E" ? "East" : "West"} Wing
|
||||
</p>
|
||||
<div className="w-1 h-1 bg-[#E2E2DC] rounded-full"></div>
|
||||
<p>{unit.floor}</p>
|
||||
<div className="w-1 h-1 bg-[#E2E2DC] rounded-full"></div>
|
||||
<p>{unit.unitNo}</p>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className="w-10 h-10 flex items-center justify-center border border-[#E2E2DC] rounded-full bg-[#FFFFFF] bg-opacity-80 hover:text-[#0D1922] hover:bg-opacity-100 hover:border-[#00BED7] transition-all"
|
||||
onClick={() => addOrRemoveFromFavorites(unit)}
|
||||
>
|
||||
{favoriteUnits.some(
|
||||
(favoriteUnit) => favoriteUnit.id === unit.id
|
||||
) ? (
|
||||
<HeartFilledIcon className="w-5 h-5" />
|
||||
) : (
|
||||
<HeartIcon className="w-5 h-5" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
className="flex justify-center cursor-pointer"
|
||||
onClick={() =>
|
||||
setModal(
|
||||
<UnitModalForSearchPage
|
||||
unit={unit}
|
||||
type={
|
||||
unitTypes.find(
|
||||
(unitType) =>
|
||||
unitType.type === getTypeByUnitNo(unit.unitNo)
|
||||
)?.type || ""
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
>
|
||||
<img
|
||||
src={getImageSrc(unit.unitNo)}
|
||||
alt=""
|
||||
className="max-h-[240px] pointer-events-none"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="space-y-1 cursor-pointer"
|
||||
onClick={() =>
|
||||
setModal(
|
||||
<UnitModalForSearchPage
|
||||
unit={unit}
|
||||
type={
|
||||
unitTypes.find(
|
||||
(unitType) =>
|
||||
unitType.type === getTypeByUnitNo(unit.unitNo)
|
||||
)?.type || ""
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
>
|
||||
<p className="text-sm">
|
||||
{unit.unitType}, {unit.totalArea} Sqft
|
||||
</p>
|
||||
<p className="text-xl text-[#00BED7] font-semibold">
|
||||
{(unit.unitPrice &&
|
||||
`AED ${unit.unitPrice.toLocaleString()}`) ||
|
||||
"Unavailable"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="">
|
||||
<Button
|
||||
buttonType="cta"
|
||||
icon={<BookingIcon />}
|
||||
text="Send Enquiry"
|
||||
className="justify-center text-sm disabled:hover:bg-[#ECEDEE] w-full"
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{switcher.isSwitched ? <FavoritesSlider /> : <FavoriteCardList />}
|
||||
</div>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export default FavoritesPage;
|
||||
|
||||
@@ -1,325 +0,0 @@
|
||||
// import { useState } from "react";
|
||||
// import ChevronDownIcon from "../components/icons/ChevronDownIcon";
|
||||
import useFavoritesStore from "../store/useFavoritesStore";
|
||||
import useModal from "../store/useModal";
|
||||
import HeartIcon from "../components/icons/HeartIcon";
|
||||
import UnitModalForSearchPage from "../components/modals/UnitModalForSearchPage";
|
||||
import unitTypes from "../data/unitTypes.json";
|
||||
import HeartFilledIcon from "../components/icons/HeartFilledIcon";
|
||||
import Button from "../components/Button";
|
||||
import BookingIcon from "../components/icons/BookingIcon";
|
||||
import IUnit from "../types/IUnit";
|
||||
|
||||
function FavoritesPage2() {
|
||||
const { favoriteUnits, setFavoriteUnits } = useFavoritesStore();
|
||||
// const [isSortPriceAsc, setIsSortPriceAsc] = useState(false);
|
||||
const { setModal } = useModal();
|
||||
|
||||
function getTypeByUnitNo(unitNo: string) {
|
||||
const side = unitNo[0] === "E" ? "East" : "West";
|
||||
const floor = Number(unitNo.split("-")[1].slice(0, -2));
|
||||
const number = Number(unitNo.split("-")[1].slice(-2));
|
||||
|
||||
console.log(side, floor, number);
|
||||
|
||||
if (side === "East") {
|
||||
if ([1].includes(number)) {
|
||||
return "2br-type-a";
|
||||
} else if ([2, 4, 5, 11, 12, 13, 14].includes(number)) {
|
||||
return "studio-2";
|
||||
} else if ([3].includes(number)) {
|
||||
return "1br-type-d";
|
||||
} else if ([6, 7, 10, 15, 16].includes(number)) {
|
||||
return "1br-type-c";
|
||||
} else if ([8, 9].includes(number)) {
|
||||
return "1br-type-b";
|
||||
}
|
||||
} else if (side === "West") {
|
||||
if (floor <= 21) {
|
||||
// Floors 5-21
|
||||
if ([1].includes(number)) {
|
||||
return "2br-type-a";
|
||||
} else if ([2, 4, 5].includes(number)) {
|
||||
return "studio-2";
|
||||
} else if ([3, 6].includes(number)) {
|
||||
return "1br-type-d";
|
||||
} else if ([7, 8].includes(number)) {
|
||||
return "1br-type-a";
|
||||
} else if ([9, 10, 11, 12, 13, 14].includes(number)) {
|
||||
return "studio-flex";
|
||||
} else if ([15, 16].includes(number)) {
|
||||
return "1br-type-c";
|
||||
} else if ([17].includes(number)) {
|
||||
return "2br-type-b";
|
||||
}
|
||||
} else {
|
||||
// Floors 24-31
|
||||
if ([1].includes(number)) {
|
||||
return "2br-type-a";
|
||||
} else if ([2, 4, 5, 10, 11].includes(number)) {
|
||||
return "studio-2";
|
||||
} else if ([3, 6, 9, 12].includes(number)) {
|
||||
return "1br-type-d";
|
||||
} else if ([7, 8].includes(number)) {
|
||||
return "1br-type-a";
|
||||
} else if ([13, 14].includes(number)) {
|
||||
return "1br-type-c";
|
||||
} else if ([15].includes(number)) {
|
||||
return "2br-type-b";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Connect to DB
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function getImageSrc(unitNo: string): string {
|
||||
const side = unitNo[0];
|
||||
const floor = Number(unitNo.split("-")[1].slice(0, -2));
|
||||
const unitNumber = Number(unitNo.split("-")[1].slice(-2));
|
||||
|
||||
if (side === "W") {
|
||||
// Side "W"
|
||||
if (floor < 24) {
|
||||
switch (unitNumber) {
|
||||
case 1:
|
||||
return "/images/layouts/2br_a_left.png";
|
||||
case 2:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 3:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 4:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 5:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 6:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 7:
|
||||
return "/images/layouts/1br_a_left.png";
|
||||
case 8:
|
||||
return "/images/layouts/1br_a_left.png";
|
||||
case 9:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 10:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 11:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 12:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 13:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 14:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 15:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 16:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 17:
|
||||
return "/images/layouts/2br_b_left.png";
|
||||
}
|
||||
} else {
|
||||
switch (unitNumber) {
|
||||
case 1:
|
||||
return "/images/layouts/2br_a_left.png";
|
||||
case 2:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 3:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 4:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 5:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 6:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 7:
|
||||
return "/images/layouts/1br_a_left.png";
|
||||
case 8:
|
||||
return "/images/layouts/1br_a_left.png";
|
||||
case 9:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 10:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 11:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 12:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 13:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 14:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 15:
|
||||
return "/images/layouts/2br_b_left.png";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Side "E"
|
||||
switch (unitNumber) {
|
||||
case 1:
|
||||
return "/images/layouts/2br_a_left.png";
|
||||
case 2:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 3:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 4:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 5:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 6:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 7:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 8:
|
||||
return "/images/layouts/1br_b_left.png";
|
||||
case 9:
|
||||
return "/images/layouts/1br_b_left.png";
|
||||
case 10:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 11:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 12:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 13:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 14:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 15:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 16:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
}
|
||||
}
|
||||
|
||||
console.log(side, floor, unitNumber);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function addOrRemoveFromFavorites(unit: IUnit) {
|
||||
if (!favoriteUnits.some((favoriteUnit) => favoriteUnit.id === unit.id)) {
|
||||
setFavoriteUnits([...favoriteUnits, unit]);
|
||||
} else {
|
||||
setFavoriteUnits(
|
||||
favoriteUnits.filter((favoriteUnit) => favoriteUnit.id !== unit.id)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex-1 pt-[58px]">
|
||||
<div className="p-6">
|
||||
<div className="pb-4 border-b border-[#E2E2DC] flex justify-between">
|
||||
<p className="text-2xl font-semibold">
|
||||
<span className="text-[#0D1922]">Favorites</span>{" "}
|
||||
{favoriteUnits.length}
|
||||
</p>
|
||||
{/* <button
|
||||
className="bg-white rounded-lg flex items-center gap-2 justify-center text-[#00BED7] px-4 py-2.5"
|
||||
onClick={() => setIsSortPriceAsc((prev) => !prev)}
|
||||
>
|
||||
<p className="text-sm">Sort by ascending price</p>
|
||||
<ChevronDownIcon
|
||||
className={`w-5 h-5 transition-transform ${
|
||||
isSortPriceAsc ? "" : "rotate-180"
|
||||
}`}
|
||||
/>
|
||||
</button> */}
|
||||
</div>
|
||||
<div className="pt-4 grid grid-cols-4 gap-4">
|
||||
{favoriteUnits.map((unit) => (
|
||||
<div
|
||||
key={unit.id}
|
||||
className="bg-white rounded-2xl p-4 space-y-4 flex flex-col justify-between"
|
||||
>
|
||||
<div className="flex justify-between">
|
||||
<div className="space-y-1">
|
||||
<p className="text-sm text-[#00BED7]">{unit.projectName}</p>
|
||||
<div className="flex items-center gap-2 text-xs font-semibold">
|
||||
<p className="">
|
||||
{unit.unitNo[0] === "E" ? "East" : "West"} Wing
|
||||
</p>
|
||||
<div className="w-1 h-1 bg-[#E2E2DC] rounded-full"></div>
|
||||
<p>{unit.floor}</p>
|
||||
<div className="w-1 h-1 bg-[#E2E2DC] rounded-full"></div>
|
||||
<p>{unit.unitNo}</p>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className="w-10 h-10 flex items-center justify-center border border-[#E2E2DC] rounded-full bg-[#FFFFFF] bg-opacity-80 hover:text-[#0D1922] hover:bg-opacity-100 hover:border-[#00BED7] transition-all"
|
||||
onClick={() => addOrRemoveFromFavorites(unit)}
|
||||
>
|
||||
{favoriteUnits.some(
|
||||
(favoriteUnit) => favoriteUnit.id === unit.id
|
||||
) ? (
|
||||
<HeartFilledIcon className="w-5 h-5" />
|
||||
) : (
|
||||
<HeartIcon className="w-5 h-5" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
className="flex justify-center cursor-pointer"
|
||||
onClick={() =>
|
||||
setModal(
|
||||
<UnitModalForSearchPage
|
||||
unit={unit}
|
||||
type={
|
||||
unitTypes.find(
|
||||
(unitType) =>
|
||||
unitType.type === getTypeByUnitNo(unit.unitNo)
|
||||
)?.type || ""
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
>
|
||||
<img
|
||||
src={getImageSrc(unit.unitNo)}
|
||||
alt=""
|
||||
className="max-h-[240px] pointer-events-none"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="space-y-1 cursor-pointer"
|
||||
onClick={() =>
|
||||
setModal(
|
||||
<UnitModalForSearchPage
|
||||
unit={unit}
|
||||
type={
|
||||
unitTypes.find(
|
||||
(unitType) =>
|
||||
unitType.type === getTypeByUnitNo(unit.unitNo)
|
||||
)?.type || ""
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
>
|
||||
<p className="text-sm">
|
||||
{unit.unitType}, {unit.totalArea} Sqft
|
||||
</p>
|
||||
<p className="text-xl text-[#00BED7] font-semibold">
|
||||
{(unit.unitPrice &&
|
||||
`AED ${unit.unitPrice.toLocaleString()}`) ||
|
||||
"Unavailable"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="">
|
||||
<Button
|
||||
buttonType="cta"
|
||||
icon={<BookingIcon />}
|
||||
text="Send Enquiry"
|
||||
className="justify-center text-sm disabled:hover:bg-[#ECEDEE] w-full"
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default FavoritesPage2;
|
||||
+889
-10
@@ -1,17 +1,896 @@
|
||||
import Footer from "../components/Footer";
|
||||
import LayoutOptions from "../components/searchPage/LayoutOptions";
|
||||
import SidebarFilters from "../components/searchPage/SidebarFilters";
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { useEffect, useState } from "react";
|
||||
import RestartIcon from "../components/icons/RestartIcon";
|
||||
import api from "../utils/api";
|
||||
import IUnit from "../types/IUnit";
|
||||
import Checkbox2 from "../components/Checkbox2";
|
||||
import HeartIcon from "../components/icons/HeartIcon";
|
||||
import RangeSlider from "react-range-slider-input";
|
||||
import Input from "../components/Input";
|
||||
import ChevronDownIcon from "../components/icons/ChevronDownIcon";
|
||||
import useModal from "../store/useModal";
|
||||
import unitTypes from "../data/unitTypes.json";
|
||||
import UnitModalForSearchPage from "../components/modals/UnitModalForSearchPage";
|
||||
import useFavoritesStore from "../store/useFavoritesStore";
|
||||
import HeartFilledIcon from "../components/icons/HeartFilledIcon";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
|
||||
function SearchPage() {
|
||||
const [units, setUnits] = useState<IUnit[]>([]);
|
||||
const [filteredUnits, setFilteredUnits] = useState<IUnit[]>([]);
|
||||
const [unitTypeFilters, setUnitTypeFilters] = useState<string[]>([]);
|
||||
const [unitViewFilters, setUnitViewFilters] = useState<string[]>([]);
|
||||
const [minCost, setMinCost] = useState(0);
|
||||
const [maxCost, setMaxCost] = useState(1000000);
|
||||
const [cost, setCost] = useState<number[]>([minCost, maxCost]);
|
||||
const [minTotalArea] = useState<number>(341);
|
||||
const [maxTotalArea] = useState<number>(1058);
|
||||
const [totalArea, setTotalArea] = useState<number[]>([
|
||||
minTotalArea,
|
||||
maxTotalArea,
|
||||
]);
|
||||
const [minFloor] = useState<number>(5);
|
||||
const [maxFloor] = useState<number>(31);
|
||||
const [floor, setFloor] = useState<number[]>([minFloor, maxFloor]);
|
||||
const [isSortPriceAsc, setIsSortPriceAsc] = useState<boolean | undefined>();
|
||||
const { setModal } = useModal();
|
||||
const { favoriteUnits, setFavoriteUnits } = useFavoritesStore();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
|
||||
async function getUnits() {
|
||||
try {
|
||||
const result: IUnit[] = await api.get("units").json();
|
||||
|
||||
setUnits(result);
|
||||
} catch (error) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
function getImageSrc(unitNo: string): string {
|
||||
const side = unitNo[0];
|
||||
const floor = Number(unitNo.split("-")[1].slice(0, -2));
|
||||
const unitNumber = Number(unitNo.split("-")[1].slice(-2));
|
||||
|
||||
if (side === "W") {
|
||||
// Side "W"
|
||||
if (floor < 24) {
|
||||
switch (unitNumber) {
|
||||
case 1:
|
||||
return "/images/layouts/2br_a_left.png";
|
||||
case 2:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 3:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 4:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 5:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 6:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 7:
|
||||
return "/images/layouts/1br_a_left.png";
|
||||
case 8:
|
||||
return "/images/layouts/1br_a_left.png";
|
||||
case 9:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 10:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 11:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 12:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 13:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 14:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 15:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 16:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 17:
|
||||
return "/images/layouts/2br_b_left.png";
|
||||
}
|
||||
} else {
|
||||
switch (unitNumber) {
|
||||
case 1:
|
||||
return "/images/layouts/2br_a_left.png";
|
||||
case 2:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 3:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 4:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 5:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 6:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 7:
|
||||
return "/images/layouts/1br_a_left.png";
|
||||
case 8:
|
||||
return "/images/layouts/1br_a_left.png";
|
||||
case 9:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 10:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 11:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 12:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 13:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 14:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 15:
|
||||
return "/images/layouts/2br_b_left.png";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Side "E"
|
||||
switch (unitNumber) {
|
||||
case 1:
|
||||
return "/images/layouts/2br_a_left.png";
|
||||
case 2:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 3:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 4:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 5:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 6:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 7:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 8:
|
||||
return "/images/layouts/1br_b_left.png";
|
||||
case 9:
|
||||
return "/images/layouts/1br_b_left.png";
|
||||
case 10:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 11:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 12:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 13:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 14:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 15:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 16:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
}
|
||||
}
|
||||
|
||||
console.log(side, floor, unitNumber);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function refreshFilters() {
|
||||
console.log("call func refreshFilters");
|
||||
setUnitTypeFilters([]);
|
||||
setUnitViewFilters([]);
|
||||
setCost([minCost, maxCost]);
|
||||
setTotalArea([minTotalArea, maxTotalArea]);
|
||||
setFloor([minFloor, maxFloor]);
|
||||
}
|
||||
|
||||
function getTypeByUnitNo(unitNo: string) {
|
||||
const side = unitNo[0] === "E" ? "East" : "West";
|
||||
const floor = Number(unitNo.split("-")[1].slice(0, -2));
|
||||
const number = Number(unitNo.split("-")[1].slice(-2));
|
||||
|
||||
console.log(side, floor, number);
|
||||
|
||||
if (side === "East") {
|
||||
if ([1].includes(number)) {
|
||||
return "2br-type-a";
|
||||
} else if ([2, 4, 5, 11, 12, 13, 14].includes(number)) {
|
||||
return "studio-2";
|
||||
} else if ([3].includes(number)) {
|
||||
return "1br-type-d";
|
||||
} else if ([6, 7, 10, 15, 16].includes(number)) {
|
||||
return "1br-type-c";
|
||||
} else if ([8, 9].includes(number)) {
|
||||
return "1br-type-b";
|
||||
}
|
||||
} else if (side === "West") {
|
||||
if (floor <= 21) {
|
||||
// Floors 5-21
|
||||
if ([1].includes(number)) {
|
||||
return "2br-type-a";
|
||||
} else if ([2, 4, 5].includes(number)) {
|
||||
return "studio-2";
|
||||
} else if ([3, 6].includes(number)) {
|
||||
return "1br-type-d";
|
||||
} else if ([7, 8].includes(number)) {
|
||||
return "1br-type-a";
|
||||
} else if ([9, 10, 11, 12, 13, 14].includes(number)) {
|
||||
return "studio-flex";
|
||||
} else if ([15, 16].includes(number)) {
|
||||
return "1br-type-c";
|
||||
} else if ([17].includes(number)) {
|
||||
return "2br-type-b";
|
||||
}
|
||||
} else {
|
||||
// Floors 24-31
|
||||
if ([1].includes(number)) {
|
||||
return "2br-type-a";
|
||||
} else if ([2, 4, 5, 10, 11].includes(number)) {
|
||||
return "studio-2";
|
||||
} else if ([3, 6, 9, 12].includes(number)) {
|
||||
return "1br-type-d";
|
||||
} else if ([7, 8].includes(number)) {
|
||||
return "1br-type-a";
|
||||
} else if ([13, 14].includes(number)) {
|
||||
return "1br-type-c";
|
||||
} else if ([15].includes(number)) {
|
||||
return "2br-type-b";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Connect to DB
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function addOrRemoveFromFavorites(unit: IUnit) {
|
||||
if (!favoriteUnits.some((favoriteUnit) => favoriteUnit.id === unit.id)) {
|
||||
setFavoriteUnits([...favoriteUnits, unit]);
|
||||
} else {
|
||||
setFavoriteUnits(
|
||||
favoriteUnits.filter((favoriteUnit) => favoriteUnit.id !== unit.id)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function handleClickCard(unit: IUnit) {
|
||||
setModal(
|
||||
<UnitModalForSearchPage
|
||||
unit={unit}
|
||||
type={
|
||||
unitTypes.find(
|
||||
(unitType) => unitType.type === getTypeByUnitNo(unit.unitNo)
|
||||
)?.type || ""
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
searchParams.set("unitNo", unit.unitNo);
|
||||
setSearchParams(searchParams);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
let newFilteredUnits = units
|
||||
.filter((unit) =>
|
||||
unitTypeFilters.length ? unitTypeFilters.includes(unit.unitType) : unit
|
||||
)
|
||||
.filter((unit) =>
|
||||
unitViewFilters.length
|
||||
? unitViewFilters.some((unitViewFilter) =>
|
||||
unit.unitView.includes(unitViewFilter)
|
||||
)
|
||||
: unit
|
||||
)
|
||||
.filter(
|
||||
(unit) =>
|
||||
unit.totalArea >= totalArea[0] && unit.totalArea <= totalArea[1]
|
||||
)
|
||||
.filter((unit) => unit.floor >= floor[0] && unit.floor <= floor[1]);
|
||||
|
||||
console.log("isSortPriceAsc", isSortPriceAsc);
|
||||
|
||||
if (isSortPriceAsc !== undefined) {
|
||||
if (isSortPriceAsc) {
|
||||
newFilteredUnits = newFilteredUnits.sort(
|
||||
(a, b) => (b.unitPrice || 0) - (a.unitPrice || 0)
|
||||
);
|
||||
} else {
|
||||
newFilteredUnits = newFilteredUnits.sort(
|
||||
(a, b) => (a.unitPrice || 0) - (b.unitPrice || 0)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
setFilteredUnits(newFilteredUnits);
|
||||
|
||||
setMinCost(
|
||||
Math.min(
|
||||
...newFilteredUnits.map((unit) => unit.unitPrice!).filter(Boolean)
|
||||
)
|
||||
);
|
||||
setMaxCost(
|
||||
Math.max(
|
||||
...newFilteredUnits.map((unit) => unit.unitPrice!).filter(Boolean)
|
||||
)
|
||||
);
|
||||
setCost([
|
||||
Math.min(
|
||||
...newFilteredUnits.map((unit) => unit.unitPrice!).filter(Boolean)
|
||||
),
|
||||
Math.max(
|
||||
...newFilteredUnits.map((unit) => unit.unitPrice!).filter(Boolean)
|
||||
),
|
||||
]);
|
||||
|
||||
// setMinTotalArea(
|
||||
// Math.round(
|
||||
// Math.min(
|
||||
// ...newFilteredUnits.map((unit) => unit.totalArea).filter(Boolean)
|
||||
// )
|
||||
// )
|
||||
// );
|
||||
// setMaxTotalArea(
|
||||
// Math.round(
|
||||
// Math.max(
|
||||
// ...newFilteredUnits.map((unit) => unit.totalArea).filter(Boolean)
|
||||
// )
|
||||
// )
|
||||
// );
|
||||
// setTotalArea([
|
||||
// Math.round(
|
||||
// Math.min(
|
||||
// ...newFilteredUnits.map((unit) => unit.totalArea).filter(Boolean)
|
||||
// )
|
||||
// ),
|
||||
// Math.round(
|
||||
// Math.max(
|
||||
// ...newFilteredUnits.map((unit) => unit.totalArea).filter(Boolean)
|
||||
// )
|
||||
// ),
|
||||
// ]);
|
||||
|
||||
// setMinFloor(
|
||||
// Math.min(...newFilteredUnits.map((unit) => unit.floor).filter(Boolean))
|
||||
// );
|
||||
// setMaxFloor(
|
||||
// Math.max(...newFilteredUnits.map((unit) => unit.floor).filter(Boolean))
|
||||
// );
|
||||
// setFloor([
|
||||
// Math.min(...newFilteredUnits.map((unit) => unit.floor).filter(Boolean)),
|
||||
// Math.max(...newFilteredUnits.map((unit) => unit.floor).filter(Boolean)),
|
||||
// ]);
|
||||
}, [
|
||||
units,
|
||||
unitTypeFilters,
|
||||
unitViewFilters,
|
||||
totalArea,
|
||||
floor,
|
||||
isSortPriceAsc,
|
||||
]);
|
||||
|
||||
// useEffect(() => {
|
||||
// if (!units.length) return;
|
||||
|
||||
// setMinCost(
|
||||
// Math.min(...units.map((unit) => unit.unitPrice!).filter(Boolean))
|
||||
// );
|
||||
// setMaxCost(
|
||||
// Math.max(...units.map((unit) => unit.unitPrice!).filter(Boolean))
|
||||
// );
|
||||
// setCost([
|
||||
// Math.min(...units.map((unit) => unit.unitPrice!).filter(Boolean)),
|
||||
// Math.max(...units.map((unit) => unit.unitPrice!).filter(Boolean)),
|
||||
// ]);
|
||||
// }, [units]);
|
||||
|
||||
useEffect(() => {
|
||||
getUnits();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (searchParams.has("unitNo")) {
|
||||
const unitNo = searchParams.get("unitNo");
|
||||
|
||||
if (!unitNo) return;
|
||||
|
||||
const type = getTypeByUnitNo(unitNo);
|
||||
const unit = units.find((unit) => unit.unitNo === unitNo);
|
||||
|
||||
if (!unit) return;
|
||||
|
||||
setModal(<UnitModalForSearchPage unit={unit} type={type} />);
|
||||
}
|
||||
}, [units]);
|
||||
|
||||
const SearchPage = () => {
|
||||
return (
|
||||
<div className="overflow-scroll h-screen w-screen pt-14 select-none">
|
||||
<div className="flex">
|
||||
<SidebarFilters />
|
||||
<LayoutOptions />
|
||||
<div className="pt-[58px] flex select-none">
|
||||
<div className="p-6 min-w-[360px] w-[360px] space-y-6 border-r border-[#E2E2DC]">
|
||||
<div className="flex justify-between pb-4 border-b border-[#E2E2DC]">
|
||||
<p className="text-2xl text-[#0D1922] font-semibold">Filters</p>
|
||||
<button
|
||||
className="w-10 h-10 bg-white rounded-full flex items-center justify-center bg-opacity-80 hover:bg-opacity-100 hover:text-[#0D1922] transition-all"
|
||||
onClick={refreshFilters}
|
||||
>
|
||||
<RestartIcon className="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<p className="text-[#0D1922]">Apartment type</p>
|
||||
<div className="space-y-2">
|
||||
<div className="p-3 bg-white rounded-lg flex items-center justify-between">
|
||||
<div className="flex gap-3">
|
||||
<Checkbox2
|
||||
filterName="Studio Flex"
|
||||
checked={unitTypeFilters.some(
|
||||
(unitTypeFilter) => unitTypeFilter === "Studio Flex"
|
||||
)}
|
||||
onChange={(isChecked, filterName) => {
|
||||
if (isChecked) {
|
||||
setUnitTypeFilters((prev) => [...prev, filterName]);
|
||||
} else {
|
||||
setUnitTypeFilters(
|
||||
unitTypeFilters.filter(
|
||||
(unitTypeFilter) => unitTypeFilter !== filterName
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<p>Studio Flex</p>
|
||||
</div>
|
||||
<div className="px-2 h-6 bg-[#00BED7] rounded-full flex items-center justify-center">
|
||||
<p className="text-xs text-white font-semibold">
|
||||
{
|
||||
units.filter((unit) => unit.unitType === "Studio Flex")
|
||||
.length
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3 bg-white rounded-lg flex items-center justify-between">
|
||||
<div className="flex gap-3">
|
||||
<Checkbox2
|
||||
filterName="Studio Squared"
|
||||
checked={unitTypeFilters.some(
|
||||
(unitTypeFilter) => unitTypeFilter === "Studio Squared"
|
||||
)}
|
||||
onChange={(isChecked, filterName) => {
|
||||
if (isChecked) {
|
||||
setUnitTypeFilters((prev) => [...prev, filterName]);
|
||||
} else {
|
||||
setUnitTypeFilters(
|
||||
unitTypeFilters.filter(
|
||||
(unitTypeFilter) => unitTypeFilter !== filterName
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<p>Studio²</p>
|
||||
</div>
|
||||
<div className="px-2 h-6 bg-[#00BED7] rounded-full flex items-center justify-center">
|
||||
<p className="text-xs text-white font-semibold">
|
||||
{
|
||||
units.filter((unit) => unit.unitType === "Studio Squared")
|
||||
.length
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3 bg-white rounded-lg flex items-center justify-between">
|
||||
<div className="flex gap-3">
|
||||
<Checkbox2
|
||||
filterName="1 BR Squared"
|
||||
checked={unitTypeFilters.some(
|
||||
(unitTypeFilter) => unitTypeFilter === "1 BR Squared"
|
||||
)}
|
||||
onChange={(isChecked, filterName) => {
|
||||
if (isChecked) {
|
||||
setUnitTypeFilters((prev) => [...prev, filterName]);
|
||||
} else {
|
||||
setUnitTypeFilters(
|
||||
unitTypeFilters.filter(
|
||||
(unitTypeFilter) => unitTypeFilter !== filterName
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<p>1 Bedroom²</p>
|
||||
</div>
|
||||
<div className="px-2 h-6 bg-[#00BED7] rounded-full flex items-center justify-center">
|
||||
<p className="text-xs text-white font-semibold">
|
||||
{
|
||||
units.filter((unit) => unit.unitType === "1 BR Squared")
|
||||
.length
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3 bg-white rounded-lg flex items-center justify-between">
|
||||
<div className="flex gap-3">
|
||||
<Checkbox2
|
||||
filterName="2 BR Squared"
|
||||
checked={unitTypeFilters.some(
|
||||
(unitTypeFilter) => unitTypeFilter === "2 BR Squared"
|
||||
)}
|
||||
onChange={(isChecked, filterName) => {
|
||||
if (isChecked) {
|
||||
setUnitTypeFilters((prev) => [...prev, filterName]);
|
||||
} else {
|
||||
setUnitTypeFilters(
|
||||
unitTypeFilters.filter(
|
||||
(unitTypeFilter) => unitTypeFilter !== filterName
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<p>2 Bedroom²</p>
|
||||
</div>
|
||||
<div className="px-2 h-6 bg-[#00BED7] rounded-full flex items-center justify-center">
|
||||
<p className="text-xs text-white font-semibold">
|
||||
{
|
||||
units.filter((unit) => unit.unitType === "2 BR Squared")
|
||||
.length
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<div className="text-sm flex justify-between">
|
||||
<p className="text-[#0D1922]">Cost</p>
|
||||
<p className="text-[#0D192266]">AED</p>
|
||||
</div>
|
||||
<div className="">
|
||||
<div className="flex">
|
||||
<Input
|
||||
value={new Intl.NumberFormat("ar-AE", {
|
||||
currency: "AED",
|
||||
})
|
||||
.format(cost[0])
|
||||
.replaceAll(",", " ")}
|
||||
min={minCost}
|
||||
max={maxCost}
|
||||
onlyNumbers
|
||||
readOnly
|
||||
className="rounded-r-none"
|
||||
onChange={(value) => setCost([value as number, cost[1]])}
|
||||
/>
|
||||
<Input
|
||||
value={new Intl.NumberFormat("ar-AE", {
|
||||
currency: "AED",
|
||||
})
|
||||
.format(cost[1])
|
||||
.replaceAll(",", " ")}
|
||||
min={minCost}
|
||||
max={maxCost}
|
||||
onlyNumbers
|
||||
readOnly
|
||||
className="rounded-r-none text-right"
|
||||
onChange={(value) => setCost([cost[0], value as number])}
|
||||
/>
|
||||
</div>
|
||||
<div className="px-2 -mt-0.5">
|
||||
<RangeSlider
|
||||
min={minCost}
|
||||
max={maxCost}
|
||||
value={cost}
|
||||
onInput={(value: number[]) => setCost(value)}
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<div className="text-sm flex justify-between">
|
||||
<p className="text-[#0D1922]">Total Area</p>
|
||||
<p className="text-[#0D192266]">Sqft</p>
|
||||
</div>
|
||||
<div className="">
|
||||
<div className="flex">
|
||||
<Input
|
||||
readOnly
|
||||
value={totalArea[0]}
|
||||
min={minTotalArea}
|
||||
max={maxTotalArea}
|
||||
onlyNumbers
|
||||
className="rounded-r-none"
|
||||
onChange={(value) =>
|
||||
setTotalArea([value as number, totalArea[1]])
|
||||
}
|
||||
/>
|
||||
<Input
|
||||
readOnly
|
||||
value={totalArea[1]}
|
||||
min={minTotalArea}
|
||||
max={maxTotalArea}
|
||||
onlyNumbers
|
||||
className="rounded-r-none text-right"
|
||||
onChange={(value) =>
|
||||
setTotalArea([totalArea[0], value as number])
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="px-2 -mt-0.5">
|
||||
<RangeSlider
|
||||
min={minTotalArea}
|
||||
max={maxTotalArea}
|
||||
value={totalArea}
|
||||
onInput={(value: number[]) => setTotalArea(value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<div className="text-sm flex justify-between">
|
||||
<p className="text-[#0D1922]">Floor</p>
|
||||
</div>
|
||||
<div className="">
|
||||
<div className="flex">
|
||||
<Input
|
||||
readOnly
|
||||
value={floor[0]}
|
||||
min={minFloor}
|
||||
max={maxFloor}
|
||||
onlyNumbers
|
||||
className="rounded-r-none"
|
||||
onChange={(value) => setFloor([value as number, floor[1]])}
|
||||
/>
|
||||
<Input
|
||||
readOnly
|
||||
value={floor[1]}
|
||||
min={minFloor}
|
||||
max={maxFloor}
|
||||
onlyNumbers
|
||||
className="rounded-r-none text-right"
|
||||
onChange={(value) => setFloor([floor[0], value as number])}
|
||||
/>
|
||||
</div>
|
||||
<div className="px-2 -mt-0.5">
|
||||
<RangeSlider
|
||||
min={minFloor}
|
||||
max={maxFloor}
|
||||
value={floor}
|
||||
onInput={(value: number[]) => setFloor(value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<p className="text-[#0D1922]">View</p>
|
||||
<div className="space-y-2">
|
||||
<div className="p-3 bg-white rounded-lg flex items-center justify-between">
|
||||
<div className="flex gap-3">
|
||||
<Checkbox2
|
||||
filterName="BK/DT"
|
||||
checked={unitViewFilters.some(
|
||||
(unitViewFilter) => unitViewFilter === "BK/DT"
|
||||
)}
|
||||
onChange={(isChecked, filterName) => {
|
||||
if (isChecked) {
|
||||
setUnitViewFilters((prev) => [...prev, filterName]);
|
||||
} else {
|
||||
setUnitViewFilters(
|
||||
unitViewFilters.filter(
|
||||
(unitViewFilter) => unitViewFilter !== filterName
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<p>Burj Khalifa / Downtown</p>
|
||||
</div>
|
||||
<div className="px-2 h-6 bg-[#00BED7] rounded-full flex items-center justify-center">
|
||||
<p className="text-xs text-white font-semibold">
|
||||
{
|
||||
units.filter((unit) => unit.unitView.includes("BK/DT"))
|
||||
.length
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3 bg-white rounded-lg flex items-center justify-between">
|
||||
<div className="flex gap-3">
|
||||
<Checkbox2
|
||||
filterName="Business Bay"
|
||||
checked={unitViewFilters.some(
|
||||
(unitViewFilter) => unitViewFilter === "Business Bay"
|
||||
)}
|
||||
onChange={(isChecked, filterName) => {
|
||||
if (isChecked) {
|
||||
setUnitViewFilters((prev) => [...prev, filterName]);
|
||||
} else {
|
||||
setUnitViewFilters(
|
||||
unitViewFilters.filter(
|
||||
(unitViewFilter) => unitViewFilter !== filterName
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<p>Business Bay</p>
|
||||
</div>
|
||||
<div className="px-2 h-6 bg-[#00BED7] rounded-full flex items-center justify-center">
|
||||
<p className="text-xs text-white font-semibold">
|
||||
{
|
||||
units.filter((unit) => unit.unitView === "Business Bay")
|
||||
.length
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3 bg-white rounded-lg flex items-center justify-between">
|
||||
<div className="flex gap-3">
|
||||
<Checkbox2
|
||||
filterName="Amenities"
|
||||
checked={unitViewFilters.some(
|
||||
(unitViewFilter) => unitViewFilter === "Amenities"
|
||||
)}
|
||||
onChange={(isChecked, filterName) => {
|
||||
if (isChecked) {
|
||||
setUnitViewFilters((prev) => [...prev, filterName]);
|
||||
} else {
|
||||
setUnitViewFilters(
|
||||
unitViewFilters.filter(
|
||||
(unitViewFilter) => unitViewFilter !== filterName
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<p>Amenities</p>
|
||||
</div>
|
||||
<div className="px-2 h-6 bg-[#00BED7] rounded-full flex items-center justify-center">
|
||||
<p className="text-xs text-white font-semibold">
|
||||
{
|
||||
units.filter((unit) => unit.unitView.includes("Amenities"))
|
||||
.length
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3 bg-white rounded-lg flex items-center justify-between">
|
||||
<div className="flex gap-3">
|
||||
<Checkbox2
|
||||
filterName="Canal"
|
||||
checked={unitViewFilters.some(
|
||||
(unitViewFilter) => unitViewFilter === "Canal"
|
||||
)}
|
||||
onChange={(isChecked, filterName) => {
|
||||
if (isChecked) {
|
||||
setUnitViewFilters((prev) => [...prev, filterName]);
|
||||
} else {
|
||||
setUnitViewFilters(
|
||||
unitViewFilters.filter(
|
||||
(unitViewFilter) => unitViewFilter !== filterName
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<p>Canal</p>
|
||||
</div>
|
||||
<div className="px-2 h-6 bg-[#00BED7] rounded-full flex items-center justify-center">
|
||||
<p className="text-xs text-white font-semibold">
|
||||
{
|
||||
units.filter((unit) => unit.unitView.includes("Canal"))
|
||||
.length
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3 bg-white rounded-lg flex items-center justify-between">
|
||||
<div className="flex gap-3">
|
||||
<Checkbox2
|
||||
filterName="Park"
|
||||
checked={unitViewFilters.some(
|
||||
(unitViewFilter) => unitViewFilter === "Park"
|
||||
)}
|
||||
onChange={(isChecked, filterName) => {
|
||||
if (isChecked) {
|
||||
setUnitViewFilters((prev) => [...prev, filterName]);
|
||||
} else {
|
||||
setUnitViewFilters(
|
||||
unitViewFilters.filter(
|
||||
(unitViewFilter) => unitViewFilter !== filterName
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<p>Park</p>
|
||||
</div>
|
||||
<div className="px-2 h-6 bg-[#00BED7] rounded-full flex items-center justify-center">
|
||||
<p className="text-xs text-white font-semibold">
|
||||
{
|
||||
units.filter((unit) => unit.unitView.includes("Park"))
|
||||
.length
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-6 w-full">
|
||||
<div className="space-y-6">
|
||||
<div className="flex justify-between pb-4 border-b border-[#E2E2DC]">
|
||||
<p className="text-2xl font-semibold">
|
||||
<span className="text-[#0D1922]">Units</span>{" "}
|
||||
{filteredUnits.length}
|
||||
</p>
|
||||
<button
|
||||
className="bg-white rounded-lg flex items-center gap-2 justify-center text-[#00BED7] px-4 py-2.5"
|
||||
onClick={() => setIsSortPriceAsc((prev) => !prev)}
|
||||
>
|
||||
<p className="text-sm">Sort by ascending price</p>
|
||||
{/* descending */}
|
||||
<ChevronDownIcon
|
||||
className={`w-5 h-5 transition-transform ${
|
||||
isSortPriceAsc ? "" : "rotate-180"
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<div className="grid grid-cols-4 gap-4">
|
||||
{filteredUnits.map((unit) => (
|
||||
<div
|
||||
key={unit.id}
|
||||
className="bg-white rounded-2xl p-4 space-y-4 flex flex-col justify-between"
|
||||
>
|
||||
<div className="flex justify-between">
|
||||
<div className="space-y-1">
|
||||
<p className="text-sm text-[#00BED7]">{unit.projectName}</p>
|
||||
<div className="flex items-center gap-2 text-xs font-semibold">
|
||||
<p className="">
|
||||
{unit.unitNo[0] === "E" ? "East" : "West"} Wing
|
||||
</p>
|
||||
<div className="w-1 h-1 bg-[#E2E2DC] rounded-full"></div>
|
||||
<p>{unit.floor}</p>
|
||||
<div className="w-1 h-1 bg-[#E2E2DC] rounded-full"></div>
|
||||
<p>{unit.unitNo}</p>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className="w-10 h-10 flex items-center justify-center border border-[#E2E2DC] rounded-full bg-[#FFFFFF] bg-opacity-80 hover:text-[#0D1922] hover:bg-opacity-100 hover:border-[#00BED7] transition-all"
|
||||
onClick={() => addOrRemoveFromFavorites(unit)}
|
||||
>
|
||||
{favoriteUnits.some(
|
||||
(favoriteUnit) => favoriteUnit.id === unit.id
|
||||
) ? (
|
||||
<HeartFilledIcon className="w-5 h-5" />
|
||||
) : (
|
||||
<HeartIcon className="w-5 h-5" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
className="flex justify-center cursor-pointer"
|
||||
onClick={() => handleClickCard(unit)}
|
||||
>
|
||||
<img
|
||||
src={getImageSrc(unit.unitNo)}
|
||||
alt=""
|
||||
className="max-h-[240px] pointer-events-none"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="space-y-1 cursor-pointer"
|
||||
onClick={() => handleClickCard(unit)}
|
||||
>
|
||||
<p className="text-sm">
|
||||
{unit.unitName}, {unit.totalArea} Sqft
|
||||
</p>
|
||||
<p className="text-xl text-[#00BED7] font-semibold">
|
||||
{(unit.unitPrice &&
|
||||
`AED ${unit.unitPrice.toLocaleString()}`) ||
|
||||
"Unavailable"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export default SearchPage;
|
||||
|
||||
@@ -1,896 +0,0 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { useEffect, useState } from "react";
|
||||
import RestartIcon from "../components/icons/RestartIcon";
|
||||
import api from "../utils/api";
|
||||
import IUnit from "../types/IUnit";
|
||||
import Checkbox2 from "../components/Checkbox2";
|
||||
import HeartIcon from "../components/icons/HeartIcon";
|
||||
import RangeSlider from "react-range-slider-input";
|
||||
import Input from "../components/Input";
|
||||
import ChevronDownIcon from "../components/icons/ChevronDownIcon";
|
||||
import useModal from "../store/useModal";
|
||||
import unitTypes from "../data/unitTypes.json";
|
||||
import UnitModalForSearchPage from "../components/modals/UnitModalForSearchPage";
|
||||
import useFavoritesStore from "../store/useFavoritesStore";
|
||||
import HeartFilledIcon from "../components/icons/HeartFilledIcon";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
|
||||
function SearchPage2() {
|
||||
const [units, setUnits] = useState<IUnit[]>([]);
|
||||
const [filteredUnits, setFilteredUnits] = useState<IUnit[]>([]);
|
||||
const [unitTypeFilters, setUnitTypeFilters] = useState<string[]>([]);
|
||||
const [unitViewFilters, setUnitViewFilters] = useState<string[]>([]);
|
||||
const [minCost, setMinCost] = useState(0);
|
||||
const [maxCost, setMaxCost] = useState(1000000);
|
||||
const [cost, setCost] = useState<number[]>([minCost, maxCost]);
|
||||
const [minTotalArea] = useState<number>(341);
|
||||
const [maxTotalArea] = useState<number>(1058);
|
||||
const [totalArea, setTotalArea] = useState<number[]>([
|
||||
minTotalArea,
|
||||
maxTotalArea,
|
||||
]);
|
||||
const [minFloor] = useState<number>(5);
|
||||
const [maxFloor] = useState<number>(31);
|
||||
const [floor, setFloor] = useState<number[]>([minFloor, maxFloor]);
|
||||
const [isSortPriceAsc, setIsSortPriceAsc] = useState<boolean | undefined>();
|
||||
const { setModal } = useModal();
|
||||
const { favoriteUnits, setFavoriteUnits } = useFavoritesStore();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
|
||||
async function getUnits() {
|
||||
try {
|
||||
const result: IUnit[] = await api.get("units").json();
|
||||
|
||||
setUnits(result);
|
||||
} catch (error) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
function getImageSrc(unitNo: string): string {
|
||||
const side = unitNo[0];
|
||||
const floor = Number(unitNo.split("-")[1].slice(0, -2));
|
||||
const unitNumber = Number(unitNo.split("-")[1].slice(-2));
|
||||
|
||||
if (side === "W") {
|
||||
// Side "W"
|
||||
if (floor < 24) {
|
||||
switch (unitNumber) {
|
||||
case 1:
|
||||
return "/images/layouts/2br_a_left.png";
|
||||
case 2:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 3:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 4:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 5:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 6:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 7:
|
||||
return "/images/layouts/1br_a_left.png";
|
||||
case 8:
|
||||
return "/images/layouts/1br_a_left.png";
|
||||
case 9:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 10:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 11:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 12:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 13:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 14:
|
||||
return "/images/layouts/studio_flex_left.png";
|
||||
case 15:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 16:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 17:
|
||||
return "/images/layouts/2br_b_left.png";
|
||||
}
|
||||
} else {
|
||||
switch (unitNumber) {
|
||||
case 1:
|
||||
return "/images/layouts/2br_a_left.png";
|
||||
case 2:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 3:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 4:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 5:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 6:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 7:
|
||||
return "/images/layouts/1br_a_left.png";
|
||||
case 8:
|
||||
return "/images/layouts/1br_a_left.png";
|
||||
case 9:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 10:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 11:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 12:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 13:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 14:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 15:
|
||||
return "/images/layouts/2br_b_left.png";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Side "E"
|
||||
switch (unitNumber) {
|
||||
case 1:
|
||||
return "/images/layouts/2br_a_left.png";
|
||||
case 2:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 3:
|
||||
return "/images/layouts/1br_d_left.png";
|
||||
case 4:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 5:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 6:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 7:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 8:
|
||||
return "/images/layouts/1br_b_left.png";
|
||||
case 9:
|
||||
return "/images/layouts/1br_b_left.png";
|
||||
case 10:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 11:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 12:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 13:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 14:
|
||||
return "/images/layouts/studio_left.png";
|
||||
case 15:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
case 16:
|
||||
return "/images/layouts/1br_c_left.png";
|
||||
}
|
||||
}
|
||||
|
||||
console.log(side, floor, unitNumber);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function refreshFilters() {
|
||||
console.log("call func refreshFilters");
|
||||
setUnitTypeFilters([]);
|
||||
setUnitViewFilters([]);
|
||||
setCost([minCost, maxCost]);
|
||||
setTotalArea([minTotalArea, maxTotalArea]);
|
||||
setFloor([minFloor, maxFloor]);
|
||||
}
|
||||
|
||||
function getTypeByUnitNo(unitNo: string) {
|
||||
const side = unitNo[0] === "E" ? "East" : "West";
|
||||
const floor = Number(unitNo.split("-")[1].slice(0, -2));
|
||||
const number = Number(unitNo.split("-")[1].slice(-2));
|
||||
|
||||
console.log(side, floor, number);
|
||||
|
||||
if (side === "East") {
|
||||
if ([1].includes(number)) {
|
||||
return "2br-type-a";
|
||||
} else if ([2, 4, 5, 11, 12, 13, 14].includes(number)) {
|
||||
return "studio-2";
|
||||
} else if ([3].includes(number)) {
|
||||
return "1br-type-d";
|
||||
} else if ([6, 7, 10, 15, 16].includes(number)) {
|
||||
return "1br-type-c";
|
||||
} else if ([8, 9].includes(number)) {
|
||||
return "1br-type-b";
|
||||
}
|
||||
} else if (side === "West") {
|
||||
if (floor <= 21) {
|
||||
// Floors 5-21
|
||||
if ([1].includes(number)) {
|
||||
return "2br-type-a";
|
||||
} else if ([2, 4, 5].includes(number)) {
|
||||
return "studio-2";
|
||||
} else if ([3, 6].includes(number)) {
|
||||
return "1br-type-d";
|
||||
} else if ([7, 8].includes(number)) {
|
||||
return "1br-type-a";
|
||||
} else if ([9, 10, 11, 12, 13, 14].includes(number)) {
|
||||
return "studio-flex";
|
||||
} else if ([15, 16].includes(number)) {
|
||||
return "1br-type-c";
|
||||
} else if ([17].includes(number)) {
|
||||
return "2br-type-b";
|
||||
}
|
||||
} else {
|
||||
// Floors 24-31
|
||||
if ([1].includes(number)) {
|
||||
return "2br-type-a";
|
||||
} else if ([2, 4, 5, 10, 11].includes(number)) {
|
||||
return "studio-2";
|
||||
} else if ([3, 6, 9, 12].includes(number)) {
|
||||
return "1br-type-d";
|
||||
} else if ([7, 8].includes(number)) {
|
||||
return "1br-type-a";
|
||||
} else if ([13, 14].includes(number)) {
|
||||
return "1br-type-c";
|
||||
} else if ([15].includes(number)) {
|
||||
return "2br-type-b";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Connect to DB
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function addOrRemoveFromFavorites(unit: IUnit) {
|
||||
if (!favoriteUnits.some((favoriteUnit) => favoriteUnit.id === unit.id)) {
|
||||
setFavoriteUnits([...favoriteUnits, unit]);
|
||||
} else {
|
||||
setFavoriteUnits(
|
||||
favoriteUnits.filter((favoriteUnit) => favoriteUnit.id !== unit.id)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function handleClickCard(unit: IUnit) {
|
||||
setModal(
|
||||
<UnitModalForSearchPage
|
||||
unit={unit}
|
||||
type={
|
||||
unitTypes.find(
|
||||
(unitType) => unitType.type === getTypeByUnitNo(unit.unitNo)
|
||||
)?.type || ""
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
searchParams.set("unitNo", unit.unitNo);
|
||||
setSearchParams(searchParams);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
let newFilteredUnits = units
|
||||
.filter((unit) =>
|
||||
unitTypeFilters.length ? unitTypeFilters.includes(unit.unitType) : unit
|
||||
)
|
||||
.filter((unit) =>
|
||||
unitViewFilters.length
|
||||
? unitViewFilters.some((unitViewFilter) =>
|
||||
unit.unitView.includes(unitViewFilter)
|
||||
)
|
||||
: unit
|
||||
)
|
||||
.filter(
|
||||
(unit) =>
|
||||
unit.totalArea >= totalArea[0] && unit.totalArea <= totalArea[1]
|
||||
)
|
||||
.filter((unit) => unit.floor >= floor[0] && unit.floor <= floor[1]);
|
||||
|
||||
console.log("isSortPriceAsc", isSortPriceAsc);
|
||||
|
||||
if (isSortPriceAsc !== undefined) {
|
||||
if (isSortPriceAsc) {
|
||||
newFilteredUnits = newFilteredUnits.sort(
|
||||
(a, b) => (b.unitPrice || 0) - (a.unitPrice || 0)
|
||||
);
|
||||
} else {
|
||||
newFilteredUnits = newFilteredUnits.sort(
|
||||
(a, b) => (a.unitPrice || 0) - (b.unitPrice || 0)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
setFilteredUnits(newFilteredUnits);
|
||||
|
||||
setMinCost(
|
||||
Math.min(
|
||||
...newFilteredUnits.map((unit) => unit.unitPrice!).filter(Boolean)
|
||||
)
|
||||
);
|
||||
setMaxCost(
|
||||
Math.max(
|
||||
...newFilteredUnits.map((unit) => unit.unitPrice!).filter(Boolean)
|
||||
)
|
||||
);
|
||||
setCost([
|
||||
Math.min(
|
||||
...newFilteredUnits.map((unit) => unit.unitPrice!).filter(Boolean)
|
||||
),
|
||||
Math.max(
|
||||
...newFilteredUnits.map((unit) => unit.unitPrice!).filter(Boolean)
|
||||
),
|
||||
]);
|
||||
|
||||
// setMinTotalArea(
|
||||
// Math.round(
|
||||
// Math.min(
|
||||
// ...newFilteredUnits.map((unit) => unit.totalArea).filter(Boolean)
|
||||
// )
|
||||
// )
|
||||
// );
|
||||
// setMaxTotalArea(
|
||||
// Math.round(
|
||||
// Math.max(
|
||||
// ...newFilteredUnits.map((unit) => unit.totalArea).filter(Boolean)
|
||||
// )
|
||||
// )
|
||||
// );
|
||||
// setTotalArea([
|
||||
// Math.round(
|
||||
// Math.min(
|
||||
// ...newFilteredUnits.map((unit) => unit.totalArea).filter(Boolean)
|
||||
// )
|
||||
// ),
|
||||
// Math.round(
|
||||
// Math.max(
|
||||
// ...newFilteredUnits.map((unit) => unit.totalArea).filter(Boolean)
|
||||
// )
|
||||
// ),
|
||||
// ]);
|
||||
|
||||
// setMinFloor(
|
||||
// Math.min(...newFilteredUnits.map((unit) => unit.floor).filter(Boolean))
|
||||
// );
|
||||
// setMaxFloor(
|
||||
// Math.max(...newFilteredUnits.map((unit) => unit.floor).filter(Boolean))
|
||||
// );
|
||||
// setFloor([
|
||||
// Math.min(...newFilteredUnits.map((unit) => unit.floor).filter(Boolean)),
|
||||
// Math.max(...newFilteredUnits.map((unit) => unit.floor).filter(Boolean)),
|
||||
// ]);
|
||||
}, [
|
||||
units,
|
||||
unitTypeFilters,
|
||||
unitViewFilters,
|
||||
totalArea,
|
||||
floor,
|
||||
isSortPriceAsc,
|
||||
]);
|
||||
|
||||
// useEffect(() => {
|
||||
// if (!units.length) return;
|
||||
|
||||
// setMinCost(
|
||||
// Math.min(...units.map((unit) => unit.unitPrice!).filter(Boolean))
|
||||
// );
|
||||
// setMaxCost(
|
||||
// Math.max(...units.map((unit) => unit.unitPrice!).filter(Boolean))
|
||||
// );
|
||||
// setCost([
|
||||
// Math.min(...units.map((unit) => unit.unitPrice!).filter(Boolean)),
|
||||
// Math.max(...units.map((unit) => unit.unitPrice!).filter(Boolean)),
|
||||
// ]);
|
||||
// }, [units]);
|
||||
|
||||
useEffect(() => {
|
||||
getUnits();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (searchParams.has("unitNo")) {
|
||||
const unitNo = searchParams.get("unitNo");
|
||||
|
||||
if (!unitNo) return;
|
||||
|
||||
const type = getTypeByUnitNo(unitNo);
|
||||
const unit = units.find((unit) => unit.unitNo === unitNo);
|
||||
|
||||
if (!unit) return;
|
||||
|
||||
setModal(<UnitModalForSearchPage unit={unit} type={type} />);
|
||||
}
|
||||
}, [units]);
|
||||
|
||||
return (
|
||||
<div className="pt-[58px] flex select-none">
|
||||
<div className="p-6 min-w-[360px] w-[360px] space-y-6 border-r border-[#E2E2DC]">
|
||||
<div className="flex justify-between pb-4 border-b border-[#E2E2DC]">
|
||||
<p className="text-2xl text-[#0D1922] font-semibold">Filters</p>
|
||||
<button
|
||||
className="w-10 h-10 bg-white rounded-full flex items-center justify-center bg-opacity-80 hover:bg-opacity-100 hover:text-[#0D1922] transition-all"
|
||||
onClick={refreshFilters}
|
||||
>
|
||||
<RestartIcon className="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<p className="text-[#0D1922]">Apartment type</p>
|
||||
<div className="space-y-2">
|
||||
<div className="p-3 bg-white rounded-lg flex items-center justify-between">
|
||||
<div className="flex gap-3">
|
||||
<Checkbox2
|
||||
filterName="Studio Flex"
|
||||
checked={unitTypeFilters.some(
|
||||
(unitTypeFilter) => unitTypeFilter === "Studio Flex"
|
||||
)}
|
||||
onChange={(isChecked, filterName) => {
|
||||
if (isChecked) {
|
||||
setUnitTypeFilters((prev) => [...prev, filterName]);
|
||||
} else {
|
||||
setUnitTypeFilters(
|
||||
unitTypeFilters.filter(
|
||||
(unitTypeFilter) => unitTypeFilter !== filterName
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<p>Studio Flex</p>
|
||||
</div>
|
||||
<div className="px-2 h-6 bg-[#00BED7] rounded-full flex items-center justify-center">
|
||||
<p className="text-xs text-white font-semibold">
|
||||
{
|
||||
units.filter((unit) => unit.unitType === "Studio Flex")
|
||||
.length
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3 bg-white rounded-lg flex items-center justify-between">
|
||||
<div className="flex gap-3">
|
||||
<Checkbox2
|
||||
filterName="Studio Squared"
|
||||
checked={unitTypeFilters.some(
|
||||
(unitTypeFilter) => unitTypeFilter === "Studio Squared"
|
||||
)}
|
||||
onChange={(isChecked, filterName) => {
|
||||
if (isChecked) {
|
||||
setUnitTypeFilters((prev) => [...prev, filterName]);
|
||||
} else {
|
||||
setUnitTypeFilters(
|
||||
unitTypeFilters.filter(
|
||||
(unitTypeFilter) => unitTypeFilter !== filterName
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<p>Studio²</p>
|
||||
</div>
|
||||
<div className="px-2 h-6 bg-[#00BED7] rounded-full flex items-center justify-center">
|
||||
<p className="text-xs text-white font-semibold">
|
||||
{
|
||||
units.filter((unit) => unit.unitType === "Studio Squared")
|
||||
.length
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3 bg-white rounded-lg flex items-center justify-between">
|
||||
<div className="flex gap-3">
|
||||
<Checkbox2
|
||||
filterName="1 BR Squared"
|
||||
checked={unitTypeFilters.some(
|
||||
(unitTypeFilter) => unitTypeFilter === "1 BR Squared"
|
||||
)}
|
||||
onChange={(isChecked, filterName) => {
|
||||
if (isChecked) {
|
||||
setUnitTypeFilters((prev) => [...prev, filterName]);
|
||||
} else {
|
||||
setUnitTypeFilters(
|
||||
unitTypeFilters.filter(
|
||||
(unitTypeFilter) => unitTypeFilter !== filterName
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<p>1 Bedroom²</p>
|
||||
</div>
|
||||
<div className="px-2 h-6 bg-[#00BED7] rounded-full flex items-center justify-center">
|
||||
<p className="text-xs text-white font-semibold">
|
||||
{
|
||||
units.filter((unit) => unit.unitType === "1 BR Squared")
|
||||
.length
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3 bg-white rounded-lg flex items-center justify-between">
|
||||
<div className="flex gap-3">
|
||||
<Checkbox2
|
||||
filterName="2 BR Squared"
|
||||
checked={unitTypeFilters.some(
|
||||
(unitTypeFilter) => unitTypeFilter === "2 BR Squared"
|
||||
)}
|
||||
onChange={(isChecked, filterName) => {
|
||||
if (isChecked) {
|
||||
setUnitTypeFilters((prev) => [...prev, filterName]);
|
||||
} else {
|
||||
setUnitTypeFilters(
|
||||
unitTypeFilters.filter(
|
||||
(unitTypeFilter) => unitTypeFilter !== filterName
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<p>2 Bedroom²</p>
|
||||
</div>
|
||||
<div className="px-2 h-6 bg-[#00BED7] rounded-full flex items-center justify-center">
|
||||
<p className="text-xs text-white font-semibold">
|
||||
{
|
||||
units.filter((unit) => unit.unitType === "2 BR Squared")
|
||||
.length
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<div className="text-sm flex justify-between">
|
||||
<p className="text-[#0D1922]">Cost</p>
|
||||
<p className="text-[#0D192266]">AED</p>
|
||||
</div>
|
||||
<div className="">
|
||||
<div className="flex">
|
||||
<Input
|
||||
value={new Intl.NumberFormat("ar-AE", {
|
||||
currency: "AED",
|
||||
})
|
||||
.format(cost[0])
|
||||
.replaceAll(",", " ")}
|
||||
min={minCost}
|
||||
max={maxCost}
|
||||
onlyNumbers
|
||||
readOnly
|
||||
className="rounded-r-none"
|
||||
onChange={(value) => setCost([value as number, cost[1]])}
|
||||
/>
|
||||
<Input
|
||||
value={new Intl.NumberFormat("ar-AE", {
|
||||
currency: "AED",
|
||||
})
|
||||
.format(cost[1])
|
||||
.replaceAll(",", " ")}
|
||||
min={minCost}
|
||||
max={maxCost}
|
||||
onlyNumbers
|
||||
readOnly
|
||||
className="rounded-r-none text-right"
|
||||
onChange={(value) => setCost([cost[0], value as number])}
|
||||
/>
|
||||
</div>
|
||||
<div className="px-2 -mt-0.5">
|
||||
<RangeSlider
|
||||
min={minCost}
|
||||
max={maxCost}
|
||||
value={cost}
|
||||
onInput={(value: number[]) => setCost(value)}
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<div className="text-sm flex justify-between">
|
||||
<p className="text-[#0D1922]">Total Area</p>
|
||||
<p className="text-[#0D192266]">Sqft</p>
|
||||
</div>
|
||||
<div className="">
|
||||
<div className="flex">
|
||||
<Input
|
||||
readOnly
|
||||
value={totalArea[0]}
|
||||
min={minTotalArea}
|
||||
max={maxTotalArea}
|
||||
onlyNumbers
|
||||
className="rounded-r-none"
|
||||
onChange={(value) =>
|
||||
setTotalArea([value as number, totalArea[1]])
|
||||
}
|
||||
/>
|
||||
<Input
|
||||
readOnly
|
||||
value={totalArea[1]}
|
||||
min={minTotalArea}
|
||||
max={maxTotalArea}
|
||||
onlyNumbers
|
||||
className="rounded-r-none text-right"
|
||||
onChange={(value) =>
|
||||
setTotalArea([totalArea[0], value as number])
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="px-2 -mt-0.5">
|
||||
<RangeSlider
|
||||
min={minTotalArea}
|
||||
max={maxTotalArea}
|
||||
value={totalArea}
|
||||
onInput={(value: number[]) => setTotalArea(value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<div className="text-sm flex justify-between">
|
||||
<p className="text-[#0D1922]">Floor</p>
|
||||
</div>
|
||||
<div className="">
|
||||
<div className="flex">
|
||||
<Input
|
||||
readOnly
|
||||
value={floor[0]}
|
||||
min={minFloor}
|
||||
max={maxFloor}
|
||||
onlyNumbers
|
||||
className="rounded-r-none"
|
||||
onChange={(value) => setFloor([value as number, floor[1]])}
|
||||
/>
|
||||
<Input
|
||||
readOnly
|
||||
value={floor[1]}
|
||||
min={minFloor}
|
||||
max={maxFloor}
|
||||
onlyNumbers
|
||||
className="rounded-r-none text-right"
|
||||
onChange={(value) => setFloor([floor[0], value as number])}
|
||||
/>
|
||||
</div>
|
||||
<div className="px-2 -mt-0.5">
|
||||
<RangeSlider
|
||||
min={minFloor}
|
||||
max={maxFloor}
|
||||
value={floor}
|
||||
onInput={(value: number[]) => setFloor(value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<p className="text-[#0D1922]">View</p>
|
||||
<div className="space-y-2">
|
||||
<div className="p-3 bg-white rounded-lg flex items-center justify-between">
|
||||
<div className="flex gap-3">
|
||||
<Checkbox2
|
||||
filterName="BK/DT"
|
||||
checked={unitViewFilters.some(
|
||||
(unitViewFilter) => unitViewFilter === "BK/DT"
|
||||
)}
|
||||
onChange={(isChecked, filterName) => {
|
||||
if (isChecked) {
|
||||
setUnitViewFilters((prev) => [...prev, filterName]);
|
||||
} else {
|
||||
setUnitViewFilters(
|
||||
unitViewFilters.filter(
|
||||
(unitViewFilter) => unitViewFilter !== filterName
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<p>Burj Khalifa / Downtown</p>
|
||||
</div>
|
||||
<div className="px-2 h-6 bg-[#00BED7] rounded-full flex items-center justify-center">
|
||||
<p className="text-xs text-white font-semibold">
|
||||
{
|
||||
units.filter((unit) => unit.unitView.includes("BK/DT"))
|
||||
.length
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3 bg-white rounded-lg flex items-center justify-between">
|
||||
<div className="flex gap-3">
|
||||
<Checkbox2
|
||||
filterName="Business Bay"
|
||||
checked={unitViewFilters.some(
|
||||
(unitViewFilter) => unitViewFilter === "Business Bay"
|
||||
)}
|
||||
onChange={(isChecked, filterName) => {
|
||||
if (isChecked) {
|
||||
setUnitViewFilters((prev) => [...prev, filterName]);
|
||||
} else {
|
||||
setUnitViewFilters(
|
||||
unitViewFilters.filter(
|
||||
(unitViewFilter) => unitViewFilter !== filterName
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<p>Business Bay</p>
|
||||
</div>
|
||||
<div className="px-2 h-6 bg-[#00BED7] rounded-full flex items-center justify-center">
|
||||
<p className="text-xs text-white font-semibold">
|
||||
{
|
||||
units.filter((unit) => unit.unitView === "Business Bay")
|
||||
.length
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3 bg-white rounded-lg flex items-center justify-between">
|
||||
<div className="flex gap-3">
|
||||
<Checkbox2
|
||||
filterName="Amenities"
|
||||
checked={unitViewFilters.some(
|
||||
(unitViewFilter) => unitViewFilter === "Amenities"
|
||||
)}
|
||||
onChange={(isChecked, filterName) => {
|
||||
if (isChecked) {
|
||||
setUnitViewFilters((prev) => [...prev, filterName]);
|
||||
} else {
|
||||
setUnitViewFilters(
|
||||
unitViewFilters.filter(
|
||||
(unitViewFilter) => unitViewFilter !== filterName
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<p>Amenities</p>
|
||||
</div>
|
||||
<div className="px-2 h-6 bg-[#00BED7] rounded-full flex items-center justify-center">
|
||||
<p className="text-xs text-white font-semibold">
|
||||
{
|
||||
units.filter((unit) => unit.unitView.includes("Amenities"))
|
||||
.length
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3 bg-white rounded-lg flex items-center justify-between">
|
||||
<div className="flex gap-3">
|
||||
<Checkbox2
|
||||
filterName="Canal"
|
||||
checked={unitViewFilters.some(
|
||||
(unitViewFilter) => unitViewFilter === "Canal"
|
||||
)}
|
||||
onChange={(isChecked, filterName) => {
|
||||
if (isChecked) {
|
||||
setUnitViewFilters((prev) => [...prev, filterName]);
|
||||
} else {
|
||||
setUnitViewFilters(
|
||||
unitViewFilters.filter(
|
||||
(unitViewFilter) => unitViewFilter !== filterName
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<p>Canal</p>
|
||||
</div>
|
||||
<div className="px-2 h-6 bg-[#00BED7] rounded-full flex items-center justify-center">
|
||||
<p className="text-xs text-white font-semibold">
|
||||
{
|
||||
units.filter((unit) => unit.unitView.includes("Canal"))
|
||||
.length
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3 bg-white rounded-lg flex items-center justify-between">
|
||||
<div className="flex gap-3">
|
||||
<Checkbox2
|
||||
filterName="Park"
|
||||
checked={unitViewFilters.some(
|
||||
(unitViewFilter) => unitViewFilter === "Park"
|
||||
)}
|
||||
onChange={(isChecked, filterName) => {
|
||||
if (isChecked) {
|
||||
setUnitViewFilters((prev) => [...prev, filterName]);
|
||||
} else {
|
||||
setUnitViewFilters(
|
||||
unitViewFilters.filter(
|
||||
(unitViewFilter) => unitViewFilter !== filterName
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<p>Park</p>
|
||||
</div>
|
||||
<div className="px-2 h-6 bg-[#00BED7] rounded-full flex items-center justify-center">
|
||||
<p className="text-xs text-white font-semibold">
|
||||
{
|
||||
units.filter((unit) => unit.unitView.includes("Park"))
|
||||
.length
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-6 w-full">
|
||||
<div className="space-y-6">
|
||||
<div className="flex justify-between pb-4 border-b border-[#E2E2DC]">
|
||||
<p className="text-2xl font-semibold">
|
||||
<span className="text-[#0D1922]">Units</span>{" "}
|
||||
{filteredUnits.length}
|
||||
</p>
|
||||
<button
|
||||
className="bg-white rounded-lg flex items-center gap-2 justify-center text-[#00BED7] px-4 py-2.5"
|
||||
onClick={() => setIsSortPriceAsc((prev) => !prev)}
|
||||
>
|
||||
<p className="text-sm">Sort by ascending price</p>
|
||||
{/* descending */}
|
||||
<ChevronDownIcon
|
||||
className={`w-5 h-5 transition-transform ${
|
||||
isSortPriceAsc ? "" : "rotate-180"
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<div className="grid grid-cols-4 gap-4">
|
||||
{filteredUnits.map((unit) => (
|
||||
<div
|
||||
key={unit.id}
|
||||
className="bg-white rounded-2xl p-4 space-y-4 flex flex-col justify-between"
|
||||
>
|
||||
<div className="flex justify-between">
|
||||
<div className="space-y-1">
|
||||
<p className="text-sm text-[#00BED7]">{unit.projectName}</p>
|
||||
<div className="flex items-center gap-2 text-xs font-semibold">
|
||||
<p className="">
|
||||
{unit.unitNo[0] === "E" ? "East" : "West"} Wing
|
||||
</p>
|
||||
<div className="w-1 h-1 bg-[#E2E2DC] rounded-full"></div>
|
||||
<p>{unit.floor}</p>
|
||||
<div className="w-1 h-1 bg-[#E2E2DC] rounded-full"></div>
|
||||
<p>{unit.unitNo}</p>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className="w-10 h-10 flex items-center justify-center border border-[#E2E2DC] rounded-full bg-[#FFFFFF] bg-opacity-80 hover:text-[#0D1922] hover:bg-opacity-100 hover:border-[#00BED7] transition-all"
|
||||
onClick={() => addOrRemoveFromFavorites(unit)}
|
||||
>
|
||||
{favoriteUnits.some(
|
||||
(favoriteUnit) => favoriteUnit.id === unit.id
|
||||
) ? (
|
||||
<HeartFilledIcon className="w-5 h-5" />
|
||||
) : (
|
||||
<HeartIcon className="w-5 h-5" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
className="flex justify-center cursor-pointer"
|
||||
onClick={() => handleClickCard(unit)}
|
||||
>
|
||||
<img
|
||||
src={getImageSrc(unit.unitNo)}
|
||||
alt=""
|
||||
className="max-h-[240px] pointer-events-none"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="space-y-1 cursor-pointer"
|
||||
onClick={() => handleClickCard(unit)}
|
||||
>
|
||||
<p className="text-sm">
|
||||
{unit.unitName}, {unit.totalArea} Sqft
|
||||
</p>
|
||||
<p className="text-xl text-[#00BED7] font-semibold">
|
||||
{(unit.unitPrice &&
|
||||
`AED ${unit.unitPrice.toLocaleString()}`) ||
|
||||
"Unavailable"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SearchPage2;
|
||||
@@ -1,5 +0,0 @@
|
||||
function TestPage() {
|
||||
return <div>TestPage</div>;
|
||||
}
|
||||
|
||||
export default TestPage;
|
||||
@@ -13,7 +13,7 @@ function UnitTypesItemPage() {
|
||||
const [selectedUniTypePos, setSelectedUniTypePos] = useState<string>("left");
|
||||
|
||||
return (
|
||||
<div className="pt-[calc(58px+24px)] p-6 flex gap-4 absolute top-0 left-0 w-full min-h-screen select-none">
|
||||
<div className="pt-[calc(58px+24px)] p-6 flex gap-4 select-none">
|
||||
<div className="w-full flex flex-col gap-4">
|
||||
<div className="text-2xl font-semibold flex items-center gap-4">
|
||||
<Button
|
||||
|
||||
Reference in New Issue
Block a user