This commit is contained in:
2024-08-12 18:56:16 +05:00
parent b501321a3f
commit f05047910b
11 changed files with 1489 additions and 2248 deletions
@@ -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
View File
@@ -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: [
+6 -2
View File
@@ -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>
-312
View File
@@ -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
youll ever need. This isnt just where youll live.
<br />
Its where youll 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 Roves 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 Roves 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>
IRTHs 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;
+274 -454
View File
@@ -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
youll ever need. This isnt just where youll live. Its where youll
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
youll ever need. This isnt just where youll live.
<br />
Its where youll 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 Roves 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 Roves 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 Roves 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 Roves 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">
IRTHs 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>
IRTHs 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
View File
@@ -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;
-325
View File
@@ -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
View File
@@ -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;
-896
View File
@@ -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;
-5
View File
@@ -1,5 +0,0 @@
function TestPage() {
return <div>TestPage</div>;
}
export default TestPage;
+1 -1
View File
@@ -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