+ // ── 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 (
+
setPopup(null)}
+ >
+ {/* ── Header ──────────────────────────────────────── */}
+
+
{floorTitle}
+
+
+ {complexConfig.hasCombinable && !isSpecialFloor && (
+
+ )}
-
-
-
+
+
+ {/* ── Controls ────────────────────────────────────── */}
+
+
+
+
+
+ {/* Combinable toggle (Dubai Marina only) */}
+ {complexConfig.hasCombinable && !isSpecialFloor && (
+
+
+
+
+ )}
+
+ {/* ── Floor plan ──────────────────────────────────── */}
!isMobile && setPosition({ x: e.clientX, y: e.clientY })
}
>
- {unitsOnFloor && wing === "East" && (
-
- )}
- {wing === "West" && unitsOnFloor && (
- <>
- {floorNumber < 24 ? (
-
- ) : (
-
- )}
- >
- )}
+
- );
- }
-
- // 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 (
-
setPopup(null)}>
-
-
{selectedFloor} floor
-
-
- {!isSpecialFloor && }
-
-
-
-
-
-
- {!isSpecialFloor && (
-
-
-
-
- )}
-
- !isMobile && setPosition({ x: e.clientX, y: e.clientY })
- }
- >
- {selectedFloor && unitsOnFloor && (
- <>
- {+selectedFloor >= 7 && +selectedFloor < 39 && (
- <>
- {!isCombinable ? (
-
- ) : (
-
- )}
- >
- )}
- {selectedFloor === "39-40" && (
-
- )}
- {selectedFloor === "41-42" && (
-
- )}
- >
- )}
-
-
-
- );
- }
-
- // Default fallback
- return
Unsupported complex: {complexName}
;
+
+ );
}
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 (
+ <>
+
+
+
+
+
+
+
+ >
+ );
+ }
+
+ if (complexName === "dubai-marina") {
+ const floorNum = parseInt(selectedFloor.split(" ").at(-1)!);
+ const floorData = floorsData?.find((item) => item.floor === floorNum);
+
+ return (
+ <>
+
+
+
+
+
+
+
+ >
+ );
+ }
+
+ // HQ: no unit type badges
+ return null;
+}
+
+// ─── Floor plan renderer ────────────────────────────────
+
+function FloorPlanRenderer({
+ complexName,
+ config,
+ selectedFloor,
+ unitsOnFloor,
+ floorNumber,
+}: {
+ complexName: ComplexName;
+ config: ReturnType
;
+ selectedFloor: string;
+ unitsOnFloor?: Unit[];
+ floorNumber: number;
+}) {
+ if (!selectedFloor || !unitsOnFloor) return null;
+
+ if (!config) {
+ return (
+
+ Floor plan coming soon
+
+ );
+ }
+
+ // Component-based rendering (Marasi Drive inline SVG)
+ if (config.component) {
+ const Component = config.component;
+ return (
+
+ );
+ }
+
+ // Image-based rendering (Dubai Marina, HQ)
+ return (
+
+ );
+}
diff --git a/src/components/floor-plans/dubai-marina/GroundDubaiMarina.tsx b/src/components/floor-plans/dubai-marina/GroundDubaiMarina.tsx
deleted file mode 100644
index d910769..0000000
--- a/src/components/floor-plans/dubai-marina/GroundDubaiMarina.tsx
+++ /dev/null
@@ -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 (
-
-
-
-
-

-

-
-
-
-
-
Amenities
-
- {[
- "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) => (
-
- ))}
-
-
-

