Update .env file for local development and remove unused FloorPlan components to streamline the project structure; update high-quality images for desktop.
This commit is contained in:
@@ -1,171 +0,0 @@
|
||||
import { Fragment } from "react/jsx-runtime";
|
||||
import { dubaiMarinaMasks } from "../data/floor-plan-masks/dubai-marina_39-40";
|
||||
import { Unit } from "../types/IUnit";
|
||||
import { usePopupStore } from "../stores/usePopupStore";
|
||||
import UnitPopup from "./UnitPopup";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import { useEffect, useState } from "react";
|
||||
import clsx from "clsx";
|
||||
// import { useClickAway } from "@uidotdev/usehooks";
|
||||
|
||||
interface FloorPlanDubaiMarinaProps {
|
||||
selectedFloor: string | null;
|
||||
unitsOnFloor: Unit[];
|
||||
chosenUnit: Unit | null;
|
||||
}
|
||||
|
||||
function FloorPlanDubaiMarina39_40Unit({
|
||||
unit,
|
||||
floor,
|
||||
d,
|
||||
textTransform,
|
||||
formattedUnitType,
|
||||
onSelect,
|
||||
selectedUnit,
|
||||
}: {
|
||||
unit: Unit;
|
||||
floor: string | null;
|
||||
d: string;
|
||||
textTransform: string;
|
||||
formattedUnitType: string;
|
||||
selectedUnit: Unit | null;
|
||||
onSelect: (unit: Unit | null) => void;
|
||||
}) {
|
||||
const { setPopup, setSide, setPosition, popup } = usePopupStore();
|
||||
|
||||
function handleClick(unit: Unit) {
|
||||
window.open(`/complex/dubai-marina/${unit.unitNo}`, "_blank");
|
||||
}
|
||||
|
||||
function handleMouseEnter() {
|
||||
if (floor === null) return;
|
||||
// onSelect(unit.unitNo);
|
||||
setSide("top");
|
||||
if (!selectedUnit)
|
||||
setPopup(
|
||||
<UnitPopup
|
||||
complexName="dubai-marina"
|
||||
unitType={unit.unitType}
|
||||
floor={unit.floor}
|
||||
unitNumber={unit.unitNo}
|
||||
squareFt={unit.squareFt}
|
||||
suitesArea={unit.suitsArea}
|
||||
balconyArea={unit.balconyArea}
|
||||
price={unit.salesPrice}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// useEffect(() => {
|
||||
// if (!selectedUnit) setPopup(null);
|
||||
// setSide("top");
|
||||
// setPopup(
|
||||
// <UnitPopup
|
||||
// complexName="dubai-marina"
|
||||
// unitType={unit.unitType}
|
||||
// floor={unit.floor}
|
||||
// unitNumber={unit.unitNo}
|
||||
// squareFt={unit.squareFt}
|
||||
// suitesArea={unit.suitsArea}
|
||||
// balconyArea={unit.balconyArea}
|
||||
// price={unit.salesPrice}
|
||||
// />
|
||||
// );
|
||||
// }, [selectedUnit, setPopup, setSide, unit]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!popup) onSelect(null);
|
||||
}, [onSelect, popup]);
|
||||
|
||||
// const ref = useClickAway<SVGPathElement>(
|
||||
// () => !!selectedUnit && setPopup(null)
|
||||
// );
|
||||
|
||||
return (
|
||||
<g
|
||||
// ref={ref}
|
||||
>
|
||||
<text
|
||||
transform={textTransform}
|
||||
className="fill-white text-[8px] select-none"
|
||||
textAnchor="middle"
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{unit.unitNo}
|
||||
</tspan>
|
||||
<tspan x={0} y={15}>
|
||||
{formattedUnitType}
|
||||
</tspan>
|
||||
</text>
|
||||
<path
|
||||
onClick={() => !isMobile && !selectedUnit && handleClick(unit)}
|
||||
onMouseEnter={!isMobile ? handleMouseEnter : undefined}
|
||||
onMouseLeave={() => !isMobile && setPopup(null)}
|
||||
onTouchStart={(e) => {
|
||||
onSelect(unit);
|
||||
setPosition({ x: e.touches[0].clientX, y: e.touches[0].clientY });
|
||||
handleMouseEnter();
|
||||
}}
|
||||
className={clsx(
|
||||
"fill-transparent hover:fill-[#00BED7] opacity-40 isolate cursor-pointer transition-colors",
|
||||
selectedUnit?.unitNo === unit.unitNo &&
|
||||
"!fill-[#00BED7] opacity-40 cursor-default"
|
||||
)}
|
||||
d={d}
|
||||
/>
|
||||
</g>
|
||||
);
|
||||
}
|
||||
|
||||
function FloorPlanDubaiMarina39_41({
|
||||
selectedFloor,
|
||||
unitsOnFloor,
|
||||
chosenUnit,
|
||||
...props
|
||||
}: FloorPlanDubaiMarinaProps & React.SVGProps<SVGSVGElement>) {
|
||||
const [selectedUnit, setSelectedUnit] = useState<Unit | null>(
|
||||
chosenUnit || null
|
||||
);
|
||||
|
||||
// const ref = useClickAway<SVGSVGElement>(() => setSelectedUnit(null));
|
||||
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 632 467.5"
|
||||
className="w-full h-full"
|
||||
// ref={ref}
|
||||
{...props}
|
||||
>
|
||||
<image
|
||||
// width={1264}
|
||||
// height={935}
|
||||
transform="scale(.5)"
|
||||
xlinkHref="/images/floor-plans/dubai-marina/floor-plan_39-40.png"
|
||||
/>
|
||||
{unitsOnFloor.map((unit) =>
|
||||
dubaiMarinaMasks.has(unit.unitNo.slice(-2)) ? (
|
||||
<FloorPlanDubaiMarina39_40Unit
|
||||
key={unit.unitNo}
|
||||
selectedUnit={selectedUnit}
|
||||
onSelect={setSelectedUnit}
|
||||
formattedUnitType={
|
||||
dubaiMarinaMasks.get(unit.unitNo.slice(-2))!.formattedUnitType
|
||||
}
|
||||
unit={unit}
|
||||
floor={selectedFloor}
|
||||
d={dubaiMarinaMasks.get(unit.unitNo.slice(-2))!.d}
|
||||
textTransform={`translate(${dubaiMarinaMasks
|
||||
.get(unit.unitNo.slice(-2))!
|
||||
.textTransform.join(" ")})`}
|
||||
/>
|
||||
) : (
|
||||
<Fragment key={unit.unitNo} />
|
||||
)
|
||||
)}
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default FloorPlanDubaiMarina39_41;
|
||||
@@ -1,171 +0,0 @@
|
||||
/* eslint-disable react-refresh/only-export-components */
|
||||
import { Fragment } from "react/jsx-runtime";
|
||||
import { dubaiMarinaMasks } from "../data/floor-plan-masks/dubai-marina_39-40";
|
||||
import { Unit } from "../types/IUnit";
|
||||
import { usePopupStore } from "../stores/usePopupStore";
|
||||
import UnitPopup from "./UnitPopup";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import { useState } from "react";
|
||||
import clsx from "clsx";
|
||||
// import { useClickAway } from "@uidotdev/usehooks";
|
||||
|
||||
interface FloorPlanDubaiMarinaProps {
|
||||
selectedFloor: string | null;
|
||||
unitsOnFloor: Unit[];
|
||||
chosenUnit: Unit | null;
|
||||
}
|
||||
|
||||
function FloorPlanDubaiMarina41_42({
|
||||
selectedFloor,
|
||||
unitsOnFloor,
|
||||
chosenUnit,
|
||||
...props
|
||||
}: FloorPlanDubaiMarinaProps & React.SVGProps<SVGSVGElement>) {
|
||||
const [selectedUnit, setSelectedUnit] = useState<Unit | null>(
|
||||
chosenUnit || null
|
||||
);
|
||||
// const ref = useClickAway<SVGSVGElement>(() => setSelectedUnit(null));
|
||||
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 632 467.5"
|
||||
className="w-full h-full"
|
||||
// ref={ref}
|
||||
{...props}
|
||||
>
|
||||
<image
|
||||
// width={1264}
|
||||
// height={935}
|
||||
transform="scale(.5)"
|
||||
xlinkHref="/images/floor-plans/dubai-marina/floor-plan_39-40.png"
|
||||
/>
|
||||
{unitsOnFloor.map((unit) =>
|
||||
dubaiMarinaMasks.has(unit.unitNo.slice(-2)) ? (
|
||||
<FloorPlanDubaiMarina41_42Unit
|
||||
key={unit.unitNo}
|
||||
selectedUnit={selectedUnit}
|
||||
onSelect={setSelectedUnit}
|
||||
formattedUnitType={
|
||||
dubaiMarinaMasks.get(unit.unitNo.slice(-2))!.formattedUnitType
|
||||
}
|
||||
unit={unit}
|
||||
floor={selectedFloor}
|
||||
d={dubaiMarinaMasks.get(unit.unitNo.slice(-2))!.d}
|
||||
textTransform={`translate(${dubaiMarinaMasks
|
||||
.get(unit.unitNo.slice(-2))!
|
||||
.textTransform.join(" ")})`}
|
||||
/>
|
||||
) : (
|
||||
<Fragment key={unit.unitNo} />
|
||||
)
|
||||
)}
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default FloorPlanDubaiMarina41_42;
|
||||
|
||||
function FloorPlanDubaiMarina41_42Unit({
|
||||
unit,
|
||||
floor,
|
||||
d,
|
||||
textTransform,
|
||||
formattedUnitType,
|
||||
onSelect,
|
||||
selectedUnit,
|
||||
}: {
|
||||
unit: Unit;
|
||||
floor: string | null;
|
||||
d: string;
|
||||
textTransform: string;
|
||||
formattedUnitType: string;
|
||||
selectedUnit: Unit | null;
|
||||
onSelect: (unit: Unit | null) => void;
|
||||
}) {
|
||||
const { setPopup, setSide, setPosition } = usePopupStore();
|
||||
|
||||
function handleClick(unit: Unit) {
|
||||
window.open(`/complex/dubai-marina/${unit.unitNo}`, "_blank");
|
||||
}
|
||||
|
||||
function handleMouseEnter() {
|
||||
if (floor === null) return;
|
||||
// onSelect(unit.unitNo);
|
||||
setSide("top");
|
||||
if (!selectedUnit)
|
||||
setPopup(
|
||||
<UnitPopup
|
||||
complexName="dubai-marina"
|
||||
unitType={unit.unitType}
|
||||
floor={unit.floor}
|
||||
unitNumber={unit.unitNo}
|
||||
squareFt={unit.squareFt}
|
||||
suitesArea={unit.suitsArea}
|
||||
balconyArea={unit.balconyArea}
|
||||
price={unit.salesPrice}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// useEffect(() => {
|
||||
// if (!selectedUnit) setPopup(null);
|
||||
// setSide("top");
|
||||
// setPopup(
|
||||
// <UnitPopup
|
||||
// complexName="dubai-marina"
|
||||
// unitType={unit.unitType}
|
||||
// floor={unit.floor}
|
||||
// unitNumber={unit.unitNo}
|
||||
// squareFt={unit.squareFt}
|
||||
// suitesArea={unit.suitsArea}
|
||||
// balconyArea={unit.balconyArea}
|
||||
// price={unit.salesPrice}
|
||||
// />
|
||||
// );
|
||||
// }, [selectedUnit, setPopup, setSide, unit]);
|
||||
|
||||
// useEffect(() => {
|
||||
// if (!popup) onSelect(null);
|
||||
// }, [onSelect, popup]);
|
||||
|
||||
// const ref = useClickAway<SVGPathElement>(
|
||||
// () => !!selectedUnit && setPopup(null)
|
||||
// );
|
||||
|
||||
return (
|
||||
<g
|
||||
// ref={ref}
|
||||
>
|
||||
<text
|
||||
transform={textTransform}
|
||||
className="fill-white text-[8px] select-none"
|
||||
textAnchor="middle"
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{unit.unitNo}
|
||||
</tspan>
|
||||
<tspan x={0} y={15}>
|
||||
{formattedUnitType}
|
||||
</tspan>
|
||||
</text>
|
||||
<path
|
||||
onClick={() => !isMobile && !selectedUnit && handleClick(unit)}
|
||||
onMouseEnter={!isMobile ? handleMouseEnter : undefined}
|
||||
onMouseLeave={() => !isMobile && setPopup(null)}
|
||||
onTouchStart={(e) => {
|
||||
onSelect(unit);
|
||||
setPosition({ x: e.touches[0].clientX, y: e.touches[0].clientY });
|
||||
handleMouseEnter();
|
||||
}}
|
||||
className={clsx(
|
||||
"fill-transparent hover:fill-[#00BED7] opacity-40 isolate cursor-pointer transition-colors",
|
||||
selectedUnit?.unitNo === unit.unitNo &&
|
||||
"!fill-[#00BED7] opacity-40 cursor-default"
|
||||
)}
|
||||
d={d}
|
||||
/>
|
||||
</g>
|
||||
);
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
import { Fragment } from "react/jsx-runtime";
|
||||
import { dubaiMarinaMasks } from "../data/floor-plan-masks/dubai-marina_7-38";
|
||||
import { Unit } from "../types/IUnit";
|
||||
import { usePopupStore } from "../stores/usePopupStore";
|
||||
import UnitPopup from "./UnitPopup";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import { useState } from "react";
|
||||
import clsx from "clsx";
|
||||
// import { useClickAway } from "@uidotdev/usehooks";
|
||||
|
||||
interface FloorPlanDubaiMarinaProps {
|
||||
selectedFloor: string | null;
|
||||
unitsOnFloor: Unit[];
|
||||
chosenUnit?: Unit;
|
||||
}
|
||||
|
||||
function FloorPlanDubaiMarina7_38({
|
||||
selectedFloor,
|
||||
unitsOnFloor,
|
||||
chosenUnit,
|
||||
...props
|
||||
}: FloorPlanDubaiMarinaProps & React.SVGProps<SVGSVGElement>) {
|
||||
const [selectedUnit, setSelectedUnit] = useState<Unit | null>(
|
||||
chosenUnit || null
|
||||
);
|
||||
|
||||
// const ref = useClickAway<SVGSVGElement>(() => setSelectedUnit(null));
|
||||
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 632 467.5"
|
||||
className="w-full h-full"
|
||||
// ref={ref}
|
||||
{...props}
|
||||
>
|
||||
<image
|
||||
// width={1264}
|
||||
// height={935}
|
||||
transform="scale(.5)"
|
||||
xlinkHref="/images/floor-plans/dubai-marina/floor-plan_7-38.png"
|
||||
/>
|
||||
{unitsOnFloor.map((unit) =>
|
||||
dubaiMarinaMasks.has(unit.unitNo.slice(-2)) ? (
|
||||
<FloorPlanDubaiMarina7_38Unit
|
||||
key={unit.unitNo}
|
||||
selectedUnit={selectedUnit}
|
||||
onSelect={setSelectedUnit}
|
||||
formattedUnitType={
|
||||
dubaiMarinaMasks.get(unit.unitNo.slice(-2))!.formattedUnitType
|
||||
}
|
||||
unit={unit}
|
||||
floor={selectedFloor}
|
||||
d={dubaiMarinaMasks.get(unit.unitNo.slice(-2))!.d}
|
||||
textTransform={`translate(${dubaiMarinaMasks
|
||||
.get(unit.unitNo.slice(-2))!
|
||||
.textTransform.join(" ")})`}
|
||||
/>
|
||||
) : (
|
||||
<Fragment key={unit.unitNo} />
|
||||
)
|
||||
)}
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default FloorPlanDubaiMarina7_38;
|
||||
|
||||
export function FloorPlanDubaiMarina7_38Unit({
|
||||
unit,
|
||||
floor,
|
||||
d,
|
||||
textTransform,
|
||||
formattedUnitType,
|
||||
onSelect,
|
||||
selectedUnit,
|
||||
}: {
|
||||
unit: Unit;
|
||||
floor: string | null;
|
||||
d: string;
|
||||
textTransform: string;
|
||||
formattedUnitType: string;
|
||||
selectedUnit: Unit | null;
|
||||
onSelect: (unit: Unit | null) => void;
|
||||
}) {
|
||||
const { setPopup, setSide, setPosition } = usePopupStore();
|
||||
|
||||
function handleClick(unit: Unit) {
|
||||
window.open(`/complex/dubai-marina/${unit.unitNo}`, "_blank");
|
||||
}
|
||||
|
||||
function handleMouseEnter() {
|
||||
if (floor === null) return;
|
||||
// onSelect(unit.unitNo);
|
||||
setSide("top");
|
||||
if (!selectedUnit)
|
||||
setPopup(
|
||||
<UnitPopup
|
||||
complexName="dubai-marina"
|
||||
unitType={unit.unitType}
|
||||
floor={unit.floor}
|
||||
unitNumber={unit.unitNo}
|
||||
squareFt={unit.squareFt}
|
||||
suitesArea={unit.suitsArea}
|
||||
balconyArea={unit.balconyArea}
|
||||
price={unit.salesPrice}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// useEffect(() => {
|
||||
// if (!selectedUnit) setPopup(null);
|
||||
// setSide("top");
|
||||
// setPopup(
|
||||
// <UnitPopup
|
||||
// complexName="dubai-marina"
|
||||
// unitType={unit.unitType}
|
||||
// floor={unit.floor}
|
||||
// unitNumber={unit.unitNo}
|
||||
// squareFt={unit.squareFt}
|
||||
// suitesArea={unit.suitsArea}
|
||||
// balconyArea={unit.balconyArea}
|
||||
// price={unit.salesPrice}
|
||||
// />
|
||||
// );
|
||||
// }, [selectedUnit, setPopup, setSide, unit]);
|
||||
|
||||
// useEffect(() => {
|
||||
// if (!popup) onSelect(null);
|
||||
// }, [onSelect, popup]);
|
||||
|
||||
// const ref = useClickAway<SVGPathElement>(
|
||||
// () => !!selectedUnit && setPopup(null)
|
||||
// );
|
||||
|
||||
return (
|
||||
<g
|
||||
// ref={ref}
|
||||
>
|
||||
<text
|
||||
transform={textTransform}
|
||||
className="fill-white text-[8px] select-none"
|
||||
textAnchor="middle"
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{unit.unitNo}
|
||||
</tspan>
|
||||
<tspan x={0} y={15}>
|
||||
{formattedUnitType}
|
||||
</tspan>
|
||||
</text>
|
||||
<path
|
||||
onClick={() => !isMobile && !selectedUnit && handleClick(unit)}
|
||||
onMouseEnter={!isMobile ? handleMouseEnter : undefined}
|
||||
onMouseLeave={() => !isMobile && setPopup(null)}
|
||||
onTouchStart={(e) => {
|
||||
onSelect(unit);
|
||||
setPosition({ x: e.touches[0].clientX, y: e.touches[0].clientY });
|
||||
handleMouseEnter();
|
||||
}}
|
||||
className={clsx(
|
||||
"fill-transparent hover:fill-[#00BED7] opacity-40 isolate cursor-pointer transition-colors",
|
||||
selectedUnit?.unitNo === unit.unitNo &&
|
||||
"!fill-[#00BED7] opacity-40 cursor-default"
|
||||
)}
|
||||
d={d}
|
||||
/>
|
||||
</g>
|
||||
);
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
// import { Fragment } from "react/jsx-runtime";
|
||||
import { Unit } from "../types/IUnit";
|
||||
import { usePopupStore } from "../stores/usePopupStore";
|
||||
import UnitPopup from "./UnitPopup";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import { useState } from "react";
|
||||
import clsx from "clsx";
|
||||
import { dubaiMarinaMasks } from "../data/floor-plan-masks/dubai-marina_7-38_comb";
|
||||
import { FloorPlanDubaiMarina7_38Unit } from "./FloorPlanDubaiMarina7_38";
|
||||
import { filterDuplicateUnits } from "../utils/filterDuplicateUnits";
|
||||
// import Button from "./ui/Button";
|
||||
// import { useClickAway } from "@uidotdev/usehooks";
|
||||
|
||||
interface FloorPlanDubaiMarinaCombProps {
|
||||
selectedFloor: string | null;
|
||||
unitsOnFloor: Unit[];
|
||||
chosenUnit?: Unit;
|
||||
}
|
||||
|
||||
function FloorPlanDubaiMarina7_38Comb({
|
||||
selectedFloor,
|
||||
unitsOnFloor,
|
||||
chosenUnit,
|
||||
...props
|
||||
}: FloorPlanDubaiMarinaCombProps & React.SVGProps<SVGSVGElement>) {
|
||||
const [selectedUnit, setSelectedUnit] = useState<Unit | null>(
|
||||
chosenUnit || null
|
||||
);
|
||||
|
||||
// const ref = useClickAway<SVGSVGElement>(() => setSelectedUnit(null));
|
||||
|
||||
console.log(unitsOnFloor);
|
||||
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 626 465"
|
||||
className="w-full h-full"
|
||||
// ref={ref}
|
||||
{...props}
|
||||
>
|
||||
<image
|
||||
// width={1264}
|
||||
// height={935}
|
||||
transform="scale(.5)"
|
||||
xlinkHref="/images/floor-plans/dubai-marina/floor-plan_7-38_comb.png"
|
||||
/>
|
||||
{/* {unitsOnFloor.map((unit) =>
|
||||
dubaiMarinaMasks.has(unit.unitNo.slice(-2)) ? (
|
||||
<FloorPlanDubaiMarina7_38CombUnit
|
||||
key={unit.unitNo}
|
||||
selectedUnit={selectedUnit}
|
||||
onSelect={setSelectedUnit}
|
||||
formattedUnitType={
|
||||
dubaiMarinaMasks.get(unit.unitNo.slice(-2))!.formattedUnitType
|
||||
}
|
||||
unit={unit}
|
||||
floor={Number(selectedFloor!)}
|
||||
d={dubaiMarinaMasks.get(unit.unitNo.slice(-2))!.d}
|
||||
textTransform={`translate(${dubaiMarinaMasks
|
||||
.get(unit.unitNo.slice(-2))!
|
||||
.textTransform.join(" ")})`}
|
||||
/>
|
||||
) : (
|
||||
<Fragment key={unit.unitNo} />
|
||||
)
|
||||
)} */}
|
||||
|
||||
{filterDuplicateUnits(unitsOnFloor).map((unit) => {
|
||||
// Получаем ключ для поиска в масках: для "2901-C" и "2901" это будет "01"
|
||||
const maskKey = unit.unitNo.split("-")[0].slice(-2);
|
||||
const maskData = dubaiMarinaMasks.get(maskKey);
|
||||
|
||||
if (!maskData) {
|
||||
console.warn(
|
||||
`Mask not found for unit ${unit.unitNo}, key: ${maskKey}`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
return !unit.unitNo.endsWith("-C") ? (
|
||||
<FloorPlanDubaiMarina7_38Unit
|
||||
key={unit.unitNo}
|
||||
selectedUnit={selectedUnit}
|
||||
onSelect={setSelectedUnit}
|
||||
formattedUnitType={maskData.formattedUnitType}
|
||||
unit={unit}
|
||||
floor={selectedFloor}
|
||||
d={maskData.d}
|
||||
textTransform={`translate(${maskData.textTransform.join(" ")})`}
|
||||
/>
|
||||
) : (
|
||||
<FloorPlanDubaiMarina7_38CombUnit
|
||||
key={unit.unitNo}
|
||||
selectedUnit={selectedUnit}
|
||||
onSelect={setSelectedUnit}
|
||||
formattedUnitType={maskData.formattedUnitType}
|
||||
unit={unit}
|
||||
floor={selectedFloor}
|
||||
d={maskData.d}
|
||||
textTransform={`translate(${maskData.textTransform.join(" ")})`}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default FloorPlanDubaiMarina7_38Comb;
|
||||
|
||||
function FloorPlanDubaiMarina7_38CombUnit({
|
||||
unit,
|
||||
floor,
|
||||
d,
|
||||
textTransform,
|
||||
formattedUnitType,
|
||||
onSelect,
|
||||
selectedUnit,
|
||||
}: {
|
||||
d: string;
|
||||
textTransform: string;
|
||||
floor: string | null;
|
||||
unit: Unit;
|
||||
formattedUnitType: string;
|
||||
selectedUnit: Unit | null;
|
||||
onSelect: (unit: Unit | null) => void;
|
||||
}) {
|
||||
const { setPopup, setSide, setPosition } = usePopupStore();
|
||||
|
||||
function handleClick(unit: Unit) {
|
||||
window.open(`/complex/dubai-marina/${unit.unitNo}`, "_blank");
|
||||
}
|
||||
|
||||
function handleMouseEnter() {
|
||||
if (floor === null) return;
|
||||
// onSelect(unit.unitNo);
|
||||
setSide("top");
|
||||
if (!selectedUnit)
|
||||
setPopup(
|
||||
<UnitPopup
|
||||
complexName="dubai-marina"
|
||||
unitType={unit.unitType}
|
||||
floor={unit.floor}
|
||||
unitNumber={unit.unitNo}
|
||||
squareFt={unit.squareFt}
|
||||
suitesArea={unit.suitsArea}
|
||||
balconyArea={unit.balconyArea}
|
||||
price={unit.salesPrice}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// useEffect(() => {
|
||||
// if (!selectedUnit) setPopup(null);
|
||||
// setSide("top");
|
||||
// setPopup(
|
||||
// <UnitPopup
|
||||
// complexName="dubai-marina"
|
||||
// unitType={unit.unitType}
|
||||
// floor={unit.floor}
|
||||
// unitNumber={unit.unitNo}
|
||||
// squareFt={unit.squareFt}
|
||||
// suitesArea={unit.suitsArea}
|
||||
// balconyArea={unit.balconyArea}
|
||||
// price={unit.salesPrice}
|
||||
// />
|
||||
// );
|
||||
// }, [selectedUnit, setPopup, setSide, unit]);
|
||||
|
||||
// useEffect(() => {
|
||||
// if (!popup) onSelect(null);
|
||||
// }, [onSelect, popup]);
|
||||
|
||||
// const ref = useClickAway<SVGPathElement>(
|
||||
// () => !!selectedUnit && setPopup(null)
|
||||
// );
|
||||
|
||||
return (
|
||||
<g
|
||||
// ref={ref}
|
||||
>
|
||||
<text
|
||||
transform={textTransform}
|
||||
className="fill-white text-[8px] select-none"
|
||||
textAnchor="middle"
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{unit.unitNo}
|
||||
</tspan>
|
||||
<tspan x={0} y={15}>
|
||||
{formattedUnitType}
|
||||
</tspan>
|
||||
</text>
|
||||
<path
|
||||
onClick={() => !isMobile && !selectedUnit && handleClick(unit)}
|
||||
onMouseEnter={!isMobile ? handleMouseEnter : undefined}
|
||||
onMouseLeave={() => !isMobile && setPopup(null)}
|
||||
onTouchStart={(e) => {
|
||||
onSelect(unit);
|
||||
setPosition({ x: e.touches[0].clientX, y: e.touches[0].clientY });
|
||||
handleMouseEnter();
|
||||
}}
|
||||
className={clsx(
|
||||
"fill-transparent hover:fill-[#00BED7] opacity-40 isolate cursor-pointer transition-colors",
|
||||
selectedUnit?.unitNo === unit.unitNo &&
|
||||
"!fill-[#00BED7] opacity-40 cursor-default"
|
||||
)}
|
||||
d={d}
|
||||
/>
|
||||
</g>
|
||||
);
|
||||
}
|
||||
@@ -1,10 +1,6 @@
|
||||
import { Fragment, useState } from "react";
|
||||
import { floorPlanMarasiDriveEastMasks } from "../data/floor-plan-masks/marasi-drive";
|
||||
import { usePopupStore } from "../stores/usePopupStore";
|
||||
import { Unit } from "../types/IUnit";
|
||||
import UnitPopup from "./UnitPopup";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import clsx from "clsx";
|
||||
import GenericFloorPlan from "./floor-plans/GenericFloorPlan";
|
||||
|
||||
interface FloorPlanMarasiDriveEastProps {
|
||||
selectedFloor: string | null;
|
||||
@@ -16,16 +12,17 @@ function FloorPlanMarasiDriveEast({
|
||||
selectedFloor,
|
||||
unitsOnFloor,
|
||||
chosenUnit,
|
||||
}: FloorPlanMarasiDriveEastProps & React.SVGProps<SVGSVGElement>) {
|
||||
const [selectedUnit, setSelectedUnit] = useState<Unit | null>(
|
||||
chosenUnit || null
|
||||
);
|
||||
|
||||
}: FloorPlanMarasiDriveEastProps) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
<GenericFloorPlan
|
||||
complexName="marasi-drive"
|
||||
viewBox="0 0 633.97 568.52"
|
||||
className="w-full h-full"
|
||||
masks={floorPlanMarasiDriveEastMasks}
|
||||
getMaskKey={(unitNo) => unitNo.slice(-2)}
|
||||
selectedFloor={selectedFloor}
|
||||
unitsOnFloor={unitsOnFloor}
|
||||
chosenUnit={chosenUnit}
|
||||
wing="East"
|
||||
>
|
||||
<g>
|
||||
<g>
|
||||
@@ -1159,113 +1156,8 @@ function FloorPlanMarasiDriveEast({
|
||||
}}
|
||||
/>
|
||||
</g>
|
||||
{unitsOnFloor && unitsOnFloor.length && (
|
||||
<g>
|
||||
{unitsOnFloor.map((unit) =>
|
||||
floorPlanMarasiDriveEastMasks.has(unit.unitNo.slice(-2)) ? (
|
||||
<MarasiDriveEastFloorPlanUnit
|
||||
selectedUnit={selectedUnit}
|
||||
onSelect={setSelectedUnit}
|
||||
key={unit.unitNo}
|
||||
floor={selectedFloor}
|
||||
unit={unit}
|
||||
formattedUnitType={
|
||||
floorPlanMarasiDriveEastMasks.get(unit.unitNo.slice(-2))!
|
||||
.formattedUnitType
|
||||
}
|
||||
textTransform={`translate(${floorPlanMarasiDriveEastMasks
|
||||
.get(unit.unitNo.slice(-2))
|
||||
?.textTransform.join(" ")})`}
|
||||
d={floorPlanMarasiDriveEastMasks.get(unit.unitNo.slice(-2))!.d}
|
||||
/>
|
||||
) : (
|
||||
<Fragment key={unit.unitNo} />
|
||||
)
|
||||
)}
|
||||
</g>
|
||||
)}
|
||||
</svg>
|
||||
</GenericFloorPlan>
|
||||
);
|
||||
}
|
||||
|
||||
export default FloorPlanMarasiDriveEast;
|
||||
|
||||
function MarasiDriveEastFloorPlanUnit({
|
||||
d,
|
||||
textTransform,
|
||||
floor,
|
||||
unit,
|
||||
formattedUnitType,
|
||||
selectedUnit,
|
||||
onSelect,
|
||||
}: {
|
||||
d: string;
|
||||
textTransform: string;
|
||||
floor: string | null;
|
||||
unit: Unit;
|
||||
formattedUnitType: string;
|
||||
selectedUnit: Unit | null;
|
||||
onSelect: (unit: Unit | null) => void;
|
||||
}) {
|
||||
function handleClick(unit: Unit) {
|
||||
window.open(`/complex/marasi-drive/${unit.unitNo}`, "_blank");
|
||||
}
|
||||
|
||||
const { setPopup, setSide, setPosition } = usePopupStore();
|
||||
|
||||
function handleMouseEnter() {
|
||||
if (floor === null) return;
|
||||
setSide("top");
|
||||
if (!selectedUnit)
|
||||
setPopup(
|
||||
<UnitPopup
|
||||
complexName="marasi-drive"
|
||||
wing="East"
|
||||
unitType={unit.unitType}
|
||||
floor={unit.floor}
|
||||
unitNumber={unit.unitNo}
|
||||
squareFt={unit.squareFt}
|
||||
suitesArea={unit.suitsArea}
|
||||
balconyArea={unit.balconyArea}
|
||||
price={unit.salesPrice}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<g>
|
||||
<text
|
||||
transform={textTransform}
|
||||
style={{
|
||||
fill: "#fff",
|
||||
fontFamily: "Usual",
|
||||
fontSize: 8,
|
||||
fontWeight: 500,
|
||||
}}
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{unit.unitNo}
|
||||
</tspan>
|
||||
<tspan x={0} y={10.8}>
|
||||
{formattedUnitType}
|
||||
</tspan>
|
||||
</text>
|
||||
<path
|
||||
onClick={() => !isMobile && !selectedUnit && handleClick(unit)}
|
||||
onMouseEnter={!isMobile ? handleMouseEnter : undefined}
|
||||
onMouseLeave={() => !isMobile && setPopup(null)}
|
||||
onTouchStart={(e) => {
|
||||
onSelect(unit);
|
||||
setPosition({ x: e.touches[0].clientX, y: e.touches[0].clientY });
|
||||
handleMouseEnter();
|
||||
}}
|
||||
d={d}
|
||||
className={clsx(
|
||||
"fill-transparent hover:fill-[#00BED7] opacity-20 transition-all cursor-pointer",
|
||||
selectedUnit?.unitNo === unit.unitNo &&
|
||||
"!fill-[#00BED7] opacity-20 cursor-default"
|
||||
)}
|
||||
/>
|
||||
</g>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
import { Fragment } from "react/jsx-runtime";
|
||||
import { floorPlanMarasiDriveWestLowerMasks } from "../data/floor-plan-masks/marasi-drive";
|
||||
import { usePopupStore } from "../stores/usePopupStore";
|
||||
import { Unit } from "../types/IUnit";
|
||||
import UnitPopup from "./UnitPopup";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import clsx from "clsx";
|
||||
import { useState } from "react";
|
||||
import GenericFloorPlan from "./floor-plans/GenericFloorPlan";
|
||||
|
||||
interface FloorPlanMarasiDriveEastProps {
|
||||
interface FloorPlanMarasiDriveWestLowerProps {
|
||||
selectedFloor: string | null;
|
||||
unitsOnFloor: Unit[];
|
||||
chosenUnit?: Unit;
|
||||
}
|
||||
|
||||
function FloorPlanMarasiDriveEast({
|
||||
function FloorPlanMarasiDriveWestLower({
|
||||
selectedFloor,
|
||||
unitsOnFloor,
|
||||
chosenUnit,
|
||||
}: FloorPlanMarasiDriveEastProps & React.SVGProps<SVGSVGElement>) {
|
||||
const [selectedUnit, setSelectedUnit] = useState<Unit | null>(
|
||||
chosenUnit || null
|
||||
);
|
||||
|
||||
}: FloorPlanMarasiDriveWestLowerProps) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 619.96 585.99">
|
||||
<GenericFloorPlan
|
||||
complexName="marasi-drive"
|
||||
viewBox="0 0 619.96 585.99"
|
||||
masks={floorPlanMarasiDriveWestLowerMasks}
|
||||
getMaskKey={(unitNo) => unitNo.slice(-2)}
|
||||
selectedFloor={selectedFloor}
|
||||
unitsOnFloor={unitsOnFloor}
|
||||
chosenUnit={chosenUnit}
|
||||
wing="West"
|
||||
>
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
@@ -1197,113 +1197,8 @@ function FloorPlanMarasiDriveEast({
|
||||
}}
|
||||
/>
|
||||
</g>
|
||||
<g>
|
||||
{unitsOnFloor.map((unit) =>
|
||||
floorPlanMarasiDriveWestLowerMasks.has(unit.unitNo.slice(-2)) ? (
|
||||
<MarasiDriveWestLowerFloorPlanUnit
|
||||
selectedUnit={selectedUnit}
|
||||
onSelect={setSelectedUnit}
|
||||
formattedUnitType={
|
||||
floorPlanMarasiDriveWestLowerMasks.get(unit.unitNo.slice(-2))!
|
||||
.formattedUnitType
|
||||
}
|
||||
key={unit.unitNo}
|
||||
d={
|
||||
floorPlanMarasiDriveWestLowerMasks.get(unit.unitNo.slice(-2))!.d
|
||||
}
|
||||
textTransform={`translate(${floorPlanMarasiDriveWestLowerMasks
|
||||
.get(unit.unitNo.slice(-2))!
|
||||
.textTransform.join(" ")})`}
|
||||
floor={selectedFloor}
|
||||
unit={unit}
|
||||
/>
|
||||
) : (
|
||||
<Fragment key={unit.unitNo} />
|
||||
)
|
||||
)}
|
||||
</g>
|
||||
</svg>
|
||||
</GenericFloorPlan>
|
||||
);
|
||||
}
|
||||
|
||||
export default FloorPlanMarasiDriveEast;
|
||||
|
||||
function MarasiDriveWestLowerFloorPlanUnit({
|
||||
d,
|
||||
textTransform,
|
||||
floor,
|
||||
unit,
|
||||
formattedUnitType,
|
||||
selectedUnit,
|
||||
onSelect,
|
||||
}: {
|
||||
d: string;
|
||||
textTransform: string;
|
||||
floor: string | null;
|
||||
unit: Unit;
|
||||
formattedUnitType: string;
|
||||
selectedUnit: Unit | null;
|
||||
onSelect: (unit: Unit | null) => void;
|
||||
}) {
|
||||
function handleClick(unitNumber: string) {
|
||||
window.open(`/complex/marasi-drive/${unitNumber}`, "_blank");
|
||||
}
|
||||
|
||||
const { setPopup, setSide, setPosition } = usePopupStore();
|
||||
|
||||
function handleMouseEnter() {
|
||||
if (floor === null) return;
|
||||
setSide("top");
|
||||
if (!selectedUnit)
|
||||
setPopup(
|
||||
<UnitPopup
|
||||
complexName="marasi-drive"
|
||||
wing="West"
|
||||
unitType={unit.unitType}
|
||||
floor={unit.floor}
|
||||
unitNumber={unit.unitNo}
|
||||
squareFt={unit.squareFt}
|
||||
suitesArea={unit.suitsArea}
|
||||
balconyArea={unit.balconyArea}
|
||||
price={unit.salesPrice}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<g>
|
||||
<text
|
||||
transform={textTransform}
|
||||
style={{
|
||||
fill: "#fff",
|
||||
fontFamily: "Usual",
|
||||
fontSize: 8,
|
||||
fontWeight: 500,
|
||||
}}
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{unit.unitNo}
|
||||
</tspan>
|
||||
<tspan x={0} y={10.8}>
|
||||
{formattedUnitType}
|
||||
</tspan>
|
||||
</text>
|
||||
<path
|
||||
onClick={() => !isMobile && !selectedUnit && handleClick(unit.unitNo)}
|
||||
onMouseEnter={!isMobile ? handleMouseEnter : undefined}
|
||||
onMouseLeave={() => !isMobile && setPopup(null)}
|
||||
onTouchStart={(e) => {
|
||||
onSelect(unit);
|
||||
setPosition({ x: e.touches[0].clientX, y: e.touches[0].clientY });
|
||||
handleMouseEnter();
|
||||
}}
|
||||
d={d}
|
||||
className={clsx(
|
||||
"fill-transparent hover:fill-[#00BED7] opacity-20 transition-[fill] cursor-pointer",
|
||||
selectedUnit?.unitNo === unit.unitNo &&
|
||||
"!fill-[#00BED7] opacity-20 cursor-default"
|
||||
)}
|
||||
/>
|
||||
</g>
|
||||
);
|
||||
}
|
||||
export default FloorPlanMarasiDriveWestLower;
|
||||
|
||||
@@ -1,32 +1,29 @@
|
||||
// import { selectedFloorPlanMasksMarasiDrive } from "../data/selectedFloor-plan-masks/marasi-drive";
|
||||
|
||||
import { Fragment } from "react/jsx-runtime";
|
||||
import { floorPlanMarasiDriveWestUpperMasks } from "../data/floor-plan-masks/marasi-drive";
|
||||
import { formattedUnitTypes } from "../data/formattedUnitTypes";
|
||||
import { usePopupStore } from "../stores/usePopupStore";
|
||||
import { Unit } from "../types/IUnit";
|
||||
import UnitPopup from "./UnitPopup";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import { useState } from "react";
|
||||
import clsx from "clsx";
|
||||
import GenericFloorPlan from "./floor-plans/GenericFloorPlan";
|
||||
|
||||
interface FloorPlanMarasiDriveEastProps {
|
||||
interface FloorPlanMarasiDriveWestUpperProps {
|
||||
selectedFloor: string | null;
|
||||
unitsOnFloor: Unit[];
|
||||
chosenUnit?: Unit;
|
||||
}
|
||||
|
||||
function FloorPlanMarasiDriveEast({
|
||||
function FloorPlanMarasiDriveWestUpper({
|
||||
unitsOnFloor,
|
||||
selectedFloor,
|
||||
chosenUnit,
|
||||
}: FloorPlanMarasiDriveEastProps & React.SVGProps<SVGSVGElement>) {
|
||||
const [selectedUnit, setSelectedUnit] = useState<Unit | null>(
|
||||
chosenUnit || null
|
||||
);
|
||||
|
||||
}: FloorPlanMarasiDriveWestUpperProps) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 619.96 586.04">
|
||||
<GenericFloorPlan
|
||||
complexName="marasi-drive"
|
||||
viewBox="0 0 619.96 586.04"
|
||||
masks={floorPlanMarasiDriveWestUpperMasks}
|
||||
getMaskKey={(unitNo) => unitNo.slice(-2)}
|
||||
selectedFloor={selectedFloor}
|
||||
unitsOnFloor={unitsOnFloor}
|
||||
chosenUnit={chosenUnit}
|
||||
wing="West"
|
||||
>
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
@@ -1178,107 +1175,8 @@ function FloorPlanMarasiDriveEast({
|
||||
}}
|
||||
/>
|
||||
</g>
|
||||
<g>
|
||||
{unitsOnFloor.map((unit) =>
|
||||
floorPlanMarasiDriveWestUpperMasks.has(unit.unitNo.slice(-2)) ? (
|
||||
<MarasiDriveWestUpperFloorPlanUnit
|
||||
key={unit.unitNo}
|
||||
unit={unit}
|
||||
floor={selectedFloor}
|
||||
d={
|
||||
floorPlanMarasiDriveWestUpperMasks.get(unit.unitNo.slice(-2))!.d
|
||||
}
|
||||
textTransform={`translate(${floorPlanMarasiDriveWestUpperMasks
|
||||
.get(unit.unitNo.slice(-2))
|
||||
?.textTransform.join(" ")})`}
|
||||
selectedUnit={selectedUnit}
|
||||
onSelect={setSelectedUnit}
|
||||
/>
|
||||
) : (
|
||||
<Fragment key={unit.unitNo} />
|
||||
)
|
||||
)}
|
||||
</g>
|
||||
</svg>
|
||||
</GenericFloorPlan>
|
||||
);
|
||||
}
|
||||
|
||||
export default FloorPlanMarasiDriveEast;
|
||||
|
||||
function MarasiDriveWestUpperFloorPlanUnit({
|
||||
d,
|
||||
textTransform,
|
||||
floor,
|
||||
unit,
|
||||
selectedUnit,
|
||||
onSelect,
|
||||
}: {
|
||||
d: string;
|
||||
textTransform: string;
|
||||
floor: string | null;
|
||||
unit: Unit;
|
||||
selectedUnit: Unit | null;
|
||||
onSelect: (unit: Unit | null) => void;
|
||||
}) {
|
||||
function handleClick(unit: Unit) {
|
||||
window.open(`/complex/marasi-drive/${unit.unitNo}`, "_blank");
|
||||
}
|
||||
|
||||
const { setPopup, setPosition, setSide } = usePopupStore();
|
||||
|
||||
function handleMouseEnter() {
|
||||
if (floor === null) return;
|
||||
setSide("top");
|
||||
if (!selectedUnit)
|
||||
setPopup(
|
||||
<UnitPopup
|
||||
complexName="marasi-drive"
|
||||
wing="West"
|
||||
unitType={unit.unitType}
|
||||
floor={unit.floor}
|
||||
unitNumber={unit.unitNo}
|
||||
squareFt={unit.squareFt}
|
||||
suitesArea={unit.suitsArea}
|
||||
balconyArea={unit.balconyArea}
|
||||
price={unit.salesPrice}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<g>
|
||||
<text
|
||||
transform={textTransform}
|
||||
style={{
|
||||
fill: "#fff",
|
||||
fontFamily: "Usual",
|
||||
fontSize: 8,
|
||||
fontWeight: 500,
|
||||
}}
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{unit.unitNo}
|
||||
</tspan>
|
||||
<tspan x={0} y={10.8}>
|
||||
{formattedUnitTypes.get(unit.unitType) || unit.unitType}
|
||||
</tspan>
|
||||
</text>
|
||||
<path
|
||||
onClick={() => !isMobile && !selectedUnit && handleClick(unit)}
|
||||
onMouseEnter={!isMobile ? handleMouseEnter : undefined}
|
||||
onMouseLeave={() => !isMobile && setPopup(null)}
|
||||
onTouchStart={(e) => {
|
||||
onSelect(unit);
|
||||
setPosition({ x: e.touches[0].clientX, y: e.touches[0].clientY });
|
||||
handleMouseEnter();
|
||||
}}
|
||||
d={d}
|
||||
className={clsx(
|
||||
"fill-transparent hover:fill-[#00BED7] opacity-20 transition-all cursor-pointer",
|
||||
selectedUnit?.unitNo === unit.unitNo &&
|
||||
"!fill-[#00BED7] opacity-20 cursor-default"
|
||||
)}
|
||||
/>
|
||||
</g>
|
||||
);
|
||||
}
|
||||
export default FloorPlanMarasiDriveWestUpper;
|
||||
|
||||
@@ -585,10 +585,7 @@ function FloorSelect({
|
||||
queryFn: () =>
|
||||
api
|
||||
.get(
|
||||
`units/get-floors-data/Rove Home ${complexName
|
||||
.split("-")
|
||||
.map((w) => w[0].toUpperCase() + w.slice(1))
|
||||
.join(" ")}`,
|
||||
`units/get-floors-data/${complexName}`,
|
||||
)
|
||||
.json<FloorsData[]>(),
|
||||
});
|
||||
|
||||
@@ -1,76 +1,44 @@
|
||||
import { Unit } from "../types/IUnit";
|
||||
import FloorPlanDubaiMarina39_40 from "./FloorPlanDubaiMarina39_40";
|
||||
import FloorPlanDubaiMarina41_42 from "./FloorPlanDubaiMarina41_42";
|
||||
import FloorPlanDubaiMarina7_38 from "./FloorPlanDubaiMarina7_38";
|
||||
import FloorPlanDubaiMarina7_38Comb from "./FloorPlanDubaiMarina7_38Comb";
|
||||
import FloorPlanMarasiDriveEast from "./FloorPlanMarasiDriveEast";
|
||||
import FloorPlanMarasiDriveWestLower from "./FloorPlanMarasiDriveWestLower";
|
||||
import FloorPlanMarasiDriveWestUpper from "./FloorPlanMarasiDriveWestUpper";
|
||||
import GenericFloorPlan from "./floor-plans/GenericFloorPlan";
|
||||
import { getFloorPlanConfigForUnit } from "../data/floor-plan-config";
|
||||
import { getSlugFromProjectName } from "../data/complex-config";
|
||||
|
||||
// ─── Component ───────────────────────────────────────────
|
||||
|
||||
function OnFloorMask({ unit }: { unit: Unit }) {
|
||||
if (unit.project === "Rove Home Marasi Drive") {
|
||||
if (unit.wing === "East") {
|
||||
return (
|
||||
<FloorPlanMarasiDriveEast
|
||||
selectedFloor={null}
|
||||
unitsOnFloor={[unit]}
|
||||
chosenUnit={unit}
|
||||
/>
|
||||
);
|
||||
} else if (unit.wing === "West") {
|
||||
if (unit.floor >= 5 && unit.floor <= 21) {
|
||||
return (
|
||||
<FloorPlanMarasiDriveWestLower
|
||||
selectedFloor={unit.floor.toString()}
|
||||
unitsOnFloor={[unit]}
|
||||
chosenUnit={unit}
|
||||
/>
|
||||
);
|
||||
} else if (unit.floor >= 24 && unit.floor <= 31) {
|
||||
return (
|
||||
<FloorPlanMarasiDriveWestUpper
|
||||
selectedFloor={unit.floor.toString()}
|
||||
unitsOnFloor={[unit]}
|
||||
chosenUnit={unit}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (unit.project === "Rove Home Dubai Marina") {
|
||||
if (unit.floor >= 7 && unit.floor <= 38) {
|
||||
if (unit.unitNo.endsWith("-C"))
|
||||
return (
|
||||
<FloorPlanDubaiMarina7_38Comb
|
||||
selectedFloor={unit.floor.toString()}
|
||||
unitsOnFloor={[unit]}
|
||||
chosenUnit={unit}
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<FloorPlanDubaiMarina7_38
|
||||
selectedFloor={unit.floor.toString()}
|
||||
unitsOnFloor={[unit]}
|
||||
chosenUnit={unit}
|
||||
/>
|
||||
);
|
||||
} else if (unit.floor >= 41 && unit.floor <= 42) {
|
||||
return (
|
||||
<FloorPlanDubaiMarina41_42
|
||||
selectedFloor={unit.floor.toString()}
|
||||
unitsOnFloor={[unit]}
|
||||
chosenUnit={unit}
|
||||
/>
|
||||
);
|
||||
} else if (unit.floor >= 39 && unit.floor <= 40) {
|
||||
return (
|
||||
<FloorPlanDubaiMarina39_40
|
||||
selectedFloor={unit.floor.toString()}
|
||||
unitsOnFloor={[unit]}
|
||||
chosenUnit={unit}
|
||||
/>
|
||||
);
|
||||
}
|
||||
const complexName = getSlugFromProjectName(unit.project);
|
||||
if (!complexName) return null;
|
||||
|
||||
const config = getFloorPlanConfigForUnit(complexName, unit);
|
||||
if (!config) return null;
|
||||
|
||||
// Marasi Drive uses component-based rendering (inline SVG)
|
||||
if (config.component) {
|
||||
const Component = config.component;
|
||||
return (
|
||||
<Component
|
||||
selectedFloor={unit.floor.toString()}
|
||||
unitsOnFloor={[unit]}
|
||||
chosenUnit={unit}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// Dubai Marina & HQ use image-based rendering
|
||||
return (
|
||||
<GenericFloorPlan
|
||||
complexName={complexName}
|
||||
viewBox={config.viewBox}
|
||||
imagePath={config.imagePath}
|
||||
masks={config.masks}
|
||||
getMaskKey={config.getMaskKey}
|
||||
filterUnits={config.filterUnits}
|
||||
selectedFloor={unit.floor.toString()}
|
||||
unitsOnFloor={[unit]}
|
||||
chosenUnit={unit}
|
||||
wing={config.wing}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default OnFloorMask;
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
import { Fragment, useState } from "react";
|
||||
import { Unit } from "../../types/IUnit";
|
||||
import { ComplexName } from "../../types/ComplexName";
|
||||
import { FloorPlanMasks } from "../../types/FloorPlanMasks";
|
||||
import { usePopupStore } from "../../stores/usePopupStore";
|
||||
import UnitPopup from "../UnitPopup";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import clsx from "clsx";
|
||||
|
||||
// ─── Props ───────────────────────────────────────────────
|
||||
|
||||
interface GenericFloorPlanProps extends React.SVGProps<SVGSVGElement> {
|
||||
complexName: ComplexName;
|
||||
viewBox: string;
|
||||
/** Floor plan background image path. Either this or `children` should be provided. */
|
||||
imagePath?: string;
|
||||
masks: FloorPlanMasks;
|
||||
selectedFloor: string | null;
|
||||
unitsOnFloor: Unit[];
|
||||
chosenUnit?: Unit | null;
|
||||
/** How to extract the mask key from unit.unitNo. Default: unitNo.slice(-2) */
|
||||
getMaskKey?: (unitNo: string) => string;
|
||||
/** Optional unit filter (e.g. filterDuplicateUnits for combinable layouts) */
|
||||
filterUnits?: (units: Unit[]) => Unit[];
|
||||
/** Optional wing for Marasi Drive popups */
|
||||
wing?: "East" | "West";
|
||||
/** Custom SVG background (inline SVG groups). Used for Marasi Drive instead of imagePath. */
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
const defaultGetMaskKey = (unitNo: string) => unitNo.slice(-2);
|
||||
|
||||
// ─── Main component ──────────────────────────────────────
|
||||
|
||||
function GenericFloorPlan({
|
||||
complexName,
|
||||
viewBox: vb,
|
||||
imagePath,
|
||||
masks,
|
||||
selectedFloor,
|
||||
unitsOnFloor,
|
||||
chosenUnit,
|
||||
getMaskKey = defaultGetMaskKey,
|
||||
filterUnits,
|
||||
wing,
|
||||
children,
|
||||
...svgProps
|
||||
}: GenericFloorPlanProps) {
|
||||
const [selectedUnit, setSelectedUnit] = useState<Unit | null>(
|
||||
chosenUnit || null
|
||||
);
|
||||
|
||||
const units = filterUnits ? filterUnits(unitsOnFloor) : unitsOnFloor;
|
||||
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
viewBox={vb}
|
||||
className="w-full h-full"
|
||||
{...svgProps}
|
||||
>
|
||||
{/* Background: either an image or custom inline SVG */}
|
||||
{imagePath && <image transform="scale(.5)" xlinkHref={imagePath} />}
|
||||
{children}
|
||||
|
||||
{/* Unit overlays */}
|
||||
{units.map((unit) => {
|
||||
const maskKey = getMaskKey(unit.unitNo);
|
||||
const maskData = masks.get(maskKey);
|
||||
|
||||
if (!maskData) return <Fragment key={unit.unitNo} />;
|
||||
|
||||
return (
|
||||
<GenericFloorPlanUnit
|
||||
key={unit.unitNo}
|
||||
complexName={complexName}
|
||||
wing={wing}
|
||||
selectedUnit={selectedUnit}
|
||||
onSelect={setSelectedUnit}
|
||||
formattedUnitType={maskData.formattedUnitType}
|
||||
unit={unit}
|
||||
floor={selectedFloor}
|
||||
d={maskData.d}
|
||||
textTransform={`translate(${maskData.textTransform.join(" ")})`}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default GenericFloorPlan;
|
||||
|
||||
// ─── Unit overlay component ──────────────────────────────
|
||||
|
||||
function GenericFloorPlanUnit({
|
||||
complexName,
|
||||
wing,
|
||||
unit,
|
||||
floor,
|
||||
d,
|
||||
textTransform,
|
||||
formattedUnitType,
|
||||
onSelect,
|
||||
selectedUnit,
|
||||
}: {
|
||||
complexName: ComplexName;
|
||||
wing?: "East" | "West";
|
||||
unit: Unit;
|
||||
floor: string | null;
|
||||
d: string;
|
||||
textTransform: string;
|
||||
formattedUnitType: string;
|
||||
selectedUnit: Unit | null;
|
||||
onSelect: (unit: Unit | null) => void;
|
||||
}) {
|
||||
const { setPopup, setSide, setPosition } = usePopupStore();
|
||||
|
||||
function handleClick(unit: Unit) {
|
||||
window.open(`/complex/${complexName}/${unit.unitNo}`, "_blank");
|
||||
}
|
||||
|
||||
function handleMouseEnter() {
|
||||
if (floor === null) return;
|
||||
|
||||
setSide("top");
|
||||
|
||||
if (!selectedUnit)
|
||||
setPopup(
|
||||
<UnitPopup
|
||||
complexName={complexName}
|
||||
wing={wing}
|
||||
unitType={unit.unitType}
|
||||
floor={unit.floor}
|
||||
unitNumber={unit.unitNo}
|
||||
squareFt={unit.squareFt}
|
||||
suitesArea={unit.suitsArea}
|
||||
balconyArea={unit.balconyArea}
|
||||
price={unit.salesPrice}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<g>
|
||||
<text
|
||||
transform={textTransform}
|
||||
className="fill-white text-[8px] select-none"
|
||||
textAnchor="middle"
|
||||
>
|
||||
<tspan x={0} y={0}>
|
||||
{unit.unitNo}
|
||||
</tspan>
|
||||
<tspan x={0} y={15}>
|
||||
{formattedUnitType}
|
||||
</tspan>
|
||||
</text>
|
||||
<path
|
||||
onClick={() => !isMobile && !selectedUnit && handleClick(unit)}
|
||||
onMouseEnter={!isMobile ? handleMouseEnter : undefined}
|
||||
onMouseLeave={() => !isMobile && setPopup(null)}
|
||||
onTouchStart={(e) => {
|
||||
onSelect(unit);
|
||||
setPosition({ x: e.touches[0].clientX, y: e.touches[0].clientY });
|
||||
handleMouseEnter();
|
||||
}}
|
||||
className={clsx(
|
||||
"fill-transparent hover:fill-[#00BED7] opacity-40 isolate cursor-pointer transition-colors",
|
||||
selectedUnit?.unitNo === unit.unitNo &&
|
||||
"!fill-[#00BED7] opacity-40 cursor-default"
|
||||
)}
|
||||
d={d}
|
||||
/>
|
||||
</g>
|
||||
);
|
||||
}
|
||||
@@ -9,15 +9,11 @@ import UnitTypeBadge from "../UnitTypeBadge";
|
||||
import Button from "../ui/Button";
|
||||
import { usePopupStore } from "../../stores/usePopupStore";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import GenericFloorPlan from "./GenericFloorPlan";
|
||||
import { getFloorPlanConfig } from "../../data/floor-plan-config";
|
||||
import { getComplexConfig } from "../../data/complex-config";
|
||||
|
||||
// Import floor plan components
|
||||
import FloorPlanMarasiDriveEast from "../FloorPlanMarasiDriveEast";
|
||||
import FloorPlanMarasiDriveWestLower from "../FloorPlanMarasiDriveWestLower";
|
||||
import FloorPlanMarasiDriveWestUpper from "../FloorPlanMarasiDriveWestUpper";
|
||||
import FloorPlanDubaiMarina7_38 from "../FloorPlanDubaiMarina7_38";
|
||||
import FloorPlanDubaiMarina7_38Comb from "../FloorPlanDubaiMarina7_38Comb";
|
||||
import FloorPlanDubaiMarina39_40 from "../FloorPlanDubaiMarina39_40";
|
||||
import FloorPlanDubaiMarina41_42 from "../FloorPlanDubaiMarina41_42";
|
||||
// ─── Props ───────────────────────────────────────────────
|
||||
|
||||
interface ResidentialFloorViewProps {
|
||||
floor: ResidentialFloorData;
|
||||
@@ -28,6 +24,8 @@ interface ResidentialFloorViewProps {
|
||||
onFloorSelect: (floor: string) => void;
|
||||
}
|
||||
|
||||
// ─── Main component ──────────────────────────────────────
|
||||
|
||||
function ResidentialFloorView({
|
||||
floor,
|
||||
complexName,
|
||||
@@ -39,245 +37,265 @@ function ResidentialFloorView({
|
||||
const { setPopup, setPosition } = usePopupStore();
|
||||
const [isCombinable, setIsCombinable] = useState(false);
|
||||
|
||||
// Marasi Drive specific logic
|
||||
if (complexName === "marasi-drive") {
|
||||
const floorNumber = floor.floorNumber;
|
||||
const wing = floor.wing || selectedFloor.split(" ")[0];
|
||||
const currentFloorData = floorsData?.find(
|
||||
(item) => item.floor === floorNumber
|
||||
);
|
||||
const complexConfig = getComplexConfig(complexName);
|
||||
const floorNumber = floor.floorNumber;
|
||||
const wing = floor.wing || selectedFloor.split(" ")[0];
|
||||
|
||||
const totalUnits =
|
||||
(currentFloorData?.East?.totalUnits || 0) +
|
||||
(currentFloorData?.West?.totalUnits || 0);
|
||||
const currentFloorData = floorsData?.find(
|
||||
(item) => item.floor === floorNumber
|
||||
);
|
||||
|
||||
const wingData =
|
||||
currentFloorData?.[selectedFloor.split(" ")[0] as "West" | "East"];
|
||||
// ── Resolve floor plan config ──────────────────────────
|
||||
const config = getFloorPlanConfig(complexName, selectedFloor, {
|
||||
isCombinable,
|
||||
wing: wing as "East" | "West",
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="2xl:space-y-[1.111vw] space-y-4" onScroll={() => setPopup(null)}>
|
||||
<div className="2xl:space-y-[0.556vw] space-y-2 border-b border-[#E2E2DC] 2xl:pb-[1.667vw] pb-4">
|
||||
<p className="font-medium text-h4">{floorNumber} floor</p>
|
||||
<div className="flex items-center 2xl:gap-[0.278vw] gap-1">
|
||||
<Badge variant="secondary" text={`${totalUnits} Apartments`} />
|
||||
</div>
|
||||
// ── Floor display name ─────────────────────────────────
|
||||
const floorTitle = complexConfig.hasWings
|
||||
? `${floorNumber} floor`
|
||||
: `${selectedFloor} floor`;
|
||||
|
||||
// ── Apartment count ────────────────────────────────────
|
||||
const totalUnits = complexConfig.hasWings
|
||||
? (currentFloorData?.East?.totalUnits || 0) +
|
||||
(currentFloorData?.West?.totalUnits || 0)
|
||||
: currentFloorData?.others?.totalUnits || 0;
|
||||
|
||||
// ── Special floor check (Dubai Marina: 39-40, 41-42) ──
|
||||
const isSpecialFloor =
|
||||
selectedFloor === "39-40" || selectedFloor === "41-42";
|
||||
|
||||
// ── Select options ─────────────────────────────────────
|
||||
const selectOptions = getSelectOptions(complexName, floorsData);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="2xl:space-y-[1.111vw] space-y-4"
|
||||
onScroll={() => setPopup(null)}
|
||||
>
|
||||
{/* ── Header ──────────────────────────────────────── */}
|
||||
<div className="2xl:space-y-[0.556vw] space-y-2 border-b border-[#E2E2DC] 2xl:pb-[1.667vw] pb-4">
|
||||
<p className="font-medium text-h4">{floorTitle}</p>
|
||||
<div className="flex items-center 2xl:gap-[0.278vw] gap-1">
|
||||
<Badge variant="secondary" text={`${totalUnits} Apartments`} />
|
||||
{complexConfig.hasCombinable && !isSpecialFloor && (
|
||||
<Badge variant="primary" text="Combinable" />
|
||||
)}
|
||||
</div>
|
||||
<div className="2xl:space-y-[0.833vw] space-y-2">
|
||||
<div className="flex items-center 2xl:gap-[1.111vw] gap-2">
|
||||
<Select
|
||||
options={
|
||||
floorsData?.flatMap((item) => [
|
||||
`East ${item.floor}`,
|
||||
`West ${item.floor}`,
|
||||
]) || []
|
||||
}
|
||||
defaultOption={selectedFloor?.toString() || ""}
|
||||
onSelect={onFloorSelect}
|
||||
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">
|
||||
<UnitTypeBadge
|
||||
type="Studio Flex"
|
||||
count={wingData?.types["Studio Flex"] || 0}
|
||||
/>
|
||||
<UnitTypeBadge
|
||||
type="Studio"
|
||||
count={wingData?.types["Studio Squared"] || 0}
|
||||
/>
|
||||
<UnitTypeBadge
|
||||
type="1 Bedroom"
|
||||
count={wingData?.types["1 BR Squared"] || 0}
|
||||
/>
|
||||
<UnitTypeBadge
|
||||
type="2 Bedroom"
|
||||
count={wingData?.types["2 BR Squared"] || 0}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ── Controls ────────────────────────────────────── */}
|
||||
<div className="2xl:space-y-[0.833vw] space-y-2">
|
||||
<div className="flex items-center 2xl:gap-[1.111vw] gap-2">
|
||||
<Select
|
||||
options={selectOptions}
|
||||
defaultOption={selectedFloor?.toString() || ""}
|
||||
onSelect={onFloorSelect}
|
||||
className="2xl:w-[8.333vw] md:max-2xl:w-[120px] w-full"
|
||||
maxOptionsCount={7}
|
||||
/>
|
||||
<UnitTypeBadges
|
||||
complexName={complexName}
|
||||
floorsData={floorsData}
|
||||
selectedFloor={selectedFloor}
|
||||
currentFloorData={currentFloorData}
|
||||
wing={wing}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Combinable toggle (Dubai Marina only) */}
|
||||
{complexConfig.hasCombinable && !isSpecialFloor && (
|
||||
<div className="flex gap-2 justify-center items-center">
|
||||
<Button
|
||||
variant={!isCombinable ? "cta" : "primary"}
|
||||
onClick={() => setIsCombinable(false)}
|
||||
>
|
||||
Standard
|
||||
</Button>
|
||||
<Button
|
||||
variant={isCombinable ? "cta" : "primary"}
|
||||
onClick={() => setIsCombinable(true)}
|
||||
>
|
||||
Combinable
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ── Floor plan ──────────────────────────────────── */}
|
||||
<div
|
||||
className="2xl:p-[4.444vw] p-4 bg-[#F3F3F2] 2xl:rounded-[0.833vw] rounded-lg"
|
||||
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 })
|
||||
}
|
||||
>
|
||||
{unitsOnFloor && wing === "East" && (
|
||||
<FloorPlanMarasiDriveEast
|
||||
unitsOnFloor={unitsOnFloor}
|
||||
selectedFloor={floorNumber.toString()}
|
||||
/>
|
||||
)}
|
||||
{wing === "West" && unitsOnFloor && (
|
||||
<>
|
||||
{floorNumber < 24 ? (
|
||||
<FloorPlanMarasiDriveWestLower
|
||||
unitsOnFloor={unitsOnFloor}
|
||||
selectedFloor={floorNumber.toString()}
|
||||
/>
|
||||
) : (
|
||||
<FloorPlanMarasiDriveWestUpper
|
||||
unitsOnFloor={unitsOnFloor}
|
||||
selectedFloor={floorNumber.toString()}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<FloorPlanRenderer
|
||||
complexName={complexName}
|
||||
config={config}
|
||||
selectedFloor={selectedFloor}
|
||||
unitsOnFloor={unitsOnFloor}
|
||||
floorNumber={floorNumber}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Dubai Marina specific logic
|
||||
if (complexName === "dubai-marina") {
|
||||
const floorNumber = floor.floorNumber;
|
||||
const currentFloorData = floorsData?.find(
|
||||
(item) => item.floor === floorNumber
|
||||
);
|
||||
|
||||
const isSpecialFloor =
|
||||
selectedFloor === "39-40" || selectedFloor === "41-42";
|
||||
|
||||
return (
|
||||
<div className="2xl:space-y-[1.111vw] space-y-4" onScroll={() => setPopup(null)}>
|
||||
<div className="2xl:space-y-[0.556vw] space-y-2 border-b border-[#E2E2DC] 2xl:pb-[1.667vw] pb-4">
|
||||
<p className="font-medium text-h4">{selectedFloor} floor</p>
|
||||
<div className="flex items-center 2xl:gap-[0.278vw] gap-1">
|
||||
<Badge
|
||||
variant="secondary"
|
||||
text={`${currentFloorData?.others.totalUnits || 0} Apartments`}
|
||||
/>
|
||||
{!isSpecialFloor && <Badge variant="primary" text="Combinable" />}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="2xl:space-y-[0.833vw] space-y-2">
|
||||
<div className="flex items-center 2xl:gap-[1.111vw] gap-2">
|
||||
<Select
|
||||
options={
|
||||
floorsData?.map((item) => {
|
||||
if (item.floor === 39) {
|
||||
return "39-40";
|
||||
}
|
||||
if (item.floor === 41) {
|
||||
return "41-42";
|
||||
}
|
||||
return item.floor.toString();
|
||||
}) || []
|
||||
}
|
||||
defaultOption={selectedFloor?.toString() || ""}
|
||||
onSelect={onFloorSelect}
|
||||
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">
|
||||
<UnitTypeBadge
|
||||
type="Studio"
|
||||
count={
|
||||
floorsData?.find(
|
||||
(item) =>
|
||||
item.floor ===
|
||||
parseInt(selectedFloor!.split(" ").at(-1)!)
|
||||
)?.others.types["Studio2"] || 0
|
||||
}
|
||||
/>
|
||||
<UnitTypeBadge
|
||||
type="1 Bedroom"
|
||||
count={
|
||||
floorsData?.find(
|
||||
(item) =>
|
||||
item.floor ===
|
||||
parseInt(selectedFloor!.split(" ").at(-1)!)
|
||||
)?.others.types["One Bedroom2"] || 0
|
||||
}
|
||||
/>
|
||||
<UnitTypeBadge
|
||||
type="1 Bedroom Loft"
|
||||
count={
|
||||
floorsData?.find(
|
||||
(item) =>
|
||||
item.floor ===
|
||||
parseInt(selectedFloor!.split(" ").at(-1)!)
|
||||
)?.others.types["One Bedroom Loft"] || 0
|
||||
}
|
||||
/>
|
||||
<UnitTypeBadge
|
||||
type="2 Bedroom Loft"
|
||||
count={
|
||||
floorsData?.find(
|
||||
(item) =>
|
||||
item.floor ===
|
||||
parseInt(selectedFloor!.split(" ").at(-1)!)
|
||||
)?.others.types["Two Bedroom Loft"] || 0
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{!isSpecialFloor && (
|
||||
<div className="flex gap-2 justify-center items-center">
|
||||
<Button
|
||||
variant={!isCombinable ? "cta" : "primary"}
|
||||
onClick={() => setIsCombinable(false)}
|
||||
>
|
||||
Standard
|
||||
</Button>
|
||||
<Button
|
||||
variant={isCombinable ? "cta" : "primary"}
|
||||
onClick={() => setIsCombinable(true)}
|
||||
>
|
||||
Combinable
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
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 && (
|
||||
<>
|
||||
{!isCombinable ? (
|
||||
<FloorPlanDubaiMarina7_38
|
||||
selectedFloor={selectedFloor}
|
||||
unitsOnFloor={unitsOnFloor}
|
||||
/>
|
||||
) : (
|
||||
<FloorPlanDubaiMarina7_38Comb
|
||||
selectedFloor={selectedFloor}
|
||||
unitsOnFloor={unitsOnFloor}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{selectedFloor === "39-40" && (
|
||||
<FloorPlanDubaiMarina39_40
|
||||
selectedFloor={selectedFloor}
|
||||
unitsOnFloor={unitsOnFloor}
|
||||
chosenUnit={null}
|
||||
/>
|
||||
)}
|
||||
{selectedFloor === "41-42" && (
|
||||
<FloorPlanDubaiMarina41_42
|
||||
selectedFloor={selectedFloor}
|
||||
unitsOnFloor={unitsOnFloor}
|
||||
chosenUnit={null}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Default fallback
|
||||
return <div>Unsupported complex: {complexName}</div>;
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ResidentialFloorView;
|
||||
|
||||
// ─── Select options helper ──────────────────────────────
|
||||
|
||||
function getSelectOptions(
|
||||
complexName: ComplexName,
|
||||
floorsData?: FloorsData[]
|
||||
): string[] {
|
||||
if (!floorsData) return [];
|
||||
|
||||
if (complexName === "marasi-drive") {
|
||||
return floorsData.flatMap((item) => [
|
||||
`East ${item.floor}`,
|
||||
`West ${item.floor}`,
|
||||
]);
|
||||
}
|
||||
|
||||
if (complexName === "dubai-marina") {
|
||||
return floorsData.map((item) => {
|
||||
if (item.floor === 39) return "39-40";
|
||||
if (item.floor === 41) return "41-42";
|
||||
return item.floor.toString();
|
||||
});
|
||||
}
|
||||
|
||||
// HQ and default
|
||||
return floorsData.map((item) => item.floor.toString());
|
||||
}
|
||||
|
||||
// ─── Unit type badges ───────────────────────────────────
|
||||
|
||||
function UnitTypeBadges({
|
||||
complexName,
|
||||
floorsData,
|
||||
selectedFloor,
|
||||
currentFloorData,
|
||||
wing,
|
||||
}: {
|
||||
complexName: ComplexName;
|
||||
floorsData?: FloorsData[];
|
||||
selectedFloor: string;
|
||||
currentFloorData?: FloorsData;
|
||||
wing: string;
|
||||
}) {
|
||||
if (complexName === "marasi-drive") {
|
||||
const wingData =
|
||||
currentFloorData?.[wing as "West" | "East"];
|
||||
|
||||
return (
|
||||
<>
|
||||
<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">
|
||||
<UnitTypeBadge
|
||||
type="Studio Flex"
|
||||
count={wingData?.types["Studio Flex"] || 0}
|
||||
/>
|
||||
<UnitTypeBadge
|
||||
type="Studio"
|
||||
count={wingData?.types["Studio Squared"] || 0}
|
||||
/>
|
||||
<UnitTypeBadge
|
||||
type="1 Bedroom"
|
||||
count={wingData?.types["1 BR Squared"] || 0}
|
||||
/>
|
||||
<UnitTypeBadge
|
||||
type="2 Bedroom"
|
||||
count={wingData?.types["2 BR Squared"] || 0}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (complexName === "dubai-marina") {
|
||||
const floorNum = parseInt(selectedFloor.split(" ").at(-1)!);
|
||||
const floorData = floorsData?.find((item) => item.floor === floorNum);
|
||||
|
||||
return (
|
||||
<>
|
||||
<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">
|
||||
<UnitTypeBadge
|
||||
type="Studio"
|
||||
count={floorData?.others.types["Studio2"] || 0}
|
||||
/>
|
||||
<UnitTypeBadge
|
||||
type="1 Bedroom"
|
||||
count={floorData?.others.types["One Bedroom2"] || 0}
|
||||
/>
|
||||
<UnitTypeBadge
|
||||
type="1 Bedroom Loft"
|
||||
count={floorData?.others.types["One Bedroom Loft"] || 0}
|
||||
/>
|
||||
<UnitTypeBadge
|
||||
type="2 Bedroom Loft"
|
||||
count={floorData?.others.types["Two Bedroom Loft"] || 0}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// HQ: no unit type badges
|
||||
return null;
|
||||
}
|
||||
|
||||
// ─── Floor plan renderer ────────────────────────────────
|
||||
|
||||
function FloorPlanRenderer({
|
||||
complexName,
|
||||
config,
|
||||
selectedFloor,
|
||||
unitsOnFloor,
|
||||
floorNumber,
|
||||
}: {
|
||||
complexName: ComplexName;
|
||||
config: ReturnType<typeof getFloorPlanConfig>;
|
||||
selectedFloor: string;
|
||||
unitsOnFloor?: Unit[];
|
||||
floorNumber: number;
|
||||
}) {
|
||||
if (!selectedFloor || !unitsOnFloor) return null;
|
||||
|
||||
if (!config) {
|
||||
return (
|
||||
<div className="text-center text-gray-400 py-8">
|
||||
Floor plan coming soon
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Component-based rendering (Marasi Drive inline SVG)
|
||||
if (config.component) {
|
||||
const Component = config.component;
|
||||
return (
|
||||
<Component
|
||||
selectedFloor={floorNumber.toString()}
|
||||
unitsOnFloor={unitsOnFloor}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// Image-based rendering (Dubai Marina, HQ)
|
||||
return (
|
||||
<GenericFloorPlan
|
||||
complexName={complexName}
|
||||
viewBox={config.viewBox}
|
||||
imagePath={config.imagePath}
|
||||
masks={config.masks}
|
||||
getMaskKey={config.getMaskKey}
|
||||
filterUnits={config.filterUnits}
|
||||
selectedFloor={selectedFloor}
|
||||
unitsOnFloor={unitsOnFloor}
|
||||
wing={config.wing}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
import useModalStore from "../../../stores/useModalStore";
|
||||
import AmentitiesBadge from "../../AmentitiesCard";
|
||||
import PlayIcon from "../../icons/PlayIcon";
|
||||
import Badge from "../../ui/Badge";
|
||||
import Button from "../../ui/Button";
|
||||
import VideoModal from "../../VideoModal";
|
||||
|
||||
function GroundDubaiMarina() {
|
||||
const { setModal } = useModalStore();
|
||||
|
||||
return (
|
||||
<div className="2xl:space-y-[2.222vw] space-y-8">
|
||||
<div className="2xl:space-y-[1.667vw] space-y-6">
|
||||
<div className="2xl:space-y-[0.556vw] space-y-2 border-b border-[#E2E2DC] 2xl:pb-[1.667vw] pb-6">
|
||||
<p className="text-h4 font-medium">Ground Level</p>
|
||||
<Badge variant="secondary" text="14 Amenities" />
|
||||
</div>
|
||||
<div className="bg-[#F3F3F2] 2xl:rounded-[1.111vw] rounded-2xl 2xl:p-[1.111vw] p-4 relative">
|
||||
<img
|
||||
src="/images/floor-plans/compass.png"
|
||||
className="absolute top-0 left-0 size-[7.222vw]"
|
||||
alt=""
|
||||
/>
|
||||
<img
|
||||
src="/images/floor-plans/dubai-marina/ground.png"
|
||||
alt="podium"
|
||||
className="w-full"
|
||||
/>
|
||||
<Button
|
||||
variant="cta"
|
||||
className="absolute 2xl:top-[1.667vw] 2xl:right-[1.667vw] md:max-2xl:top-6 md:max-2xl:right-6 top-4 right-4"
|
||||
onlyIcon
|
||||
size="small"
|
||||
onClick={() =>
|
||||
setModal(
|
||||
<VideoModal src="/videos/dubai-marina/GroundDubaiMarina.mp4" />
|
||||
)
|
||||
}
|
||||
>
|
||||
<span className="2xl:size-[1.111vw] size-4">
|
||||
<PlayIcon />
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="2xl:space-y-[1.111vw] space-y-4">
|
||||
<h4 className="text-h4 font-medium">Amenities</h4>
|
||||
<div className="flex flex-wrap 2xl:gap-[0.556vw] gap-2">
|
||||
{[
|
||||
"Residential Entrance",
|
||||
"Multifunctional Feature Staircase",
|
||||
"Lobby Lounge & Concierge",
|
||||
"Outdoor Landscape Seating Area",
|
||||
"Lift Lobby",
|
||||
"Rove Cafe & Energize Bar",
|
||||
"Organic Smart Gardens & Seating",
|
||||
"Co-working Area ",
|
||||
"24x7 Convenience Store",
|
||||
"WCs",
|
||||
"Visitor Parking",
|
||||
"EV Charging Stations",
|
||||
"Bicycle/Scooter Rental & Storage",
|
||||
"Drop-off Area",
|
||||
].map((amentity) => (
|
||||
<AmentitiesBadge key={amentity} title={amentity} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<img
|
||||
src="/images/floor-plans/dubai-marina/ground/content.jpg"
|
||||
className="2xl:rounded-[1.111vw] rounded-2xl select-none"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default GroundDubaiMarina;
|
||||
@@ -1,103 +0,0 @@
|
||||
import useModalStore from "../../../stores/useModalStore";
|
||||
import AmentitiesBadge from "../../AmentitiesCard";
|
||||
import AmenitiesBadge from "../../icons/AmenitiesBadge";
|
||||
import PlayIcon from "../../icons/PlayIcon";
|
||||
import Badge from "../../ui/Badge";
|
||||
import Button from "../../ui/Button";
|
||||
import VideoModal from "../../VideoModal";
|
||||
import AmentitiesContentSlider from "../../AmentitiesContentSlider";
|
||||
|
||||
function PodiumDubaiMarina() {
|
||||
const { setModal } = useModalStore();
|
||||
|
||||
return (
|
||||
<div className="2xl:space-y-[2.222vw] space-y-8">
|
||||
<div className="2xl:space-y-[1.667vw] space-y-6">
|
||||
<div className="2xl:space-y-[0.556vw] space-y-2 border-b border-[#E2E2DC] 2xl:pb-[1.667vw] pb-6">
|
||||
<p className="text-h4 font-medium">Podium</p>
|
||||
<Badge variant="secondary" text="14 Amenities" />
|
||||
</div>
|
||||
<div className="flex items-center 2xl:gap-[1.667vw] gap-6">
|
||||
<AmenitiesBadge count={3} type="Indoor" />
|
||||
<AmenitiesBadge count={12} type="Outdoor" />
|
||||
</div>
|
||||
<div className="bg-[#F3F3F2] 2xl:rounded-[1.111vw] rounded-2xl 2xl:p-[1.111vw] p-4 relative">
|
||||
<img
|
||||
src="/images/floor-plans/compass.png"
|
||||
className="absolute top-0 left-0 size-[7.222vw]"
|
||||
alt=""
|
||||
/>
|
||||
<img
|
||||
src="/images/floor-plans/dubai-marina/podium.png"
|
||||
alt="podium"
|
||||
className="w-full"
|
||||
/>
|
||||
<Button
|
||||
variant="cta"
|
||||
className="absolute 2xl:top-[1.667vw] 2xl:right-[1.667vw] md:max-2xl:top-6 md:max-2xl:right-6 top-4 right-4"
|
||||
onlyIcon
|
||||
size="small"
|
||||
onClick={() =>
|
||||
setModal(
|
||||
<VideoModal src="/videos/dubai-marina/PodiumDubaiMarina.mp4" />
|
||||
)
|
||||
}
|
||||
>
|
||||
<span className="2xl:size-[1.111vw] size-4">
|
||||
<PlayIcon />
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="2xl:space-y-[1.111vw] space-y-4">
|
||||
<h4 className="text-h4 font-medium">Indoor Amenities</h4>
|
||||
<div className="flex flex-wrap 2xl:gap-[0.556vw] gap-2">
|
||||
{[
|
||||
"Multipurpose Hall",
|
||||
"Gaming Lounge",
|
||||
"State-of-the-art Gym",
|
||||
"7m Climbing Wall",
|
||||
"Changing Rooms & Lockers",
|
||||
"Hydration Station",
|
||||
"Boutique Fitness Studio - Crank",
|
||||
"Rentable Guest Rooms",
|
||||
].map((amentity) => (
|
||||
<AmentitiesBadge key={amentity} title={amentity} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<hr className="border-[#E2E2DC] 2xl:h-[0.069vw] h-px" />
|
||||
<div className="2xl:space-y-[1.111vw] space-y-4">
|
||||
<h4 className="text-h4 font-medium">Outdoor Amenities</h4>
|
||||
<div className="flex flex-wrap 2xl:gap-[0.556vw] gap-2">
|
||||
{[
|
||||
"Semi-Olympic Leisure Pool",
|
||||
"Outdoor Cinema & Amphitheatre",
|
||||
"Water Feature Wall",
|
||||
"Multipurpose Fitness Pool",
|
||||
"Communal Gardens",
|
||||
"BBQ & Social Zone",
|
||||
"Popsicle Cart",
|
||||
"Gaming Lounge - Terrace",
|
||||
"Zen Library",
|
||||
"Co-working Area",
|
||||
"Multipurpose Hall with Terrace",
|
||||
"Marina View Chill Zone",
|
||||
"Outdoor Gym",
|
||||
].map((amentity) => (
|
||||
<AmentitiesBadge key={amentity} title={amentity} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<AmentitiesContentSlider
|
||||
srcs={[
|
||||
"/images/floor-plans/dubai-marina/podium/content1.jpg",
|
||||
"/images/floor-plans/dubai-marina/podium/content2.jpg",
|
||||
"/images/floor-plans/dubai-marina/podium/content3.jpg",
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PodiumDubaiMarina;
|
||||
@@ -1,80 +0,0 @@
|
||||
import useModalStore from "../../../stores/useModalStore";
|
||||
import AmentitiesBadge from "../../AmentitiesCard";
|
||||
import PlayIcon from "../../icons/PlayIcon";
|
||||
import Badge from "../../ui/Badge";
|
||||
import Button from "../../ui/Button";
|
||||
import VideoModal from "../../VideoModal";
|
||||
|
||||
const amenities = [
|
||||
"Sky Viewing Lounges",
|
||||
"Convertible Indoor Infinity Pool",
|
||||
"Marina View Amphitheatre",
|
||||
"Ultra Shield Oxygen Pod",
|
||||
"Aroma Steam Pod",
|
||||
"Reflexology Pool",
|
||||
"Cold Bucket Experience Shower Pod",
|
||||
"Experience Shower Pod",
|
||||
"Cold Plunge Pool",
|
||||
"Salt Steam Pod",
|
||||
"Finnish Sauna Pod",
|
||||
"Water Feature Wall",
|
||||
"Vitality Pool",
|
||||
"Changing Rooms and Lockers",
|
||||
];
|
||||
|
||||
function RooftopDubaiMarina() {
|
||||
const { setModal } = useModalStore();
|
||||
|
||||
return (
|
||||
<div className="2xl:space-y-[2.222vw] space-y-8">
|
||||
<div className="2xl:space-y-[1.667vw] space-y-6">
|
||||
<div className="2xl:space-y-[0.556vw] space-y-2 border-b border-[#E2E2DC] 2xl:pb-[1.667vw] pb-6">
|
||||
<p className="text-h4 font-medium">Sky 44 - Rooftop</p>
|
||||
<Badge variant="secondary" text="14 Amenities" />
|
||||
</div>
|
||||
<div className="bg-[#F3F3F2] 2xl:rounded-[1.111vw] rounded-2xl 2xl:p-[1.111vw] p-4 relative">
|
||||
<img
|
||||
src="/images/floor-plans/compass.png"
|
||||
className="absolute top-0 left-0 size-[7.222vw]"
|
||||
alt=""
|
||||
/>
|
||||
<img
|
||||
src="/images/floor-plans/dubai-marina/rooftop.png"
|
||||
alt="podium"
|
||||
className="w-full"
|
||||
/>
|
||||
<Button
|
||||
variant="cta"
|
||||
className="absolute 2xl:top-[1.667vw] 2xl:right-[1.667vw] md:max-2xl:top-6 md:max-2xl:right-6 top-4 right-4"
|
||||
onlyIcon
|
||||
size="small"
|
||||
onClick={() =>
|
||||
setModal(
|
||||
<VideoModal src="/videos/dubai-marina/SkyDubaiMarina.mp4" />
|
||||
)
|
||||
}
|
||||
>
|
||||
<span className="2xl:size-[1.111vw] size-4">
|
||||
<PlayIcon />
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="2xl:space-y-[1.111vw] space-y-4">
|
||||
<h4 className="text-h4 font-medium">Amenities</h4>
|
||||
<div className="flex flex-wrap 2xl:gap-[0.556vw] gap-2">
|
||||
{amenities.map((amentity) => (
|
||||
<AmentitiesBadge key={amentity} title={amentity} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<img
|
||||
src="/images/floor-plans/dubai-marina/rooftop/content.jpg"
|
||||
className="2xl:rounded-[1.111vw] rounded-2xl select-none"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default RooftopDubaiMarina;
|
||||
@@ -1,92 +0,0 @@
|
||||
import useModalStore from "../../../stores/useModalStore";
|
||||
import AmentitiesBadge from "../../AmentitiesCard";
|
||||
import AmentitiesContentSlider from "../../AmentitiesContentSlider";
|
||||
import ConvenienceIcon from "../../icons/amentities/ConvenienceIcon";
|
||||
import CoworkingIcon from "../../icons/amentities/CoworkingIcon";
|
||||
import LoungingSpaceIcon from "../../icons/amentities/LoungingSpaceIcon";
|
||||
import LushLandscapeIcon from "../../icons/amentities/LushLandscapeIcon";
|
||||
import PrivateMeetingRoomsIcon from "../../icons/amentities/PrivateMeetingRoomsIcon";
|
||||
import RoveCafe from "../../icons/amentities/RoveCafe";
|
||||
import SoundproofMeetingPodsIcon from "../../icons/amentities/SoundproofMeetingPodsIcon";
|
||||
import PlayIcon from "../../icons/PlayIcon";
|
||||
import Badge from "../../ui/Badge";
|
||||
import Button from "../../ui/Button";
|
||||
import VideoModal from "../../VideoModal";
|
||||
|
||||
function GroundMarasiDrive() {
|
||||
const { setModal } = useModalStore();
|
||||
|
||||
return (
|
||||
<div className="space-y-[2.222vw]">
|
||||
<div className="space-y-[1.667vw]">
|
||||
<div className="space-y-[0.556vw] border-b border-[#E2E2DC] pb-[1.667vw]">
|
||||
<p className="text-h4 font-medium">Ground Level</p>
|
||||
<Badge variant="secondary" text="7 Amenities" />
|
||||
</div>
|
||||
<div className="bg-[#F3F3F2] 2xl:rounded-[1.111vw] rounded-2xl 2xl:p-[1.111vw] p-4 relative">
|
||||
<img
|
||||
src="/images/floor-plans/compass.png"
|
||||
className="absolute top-0 left-0 size-[7.222vw]"
|
||||
alt=""
|
||||
/>
|
||||
<img
|
||||
src="/images/floor-plans/marasi-drive/ground.png"
|
||||
alt="podium"
|
||||
className="w-full"
|
||||
/>
|
||||
<Button
|
||||
variant="cta"
|
||||
className="absolute 2xl:top-[1.667vw] 2xl:right-[1.667vw] md:max-2xl:top-6 md:max-2xl:right-6 top-4 right-4"
|
||||
onlyIcon
|
||||
size="small"
|
||||
onClick={() =>
|
||||
setModal(
|
||||
<VideoModal src="/videos/marasi-drive/GroundMarasiDrive.mp4" />
|
||||
)
|
||||
}
|
||||
>
|
||||
<span className="2xl:size-[1.111vw] size-4">
|
||||
<PlayIcon />
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-[1.667vw]">
|
||||
<p className="font-medium text-h4">Amenities</p>
|
||||
<div className="grid md:grid-cols-4 grid-cols-3 gap-[1.111vw]">
|
||||
<AmentitiesBadge icon={<RoveCafe />} title="Rove Café" />
|
||||
<AmentitiesBadge icon={<LoungingSpaceIcon />} title="Lobby Lounge" />
|
||||
<AmentitiesBadge icon={<CoworkingIcon />} title="Coworking Space" />
|
||||
<AmentitiesBadge
|
||||
icon={<LushLandscapeIcon />}
|
||||
title="Outdoor Terrace"
|
||||
/>
|
||||
<AmentitiesBadge
|
||||
icon={<PrivateMeetingRoomsIcon />}
|
||||
title="Private Meeting Rooms"
|
||||
/>
|
||||
<AmentitiesBadge
|
||||
icon={<ConvenienceIcon />}
|
||||
title="Convenience Store"
|
||||
/>
|
||||
<AmentitiesBadge
|
||||
icon={<SoundproofMeetingPodsIcon />}
|
||||
title="Soundproof Meeting Pods"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<AmentitiesContentSlider
|
||||
srcs={[
|
||||
"/images/floor-plans/marasi-drive/ground/content1.jpg",
|
||||
"/images/floor-plans/marasi-drive/ground/content2.jpg",
|
||||
"/images/floor-plans/marasi-drive/ground/content3.jpg",
|
||||
"/images/floor-plans/marasi-drive/ground/content4.jpg",
|
||||
"/images/floor-plans/marasi-drive/ground/content5.jpg",
|
||||
"/images/floor-plans/marasi-drive/ground/content6.jpg",
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default GroundMarasiDrive;
|
||||
@@ -1,177 +0,0 @@
|
||||
import AmentitiesBadge from "../../AmentitiesCard";
|
||||
import AmenitiesBadge from "../../icons/AmenitiesBadge";
|
||||
import ArcadeGameIcon from "../../icons/amentities/ArcadeGameIcon";
|
||||
import ChangingRoomIcon from "../../icons/amentities/ChangingRoomIcon";
|
||||
import ClimbingWallIcon from "../../icons/amentities/ClimbingWallIcon";
|
||||
import FullyEquippedGymIcon from "../../icons/amentities/FullyEquippedGymIcon";
|
||||
import GuestRooms from "../../icons/amentities/GuestRooms";
|
||||
import HammockMovieLoungeIcon from "../../icons/amentities/HammockMovieLoungeIcon";
|
||||
import KaraokeIcon from "../../icons/amentities/KaraokeIcon";
|
||||
import LoungeIcon from "../../icons/amentities/LoungeIcon";
|
||||
import MonkeyBarsIcon from "../../icons/amentities/MonkeyBarsIcon";
|
||||
import MultiballInteractiveGamingIcon from "../../icons/amentities/MultiballInteractiveGamingIcon";
|
||||
import MultiPurposeRoomWithKitchenIcon from "../../icons/amentities/MultiPurposeRoomWithKitchenIcon";
|
||||
import PlaystationIcon from "../../icons/amentities/PlaystationIcon";
|
||||
import Badge from "../../ui/Badge";
|
||||
import GamingLoungeIcon from "../../icons/amentities/GamingLoungeIcon";
|
||||
import UrbanBeachPoolIcon from "../../icons/amentities/UrbanBeachPoolIcon";
|
||||
import JacuzziIcon from "../../icons/amentities/JacuzziIcon";
|
||||
import YogaLoungeIcon from "../../icons/amentities/YogaLoungeIcon";
|
||||
import SunLoungeIcon from "../../icons/amentities/SunLoungeIcon";
|
||||
import CascadingLeisurePoolIcon from "../../icons/amentities/CascadingLeisurePoolIcon";
|
||||
import AquaCyclingIcon from "../../icons/amentities/AquaCyclingIcon";
|
||||
import OpenAirGymIcon from "../../icons/amentities/OpenAirGymIcon";
|
||||
import RoveBeverageTruckIcon from "../../icons/amentities/RoveBeverageTruckIcon";
|
||||
import CabanasWithDaybeds from "../../icons/amentities/CabanasWithDaybeds";
|
||||
import IntegratedLapPoolIcon from "../../icons/amentities/IntegratedLapPoolIcon";
|
||||
import SunkenGardensIcon from "../../icons/amentities/SunkenGardensIcon";
|
||||
import GamingTerraceIcon from "../../icons/amentities/GamingTerraceIcon";
|
||||
import CoworkingIcon from "../../icons/amentities/CoworkingIcon";
|
||||
import Button from "../../ui/Button";
|
||||
import VideoModal from "../../VideoModal";
|
||||
import PlayIcon from "../../icons/PlayIcon";
|
||||
import useModalStore from "../../../stores/useModalStore";
|
||||
import AmentitiesContentSlider from "../../AmentitiesContentSlider";
|
||||
|
||||
function PodiumMarasiDrive() {
|
||||
const { setModal } = useModalStore();
|
||||
|
||||
return (
|
||||
<div className="2xl:space-y-[2.222vw] space-y-8">
|
||||
<div className="2xl:space-y-[1.667vw] space-y-6">
|
||||
<div className="2xl:space-y-[0.556vw] space-y-2 border-b border-[#E2E2DC] 2xl:pb-[1.667vw] pb-6">
|
||||
<p className="text-h4 font-medium">Podium Level</p>
|
||||
<Badge variant="secondary" text="27 Amenities" />
|
||||
</div>
|
||||
<div className="flex items-center 2xl:gap-[1.667vw] gap-6">
|
||||
<AmenitiesBadge count={13} type="Indoor" />
|
||||
<AmenitiesBadge count={14} type="Outdoor" />
|
||||
</div>
|
||||
<div className="bg-[#F3F3F2] 2xl:rounded-[1.111vw] rounded-2xl 2xl:p-[1.111vw] p-4 relative">
|
||||
<img
|
||||
src="/images/floor-plans/compass.png"
|
||||
className="absolute top-0 left-0 size-[7.222vw]"
|
||||
alt=""
|
||||
/>
|
||||
<img
|
||||
src="/images/floor-plans/marasi-drive/podium.png"
|
||||
alt="podium"
|
||||
className="w-full"
|
||||
/>
|
||||
<Button
|
||||
variant="cta"
|
||||
className="absolute 2xl:top-[1.667vw] 2xl:right-[1.667vw] md:max-2xl:top-6 md:max-2xl:right-6 top-4 right-4"
|
||||
onlyIcon
|
||||
size="small"
|
||||
onClick={() =>
|
||||
setModal(
|
||||
<VideoModal src="/videos/marasi-drive/PodiumMarasiDrive.mp4" />
|
||||
)
|
||||
}
|
||||
>
|
||||
<span className="2xl:size-[1.111vw] size-4">
|
||||
<PlayIcon />
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="2xl:space-y-[1.667vw] space-y-6">
|
||||
<p className="font-medium text-h4">Indoor Amenities</p>
|
||||
<div className="grid md:grid-cols-4 grid-cols-3 2xl:gap-[1.111vw] gap-4">
|
||||
<AmentitiesBadge icon={<LoungeIcon />} title="Indoor Lounge" />
|
||||
<AmentitiesBadge icon={<MonkeyBarsIcon />} title="Monkey Bars" />
|
||||
<AmentitiesBadge icon={<KaraokeIcon />} title="Karaoke Room" />
|
||||
<AmentitiesBadge icon={<ArcadeGameIcon />} title="Arcade Games" />
|
||||
<AmentitiesBadge icon={<ClimbingWallIcon />} title="Climbing Wall" />
|
||||
<AmentitiesBadge
|
||||
icon={<PlaystationIcon />}
|
||||
title="Playstation Deck"
|
||||
/>
|
||||
<AmentitiesBadge
|
||||
icon={<FullyEquippedGymIcon />}
|
||||
title="Fully Equipped Gym"
|
||||
/>
|
||||
<AmentitiesBadge icon={<ChangingRoomIcon />} title="Changing Rooms" />
|
||||
<AmentitiesBadge
|
||||
icon={<HammockMovieLoungeIcon />}
|
||||
title="Hammock Movie Lounge"
|
||||
/>
|
||||
<AmentitiesBadge icon={<GuestRooms />} title="Guest Rooms" />
|
||||
<AmentitiesBadge
|
||||
icon={<MultiballInteractiveGamingIcon />}
|
||||
title="Multi Ball Interactive Gaming"
|
||||
/>
|
||||
<AmentitiesBadge
|
||||
icon={<MultiPurposeRoomWithKitchenIcon />}
|
||||
title="Multi-purpose Room for Kitchen"
|
||||
/>
|
||||
<AmentitiesBadge icon={<GamingLoungeIcon />} title="Gaming Lounge" />
|
||||
</div>
|
||||
</div>
|
||||
<hr className="border-[#E2E2DC] h-[0.069vw]" />
|
||||
<div className="2xl:space-y-[1.667vw] space-y-6">
|
||||
<p className="font-medium text-h4">Outdoor Amenities</p>
|
||||
<div className="grid md:grid-cols-4 grid-cols-3 2xl:gap-x-[1.111vw] 2xl:gap-y-[1.667vw] gap-x-4 gap-y-6">
|
||||
<AmentitiesBadge
|
||||
icon={<UrbanBeachPoolIcon />}
|
||||
title="Urban Beach Pool"
|
||||
/>
|
||||
<AmentitiesBadge icon={<JacuzziIcon />} title="Jacuzzi" />
|
||||
<AmentitiesBadge icon={<YogaLoungeIcon />} title="Yoga Lounge" />
|
||||
<AmentitiesBadge icon={<SunLoungeIcon />} title="Sun Lounging Pool" />
|
||||
<AmentitiesBadge
|
||||
icon={<CascadingLeisurePoolIcon />}
|
||||
title="Cascading Leisure Pool"
|
||||
/>
|
||||
<AmentitiesBadge icon={<AquaCyclingIcon />} title="AquaCycling" />
|
||||
<AmentitiesBadge icon={<OpenAirGymIcon />} title="Open-Air Gym" />
|
||||
<AmentitiesBadge
|
||||
icon={<RoveBeverageTruckIcon />}
|
||||
title="Rove Beverage Truck"
|
||||
/>
|
||||
<AmentitiesBadge
|
||||
icon={<CabanasWithDaybeds />}
|
||||
title="Cabanas with Daybeds"
|
||||
/>
|
||||
<AmentitiesBadge
|
||||
icon={<IntegratedLapPoolIcon />}
|
||||
title="Integrated Lap Pool"
|
||||
/>
|
||||
<AmentitiesBadge
|
||||
icon={<SunkenGardensIcon />}
|
||||
title="Sunken Gardens"
|
||||
/>
|
||||
<AmentitiesBadge
|
||||
icon={<MultiPurposeRoomWithKitchenIcon />}
|
||||
title="Outdoor Multi-Purpose Terrace"
|
||||
/>
|
||||
<AmentitiesBadge
|
||||
icon={<GamingTerraceIcon />}
|
||||
title="Outdoor Gaming Terrace"
|
||||
/>
|
||||
<AmentitiesBadge
|
||||
icon={<CoworkingIcon />}
|
||||
title="Outdoor Coworking Space"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<AmentitiesContentSlider
|
||||
srcs={[
|
||||
"/images/floor-plans/marasi-drive/podium/content1.jpg",
|
||||
"/images/floor-plans/marasi-drive/podium/content2.jpg",
|
||||
"/images/floor-plans/marasi-drive/podium/content3.jpg",
|
||||
"/images/floor-plans/marasi-drive/podium/content4.jpg",
|
||||
"/images/floor-plans/marasi-drive/podium/content5.jpg",
|
||||
"/images/floor-plans/marasi-drive/podium/content6.jpg",
|
||||
"/images/floor-plans/marasi-drive/podium/content7.jpg",
|
||||
"/images/floor-plans/marasi-drive/podium/content8.jpg",
|
||||
"/images/floor-plans/marasi-drive/podium/content9.jpg",
|
||||
"/images/floor-plans/marasi-drive/podium/content10.jpg",
|
||||
"/images/floor-plans/marasi-drive/podium/content11.jpg",
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PodiumMarasiDrive;
|
||||
@@ -1,101 +0,0 @@
|
||||
import useModalStore from "../../../stores/useModalStore";
|
||||
import AmentitiesBadge from "../../AmentitiesCard";
|
||||
import BBQTerraceIcon from "../../icons/amentities/BBQTerraceIcon";
|
||||
import CabanasWithDaybeds from "../../icons/amentities/CabanasWithDaybeds";
|
||||
import CommunalDiningTablesRoundedIcon from "../../icons/amentities/CommunalDiningTablesRoundedIcon";
|
||||
import FirePitIcon from "../../icons/amentities/FirePitIcon";
|
||||
import LoungingSpaceIcon from "../../icons/amentities/LoungingSpaceIcon";
|
||||
import OutdoorKitchenIcon from "../../icons/amentities/OutdoorKitchenIcon";
|
||||
import RooftopGardenIcon from "../../icons/amentities/RooftopGardenIcon";
|
||||
import StargazingIcon from "../../icons/amentities/StargazingIcon";
|
||||
import SunkenSeatingIcon from "../../icons/amentities/SunkenSeatingIcon";
|
||||
import ViewingDeckWithWingsIcon from "../../icons/amentities/ViewingDeckWithWingsIcon";
|
||||
import PlayIcon from "../../icons/PlayIcon";
|
||||
import Badge from "../../ui/Badge";
|
||||
import Button from "../../ui/Button";
|
||||
import VideoModal from "../../VideoModal";
|
||||
|
||||
function RooftopMarasiDrive() {
|
||||
const { setModal } = useModalStore();
|
||||
|
||||
return (
|
||||
<div className="2xl:space-y-[2.222vw] space-y-8">
|
||||
<div className="2xl:space-y-[1.667vw] space-y-6">
|
||||
<div className="2xl:space-y-[0.556vw] space-y-2 border-b border-[#E2E2DC] 2xl:pb-[1.667vw] pb-6">
|
||||
<p className="text-h4 font-medium">Rooftop</p>
|
||||
<Badge variant="secondary" text="10 Amenities" />
|
||||
</div>
|
||||
<div className="bg-[#F3F3F2] 2xl:rounded-[1.111vw] rounded-2xl 2xl:p-[1.111vw] p-4 relative">
|
||||
<img
|
||||
src="/images/floor-plans/compass.png"
|
||||
className="absolute top-0 left-0 size-[7.222vw]"
|
||||
alt=""
|
||||
/>
|
||||
<img
|
||||
src="/images/floor-plans/marasi-drive/rooftop.png"
|
||||
alt="podium"
|
||||
className="w-full"
|
||||
/>
|
||||
<Button
|
||||
variant="cta"
|
||||
className="absolute 2xl:top-[1.667vw] 2xl:right-[1.667vw] md:max-2xl:top-6 md:max-2xl:right-6 top-4 right-4"
|
||||
onlyIcon
|
||||
size="small"
|
||||
onClick={() =>
|
||||
setModal(
|
||||
<VideoModal src="/videos/marasi-drive/RooftopMarasiDrive.mp4" />
|
||||
)
|
||||
}
|
||||
>
|
||||
<span className="2xl:size-[1.111vw] size-4">
|
||||
<PlayIcon />
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="2xl:space-y-[1.667vw] space-y-6">
|
||||
<p className="font-medium text-h4">Amenities</p>
|
||||
<div className="grid md:grid-cols-4 grid-cols-3 2xl:gap-[1.111vw] gap-4">
|
||||
<AmentitiesBadge icon={<StargazingIcon />} title="Stargazing Point" />
|
||||
<AmentitiesBadge icon={<BBQTerraceIcon />} title="BBQ Terrace" />
|
||||
<AmentitiesBadge
|
||||
icon={<OutdoorKitchenIcon />}
|
||||
title="Outdoor Kitchen"
|
||||
/>
|
||||
<AmentitiesBadge
|
||||
icon={<CabanasWithDaybeds />}
|
||||
title="Cabanas with Daybeds"
|
||||
/>
|
||||
<AmentitiesBadge
|
||||
icon={<ViewingDeckWithWingsIcon />}
|
||||
title="Viewing Deck with Wings"
|
||||
/>
|
||||
<AmentitiesBadge
|
||||
icon={<LoungingSpaceIcon />}
|
||||
title="Lounging Space"
|
||||
/>
|
||||
<AmentitiesBadge
|
||||
icon={<SunkenSeatingIcon />}
|
||||
title="Sunken Seating"
|
||||
/>
|
||||
<AmentitiesBadge icon={<FirePitIcon />} title="Firepit" />
|
||||
<AmentitiesBadge
|
||||
icon={<RooftopGardenIcon />}
|
||||
title="Rooftop Garden"
|
||||
/>
|
||||
<AmentitiesBadge
|
||||
icon={<CommunalDiningTablesRoundedIcon />}
|
||||
title="Communal Dining Tables"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<img
|
||||
src="/images/floor-plans/marasi-drive/rooftop/content.jpg"
|
||||
alt="rooftop"
|
||||
className="w-full 2xl:rounded-[1.111vw] rounded-2xl select-none"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default RooftopMarasiDrive;
|
||||
@@ -1,130 +0,0 @@
|
||||
import useModalStore from "../../../stores/useModalStore";
|
||||
import AmentitiesBadge from "../../AmentitiesCard";
|
||||
import AmentitiesContentSlider from "../../AmentitiesContentSlider";
|
||||
import AmenitiesBadge from "../../icons/AmenitiesBadge";
|
||||
import AmphitheatreIcon from "../../icons/amentities/AmphitheatreIcon";
|
||||
import BoulderingWallIcon from "../../icons/amentities/BoulderingWallIcon";
|
||||
import ChangingRoomIcon from "../../icons/amentities/ChangingRoomIcon";
|
||||
import ChessIcon from "../../icons/amentities/ChessIcon";
|
||||
import CinemaIcon from "../../icons/amentities/CinemaIcon";
|
||||
import ClimbingWallIcon from "../../icons/amentities/ClimbingWallIcon";
|
||||
import CommunalDiningTablesIcon from "../../icons/amentities/CommunalDiningTablesIcon";
|
||||
import CoworkingIcon from "../../icons/amentities/CoworkingIcon";
|
||||
import LushLandscapeIcon from "../../icons/amentities/LushLandscapeIcon";
|
||||
import MultiPurposeIcon from "../../icons/amentities/MultiPurposeIcon";
|
||||
import PingPongIcon from "../../icons/amentities/PingPongIcon";
|
||||
import PingPongInTubeIcon from "../../icons/amentities/PingPongInTubeIcon";
|
||||
import PoolIcon from "../../icons/amentities/PoolIcon";
|
||||
import RunningWheelIcon from "../../icons/amentities/RunningWheelIcon";
|
||||
import SunLoungeIcon from "../../icons/amentities/SunLoungeIcon";
|
||||
import SuspendedLoungingNetsIcon from "../../icons/amentities/SuspendedLoungingNetsIcon";
|
||||
import WellnessIcon from "../../icons/amentities/WellnessIcon";
|
||||
import PlayIcon from "../../icons/PlayIcon";
|
||||
import Badge from "../../ui/Badge";
|
||||
import Button from "../../ui/Button";
|
||||
import VideoModal from "../../VideoModal";
|
||||
|
||||
function SkyGardenMarasiDrive() {
|
||||
const { setModal } = useModalStore();
|
||||
|
||||
return (
|
||||
<div className="2xl:space-y-[2.222vw] space-y-8">
|
||||
<div className="2xl:space-y-[1.667vw] space-y-6">
|
||||
<div className="2xl:space-y-[0.556vw] space-y-2 border-b border-[#E2E2DC] 2xl:pb-[1.667vw] pb-6">
|
||||
<p className="text-h4 font-medium">Sky Garden</p>
|
||||
<Badge variant="secondary" text="15 Amenities" />
|
||||
</div>
|
||||
<div className="flex items-center 2xl:gap-[1.667vw] gap-4">
|
||||
<AmenitiesBadge count={3} type="Indoor" />
|
||||
<AmenitiesBadge count={12} type="Outdoor" />
|
||||
</div>
|
||||
<div className="bg-[#F3F3F2] 2xl:rounded-[1.111vw] rounded-2xl 2xl:p-[1.111vw] p-4 relative">
|
||||
<img
|
||||
src="/images/floor-plans/compass.png"
|
||||
className="absolute top-0 left-0 size-[7.222vw]"
|
||||
alt=""
|
||||
/>
|
||||
<img
|
||||
src="/images/floor-plans/marasi-drive/sky-garden.png"
|
||||
alt="sky-garden"
|
||||
className="w-full"
|
||||
/>
|
||||
<Button
|
||||
variant="cta"
|
||||
className="absolute 2xl:top-[1.667vw] 2xl:right-[1.667vw] md:max-2xl:top-6 md:max-2xl:right-6 top-4 right-4"
|
||||
onlyIcon
|
||||
size="small"
|
||||
onClick={() =>
|
||||
setModal(
|
||||
<VideoModal src="/videos/marasi-drive/SkyGardenMarasiDrive.mp4" />
|
||||
)
|
||||
}
|
||||
>
|
||||
<span className="2xl:size-[1.111vw] size-4">
|
||||
<PlayIcon />
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="2xl:space-y-[1.667vw] space-y-6">
|
||||
<p className="font-medium text-h4">Indoor Amenities</p>
|
||||
<div className="grid md:grid-cols-4 grid-cols-3 2xl:gap-[1.111vw] gap-4">
|
||||
<AmentitiesBadge icon={<PoolIcon />} title="Indoor Lap Pool" />
|
||||
<AmentitiesBadge icon={<WellnessIcon />} title="Wellness Features" />
|
||||
<AmentitiesBadge icon={<ChangingRoomIcon />} title="Changing Rooms" />
|
||||
</div>
|
||||
</div>
|
||||
<hr className="border-[#E2E2DC] h-[0.069vw]" />
|
||||
<div className="2xl:space-y-[1.667vw] space-y-6">
|
||||
<p className="font-medium text-h4">Outdoor Amenities</p>
|
||||
<div className="grid grid-cols-3 2xl:gap-x-[1.111vw] 2xl:gap-y-[1.667vw] gap-x-4 gap-y-6">
|
||||
<AmentitiesBadge icon={<PingPongIcon />} title="Padel Pong" />
|
||||
<AmentitiesBadge icon={<SunLoungeIcon />} title="Sun Lounging Deck" />
|
||||
<AmentitiesBadge icon={<CinemaIcon />} title="Outdoor Cinema" />
|
||||
<AmentitiesBadge
|
||||
icon={<BoulderingWallIcon />}
|
||||
title="Bouldering Wall"
|
||||
/>
|
||||
<AmentitiesBadge
|
||||
icon={<PingPongInTubeIcon />}
|
||||
title="Ping Pong in a Tube"
|
||||
/>
|
||||
<AmentitiesBadge icon={<AmphitheatreIcon />} title="Amphitheatre" />
|
||||
<AmentitiesBadge
|
||||
icon={<CommunalDiningTablesIcon />}
|
||||
title="Communal Dining Tables"
|
||||
/>
|
||||
<AmentitiesBadge
|
||||
icon={<SuspendedLoungingNetsIcon />}
|
||||
title="Suspended Lounging Nets "
|
||||
/>
|
||||
<AmentitiesBadge
|
||||
icon={<LushLandscapeIcon />}
|
||||
title="Lush Landscape"
|
||||
/>
|
||||
<AmentitiesBadge icon={<RunningWheelIcon />} title="Running Wheel" />
|
||||
<AmentitiesBadge icon={<ChessIcon />} title="Chess Tables" />
|
||||
<AmentitiesBadge icon={<ClimbingWallIcon />} title="Climbing Wall" />
|
||||
<AmentitiesBadge
|
||||
icon={<CoworkingIcon />}
|
||||
title="Outdoor Coworking Space"
|
||||
/>
|
||||
<AmentitiesBadge
|
||||
icon={<MultiPurposeIcon />}
|
||||
title="Multi-purpose Court"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<AmentitiesContentSlider
|
||||
srcs={[
|
||||
"/images/floor-plans/marasi-drive/skygarden/content1.jpg",
|
||||
"/images/floor-plans/marasi-drive/skygarden/content2.jpg",
|
||||
"/images/floor-plans/marasi-drive/skygarden/content3.jpg",
|
||||
"/images/floor-plans/marasi-drive/skygarden/content4.jpg",
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SkyGardenMarasiDrive;
|
||||
Reference in New Issue
Block a user