This commit is contained in:
2025-07-21 16:28:05 +05:00
parent 3a4af48d8f
commit a6286c0652
30 changed files with 292 additions and 217 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="icon" type="image/svg+xml" href="/irth.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>Rove Home</title>
</head>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

After

Width:  |  Height:  |  Size: 836 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 797 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

After

Width:  |  Height:  |  Size: 849 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 820 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 850 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 856 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 896 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 648 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 600 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 504 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 885 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 951 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 828 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 609 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 633 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 460 B

-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

+36 -14
View File
@@ -1,5 +1,7 @@
import { useEffect, useState } from "react";
import { formattedUnitTypes } from "../data/formattedUnitTypes";
import { usePopupStore } from "../stores/usePopupStore";
import getAmentiesCount, { AmentiesCount } from "../utils/getAmentiesCount";
import { FloorsData } from "./FloorSelect";
import ArrowRightIcon from "./icons/ArrowRightIcon";
import HumanIcon from "./icons/HumanIcon";
@@ -14,26 +16,40 @@ interface FloorPopupProps {
function FloorPopup({ title, complexName, data, onSelect }: FloorPopupProps) {
const { setPopup } = usePopupStore();
const [amentiesCount, setAmentiesCount] = useState<AmentiesCount | null>(
null
);
useEffect(() => {
if (Number.isNaN(+title.split(" ").at(-1)!)) {
setAmentiesCount(getAmentiesCount(complexName, title));
} else {
setAmentiesCount(null);
}
return () => setAmentiesCount(null);
}, [complexName, title]);
useEffect(() => {
console.log(amentiesCount);
}, [amentiesCount]);
return (
<div className="flex flex-col 2xl:gap-y-[0.556vw] gap-y-2">
<div className="flex 2xl:gap-[0.556vw] gap-2">
<p className="font-medium text-h5">
{Number.isNaN(+title.split(" ").at(-1)!)
? title
: `${title.split(" ").at(-1)} floor`}
</p>
{complexName === "marasi-drive" &&
!Number.isNaN(+title.split(" ").at(-1)!) && (
<p className="text-[#0D1922]/40 text-s">
{title.split(" ")[0]} Wing
{amentiesCount ? title : `${title.split(" ").at(-1)} floor`}
</p>
{complexName === "marasi-drive" && !amentiesCount && (
<p className="text-[#0D1922]/40 text-s">{title.split(" ")[0]} Wing</p>
)}
</div>
{amentiesCount !== null && (
<>
<div className="flex 2xl:gap-[0.278vw] gap-1">
<p className="2xl:px-[0.556vw] 2xl:py-[0.278vw] px-2 py-0.5 bg-[#F3F3F2] 2xl:rounded-[0.278vw] rounded text-caption-s text-[#0D1922]/70">
{title && Number.isNaN(+title!.split(" ").at(-1)!)
? "16 Amen ties"
{amentiesCount
? `${amentiesCount?.total} Amenties`
: `${
complexName === "marasi-drive"
? data[
@@ -46,7 +62,7 @@ function FloorPopup({ title, complexName, data, onSelect }: FloorPopupProps) {
: data.others.totalUnits
} apartments`}
</p>
{!Number.isNaN(+title.split(" ").at(-1)!) && (
{!amentiesCount && (
<div className="2xl:px-[0.556vw] 2xl:py-[0.278vw] px-2 py-0.5 bg-[#30B216]/8 2xl:rounded-[0.278vw] rounded flex 2xl:gap-[0.278vw] gap-1">
<span className="2xl:size-[0.833vw] size-3 text-[#30B216]">
<HumanIcon />
@@ -57,7 +73,7 @@ function FloorPopup({ title, complexName, data, onSelect }: FloorPopupProps) {
</div>
<hr className="border-[#E2E2DC] 2xl:h-[0.069vw] h-px" />
<div className="2xl:space-y-[0.556vw] space-y-2">
{!Number.isNaN(+title.split(" ").at(-1)!) ? (
{!amentiesCount ? (
Object.entries(
data[
title.split(" ")[0] === "East"
@@ -78,25 +94,31 @@ function FloorPopup({ title, complexName, data, onSelect }: FloorPopupProps) {
))
) : (
<>
{amentiesCount?.indoor && (
<div className="flex 2xl:gap-[0.556vw] gap-2">
<p className="bg-[#00BED7] rounded-full flex justify-center items-center font-mono text-caption-s text-white 2xl:w-[1.111vw] 2xl:h-[1.111vw] w-4 h-4">
8
{amentiesCount.indoor}
</p>
<p className="text-caption-m text-[#0D1922]/70">
Indoor Amenties
</p>
</div>
)}
{amentiesCount?.outdoor && (
<div className="flex 2xl:gap-[0.556vw] gap-2">
<p className="bg-[#00BED7] rounded-full flex justify-center items-center font-mono text-caption-s text-white 2xl:w-[1.111vw] 2xl:h-[1.111vw] w-4 h-4">
8
{amentiesCount.outdoor}
</p>
<p className="text-caption-m text-[#0D1922]/70">
Outdoor Amenties
</p>
</div>
)}
</>
)}
</div>
</>
)}
<Button
variant="cta"
size="small"
+3 -3
View File
@@ -73,7 +73,7 @@ function UnitCard({ unit }: { unit: Unit }) {
</span>
</Button>
</div>
<div className="2xl:rounded-[0.556vw] rounded-xl 2xl:p-[0.556vw] p-2 bg-[#F3F3F2] overflow-hidden mx-auto">
<div className="2xl:rounded-[0.556vw] rounded-xl 2xl:p-[0.556vw] p-2 overflow-hidden mx-auto">
<img
src={`/images/unit-types/${complexSlug}/${getUnitTypeSlug(
complexSlug,
@@ -91,14 +91,14 @@ function UnitCard({ unit }: { unit: Unit }) {
maximumFractionDigits: 2,
})} Sqft`}
</p>
{(
{
<p className="text-[#00BED7] text-h4 font-medium">
{`AED ${Intl.NumberFormat("ar-AE", {
currency: "AED",
minimumFractionDigits: 0,
}).format(unit.salesPrice)}`}
</p>
)}
}
</div>
</Link>
);
+1 -1
View File
@@ -21,7 +21,7 @@ function UnitTypeCard({ project, type }: { project: Project; type: UnitType }) {
<p className="text-caption-m text-[#0D1922]/70">{type.floors}</p>
</div>
</div>
<div className="2xl:p-[1.111vw] 2xl:rounded-[0.556vw] bg-[#F3F3F2]">
<div className="2xl:p-[1.111vw] 2xl:rounded-[0.556vw]">
<img
src={`/images/unit-types/${project.slug}/${type.slug}.jpg`}
alt=""
+26 -3
View File
@@ -13,12 +13,14 @@ function Select({
className = "",
label = "",
defaultOption = "",
maxOptionsCount,
}: {
options: string[];
onSelect: (option: string) => void;
defaultOption: string;
className?: string;
label?: string;
maxOptionsCount?: number;
}) {
const [isShow, setIsShow] = useState(false);
const [selectedOption, setSelectedOption] = useState(defaultOption);
@@ -32,18 +34,39 @@ function Select({
useEffect(() => onSelect(selectedOption), [selectedOption]);
function handleScroll() {
if (dropDownRef.current)
if (!dropDownRef.current) return;
dropDownRef.current.style.maxHeight = `calc(100vh - ${
dropDownRef.current?.getBoundingClientRect().y
}px - 0.278vw)`;
}
function dropdownRefCallback(el: HTMLDivElement) {
if (!el) return;
dropDownRef.current = el;
if (!maxOptionsCount) return;
const optionHeight = el.clientHeight / options.length;
el.style.maxHeight = `${optionHeight * maxOptionsCount}px`;
const scrollOffset =
(options.findIndex((option) => option === selectedOption) -
Math.floor(maxOptionsCount / 2)) *
optionHeight;
el.scrollTo({ top: scrollOffset });
}
useEffect(() => {
if (maxOptionsCount) return;
handleScroll();
document.addEventListener("scroll", handleScroll);
return () => document.removeEventListener("scroll", handleScroll);
}, [isShow]);
}, [isShow, maxOptionsCount]);
return (
<div ref={ref} className={clsx("relative", className)}>
@@ -74,7 +97,7 @@ function Select({
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.15 }}
ref={dropDownRef}
ref={dropdownRefCallback}
className="absolute 2xl:mt-[0.278vw] 2xl:pt-[0.278vw] mt-1 p-1 2xl:space-y-[0.139vw] space-y-0.5 shadow-[0px_2px_8px_rgba(0,0,0,0.15)] overflow-auto rounded-xl bg-white w-full z-1"
>
{options.map((option, index) => (
+4 -5
View File
@@ -45,9 +45,7 @@ function FloorsPage() {
});
const { data: unitsOnFloor } = useQuery({
enabled:
!!selectedFloor &&
!SPECIAL_FLOORS.includes(selectedFloor),
enabled: !!selectedFloor && !SPECIAL_FLOORS.includes(selectedFloor),
queryKey: ["units-on-floor", complexName, selectedFloor],
queryFn: () =>
api
@@ -110,6 +108,7 @@ function FloorsPage() {
defaultOption={selectedFloor?.toString() || ""}
onSelect={setSelectedFloor}
className="2xl:w-[8.333vw] md:max-xl:w-[120px] w-full"
maxOptionsCount={7}
/>
<div className="bg-[#E2E2DC] w-px 2xl:h-[1.667vw] h-1.5"></div>
<div className="flex items-center 2xl:gap-[1.667vw] gap-2 max-md:hidden">
@@ -156,12 +155,11 @@ function FloorsPage() {
</div>
</div>
<div
className="2xl:p-[4.444vw] p-4 bg-[#F3F3F2] 2xl:rounded-[0.833vw] rounded-lg relative 2xl:space-y-[2.222vw] space-y-8"
className="2xl:py-[1.667vw] 2xl:px-[1.111vw] max:2xl:p-4 bg-[#F3F3F2] 2xl:rounded-[0.833vw] rounded-lg relative 2xl:space-y-[2.222vw] space-y-8"
onMouseMove={(e) =>
!isMobile && setPosition({ x: e.clientX, y: e.clientY })
}
>
{selectedFloor && unitsOnFloor && (
<>
{+selectedFloor >= 7 && +selectedFloor < 39 && (
@@ -236,6 +234,7 @@ function FloorsPage() {
defaultOption={selectedFloor?.toString() || ""}
onSelect={setSelectedFloor}
className="2xl:w-[8.333vw] md:max-2xl:w-[120px] w-full"
maxOptionsCount={7}
/>
<div className="bg-[#E2E2DC] w-px 2xl:h-[1.667vw] h-1.5"></div>
<div className="flex items-center 2xl:gap-[1.667vw] gap-2 max-md:hidden">
+11 -1
View File
@@ -14,6 +14,7 @@ import { projects } from "../data/projects";
import { useEffect, useState } from "react";
import UnitTypeImageWithMarkers from "../components/UnitTypeImageWithMarkers";
import { getUnitTypeVariantMarasiDrive } from "../utils/getUnitTypeVariantMarasiDrive";
import { formattedUnitTypes } from "../data/formattedUnitTypes";
// import { useEffect } from "react";
// import PlayIcon from "../components/icons/PlayIcon";
// import { useRef } from "react";
@@ -81,6 +82,11 @@ function UnitPage() {
}
return (
<html>
<head>
<title>{formattedUnitTypes.get(unit.unitType)}</title>
</head>
<body>
<div className="2xl:p-[2.222vw] md:max-2xl:p-6 p-4 max-2xl:pb-0 bg-white flex 2xl:gap-[2.222vw] md:max-2xl:gap-8 gap-6 max-2xl:flex-col">
<div className="relative 2xl:w-full flex flex-col items-center justify-center bg-[#F3F3F2] 2xl:rounded-[1.111vw] rounded-xl 2xl:p-[2.222vw] p-6 2xl:gap-[1.111vw] gap-4">
<UnitTypeImageWithMarkers
@@ -137,7 +143,9 @@ function UnitPage() {
<div className="2xl:space-y-[1.667vw] space-y-6">
<div className="flex justify-between items-start">
<div className="2xl:space-y-[1.111vw] space-y-4">
<h3 className="text-h3 font-medium">{unit.unitType}</h3>
<h3 className="text-h3 font-medium">
{formattedUnitTypes.get(unit.unitType)}
</h3>
<div className="2xl:space-y-[0.556vw] space-y-2">
<p className="text-s text-[#00BED7]">{unit.project}</p>
<div className="flex items-center 2xl:gap-[0.556vw]">
@@ -243,6 +251,8 @@ function UnitPage() {
</div>
</div>
</div>
</body>
</html>
);
}
+22
View File
@@ -0,0 +1,22 @@
export interface AmentiesCount {
total: number;
indoor?: number;
outdoor?: number;
}
export default function getAmentiesCount(
complexName: string,
floorTitle: string
):AmentiesCount | null {
const dict = new Map<string, AmentiesCount>([
["marasi-drive Rooftop", { total: 10 }],
["marasi-drive Sky Garden", { total: 15, indoor: 3, outdoor: 12 }],
["marasi-drive Podium Level", { total: 27, indoor: 13, outdoor: 14 }],
["marasi-drive Ground Level", { total: 7 }],
["dubai-marina Rooftop", { total: 14 }],
["dubai-marina Podium Level", { total: 21, indoor: 8, outdoor: 13 }],
["dubai-marina Ground Level", { total: 14 }],
]);
return dict.get(`${complexName} ${floorTitle}`) || null;
}