-
- );
-}
-
-export default GroundDubaiMarina;
diff --git a/src/components/floor-plans/dubai-marina/PodiumDubaiMarina.tsx b/src/components/floor-plans/dubai-marina/PodiumDubaiMarina.tsx
deleted file mode 100644
index 05be4d3..0000000
--- a/src/components/floor-plans/dubai-marina/PodiumDubaiMarina.tsx
+++ /dev/null
@@ -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 (
-
-
-
-
-
-

-

-
-
-
-
-
Indoor Amenities
-
- {[
- "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) => (
-
- ))}
-
-
-
-
-
Outdoor Amenities
-
- {[
- "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) => (
-
- ))}
-
-
-
-
- );
-}
-
-export default PodiumDubaiMarina;
diff --git a/src/components/floor-plans/dubai-marina/RooftopDubaiMarina.tsx b/src/components/floor-plans/dubai-marina/RooftopDubaiMarina.tsx
deleted file mode 100644
index b5a649b..0000000
--- a/src/components/floor-plans/dubai-marina/RooftopDubaiMarina.tsx
+++ /dev/null
@@ -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 (
-
-
-
-
-

-

-
-
-
-
-
Amenities
-
- {amenities.map((amentity) => (
-
- ))}
-
-
-

-
- );
-}
-
-export default RooftopDubaiMarina;
diff --git a/src/components/floor-plans/marasi-drive/GroundMarasiDrive.tsx b/src/components/floor-plans/marasi-drive/GroundMarasiDrive.tsx
deleted file mode 100644
index a9b5d0f..0000000
--- a/src/components/floor-plans/marasi-drive/GroundMarasiDrive.tsx
+++ /dev/null
@@ -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 (
-
-
-
-
-

-

-
-
-
-
-
Amenities
-
-
} title="Rove Café" />
-
} title="Lobby Lounge" />
-
} title="Coworking Space" />
-
}
- title="Outdoor Terrace"
- />
-
}
- title="Private Meeting Rooms"
- />
-
}
- title="Convenience Store"
- />
-
}
- title="Soundproof Meeting Pods"
- />
-
-
-
-
- );
-}
-
-export default GroundMarasiDrive;
diff --git a/src/components/floor-plans/marasi-drive/PodiumMarasiDrive.tsx b/src/components/floor-plans/marasi-drive/PodiumMarasiDrive.tsx
deleted file mode 100644
index 6fd060d..0000000
--- a/src/components/floor-plans/marasi-drive/PodiumMarasiDrive.tsx
+++ /dev/null
@@ -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 (
-
-
-
-
-
-

-

-
-
-
-
-
Indoor Amenities
-
-
} title="Indoor Lounge" />
-
} title="Monkey Bars" />
-
} title="Karaoke Room" />
-
} title="Arcade Games" />
-
} title="Climbing Wall" />
-
}
- title="Playstation Deck"
- />
-
}
- title="Fully Equipped Gym"
- />
-
} title="Changing Rooms" />
-
}
- title="Hammock Movie Lounge"
- />
-
} title="Guest Rooms" />
-
}
- title="Multi Ball Interactive Gaming"
- />
-
}
- title="Multi-purpose Room for Kitchen"
- />
-
} title="Gaming Lounge" />
-
-
-
-
-
Outdoor Amenities
-
-
}
- title="Urban Beach Pool"
- />
-
} title="Jacuzzi" />
-
} title="Yoga Lounge" />
-
} title="Sun Lounging Pool" />
-
}
- title="Cascading Leisure Pool"
- />
-
} title="AquaCycling" />
-
} title="Open-Air Gym" />
-
}
- title="Rove Beverage Truck"
- />
-
}
- title="Cabanas with Daybeds"
- />
-
}
- title="Integrated Lap Pool"
- />
-
}
- title="Sunken Gardens"
- />
-
}
- title="Outdoor Multi-Purpose Terrace"
- />
-
}
- title="Outdoor Gaming Terrace"
- />
-
}
- title="Outdoor Coworking Space"
- />
-
-
-
-
- );
-}
-
-export default PodiumMarasiDrive;
diff --git a/src/components/floor-plans/marasi-drive/RooftopMarasiDrive.tsx b/src/components/floor-plans/marasi-drive/RooftopMarasiDrive.tsx
deleted file mode 100644
index 3d9207c..0000000
--- a/src/components/floor-plans/marasi-drive/RooftopMarasiDrive.tsx
+++ /dev/null
@@ -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 (
-
-
-
-
-

-

-
-
-
-
-
Amenities
-
-
} title="Stargazing Point" />
-
} title="BBQ Terrace" />
-
}
- title="Outdoor Kitchen"
- />
-
}
- title="Cabanas with Daybeds"
- />
-
}
- title="Viewing Deck with Wings"
- />
-
}
- title="Lounging Space"
- />
-
}
- title="Sunken Seating"
- />
-
} title="Firepit" />
-
}
- title="Rooftop Garden"
- />
-
}
- title="Communal Dining Tables"
- />
-
-
-

