From 8ed33a13b121f1b72166876e970f703a8b9a1ae3 Mon Sep 17 00:00:00 2001 From: inmake Date: Wed, 21 Jan 2026 17:47:31 +0500 Subject: [PATCH 1/3] Fix typos in "Amenities" across multiple components and data files; refactor related code for consistency. Update brochure links and improve layout in AboutHQ and AboutMarasiDrive components. --- src/components/AboutHQ.tsx | 14 +++--- src/components/AboutMarasiDrive.tsx | 34 ++++++------- src/components/FloorPopup.tsx | 40 +++++++-------- .../dubai-marina/GroundDubaiMarina.tsx | 2 +- .../dubai-marina/PodiumDubaiMarina.tsx | 2 +- .../dubai-marina/RooftopDubaiMarina.tsx | 2 +- .../marasi-drive/GroundMarasiDrive.tsx | 4 +- .../marasi-drive/PodiumMarasiDrive.tsx | 6 +-- .../marasi-drive/RooftopMarasiDrive.tsx | 4 +- .../marasi-drive/SkyGardenMarasiDrive.tsx | 6 +-- src/components/header/BrochuresDropdown.tsx | 2 +- .../header/ProjectBrochuresList.tsx | 4 +- src/components/ui/BrochureButton.tsx | 4 +- src/data/aboutDubaiMarina.ts | 4 +- src/data/aboutMarasiDrive.ts | 4 +- src/data/brochures.ts | 49 +++++-------------- src/data/projects.ts | 8 +-- src/types/Project.ts | 6 +-- 18 files changed, 84 insertions(+), 111 deletions(-) diff --git a/src/components/AboutHQ.tsx b/src/components/AboutHQ.tsx index 4a13d0f..52e8d0f 100644 --- a/src/components/AboutHQ.tsx +++ b/src/components/AboutHQ.tsx @@ -53,7 +53,7 @@ export default function AboutHQ() { {`Welcome to the office you actually want to show up for`} -

+

HQ by Rove was born out of a question: what if the office could feel alive again? Now, the first ever hospitality-branded office building in Dubai is here to @@ -65,12 +65,12 @@ export default function AboutHQ() {

-
+

{`Welcome to the office you actually want to show up for`}

-

+

HQ by Rove was born out of a question: what if the office could feel alive again? Now, the first ever hospitality-branded office building in Dubai is here to @@ -91,7 +91,7 @@ export default function AboutHQ() {

More than an office,
a lifestyle.

-

+

{`Living rooms became boardrooms, kitchens became creative hubs. But as the world returned, the office didn’t keep up. HQ by Rove is the answer - an office with a living touch.`} @@ -286,7 +286,7 @@ export default function AboutHQ() { {marasiDriveMapCards.map((card) => ( ))} -

+
-

+

{`Work looks different here`}

@@ -327,7 +327,7 @@ export default function AboutHQ() { />

diff --git a/src/components/AboutMarasiDrive.tsx b/src/components/AboutMarasiDrive.tsx index a8a3bef..a53bfca 100644 --- a/src/components/AboutMarasiDrive.tsx +++ b/src/components/AboutMarasiDrive.tsx @@ -53,7 +53,7 @@ function AboutMarasiDrive() { {`A home for the young and young in heart`} -

+

The dynamic essence of Rove comes to life at our new location in Marasi Drive, Business Bay. Enjoy an urban living experience beyond the ordinary. @@ -62,12 +62,12 @@ function AboutMarasiDrive() {

-
+

{`A home for the young and young in heart`}

-

+

The dynamic essence of Rove comes to life at our new location in Marasi Drive, Business Bay. Enjoy an urban living experience beyond the ordinary. @@ -79,11 +79,11 @@ function AboutMarasiDrive() {

-

+

{`What makes a Rove Home?`}

-

+

{`Experience the difference with Rove Home where modern amenities, trendy interiors, and smart features cater to your unique style. Rove Home is your destination for artful inspiration and cleverly activated spaces.`} @@ -118,11 +118,11 @@ function AboutMarasiDrive() {

-

+

{`Expandable living solutions`}

-

+

{`ORI introduces a revolutionary solution to apartment living, where space is not just a constraint but an opportunity.`}

@@ -158,10 +158,10 @@ function AboutMarasiDrive() {
-

+

Inspired interiors

-

+

{`Smart, flexible designs maximize every inch. The ORI Cloud Bed expands space by 33%, while the Flexibed transforms living areas into bedrooms. Multipurpose layouts adapt effortlessly—blending @@ -173,14 +173,14 @@ function AboutMarasiDrive() {

-
+
-

+

{`A home for the young and young in heart`}

-

+

{`The dynamic essence of Rove comes to life at our new location in Marasi Drive, Business Bay. Enjoy an urban living experience beyond the ordinary.`} @@ -201,7 +201,7 @@ function AboutMarasiDrive() {

{`Explore the neighbourhood`}

-

+

{`With Dubai's trendiest spots right at your doorstep, explore nearby entertainment and dining experiences in just 15 minutes. Live your best life at Rove Home Marasi Drive!`} @@ -229,7 +229,7 @@ function AboutMarasiDrive() { {marasiDriveMapCards.map((card) => ( ))} -

+
-

+

{`Live Different with Rove Home`}

@@ -268,8 +268,8 @@ function AboutMarasiDrive() { link="/files/marasi-drive/Main Brochure.pdf" /> void; } -function getAmentiesCount(complexName: string, title: string) { - const amenties = projects.find( +function getAmenitiesCount(complexName: string, title: string) { + const amenities = projects.find( (proj) => proj.slug === complexName - )?.amentiesFloors; - return amenties?.find((amenty) => amenty.title === title); + )?.amenitiesFloors; + return amenities?.find((amenity) => amenity.title === title); } function FloorPopup({ title, complexName, data, onSelect }: FloorPopupProps) { const { setPopup } = usePopupStore(); - const amentiesCount = useMemo( + const amenitiesCount = useMemo( () => Number.isNaN(+title.at(-1)!) - ? getAmentiesCount(complexName, title) + ? getAmenitiesCount(complexName, title) : null, [title, complexName] ); @@ -35,16 +35,16 @@ function FloorPopup({ title, complexName, data, onSelect }: FloorPopupProps) {

- {amentiesCount ? title : `${title.split(" ").at(-1)} floor`} + {amenitiesCount ? title : `${title.split(" ").at(-1)} floor`}

- {complexName === "marasi-drive" && !amentiesCount && ( + {complexName === "marasi-drive" && !amenitiesCount && (

{title.split(" ")[0]} Wing

)}

- {amentiesCount !== null - ? `${amentiesCount?.total} Amenties` + {amenitiesCount !== null + ? `${amenitiesCount?.total} Amenities` : `${ complexName === "marasi-drive" && data ? data[ @@ -57,7 +57,7 @@ function FloorPopup({ title, complexName, data, onSelect }: FloorPopupProps) { : data?.others.totalUnits } apartments`}

- {!amentiesCount && ( + {!amenitiesCount && (
@@ -66,12 +66,12 @@ function FloorPopup({ title, complexName, data, onSelect }: FloorPopupProps) {
)}
- {((amentiesCount?.indoor && amentiesCount?.outdoor) || - !amentiesCount) && ( + {((amenitiesCount?.indoor && amenitiesCount?.outdoor) || + !amenitiesCount) && (
)}
- {!amentiesCount && data ? ( + {!amenitiesCount && data ? ( Object.entries( data[ title.split(" ")[0] === "East" @@ -92,20 +92,20 @@ function FloorPopup({ title, complexName, data, onSelect }: FloorPopupProps) { )) ) : ( <> - {amentiesCount?.indoor && ( + {amenitiesCount?.indoor && (

- {amentiesCount.indoor} + {amenitiesCount.indoor}

-

Indoor Amenties

+

Indoor Amenities

)} - {amentiesCount?.outdoor && ( + {amenitiesCount?.outdoor && (

- {amentiesCount.outdoor} + {amenitiesCount.outdoor}

-

Outdoor Amenties

+

Outdoor Amenities

)} diff --git a/src/components/floor-plans/dubai-marina/GroundDubaiMarina.tsx b/src/components/floor-plans/dubai-marina/GroundDubaiMarina.tsx index 828085d..d910769 100644 --- a/src/components/floor-plans/dubai-marina/GroundDubaiMarina.tsx +++ b/src/components/floor-plans/dubai-marina/GroundDubaiMarina.tsx @@ -13,7 +13,7 @@ function GroundDubaiMarina() {

Ground Level

- +

Podium

- +
diff --git a/src/components/floor-plans/dubai-marina/RooftopDubaiMarina.tsx b/src/components/floor-plans/dubai-marina/RooftopDubaiMarina.tsx index d94661e..b5a649b 100644 --- a/src/components/floor-plans/dubai-marina/RooftopDubaiMarina.tsx +++ b/src/components/floor-plans/dubai-marina/RooftopDubaiMarina.tsx @@ -30,7 +30,7 @@ function RooftopDubaiMarina() {

Sky 44 - Rooftop

- +

Ground Level

- +
-

Amenties

+

Amenities

} title="Rove Café" /> } title="Lobby Lounge" /> diff --git a/src/components/floor-plans/marasi-drive/PodiumMarasiDrive.tsx b/src/components/floor-plans/marasi-drive/PodiumMarasiDrive.tsx index 6e3d0ad..6fd060d 100644 --- a/src/components/floor-plans/marasi-drive/PodiumMarasiDrive.tsx +++ b/src/components/floor-plans/marasi-drive/PodiumMarasiDrive.tsx @@ -41,7 +41,7 @@ function PodiumMarasiDrive() {

Podium Level

- +
@@ -76,7 +76,7 @@ function PodiumMarasiDrive() {
-

Indoor Amenties

+

Indoor Amenities

} title="Indoor Lounge" /> } title="Monkey Bars" /> @@ -110,7 +110,7 @@ function PodiumMarasiDrive() {

-

Outdoor Amenties

+

Outdoor Amenities

} diff --git a/src/components/floor-plans/marasi-drive/RooftopMarasiDrive.tsx b/src/components/floor-plans/marasi-drive/RooftopMarasiDrive.tsx index fe0e391..3d9207c 100644 --- a/src/components/floor-plans/marasi-drive/RooftopMarasiDrive.tsx +++ b/src/components/floor-plans/marasi-drive/RooftopMarasiDrive.tsx @@ -23,7 +23,7 @@ function RooftopMarasiDrive() {

Rooftop

- +
-

Amenties

+

Amenities

} title="Stargazing Point" /> } title="BBQ Terrace" /> diff --git a/src/components/floor-plans/marasi-drive/SkyGardenMarasiDrive.tsx b/src/components/floor-plans/marasi-drive/SkyGardenMarasiDrive.tsx index 8cb9769..70d4966 100644 --- a/src/components/floor-plans/marasi-drive/SkyGardenMarasiDrive.tsx +++ b/src/components/floor-plans/marasi-drive/SkyGardenMarasiDrive.tsx @@ -32,7 +32,7 @@ function SkyGardenMarasiDrive() {

Sky Garden

- +
@@ -67,7 +67,7 @@ function SkyGardenMarasiDrive() {
-

Indoor Amenties

+

Indoor Amenities

} title="Indoor Lap Pool" /> } title="Wellness Features" /> @@ -76,7 +76,7 @@ function SkyGardenMarasiDrive() {

-

Outdoor Amenties

+

Outdoor Amenities

} title="Padel Pong" /> } title="Sun Lounging Deck" /> diff --git a/src/components/header/BrochuresDropdown.tsx b/src/components/header/BrochuresDropdown.tsx index 5511795..131ee9c 100644 --- a/src/components/header/BrochuresDropdown.tsx +++ b/src/components/header/BrochuresDropdown.tsx @@ -37,7 +37,7 @@ export default function BrochuresDropdown() { animate={{ opacity: 1 }} exit={{ opacity: 0 }} transition={{ bounce: 0, duration: 0.3 }} - className="max-2xl:hidden p-[1.667vw] flex gap-[1.111vw] justify-stretch items-stretch fixed top-[calc(3.889vw+20px)] left-[40vw] w-[50vw] rounded-[1.111vw] bg-white shadow-[0_2px_8px_rgba(0,0,0,0.15)]" + className="max-2xl:hidden p-[1.111vw] flex gap-[1.111vw] justify-stretch items-stretch fixed top-[calc(3.889vw+20px)] left-[21%] rounded-[1.111vw] bg-white shadow-[0_2px_8px_rgba(0,0,0,0.15)]" > {projectBrochures.map((project, index) => ( -

{projectTitle}

+
+

{projectTitle}

- {title} + {title} diff --git a/src/data/aboutDubaiMarina.ts b/src/data/aboutDubaiMarina.ts index dc87620..7973f2a 100644 --- a/src/data/aboutDubaiMarina.ts +++ b/src/data/aboutDubaiMarina.ts @@ -6,8 +6,8 @@ export const dubaiMarinaDescriptionBadges = [ export const dubaiMarinaFeatures = [ { - name: "Life-enhancing Amenties", - image: "/images/about-complex/dubai-marina/amenties.jpg", + name: "Life-enhancing Amenities", + image: "/images/about-complex/dubai-marina/amenities.jpg", }, { name: "Community", diff --git a/src/data/aboutMarasiDrive.ts b/src/data/aboutMarasiDrive.ts index 730ad88..da88d7b 100644 --- a/src/data/aboutMarasiDrive.ts +++ b/src/data/aboutMarasiDrive.ts @@ -14,8 +14,8 @@ export const marasiDriveFeatures = [ image: "/images/about-complex/marasi-drive/location.jpg", }, { - name: "Fully Loaded Amenties", - image: "/images/about-complex/marasi-drive/amenties.jpg", + name: "Fully Loaded Amenities", + image: "/images/about-complex/marasi-drive/amenities.jpg", }, { name: "Rove-Inspired Design", diff --git a/src/data/brochures.ts b/src/data/brochures.ts index e290f00..44ce5f6 100644 --- a/src/data/brochures.ts +++ b/src/data/brochures.ts @@ -24,14 +24,6 @@ export const projectBrochures: ProjectBrochures[] = [ title: "Technical Brochure", link: "/files/brochures/marasi-drive/Technical Brochure.pdf", }, - { - title: "Factsheet", - link: "/files/brochures/marasi-drive/Factsheet.pdf", - }, - { - title: "Reasons to buy", - link: "/files/brochures/marasi-drive/Reasons to buy.pdf", - }, ], }, { @@ -46,24 +38,8 @@ export const projectBrochures: ProjectBrochures[] = [ link: "/files/brochures/downtown/Amenities Brochure.pdf", }, { - title: "Unit Plans", - link: "/files/brochures/downtown/Unit Plan.pdf", - }, - { - title: "Typical Floor plan 2-13", - link: "/files/brochures/downtown/Typical Floor plan 2-13.pdf", - }, - { - title: "Typical Floor plan 14-19", - link: "/files/brochures/downtown/Typical Floor plan 14-19.pdf", - }, - { - title: "Factsheet", - link: "/files/brochures/downtown/Factsheet.pdf", - }, - { - title: "Reasons to buy", - link: "/files/brochures/downtown/Reasons to buy.pdf", + title: "Technical Brochure", + link: "/files/brochures/downtown/Technical Brochure.pdf", }, ], }, @@ -82,21 +58,18 @@ export const projectBrochures: ProjectBrochures[] = [ title: "Technical Brochure", link: "/files/brochures/dubai-marina/Technical Brochure.pdf", }, + ], + }, + { + projectTitle: "Rove Home HQ", + brochures: [ { - title: "Factsheet", - link: "/files/brochures/dubai-marina/Factsheet.pdf", + title: "Main Brochure", + link: "/files/brochures/hq/Main Brochure.pdf", }, { - title: "RHDM Arabic", - link: "/files/brochures/dubai-marina/RHDM Arabic.pdf", - }, - { - title: "RHDM Turkish", - link: "/files/brochures/dubai-marina/RHDM Turkish.pdf", - }, - { - title: "RHDM Russian", - link: "/files/brochures/dubai-marina/RHDM Russian.pdf", + title: "Technical Brochure", + link: "/files/brochures/hq/Technical Brochure.pdf", }, ], }, diff --git a/src/data/projects.ts b/src/data/projects.ts index fb174b4..8863d5d 100644 --- a/src/data/projects.ts +++ b/src/data/projects.ts @@ -572,7 +572,7 @@ export const projects: Project[] = [ tourAvailable: true, }, ], - amentiesFloors: [ + amenitiesFloors: [ { title: "Rooftop", total: 10, @@ -1971,7 +1971,7 @@ export const projects: Project[] = [ tourAvailable: true, }, ], - amentiesFloors: [ + amenitiesFloors: [ { title: "Rooftop", total: 14, @@ -1994,6 +1994,6 @@ export const projects: Project[] = [ img: "/images/search/rove_home_hq.png", buildingType: "commercial", types: [], - amentiesFloors: [], - } + amenitiesFloors: [], + }, ]; diff --git a/src/types/Project.ts b/src/types/Project.ts index bd8c510..dd66aeb 100644 --- a/src/types/Project.ts +++ b/src/types/Project.ts @@ -6,12 +6,12 @@ export default interface Project { img: string; buildingType: "residential" | "commercial"; types: UnitType[]; - amentiesFloors: AmentiesFloor[]; + amenitiesFloors: AmenitiesFloor[]; } -export interface AmentiesFloor { +export interface AmenitiesFloor { title: string; total: number; indoor?: number; outdoor?: number; -} \ No newline at end of file +} From 36046214e1b7d746c4aa177438ff7dc9eb673c14 Mon Sep 17 00:00:00 2001 From: inmake Date: Wed, 21 Jan 2026 18:04:59 +0500 Subject: [PATCH 2/3] Refactor ProjectBrochuresList and BrochureButton components for improved styling and consistency; update font weight and class names for better UI presentation. --- src/components/header/ProjectBrochuresList.tsx | 14 ++++++++------ src/components/ui/BrochureButton.tsx | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/components/header/ProjectBrochuresList.tsx b/src/components/header/ProjectBrochuresList.tsx index d0fbecd..6a6e895 100644 --- a/src/components/header/ProjectBrochuresList.tsx +++ b/src/components/header/ProjectBrochuresList.tsx @@ -16,13 +16,15 @@ export default function ProjectBrochuresList({ const isMobile = variant === "mobile"; return ( -
-

{projectTitle}

+
+

{projectTitle}

{brochures.map((brochure, index) => ( - {title} + {title} From 454882392b52ff6271b64dd6fca42bd79eeaa4c7 Mon Sep 17 00:00:00 2001 From: inmake Date: Wed, 21 Jan 2026 19:11:32 +0500 Subject: [PATCH 3/3] Refactor FloorsPage component to streamline floor selection and rendering; replace individual floor components with a centralized FloorPlanViewer for improved maintainability. Introduce new floor data structure in Project type for better data management. --- .../floor-plans/AmenitiesFloorView.tsx | 142 ++++++++ .../floor-plans/FloorPlanViewer.tsx | 46 +++ .../floor-plans/ResidentialFloorView.tsx | 283 +++++++++++++++ .../floor-plans/ViewToggleButtons.tsx | 47 +++ src/data/floors/dubai-marina.ts | 156 ++++++++ src/data/floors/marasi-drive.ts | 207 +++++++++++ src/pages/FloorsPage.tsx | 336 ++---------------- src/types/Floor.ts | 36 ++ src/types/Project.ts | 2 + 9 files changed, 950 insertions(+), 305 deletions(-) create mode 100644 src/components/floor-plans/AmenitiesFloorView.tsx create mode 100644 src/components/floor-plans/FloorPlanViewer.tsx create mode 100644 src/components/floor-plans/ResidentialFloorView.tsx create mode 100644 src/components/floor-plans/ViewToggleButtons.tsx create mode 100644 src/data/floors/dubai-marina.ts create mode 100644 src/data/floors/marasi-drive.ts create mode 100644 src/types/Floor.ts diff --git a/src/components/floor-plans/AmenitiesFloorView.tsx b/src/components/floor-plans/AmenitiesFloorView.tsx new file mode 100644 index 0000000..93ab6b9 --- /dev/null +++ b/src/components/floor-plans/AmenitiesFloorView.tsx @@ -0,0 +1,142 @@ +import { useState } from "react"; +import { AmenitiesFloorData } from "../../types/Floor"; +import Badge from "../ui/Badge"; +import Button from "../ui/Button"; +import PlayIcon from "../icons/PlayIcon"; +import useModalStore from "../../stores/useModalStore"; +import VideoModal from "../VideoModal"; +import ViewToggleButtons from "./ViewToggleButtons"; +import AmentitiesBadge from "../AmentitiesCard"; +import AmenitiesBadge from "../icons/AmenitiesBadge"; +import AmentitiesContentSlider from "../AmentitiesContentSlider"; + +interface AmenitiesFloorViewProps { + floor: AmenitiesFloorData; +} + +function AmenitiesFloorView({ floor }: AmenitiesFloorViewProps) { + const { setModal } = useModalStore(); + const [currentView, setCurrentView] = useState<"exterior" | "interior">( + "exterior" + ); + + const hasInteriorView = !!floor.images.interior; + const currentImage = + currentView === "interior" && floor.images.interior + ? floor.images.interior + : floor.images.main; + + // Split amenities into indoor and outdoor if counts are provided + const hasIndoorOutdoorSplit = + floor.amenitiesCount.indoor !== undefined && + floor.amenitiesCount.outdoor !== undefined; + + const indoorAmenities = hasIndoorOutdoorSplit + ? floor.amenitiesList.slice(0, floor.amenitiesCount.indoor) + : []; + + const outdoorAmenities = hasIndoorOutdoorSplit + ? floor.amenitiesList.slice(floor.amenitiesCount.indoor) + : floor.amenitiesList; + + return ( +
+
+
+

{floor.displayName}

+ +
+ + {hasIndoorOutdoorSplit && ( +
+ + +
+ )} + + + +
+ + {floor.name} + {floor.video && ( + + )} +
+
+ + {hasIndoorOutdoorSplit && indoorAmenities.length > 0 && ( +
+

Indoor Amenities

+
+ {indoorAmenities.map((amenity, index) => ( + + ))} +
+
+ )} + + {hasIndoorOutdoorSplit && indoorAmenities.length > 0 && ( +
+ )} + +
+

+ {hasIndoorOutdoorSplit ? "Outdoor Amenities" : "Amenities"} +

+
+ {outdoorAmenities.map((amenity, index) => ( + + ))} +
+
+ + {floor.images.content.length > 1 ? ( + + ) : ( + floor.images.content.length === 1 && ( + {floor.name} + ) + )} +
+ ); +} + +export default AmenitiesFloorView; diff --git a/src/components/floor-plans/FloorPlanViewer.tsx b/src/components/floor-plans/FloorPlanViewer.tsx new file mode 100644 index 0000000..e596b86 --- /dev/null +++ b/src/components/floor-plans/FloorPlanViewer.tsx @@ -0,0 +1,46 @@ +import { FloorData } from "../../types/Floor"; +import { Unit } from "../../types/IUnit"; +import { ComplexName } from "../../types/ComplexName"; +import { FloorsData } from "../FloorSelect"; +import ResidentialFloorView from "./ResidentialFloorView"; +import AmenitiesFloorView from "./AmenitiesFloorView"; + +interface FloorPlanViewerProps { + floor: FloorData; + complexName: ComplexName; + unitsOnFloor?: Unit[]; + floorsData?: FloorsData[]; + selectedFloor: string; + onFloorSelect: (floor: string) => void; +} + +function FloorPlanViewer({ + floor, + complexName, + unitsOnFloor, + floorsData, + selectedFloor, + onFloorSelect, +}: FloorPlanViewerProps) { + if (floor.type === "residential") { + return ( + + ); + } + + if (floor.type === "amenities") { + return ; + } + + // This should never happen with proper TypeScript typing + return null; +} + +export default FloorPlanViewer; diff --git a/src/components/floor-plans/ResidentialFloorView.tsx b/src/components/floor-plans/ResidentialFloorView.tsx new file mode 100644 index 0000000..00cd0e2 --- /dev/null +++ b/src/components/floor-plans/ResidentialFloorView.tsx @@ -0,0 +1,283 @@ +import { useState } from "react"; +import { ResidentialFloorData } from "../../types/Floor"; +import { Unit } from "../../types/IUnit"; +import { ComplexName } from "../../types/ComplexName"; +import { FloorsData } from "../FloorSelect"; +import Badge from "../ui/Badge"; +import Select from "../ui/Select"; +import UnitTypeBadge from "../UnitTypeBadge"; +import Button from "../ui/Button"; +import { usePopupStore } from "../../stores/usePopupStore"; +import { isMobile } from "react-device-detect"; + +// 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"; + +interface ResidentialFloorViewProps { + floor: ResidentialFloorData; + complexName: ComplexName; + unitsOnFloor?: Unit[]; + floorsData?: FloorsData[]; + selectedFloor: string; + onFloorSelect: (floor: string) => void; +} + +function ResidentialFloorView({ + floor, + complexName, + unitsOnFloor, + floorsData, + selectedFloor, + onFloorSelect, +}: ResidentialFloorViewProps) { + 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 totalUnits = + (currentFloorData?.East?.totalUnits || 0) + + (currentFloorData?.West?.totalUnits || 0); + + const wingData = + currentFloorData?.[selectedFloor.split(" ")[0] as "West" | "East"]; + + return ( +
setPopup(null)}> +
+

{floorNumber} floor

+
+ +
+
+
+
+ { + 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} + /> +
+
+ + item.floor === + parseInt(selectedFloor!.split(" ").at(-1)!) + )?.others.types["Studio2"] || 0 + } + /> + + item.floor === + parseInt(selectedFloor!.split(" ").at(-1)!) + )?.others.types["One Bedroom2"] || 0 + } + /> + + item.floor === + parseInt(selectedFloor!.split(" ").at(-1)!) + )?.others.types["One Bedroom Loft"] || 0 + } + /> + + item.floor === + parseInt(selectedFloor!.split(" ").at(-1)!) + )?.others.types["Two Bedroom Loft"] || 0 + } + /> +
+
+ {!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; diff --git a/src/components/floor-plans/ViewToggleButtons.tsx b/src/components/floor-plans/ViewToggleButtons.tsx new file mode 100644 index 0000000..ea94d95 --- /dev/null +++ b/src/components/floor-plans/ViewToggleButtons.tsx @@ -0,0 +1,47 @@ +import clsx from "clsx"; +import Button from "../ui/Button"; + +interface ViewToggleButtonsProps { + currentView: "exterior" | "interior"; + onViewChange: (view: "exterior" | "interior") => void; + hasInteriorView: boolean; +} + +function ViewToggleButtons({ + currentView, + onViewChange, + hasInteriorView, +}: ViewToggleButtonsProps) { + if (!hasInteriorView) { + return null; + } + + return ( +
+ + +
+ ); +} + +export default ViewToggleButtons; diff --git a/src/data/floors/dubai-marina.ts b/src/data/floors/dubai-marina.ts new file mode 100644 index 0000000..98d7b09 --- /dev/null +++ b/src/data/floors/dubai-marina.ts @@ -0,0 +1,156 @@ +import { FloorData } from "../../types/Floor"; + +export const dubaiMarinaFloors: FloorData[] = [ + // Ground Level + { + id: "ground-level", + name: "Ground Level", + displayName: "Ground Level", + type: "amenities", + amenitiesCount: { + total: 14, + }, + amenitiesList: [ + { icon: "text", title: "Residential Entrance" }, + { icon: "text", title: "Multifunctional Feature Staircase" }, + { icon: "text", title: "Lobby Lounge & Concierge" }, + { icon: "text", title: "Outdoor Landscape Seating Area" }, + { icon: "text", title: "Lift Lobby" }, + { icon: "text", title: "Rove Cafe & Energize Bar" }, + { icon: "text", title: "Organic Smart Gardens & Seating" }, + { icon: "text", title: "Co-working Area " }, + { icon: "text", title: "24x7 Convenience Store" }, + { icon: "text", title: "WCs" }, + { icon: "text", title: "Visitor Parking" }, + { icon: "text", title: "EV Charging Stations" }, + { icon: "text", title: "Bicycle/Scooter Rental & Storage" }, + { icon: "text", title: "Drop-off Area" }, + ], + images: { + main: "/images/floor-plans/dubai-marina/ground.png", + content: ["/images/floor-plans/dubai-marina/ground/content.jpg"], + }, + video: "/videos/dubai-marina/GroundDubaiMarina.mp4", + }, + + // Podium Level + { + id: "podium-level", + name: "Podium Level", + displayName: "Podium Level", + type: "amenities", + amenitiesCount: { + total: 14, + indoor: 3, + outdoor: 12, + }, + amenitiesList: [ + // Indoor + { icon: "text", title: "Multipurpose Hall" }, + { icon: "text", title: "Gaming Lounge" }, + { icon: "text", title: "State-of-the-art Gym" }, + { icon: "text", title: "7m Climbing Wall" }, + { icon: "text", title: "Changing Rooms & Lockers" }, + { icon: "text", title: "Hydration Station" }, + { icon: "text", title: "Boutique Fitness Studio - Crank" }, + { icon: "text", title: "Rentable Guest Rooms" }, + // Outdoor + { icon: "text", title: "Semi-Olympic Leisure Pool" }, + { icon: "text", title: "Outdoor Cinema & Amphitheatre" }, + { icon: "text", title: "Water Feature Wall" }, + { icon: "text", title: "Multipurpose Fitness Pool" }, + { icon: "text", title: "Communal Gardens" }, + { icon: "text", title: "BBQ & Social Zone" }, + { icon: "text", title: "Popsicle Cart" }, + { icon: "text", title: "Gaming Lounge - Terrace" }, + { icon: "text", title: "Zen Library" }, + { icon: "text", title: "Co-working Area" }, + { icon: "text", title: "Multipurpose Hall with Terrace" }, + { icon: "text", title: "Marina View Chill Zone" }, + { icon: "text", title: "Outdoor Gym" }, + ], + images: { + main: "/images/floor-plans/dubai-marina/podium.png", + content: [ + "/images/floor-plans/dubai-marina/podium/content1.jpg", + "/images/floor-plans/dubai-marina/podium/content2.jpg", + "/images/floor-plans/dubai-marina/podium/content3.jpg", + ], + }, + video: "/videos/dubai-marina/PodiumDubaiMarina.mp4", + }, + + // Residential floors 7-20 + ...Array.from({ length: 14 }, (_, i) => { + const floor = i + 7; + return { + id: `floor-${floor}`, + name: `${floor}`, + displayName: `${floor}`, + type: "residential" as const, + floorNumber: floor, + }; + }), + + // Residential floors 22-38 + ...Array.from({ length: 17 }, (_, i) => { + const floor = i + 22; + return { + id: `floor-${floor}`, + name: `${floor}`, + displayName: `${floor}`, + type: "residential" as const, + floorNumber: floor, + }; + }), + + // Residential floors 39-40 (special layout) + { + id: "floor-39-40", + name: "39-40", + displayName: "39-40", + type: "residential", + floorNumber: 39, + }, + + // Residential floors 41-42 (special layout) + { + id: "floor-41-42", + name: "41-42", + displayName: "41-42", + type: "residential", + floorNumber: 41, + }, + + // Rooftop (Sky 44) + { + id: "rooftop", + name: "Rooftop", + displayName: "Sky 44 - Rooftop", + type: "amenities", + amenitiesCount: { + total: 14, + }, + amenitiesList: [ + { icon: "text", title: "Sky Viewing Lounges" }, + { icon: "text", title: "Convertible Indoor Infinity Pool" }, + { icon: "text", title: "Marina View Amphitheatre" }, + { icon: "text", title: "Ultra Shield Oxygen Pod" }, + { icon: "text", title: "Aroma Steam Pod" }, + { icon: "text", title: "Reflexology Pool" }, + { icon: "text", title: "Cold Bucket Experience Shower Pod" }, + { icon: "text", title: "Experience Shower Pod" }, + { icon: "text", title: "Cold Plunge Pool" }, + { icon: "text", title: "Salt Steam Pod" }, + { icon: "text", title: "Finnish Sauna Pod" }, + { icon: "text", title: "Water Feature Wall" }, + { icon: "text", title: "Vitality Pool" }, + { icon: "text", title: "Changing Rooms and Lockers" }, + ], + images: { + main: "/images/floor-plans/dubai-marina/rooftop.png", + content: ["/images/floor-plans/dubai-marina/rooftop/content.jpg"], + }, + video: "/videos/dubai-marina/SkyDubaiMarina.mp4", + }, +]; diff --git a/src/data/floors/marasi-drive.ts b/src/data/floors/marasi-drive.ts new file mode 100644 index 0000000..2ecb928 --- /dev/null +++ b/src/data/floors/marasi-drive.ts @@ -0,0 +1,207 @@ +import { FloorData } from "../../types/Floor"; + +export const marasiDriveFloors: FloorData[] = [ + // Ground Level + { + id: "ground-level", + name: "Ground Level", + displayName: "Ground Level", + type: "amenities", + amenitiesCount: { + total: 7, + }, + amenitiesList: [ + { icon: "RoveCafe", title: "Rove Café" }, + { icon: "LoungingSpaceIcon", title: "Lobby Lounge" }, + { icon: "CoworkingIcon", title: "Coworking Space" }, + { icon: "LushLandscapeIcon", title: "Outdoor Terrace" }, + { icon: "PrivateMeetingRoomsIcon", title: "Private Meeting Rooms" }, + { icon: "ConvenienceIcon", title: "Convenience Store" }, + { icon: "SoundproofMeetingPodsIcon", title: "Soundproof Meeting Pods" }, + ], + images: { + main: "/images/floor-plans/marasi-drive/ground.png", + content: [ + "/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", + ], + }, + video: "/videos/marasi-drive/GroundMarasiDrive.mp4", + }, + + // Podium Level + { + id: "podium-level", + name: "Podium Level", + displayName: "Podium Level", + type: "amenities", + amenitiesCount: { + total: 27, + indoor: 13, + outdoor: 14, + }, + amenitiesList: [ + // Indoor + { icon: "LoungeIcon", title: "Indoor Lounge" }, + { icon: "MonkeyBarsIcon", title: "Monkey Bars" }, + { icon: "KaraokeIcon", title: "Karaoke Room" }, + { icon: "ArcadeGameIcon", title: "Arcade Games" }, + { icon: "ClimbingWallIcon", title: "Climbing Wall" }, + { icon: "PlaystationIcon", title: "Playstation Deck" }, + { icon: "FullyEquippedGymIcon", title: "Fully Equipped Gym" }, + { icon: "ChangingRoomIcon", title: "Changing Rooms" }, + { icon: "HammockMovieLoungeIcon", title: "Hammock Movie Lounge" }, + { icon: "GuestRooms", title: "Guest Rooms" }, + { icon: "MultiballInteractiveGamingIcon", title: "Multi Ball Interactive Gaming" }, + { icon: "MultiPurposeRoomWithKitchenIcon", title: "Multi-purpose Room for Kitchen" }, + { icon: "GamingLoungeIcon", title: "Gaming Lounge" }, + // Outdoor + { icon: "UrbanBeachPoolIcon", title: "Urban Beach Pool" }, + { icon: "JacuzziIcon", title: "Jacuzzi" }, + { icon: "YogaLoungeIcon", title: "Yoga Lounge" }, + { icon: "SunLoungeIcon", title: "Sun Lounging Pool" }, + { icon: "CascadingLeisurePoolIcon", title: "Cascading Leisure Pool" }, + { icon: "AquaCyclingIcon", title: "AquaCycling" }, + { icon: "OpenAirGymIcon", title: "Open-Air Gym" }, + { icon: "RoveBeverageTruckIcon", title: "Rove Beverage Truck" }, + { icon: "CabanasWithDaybeds", title: "Cabanas with Daybeds" }, + { icon: "IntegratedLapPoolIcon", title: "Integrated Lap Pool" }, + { icon: "SunkenGardensIcon", title: "Sunken Gardens" }, + { icon: "MultiPurposeRoomWithKitchenIcon", title: "Outdoor Multi-Purpose Terrace" }, + { icon: "GamingTerraceIcon", title: "Outdoor Gaming Terrace" }, + { icon: "CoworkingIcon", title: "Outdoor Coworking Space" }, + ], + images: { + main: "/images/floor-plans/marasi-drive/podium.png", + content: [ + "/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", + ], + }, + video: "/videos/marasi-drive/PodiumMarasiDrive.mp4", + }, + + // Residential floors 5-21 East Wing + ...Array.from({ length: 17 }, (_, i) => { + const floor = i + 5; + return { + id: `east-${floor}`, + name: `East ${floor}`, + displayName: `East Wing ${floor}`, + type: "residential" as const, + floorNumber: floor, + wing: "East" as const, + }; + }), + + // Residential floors 5-21 West Wing + ...Array.from({ length: 17 }, (_, i) => { + const floor = i + 5; + return { + id: `west-${floor}`, + name: `West ${floor}`, + displayName: `West Wing ${floor}`, + type: "residential" as const, + floorNumber: floor, + wing: "West" as const, + }; + }), + + // Residential floors 24-31 West Wing (upper) + ...Array.from({ length: 8 }, (_, i) => { + const floor = i + 24; + return { + id: `west-${floor}`, + name: `West ${floor}`, + displayName: `West Wing ${floor}`, + type: "residential" as const, + floorNumber: floor, + wing: "West" as const, + }; + }), + + // Sky Garden + { + id: "sky-garden", + name: "Sky Garden", + displayName: "Sky Garden", + type: "amenities", + amenitiesCount: { + total: 15, + indoor: 3, + outdoor: 12, + }, + amenitiesList: [ + // Indoor + { icon: "PoolIcon", title: "Indoor Lap Pool" }, + { icon: "WellnessIcon", title: "Wellness Features" }, + { icon: "ChangingRoomIcon", title: "Changing Rooms" }, + // Outdoor + { icon: "PingPongIcon", title: "Padel Pong" }, + { icon: "SunLoungeIcon", title: "Sun Lounging Deck" }, + { icon: "CinemaIcon", title: "Outdoor Cinema" }, + { icon: "BoulderingWallIcon", title: "Bouldering Wall" }, + { icon: "PingPongInTubeIcon", title: "Ping Pong in a Tube" }, + { icon: "AmphitheatreIcon", title: "Amphitheatre" }, + { icon: "CommunalDiningTablesIcon", title: "Communal Dining Tables" }, + { icon: "SuspendedLoungingNetsIcon", title: "Suspended Lounging Nets " }, + { icon: "LushLandscapeIcon", title: "Lush Landscape" }, + { icon: "RunningWheelIcon", title: "Running Wheel" }, + { icon: "ChessIcon", title: "Chess Tables" }, + { icon: "ClimbingWallIcon", title: "Climbing Wall" }, + { icon: "CoworkingIcon", title: "Outdoor Coworking Space" }, + { icon: "MultiPurposeIcon", title: "Multi-purpose Court" }, + ], + images: { + main: "/images/floor-plans/marasi-drive/sky-garden.png", + content: [ + "/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", + ], + }, + video: "/videos/marasi-drive/SkyGardenMarasiDrive.mp4", + }, + + // Rooftop + { + id: "rooftop", + name: "Rooftop", + displayName: "Rooftop", + type: "amenities", + amenitiesCount: { + total: 10, + }, + amenitiesList: [ + { icon: "StargazingIcon", title: "Stargazing Point" }, + { icon: "BBQTerraceIcon", title: "BBQ Terrace" }, + { icon: "OutdoorKitchenIcon", title: "Outdoor Kitchen" }, + { icon: "CabanasWithDaybeds", title: "Cabanas with Daybeds" }, + { icon: "ViewingDeckWithWingsIcon", title: "Viewing Deck with Wings" }, + { icon: "LoungingSpaceIcon", title: "Lounging Space" }, + { icon: "SunkenSeatingIcon", title: "Sunken Seating" }, + { icon: "FirePitIcon", title: "Firepit" }, + { icon: "RooftopGardenIcon", title: "Rooftop Garden" }, + { icon: "CommunalDiningTablesRoundedIcon", title: "Communal Dining Tables" }, + ], + images: { + main: "/images/floor-plans/marasi-drive/rooftop.png", + content: ["/images/floor-plans/marasi-drive/rooftop/content.jpg"], + }, + video: "/videos/marasi-drive/RooftopMarasiDrive.mp4", + }, +]; diff --git a/src/pages/FloorsPage.tsx b/src/pages/FloorsPage.tsx index 1a81f16..5684aee 100644 --- a/src/pages/FloorsPage.tsx +++ b/src/pages/FloorsPage.tsx @@ -2,33 +2,16 @@ import FloorSelect, { FloorsData } from "../components/FloorSelect"; import { useParams } from "react-router"; import FloorSidebar from "../components/FloorSidebar"; -import { useEffect, useState } from "react"; -import Select from "../components/ui/Select"; +import { useState, useMemo } from "react"; import { useQuery } from "@tanstack/react-query"; import { api } from "../api/ky"; -import UnitTypeBadge from "../components/UnitTypeBadge"; -import FloorPlanMarasiDriveEast from "../components/FloorPlanMarasiDriveEast"; -import RooftopMarasiDrive from "../components/floor-plans/marasi-drive/RooftopMarasiDrive"; -import GroundMarasiDrive from "../components/floor-plans/marasi-drive/GroundMarasiDrive"; -import PodiumMarasiDrive from "../components/floor-plans/marasi-drive/PodiumMarasiDrive"; -import SkyGardenMarasiDrive from "../components/floor-plans/marasi-drive/SkyGardenMarasiDrive"; -import Badge from "../components/ui/Badge"; -import RooftopDubaiMarina from "../components/floor-plans/dubai-marina/RooftopDubaiMarina"; -import GroundDubaiMarina from "../components/floor-plans/dubai-marina/GroundDubaiMarina"; -import PodiumDubaiMarina from "../components/floor-plans/dubai-marina/PodiumDubaiMarina"; -import FloorPlanMarasiDriveWestLower from "../components/FloorPlanMarasiDriveWestLower"; -import FloorPlanMarasiDriveWestUpper from "../components/FloorPlanMarasiDriveWestUpper"; import { SPECIAL_FLOORS } from "../constants/floors"; import { Unit } from "../types/IUnit"; import slugToComplexName from "../utils/slugToComplexName"; -import { usePopupStore } from "../stores/usePopupStore"; -import { isMobile } from "react-device-detect"; -import FloorPlanDubaiMarina41_42 from "../components/FloorPlanDubaiMarina41_42"; -import FloorPlanDubaiMarina39_40 from "../components/FloorPlanDubaiMarina39_40"; -import FloorPlanDubaiMarina7_38Comb from "../components/FloorPlanDubaiMarina7_38Comb"; -import FloorPlanDubaiMarina7_38 from "../components/FloorPlanDubaiMarina7_38"; -import Button from "../components/ui/Button"; 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"; function FloorsPage() { const [selectedFloor, setSelectedFloor] = useState(null); @@ -66,12 +49,22 @@ function FloorsPage() { .json(), }); - const { setPosition, setPopup } = usePopupStore(); - const [isCombinable, setIsCombinable] = useState(false); + // Get floor data based on complex + const allFloors = useMemo(() => { + if (complexName === "marasi-drive") { + return marasiDriveFloors; + } + if (complexName === "dubai-marina") { + return dubaiMarinaFloors; + } + return []; + }, [complexName]); - useEffect(() => { - setIsCombinable(false); - }, [selectedFloor]); + // Find current floor + const currentFloor = useMemo(() => { + if (!selectedFloor) return null; + return allFloors.find((floor) => floor.name === selectedFloor); + }, [selectedFloor, allFloors]); return (
@@ -84,287 +77,20 @@ function FloorsPage() { isOpen={!!selectedFloor} onClose={() => setSelectedFloor(null)} > - {complexName === "dubai-marina" && ( - <> - {selectedFloor === "Rooftop" && } - {selectedFloor === "Ground Level" && } - {selectedFloor === "Podium Level" && } - {!!parseInt(selectedFloor!) && ( -
setPopup(null)} - > -
-

{selectedFloor} floor

-
- item.floor === parseInt(selectedFloor!), - )?.others.totalUnits || 0 - } Apartments`} - /> - -
-
- -
-
- [ - `East ${item.floor}`, - `West ${item.floor}`, - ]) || [] - } - defaultOption={selectedFloor?.toString() || ""} - onSelect={setSelectedFloor} - className="2xl:w-[8.333vw] md:max-2xl:w-[120px] w-full" - maxOptionsCount={7} - /> -
-
- - item.floor === - parseInt(selectedFloor.split(" ").at(-1)!), - )?.[selectedFloor.split(" ")[0] as "West" | "East"] - .types["Studio Flex"] || 0 - } - /> - - item.floor === - parseInt(selectedFloor.split(" ").at(-1)!), - )?.[selectedFloor.split(" ")[0] as "West" | "East"] - .types["Studio Squared"] || 0 - } - /> - - item.floor === - parseInt(selectedFloor.split(" ").at(-1)!), - )?.[selectedFloor.split(" ")[0] as "West" | "East"] - .types["1 BR Squared"] || 0 - } - /> - - item.floor === - parseInt(selectedFloor.split(" ").at(-1)!), - )?.[selectedFloor.split(" ")[0] as "West" | "East"] - .types["2 BR Squared"] || 0 - } - /> -
-
-
-
- !isMobile && setPosition({ x: e.clientX, y: e.clientY }) - } - > - {unitsOnFloor && selectedFloor.split(" ")[0] === "East" && ( - - )} - {selectedFloor.split(" ")[0] === "West" && unitsOnFloor && ( - <> - {+selectedFloor.split(" ")[1] < 24 ? ( - - ) : ( - - )} - - )} -
-
- )} - + {!currentFloor && complexName === "hq" && <>HQ} + {!currentFloor && selectedFloor && ( +
Floor not found: {selectedFloor}
)} - {complexName === "hq" && <>HQ}
); diff --git a/src/types/Floor.ts b/src/types/Floor.ts new file mode 100644 index 0000000..0a1b029 --- /dev/null +++ b/src/types/Floor.ts @@ -0,0 +1,36 @@ +// Базовый интерфейс для всех этажей +export interface BaseFloorData { + id: string; + name: string; // "1", "Rooftop", "Ground Level" и т.д. + displayName: string; // "1st Floor", "Rooftop" +} + +// Жилой этаж с квартирами и SVG масками +export interface ResidentialFloorData extends BaseFloorData { + type: 'residential'; + floorNumber: number; + wing?: 'East' | 'West'; // для Marasi Drive +} + +// Этаж с удобствами +export interface AmenitiesFloorData extends BaseFloorData { + type: 'amenities'; + amenitiesCount: { + total: number; + indoor?: number; + outdoor?: number; + }; + amenitiesList: { + icon: string; // название компонента иконки + title: string; + }[]; + images: { + main: string; // основное изображение (exterior) + interior?: string; // для переключения вида + content: string[]; // изображения для слайдера/галереи + }; + video?: string; // путь к видео +} + +// Discriminated union +export type FloorData = ResidentialFloorData | AmenitiesFloorData; diff --git a/src/types/Project.ts b/src/types/Project.ts index dd66aeb..bc589ca 100644 --- a/src/types/Project.ts +++ b/src/types/Project.ts @@ -1,4 +1,5 @@ import UnitType from "./UnitType"; +import { FloorData } from "./Floor"; export default interface Project { title: string; @@ -7,6 +8,7 @@ export default interface Project { buildingType: "residential" | "commercial"; types: UnitType[]; amenitiesFloors: AmenitiesFloor[]; + floors?: FloorData[]; // New centralized floor data structure } export interface AmenitiesFloor {