-
- );
-}
-
-export default RooftopMarasiDrive;
diff --git a/src/components/floor-plans/marasi-drive/SkyGardenMarasiDrive.tsx b/src/components/floor-plans/marasi-drive/SkyGardenMarasiDrive.tsx
deleted file mode 100644
index 70d4966..0000000
--- a/src/components/floor-plans/marasi-drive/SkyGardenMarasiDrive.tsx
+++ /dev/null
@@ -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 (
-
-
-
-
-
-

-

-
-
-
-
-
Indoor Amenities
-
-
} title="Indoor Lap Pool" />
-
} title="Wellness Features" />
-
} title="Changing Rooms" />
-
-
-
-
-
Outdoor Amenities
-
-
} title="Padel Pong" />
-
} title="Sun Lounging Deck" />
-
} title="Outdoor Cinema" />
-
}
- title="Bouldering Wall"
- />
-
}
- title="Ping Pong in a Tube"
- />
-
} title="Amphitheatre" />
-
}
- title="Communal Dining Tables"
- />
-
}
- title="Suspended Lounging Nets "
- />
-
}
- title="Lush Landscape"
- />
-
} title="Running Wheel" />
-
} title="Chess Tables" />
-
} title="Climbing Wall" />
-
}
- title="Outdoor Coworking Space"
- />
-
}
- title="Multi-purpose Court"
- />
-
-
-
-
- );
-}
-
-export default SkyGardenMarasiDrive;
diff --git a/src/constants/floor-ranges.ts b/src/constants/floor-ranges.ts
new file mode 100644
index 0000000..202e584
--- /dev/null
+++ b/src/constants/floor-ranges.ts
@@ -0,0 +1,23 @@
+// ─── Marasi Drive ────────────────────────────────────────
+
+/** Marasi Drive East Wing: floors 5–21 */
+export const MARASI_EAST_FLOORS = [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21];
+
+/** Marasi Drive West Wing lower: floors 5–21 */
+export const MARASI_WEST_LOWER_FLOORS = [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21];
+
+/** Marasi Drive West Wing upper: floors 24–31 */
+export const MARASI_WEST_UPPER_FLOORS = [24, 25, 26, 27, 28, 29, 30, 31];
+
+// ─── Dubai Marina ────────────────────────────────────────
+
+/** Dubai Marina: standard floors (7–38, excluding 21) */
+export const DUBAI_MARINA_STANDARD_FLOORS = [
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+];
+
+// ─── HQ ──────────────────────────────────────────────────
+
+/** HQ: floors sharing the 5 / 9 / 13 layout */
+export const HQ_5_9_13_FLOORS = [5, 9, 13];
diff --git a/src/data/complex-config.ts b/src/data/complex-config.ts
new file mode 100644
index 0000000..1e8d2a5
--- /dev/null
+++ b/src/data/complex-config.ts
@@ -0,0 +1,71 @@
+import { ComplexName } from "../types/ComplexName";
+import { FloorData } from "../types/Floor";
+import { marasiDriveFloors } from "./floors/marasi-drive";
+import { dubaiMarinaFloors } from "./floors/dubai-marina";
+import { hqFloors } from "./floors/hq";
+
+// ─── Types ───────────────────────────────────────────────
+
+export interface ComplexConfig {
+ /** Slug used in routing, e.g. "dubai-marina" */
+ slug: ComplexName;
+ /** Full project name from the backend, e.g. "Rove Home Dubai Marina" */
+ projectName: string;
+ /** All floor data (residential + amenities) for this complex */
+ floors: FloorData[];
+ /** Whether this complex has wings (East/West) */
+ hasWings: boolean;
+ /** Whether some floors support combinable unit layouts */
+ hasCombinable: boolean;
+}
+
+// ─── Configuration registry ──────────────────────────────
+
+const complexConfigs: Record = {
+ "marasi-drive": {
+ slug: "marasi-drive",
+ projectName: "Rove Home Marasi Drive",
+ floors: marasiDriveFloors,
+ hasWings: true,
+ hasCombinable: false,
+ },
+ "dubai-marina": {
+ slug: "dubai-marina",
+ projectName: "Rove Home Dubai Marina",
+ floors: dubaiMarinaFloors,
+ hasWings: false,
+ hasCombinable: true,
+ },
+ hq: {
+ slug: "hq",
+ projectName: "Rove Home HQ",
+ floors: hqFloors,
+ hasWings: false,
+ hasCombinable: false,
+ },
+};
+
+// ─── Lookup helpers ──────────────────────────────────────
+
+/** Get the full complex config by slug */
+export function getComplexConfig(complexName: ComplexName): ComplexConfig {
+ return complexConfigs[complexName];
+}
+
+/** Get the floor data array for a complex */
+export function getComplexFloors(complexName: ComplexName): FloorData[] {
+ return complexConfigs[complexName].floors;
+}
+
+/** Get the full project name from slug */
+export function getProjectName(complexName: ComplexName): string {
+ return complexConfigs[complexName].projectName;
+}
+
+/** Resolve a slug from the full project name (e.g. "Rove Home Dubai Marina" → "dubai-marina") */
+export function getSlugFromProjectName(projectName: string): ComplexName | null {
+ const entry = Object.values(complexConfigs).find(
+ (c) => c.projectName === projectName
+ );
+ return entry?.slug ?? null;
+}
diff --git a/src/data/complexNamesSlugs.ts b/src/data/complexNamesSlugs.ts
deleted file mode 100644
index ef0366a..0000000
--- a/src/data/complexNamesSlugs.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export const complexNamesSlugs = {
- "Rove Home Dubai Marina": "dubai-marina",
- "Rove Home Marasi Drive": "marasi-drive",
-};
diff --git a/src/data/floor-plan-config.ts b/src/data/floor-plan-config.ts
new file mode 100644
index 0000000..0339d15
--- /dev/null
+++ b/src/data/floor-plan-config.ts
@@ -0,0 +1,174 @@
+import { ComplexName } from "../types/ComplexName";
+import { FloorPlanMasks } from "../types/FloorPlanMasks";
+import { dubaiMarinaMasks as dubaiMarina738Masks } from "./floor-plan-masks/dubai-marina_7-38";
+import { dubaiMarinaMasks as dubaiMarina738CombMasks } from "./floor-plan-masks/dubai-marina_7-38_comb";
+import { dubaiMarinaMasks as dubaiMarina3940Masks } from "./floor-plan-masks/dubai-marina_39-40";
+import { dubaiMarinaMasks as dubaiMarina4142Masks } from "./floor-plan-masks/dubai-marina_41-42";
+import { hq5_9_13Masks } from "./floor-plan-masks/hq_5_9_13";
+import { Unit } from "../types/IUnit";
+import { filterDuplicateUnits } from "../utils/filterDuplicateUnits";
+import {
+ DUBAI_MARINA_STANDARD_FLOORS,
+ HQ_5_9_13_FLOORS,
+ MARASI_EAST_FLOORS,
+ MARASI_WEST_LOWER_FLOORS,
+ MARASI_WEST_UPPER_FLOORS,
+} from "../constants/floor-ranges";
+import {
+ floorPlanMarasiDriveEastMasks,
+ floorPlanMarasiDriveWestLowerMasks,
+ floorPlanMarasiDriveWestUpperMasks,
+} from "./floor-plan-masks/marasi-drive";
+import FloorPlanMarasiDriveEast from "../components/FloorPlanMarasiDriveEast";
+import FloorPlanMarasiDriveWestLower from "../components/FloorPlanMarasiDriveWestLower";
+import FloorPlanMarasiDriveWestUpper from "../components/FloorPlanMarasiDriveWestUpper";
+
+// ─── Types ───────────────────────────────────────────────
+
+export interface FloorPlanLayoutConfig {
+ viewBox: string;
+ imagePath?: string;
+ masks: FloorPlanMasks;
+ getMaskKey: (unitNo: string) => string;
+ filterUnits?: (units: Unit[]) => Unit[];
+ /** React component for inline-SVG floor plans (Marasi Drive) */
+ component?: React.ComponentType<{
+ selectedFloor: string | null;
+ unitsOnFloor: Unit[];
+ chosenUnit?: Unit;
+ }>;
+ /** Wing designation for Marasi Drive popups */
+ wing?: "East" | "West";
+}
+
+// ─── Layout configs ──────────────────────────────────────
+
+const dubaiMarinaStandard: FloorPlanLayoutConfig = {
+ viewBox: "0 0 632 467.5",
+ imagePath: "/images/floor-plans/dubai-marina/floor-plan_7-38.png",
+ masks: dubaiMarina738Masks,
+ getMaskKey: (unitNo) => unitNo.slice(-2),
+};
+
+const dubaiMarinaStandardComb: FloorPlanLayoutConfig = {
+ viewBox: "0 0 626 465",
+ imagePath: "/images/floor-plans/dubai-marina/floor-plan_7-38_comb.png",
+ masks: dubaiMarina738CombMasks,
+ getMaskKey: (unitNo) => unitNo.split("-")[0].slice(-2),
+ filterUnits: filterDuplicateUnits,
+};
+
+const dubaiMarina3940: FloorPlanLayoutConfig = {
+ viewBox: "0 0 632 467.5",
+ imagePath: "/images/floor-plans/dubai-marina/floor-plan_39-40.png",
+ masks: dubaiMarina3940Masks,
+ getMaskKey: (unitNo) => unitNo.slice(-2),
+};
+
+const dubaiMarina4142: FloorPlanLayoutConfig = {
+ viewBox: "0 0 632 467.5",
+ imagePath: "/images/floor-plans/dubai-marina/floor-plan_39-40.png",
+ masks: dubaiMarina4142Masks,
+ getMaskKey: (unitNo) => unitNo.slice(-2),
+};
+
+const hq5913: FloorPlanLayoutConfig = {
+ viewBox: "0 0 632 467.5",
+ imagePath: "/images/floor-plans/hq/floor-plan_5-9-13.png",
+ masks: hq5_9_13Masks,
+ getMaskKey: (unitNo) => unitNo.slice(-2),
+};
+
+// ─── Marasi Drive layout configs ─────────────────────────
+
+const marasiDriveEast: FloorPlanLayoutConfig = {
+ viewBox: "0 0 633.97 568.52",
+ masks: floorPlanMarasiDriveEastMasks,
+ getMaskKey: (unitNo) => unitNo.slice(-2),
+ wing: "East",
+ component: FloorPlanMarasiDriveEast,
+};
+
+const marasiDriveWestLower: FloorPlanLayoutConfig = {
+ viewBox: "0 0 633.97 568.52",
+ masks: floorPlanMarasiDriveWestLowerMasks,
+ getMaskKey: (unitNo) => unitNo.slice(-2),
+ wing: "West",
+ component: FloorPlanMarasiDriveWestLower,
+};
+
+const marasiDriveWestUpper: FloorPlanLayoutConfig = {
+ viewBox: "0 0 633.97 568.52",
+ masks: floorPlanMarasiDriveWestUpperMasks,
+ getMaskKey: (unitNo) => unitNo.slice(-2),
+ wing: "West",
+ component: FloorPlanMarasiDriveWestUpper,
+};
+
+// ─── Config resolver ─────────────────────────────────────
+
+/**
+ * Returns the floor plan layout config for a given complex, floor, and options.
+ * For Marasi Drive, pass the wing via the `wing` parameter or parse it from `floorStr`.
+ */
+export function getFloorPlanConfig(
+ complexName: ComplexName,
+ floorStr: string,
+ options?: { isCombinable?: boolean; wing?: "East" | "West" }
+): FloorPlanLayoutConfig | null {
+ const floorNum = parseInt(floorStr);
+
+ // ── Marasi Drive ──────────────────────────────────────
+ if (complexName === "marasi-drive") {
+ // Wing can be passed explicitly or parsed from "East 5" / "West 5"
+ const wing = options?.wing || (floorStr.startsWith("East") ? "East" : floorStr.startsWith("West") ? "West" : null);
+ const num = wing ? parseInt(floorStr.split(" ").at(-1) || "") : floorNum;
+
+ if (wing === "East" && MARASI_EAST_FLOORS.includes(num)) {
+ return marasiDriveEast;
+ }
+ if (wing === "West") {
+ if (MARASI_WEST_LOWER_FLOORS.includes(num)) return marasiDriveWestLower;
+ if (MARASI_WEST_UPPER_FLOORS.includes(num)) return marasiDriveWestUpper;
+ }
+ return null;
+ }
+
+ // ── Dubai Marina ──────────────────────────────────────
+ if (complexName === "dubai-marina") {
+ if (DUBAI_MARINA_STANDARD_FLOORS.includes(floorNum)) {
+ return options?.isCombinable ? dubaiMarinaStandardComb : dubaiMarinaStandard;
+ }
+ if (floorStr === "39-40" || floorNum === 39 || floorNum === 40) {
+ return dubaiMarina3940;
+ }
+ if (floorStr === "41-42" || floorNum === 41 || floorNum === 42) {
+ return dubaiMarina4142;
+ }
+ }
+
+ // ── HQ ────────────────────────────────────────────────
+ if (complexName === "hq") {
+ if (HQ_5_9_13_FLOORS.includes(floorNum)) {
+ return hq5913;
+ }
+ // Other HQ floor layouts can be added here as mask data becomes available
+ }
+
+ return null;
+}
+
+/**
+ * Returns the floor plan layout config for OnFloorMask (unit detail view).
+ * Uses the unit's floor number and wing directly.
+ */
+export function getFloorPlanConfigForUnit(
+ complexName: ComplexName,
+ unit: Unit
+): FloorPlanLayoutConfig | null {
+ const floorStr = unit.floor.toString();
+ return getFloorPlanConfig(complexName, floorStr, {
+ isCombinable: unit.unitNo.endsWith("-C"),
+ wing: unit.wing as "East" | "West" | undefined,
+ });
+}
diff --git a/src/data/floor-plan-masks/dubai-marina_39-40.ts b/src/data/floor-plan-masks/dubai-marina_39-40.ts
index 8111c22..5f57bdf 100644
--- a/src/data/floor-plan-masks/dubai-marina_39-40.ts
+++ b/src/data/floor-plan-masks/dubai-marina_39-40.ts
@@ -1,4 +1,4 @@
-import { FloorPlanMasks } from "./marasi-drive";
+import { FloorPlanMasks } from "../../types/FloorPlanMasks";
export const dubaiMarinaMasks: FloorPlanMasks = new Map([
[
diff --git a/src/data/floor-plan-masks/dubai-marina_41-42.ts b/src/data/floor-plan-masks/dubai-marina_41-42.ts
index 142cc43..f2bab23 100644
--- a/src/data/floor-plan-masks/dubai-marina_41-42.ts
+++ b/src/data/floor-plan-masks/dubai-marina_41-42.ts
@@ -1,4 +1,4 @@
-import { FloorPlanMasks } from "./marasi-drive";
+import { FloorPlanMasks } from "../../types/FloorPlanMasks";
export const dubaiMarinaMasks: FloorPlanMasks = new Map([
[
diff --git a/src/data/floor-plan-masks/dubai-marina_7-38.ts b/src/data/floor-plan-masks/dubai-marina_7-38.ts
index 3b7e91b..b1a7faa 100644
--- a/src/data/floor-plan-masks/dubai-marina_7-38.ts
+++ b/src/data/floor-plan-masks/dubai-marina_7-38.ts
@@ -1,4 +1,4 @@
-import { FloorPlanMasks } from "./marasi-drive";
+import { FloorPlanMasks } from "../../types/FloorPlanMasks";
// export const floorPlanMasksDubaiMarina = [
// {
diff --git a/src/data/floor-plan-masks/dubai-marina_7-38_comb.ts b/src/data/floor-plan-masks/dubai-marina_7-38_comb.ts
index b98dc99..822ff64 100644
--- a/src/data/floor-plan-masks/dubai-marina_7-38_comb.ts
+++ b/src/data/floor-plan-masks/dubai-marina_7-38_comb.ts
@@ -1,4 +1,4 @@
-import { FloorPlanMasks } from "./marasi-drive";
+import { FloorPlanMasks } from "../../types/FloorPlanMasks";
export const dubaiMarinaMasks: FloorPlanMasks = new Map([
[
diff --git a/src/data/floor-plan-masks/hq_5_9_13.ts b/src/data/floor-plan-masks/hq_5_9_13.ts
new file mode 100644
index 0000000..32c136b
--- /dev/null
+++ b/src/data/floor-plan-masks/hq_5_9_13.ts
@@ -0,0 +1,28 @@
+import { FloorPlanMasks } from "../../types/FloorPlanMasks";
+
+export const hq5_9_13Masks: FloorPlanMasks = new Map([
+ [
+ "5",
+ {
+ d: "M100 100 L 200 100 L 200 200 L 100 200 Z",
+ textTransform: [150, 150],
+ formattedUnitType: "1BR",
+ },
+ ],
+ [
+ "9",
+ {
+ d: "M100 100 L 200 100 L 200 200 L 100 200 Z",
+ textTransform: [150, 150],
+ formattedUnitType: "1BR",
+ },
+ ],
+ [
+ "13",
+ {
+ d: "M100 100 L 200 100 L 200 200 L 100 200 Z",
+ textTransform: [150, 150],
+ formattedUnitType: "1BR",
+ },
+ ],
+]);
diff --git a/src/data/floor-plan-masks/marasi-drive.ts b/src/data/floor-plan-masks/marasi-drive.ts
index 819f007..6115796 100644
--- a/src/data/floor-plan-masks/marasi-drive.ts
+++ b/src/data/floor-plan-masks/marasi-drive.ts
@@ -211,14 +211,7 @@
// },
// ];
-export type FloorPlanMasks = Map<
- string,
- {
- d: string;
- textTransform: [number, number];
- formattedUnitType: string;
- }
->;
+import { FloorPlanMasks } from "../../types/FloorPlanMasks";
export const floorPlanMarasiDriveEastMasks: FloorPlanMasks = new Map([
[
diff --git a/src/data/floors/hq.ts b/src/data/floors/hq.ts
index 8a60e25..8c1e949 100644
--- a/src/data/floors/hq.ts
+++ b/src/data/floors/hq.ts
@@ -32,4 +32,37 @@ export const hqFloors: FloorData[] = [
},
video: "/videos/hq/roof.mp4",
},
+
+ // Residential floor 29-30 (combined)
+ {
+ id: "floor-29-30",
+ name: "29-30",
+ displayName: "29-30",
+ type: "residential",
+ floorNumber: 29,
+ },
+
+ // Residential floors 28 down to 17
+ ...Array.from({ length: 12 }, (_, i) => {
+ const floor = 28 - i;
+ return {
+ id: `floor-${floor}`,
+ name: `${floor}`,
+ displayName: `${floor}`,
+ type: "residential" as const,
+ floorNumber: floor,
+ };
+ }),
+
+ // Residential floors 14 down to 5
+ ...Array.from({ length: 10 }, (_, i) => {
+ const floor = 14 - i;
+ return {
+ id: `floor-${floor}`,
+ name: `${floor}`,
+ displayName: `${floor}`,
+ type: "residential" as const,
+ floorNumber: floor,
+ };
+ }),
];
diff --git a/src/data/masks.ts b/src/data/masks.ts
index 236214c..aca39bd 100644
--- a/src/data/masks.ts
+++ b/src/data/masks.ts
@@ -181,8 +181,10 @@ export const floorsMasks = {
hq: {
"Roof Level":
"M1628.34 295.302c-.4 10.458 3.96 18.094 6.18 20.604l.18 79.548c.64-1.031 2.71-3.258 5.91-3.913 4.01-.818 74.13 3.6 83.13 4.337 7.21.589 29.73 12.464 40.1 18.328l-4.05 3.803 96.2 57.429 31.74 4.385 35.34-33.022h4.9l.59-8.958h10.42c4.93-5.825 16.13-17.881 21.53-19.503 6.76-2.028 60.09 0 64.45 0 3.5 0 26.72 17.386 37.9 26.079l-5.73 4.051 22.45 15.332h6.57l34.13 24.095v4.016l31.04 23.912 5.29-2.556 31.21 25.19v5.111l29.57 22.451h4.75l27.93 19.166v3.651l10 7.185 3.71-3.374 37.96 26.886-.44-23.635c4.09-1.312 6.34-5.028 6.85-10.857.41-4.663-4.39-10.298-6.85-12.532-83.11-64.82-250.44-195.35-254.87-198.912-5.54-4.451-11.68-10.585-20.19-11.476-8.5-.89-49.36-3.166-57.77-2.968-6.73.159-25.16 19.127-33.54 28.592v25.34l-3.17-.692v-1.385l-186.82-125.793-15.46-7.108c-25.8-1.587-78.97-4.805-85.22-4.976-7.82-.213-15.42 9.095-15.92 22.169",
- "30": "M2306.48 629.883c-.12-4.43-3.21-8.743-4.74-10.346l-37.96-26.886-3.71 3.374-10-7.185v-3.651l-27.93-19.166h-4.75l-29.57-22.452v-5.111l-31.21-25.189-5.3 2.555-31.03-23.912v-4.015l-34.13-24.095h-6.57l-22.45-15.333 5.73-4.05c-11.18-8.693-34.4-26.079-37.9-26.079-4.37 0-57.69-2.028-64.45 0-5.4 1.622-16.6 13.678-21.53 19.503h-10.42l-.59 8.958h-4.9l-35.34 33.022-31.74-4.386-96.2-57.428 4.05-3.803c-10.37-5.864-32.89-17.739-40.1-18.328-9-.737-79.12-5.155-83.13-4.337-3.2.655-5.27 2.881-5.91 3.913-2.27.66-6.81 4.179-6.81 12.976s10.7 25.146 16.05 32.221v10.776h30.6l18.5-19.707 28.76 1.807c3.14-.162 10.84.097 16.55 2.433s80.81 47.585 117.64 69.917h37.58l28.57-26.054h18.17l23.72-27.164c2.7-3.162 55.36-6.834 60.93-2.783l271.9 199.66v-6.248c3.25-2.623 9.73-8.977 9.62-13.407",
- "29": "M1643.94 451.428c-5.35 1.686-33.71 21.737 0 48.36.07.055 0-5.57 0-5.57-7.22-8.621-8.44-13.81-5.87-21.053 3.36-9.473 16.72-8.086 24.37-7.602 15.49.978 54.16 4.62 71.55 6.319 5.81 2.446 18.26 8.113 21.61 11.212s9.55 2.378 12.23 1.631l22.67 15.063c-.1.69-.1 2.258.73 3.004.83.745 28.24 16.677 41.85 24.55l5.38-1.865 17.53 12.431h37.58l27.45-25.172h7.54l5.62-.621v-7.252l7.15 7.252c5.87-6.665 19-20.2 24.55-21.029 6.94-1.036 56.97 1.865 60.29 1.865 2.65 0 21.47 13.546 30.55 20.319h8.81v2.555l9.32 6.234 3.6 2.076v3.293c0 .595 119.03 83.07 178.55 124.233 2.34-1.84 7.35-5.706 8.68-6.444 1.66-.923 2.77-.369 5.26 1.292 1.99 1.33 18.11 12.834 25.92 18.42v-15.392l-271.9-199.66c-5.57-4.051-58.22-.379-60.93 2.782l-23.72 27.165h-18.17l-28.57 26.054h-37.58c-36.83-22.333-111.93-67.581-117.64-69.917s-13.41-2.596-16.55-2.433l-28.76-1.807-18.5 19.707z",
+ "29-30":
+ "M1640.61 391.543c4.01-.818 74.13 3.601 83.13 4.337 7.21.589 29.73 12.464 40.1 18.328l-4.05 3.803 96.2 57.428 31.74 4.386 35.34-33.022h4.9l.59-8.958h10.42c4.93-5.825 16.13-17.881 21.53-19.503 6.76-2.028 60.08 0 64.45 0 3.5 0 26.72 17.386 37.9 26.079l-5.73 4.051 22.45 15.333h6.57l34.13 24.093v4.016l31.03 23.912 5.3-2.555 31.21 25.19v5.11l29.57 22.452h4.75l27.92 19.166v3.651l10.01 7.185 3.71-3.375 37.96 26.887c1.53 1.603 4.62 5.917 4.74 10.347.11 4.43-6.37 10.783-9.62 13.406v21.639c-7.81-5.586-23.93-17.089-25.92-18.419-2.49-1.662-3.6-2.216-5.26-1.293-1.33.738-6.34 4.604-8.68 6.444-59.52-41.163-178.55-123.638-178.55-124.233v-3.293l-3.6-2.076-9.32-6.234v-2.555h-8.81c-9.08-6.773-27.9-20.319-30.55-20.319-3.32 0-53.35-2.901-60.29-1.865-5.55.829-18.68 14.364-24.55 21.028l-7.15-7.251v7.251l-5.62.622h-7.54l-27.45 25.172h-37.58l-17.53-12.43-5.38 1.864c-13.61-7.873-41.02-23.804-41.85-24.55s-.83-2.313-.73-3.004l-22.67-15.063c-2.68.747-8.88 1.467-12.23-1.631-3.35-3.099-15.8-8.766-21.61-11.212-17.39-1.699-56.06-5.341-71.55-6.319-7.65-.484-21.01-1.871-24.37 7.602-2.57 7.243-1.35 12.432 5.87 21.053 0 .042.07 5.609 0 5.57-33.18-26.207-6.22-46.045-.27-48.267l.27-.093v-10.776c-5.35-7.074-16.05-23.423-16.05-32.22s4.54-12.316 6.81-12.976c.64-1.031 2.71-3.258 5.91-3.913",
+ // "30": "M2306.48 629.883c-.12-4.43-3.21-8.743-4.74-10.346l-37.96-26.886-3.71 3.374-10-7.185v-3.651l-27.93-19.166h-4.75l-29.57-22.452v-5.111l-31.21-25.189-5.3 2.555-31.03-23.912v-4.015l-34.13-24.095h-6.57l-22.45-15.333 5.73-4.05c-11.18-8.693-34.4-26.079-37.9-26.079-4.37 0-57.69-2.028-64.45 0-5.4 1.622-16.6 13.678-21.53 19.503h-10.42l-.59 8.958h-4.9l-35.34 33.022-31.74-4.386-96.2-57.428 4.05-3.803c-10.37-5.864-32.89-17.739-40.1-18.328-9-.737-79.12-5.155-83.13-4.337-3.2.655-5.27 2.881-5.91 3.913-2.27.66-6.81 4.179-6.81 12.976s10.7 25.146 16.05 32.221v10.776h30.6l18.5-19.707 28.76 1.807c3.14-.162 10.84.097 16.55 2.433s80.81 47.585 117.64 69.917h37.58l28.57-26.054h18.17l23.72-27.164c2.7-3.162 55.36-6.834 60.93-2.783l271.9 199.66v-6.248c3.25-2.623 9.73-8.977 9.62-13.407",
+ // "29": "M1643.94 451.428c-5.35 1.686-33.71 21.737 0 48.36.07.055 0-5.57 0-5.57-7.22-8.621-8.44-13.81-5.87-21.053 3.36-9.473 16.72-8.086 24.37-7.602 15.49.978 54.16 4.62 71.55 6.319 5.81 2.446 18.26 8.113 21.61 11.212s9.55 2.378 12.23 1.631l22.67 15.063c-.1.69-.1 2.258.73 3.004.83.745 28.24 16.677 41.85 24.55l5.38-1.865 17.53 12.431h37.58l27.45-25.172h7.54l5.62-.621v-7.252l7.15 7.252c5.87-6.665 19-20.2 24.55-21.029 6.94-1.036 56.97 1.865 60.29 1.865 2.65 0 21.47 13.546 30.55 20.319h8.81v2.555l9.32 6.234 3.6 2.076v3.293c0 .595 119.03 83.07 178.55 124.233 2.34-1.84 7.35-5.706 8.68-6.444 1.66-.923 2.77-.369 5.26 1.292 1.99 1.33 18.11 12.834 25.92 18.42v-15.392l-271.9-199.66c-5.57-4.051-58.22-.379-60.93 2.782l-23.72 27.165h-18.17l-28.57 26.054h-37.58c-36.83-22.333-111.93-67.581-117.64-69.917s-13.41-2.596-16.55-2.433l-28.76-1.807-18.5 19.707z",
"28": "M2308.01 678.627c.11-6.353-7.39-11.779-11.15-13.698-7.81-5.586-23.93-17.09-25.92-18.42-2.49-1.661-3.6-2.215-5.26-1.292-1.33.739-6.34 4.604-8.68 6.444-59.52-41.163-178.55-123.638-178.55-124.233v-3.293l-3.6-2.076-9.32-6.234v-2.555h-8.81c-9.08-6.773-27.9-20.319-30.55-20.319-3.32 0-53.35-2.901-60.29-1.865-5.55.829-18.68 14.364-24.55 21.029l-7.15-7.252v7.252l-5.62.621h-7.54l-27.45 25.172h-37.58l-17.53-12.431-5.38 1.865c-13.61-7.873-41.02-23.804-41.85-24.55s-.83-2.314-.73-3.004l-22.67-15.063c-2.68.747-8.88 1.468-12.23-1.631s-15.8-8.766-21.61-11.212c-17.39-1.699-56.06-5.341-71.55-6.319-15.49-.979-21.55.001-24.42 7.512-3.83 10.026.57 15.312 5.92 21.104v25.429l80.9 2.031v-16.776l32.46 14.745 10.53-1.395 90.1 51.209h35.64l27.45-24.703h18.7c7.02-7.554 22.09-22.66 26.16-22.66h60.29c2.29 0 23.02 11.981 33.09 17.972h6.27v7.573l12.92 9.376 7.88-5.639 35.34 24.243v8.169l29.14 19.92 7.66-3.939 30.61 20.37v9.229l26 17.894 6.75-4.502 28.25 18.119v8.779l6.92 4.614 8.68-5.568-.96 31.872c.21 1.062 6.22 6.773 6.22 6.773s15.8 9.212 25.92 14.371v-30.234c3.67-1.627 11.03-6.47 11.15-12.824",
"27": "M2308.01 734.658c0-4.954-7.43-10.326-11.15-12.973-10.12-5.159-25.92-14.371-25.92-14.371s-6.01-5.711-6.22-6.773l.96-31.872-8.68 5.568-6.92-4.615v-8.778l-28.25-18.119-6.75 4.502-26-17.895v-9.228l-30.61-20.37-7.66 3.939-29.14-19.92v-8.169l-35.34-24.243-7.88 5.639-12.92-9.376v-7.574h-6.27c-10.07-5.99-30.8-17.971-33.09-17.971h-60.29c-4.07 0-19.14 15.106-26.16 22.66h-18.7l-27.45 24.703h-35.64l-90.1-51.21-10.53 1.396-32.46-14.745v16.775l-80.9-2.03c-5.45.703-7.48 6.598-7.81 9.457-2.74 1.649-8.24 6.576-8.24 13.086 0 5.511 3.94 10.991 6.82 14.011-.3-4.839 1.08-15.263 8.9-18.254 7.83-2.991 63.52-1.246 90.38 0l25.45 13.078 4.35-1.187 24.54 14.048 69.6 38.076h35.64l27.45-23.577h7.54v-8.161h3.96l7.2 4.627c7.07-6.084 22.2-18.458 26.16-19.281 4.95-1.028 57.91 2.442 60.29 2.442 1.9 0 19.68 11.741 28.34 17.611l4.75-1.8 194.72 128.184c.09 2.096.61 6.529 2.01 7.492 1.39.964 29.87 19.223 43.93 28.232v8.406c2.7-1.749 8.09-6.485 8.09-11.44",
"26": "M1634.71 556.162c.52.547 1 1.014 1.43 1.385v13.554c1.04-3.223 4.8-9.635 11.47-9.49 8.35.182 84.64 5.171 88.52 5.971 3.11.64 82.49 42.935 121.8 64.003h35.64l27.46-21.821h7.53l32.3-10.305 32.65-.939v-8.074l7.72-4.016c8.33.432 25.48 1.296 27.41 1.296 1.92 0 181.66 111.25 271.28 166.875v-16.908c-14.06-9.009-42.54-27.269-43.93-28.232s-1.92-5.397-2.01-7.493l-194.71-128.183-4.76 1.799c-8.66-5.87-26.44-17.61-28.34-17.61-2.38 0-55.34-3.471-60.29-2.442-3.96.822-19.09 13.197-26.16 19.281l-7.2-4.628h-3.96v8.161h-7.53l-27.46 23.578h-35.64l-69.6-38.077-24.53-14.047-4.36 1.187-25.45-13.079c-26.86-1.246-82.55-2.991-90.38 0-7.82 2.991-9.19 13.416-8.9 18.254",
diff --git a/src/data/projects.ts b/src/data/projects.ts
index f939e95..e3f4841 100644
--- a/src/data/projects.ts
+++ b/src/data/projects.ts
@@ -2601,27 +2601,27 @@ export const projects: Project[] = [
amenitiesFloors: [
{
title: "Roof Level",
- total: 7,
+ total: 6,
},
{
title: "Reset 16",
- total: 7,
+ total: 12,
},
{
title: "Podium Level",
- total: 7,
+ total: 21,
},
{
title: "Ground Level",
- total: 7,
+ total: 15,
},
{
title: "Parking Levels",
- total: 7,
+ total: 0,
},
{
title: "Arcade Level",
- total: 7,
+ total: 0,
},
],
},
diff --git a/src/pages/FloorsPage.tsx b/src/pages/FloorsPage.tsx
index 8acd0ad..0a07278 100644
--- a/src/pages/FloorsPage.tsx
+++ b/src/pages/FloorsPage.tsx
@@ -9,9 +9,7 @@ import { SPECIAL_FLOORS } from "../constants/floors";
import { Unit } from "../types/IUnit";
import { ComplexName } from "../types/ComplexName";
import FloorPlanViewer from "../components/floor-plans/FloorPlanViewer";
-import { marasiDriveFloors } from "../data/floors/marasi-drive";
-import { dubaiMarinaFloors } from "../data/floors/dubai-marina";
-import { hqFloors } from "../data/floors/hq";
+import { getComplexFloors } from "../data/complex-config";
function FloorsPage() {
const [selectedFloor, setSelectedFloor] = useState(null);
@@ -53,16 +51,8 @@ function FloorsPage() {
// Get floor data based on complex
const allFloors = useMemo(() => {
- if (complexName === "marasi-drive") {
- return marasiDriveFloors;
- }
- if (complexName === "dubai-marina") {
- return dubaiMarinaFloors;
- }
- if (complexName === "hq") {
- return hqFloors;
- }
- return [];
+ if (!complexName) return [];
+ return getComplexFloors(complexName);
}, [complexName]);
// Find current floor
@@ -92,7 +82,6 @@ function FloorsPage() {
onFloorSelect={setSelectedFloor}
/>
)}
- {!currentFloor && complexName === "hq" && <>HQ>}
{!currentFloor && selectedFloor && (
Floor not found: {selectedFloor}
)}
diff --git a/src/types/FloorPlanMasks.ts b/src/types/FloorPlanMasks.ts
new file mode 100644
index 0000000..6045507
--- /dev/null
+++ b/src/types/FloorPlanMasks.ts
@@ -0,0 +1,8 @@
+export type FloorPlanMasks = Map<
+ string,
+ {
+ d: string;
+ textTransform: [number, number];
+ formattedUnitType: string;
+ }
+>;