modal + favorite page + video modal + fixes

This commit is contained in:
2024-06-25 14:43:21 +05:00
parent a651ab552e
commit e9fd427d50
52 changed files with 858 additions and 344 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.
+25 -9
View File
@@ -1,13 +1,26 @@
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import Button from "./Button"; import Button from "./Button";
import { formatNumber } from "../calc/formatNumber"; // import { formatNumber } from "../calc/formatNumber";
import { IAparmentRes } from "../types/apartmentsRes";
import { apartmentRoutes } from "../consts/apartmentsRoutes";
const ApartmentSidebar = () => { interface ApartmentSidebarProps {
currentApartment: IAparmentRes;
}
const ApartmentSidebar = ({ currentApartment }: ApartmentSidebarProps) => {
const navigate = useNavigate(); const navigate = useNavigate();
const route = apartmentRoutes.find(
(aprt) => aprt.type === currentApartment.Unit_Type
)?.virtualTour;
const unitNo = currentApartment.Unit_No.split("-")[1];
const wing =
currentApartment.Unit_No.split("-")[0] === "E" ? "East Wing" : "West Wing";
const handleOn3DTourClick = () => { const handleOn3DTourClick = () => {
navigate(`../virtual-tour/apartments-studio-1`); navigate(`../virtual-tour/${route ? route : "apartments-studio-1"}`);
}; };
return ( return (
<div className="flex lg:flex-col gap-2 h-full"> <div className="flex lg:flex-col gap-2 h-full">
<div className="rounded-2xl overflow-clip lg:flex-1 flex-none relative"> <div className="rounded-2xl overflow-clip lg:flex-1 flex-none relative">
@@ -28,29 +41,32 @@ const ApartmentSidebar = () => {
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
<div className="flex justify-between text-m"> <div className="flex justify-between text-m">
<p className="text-[#73787C]">Complex</p> <p className="text-[#73787C]">Complex</p>
<p className="text-[#0D1922]">ROVE Home Marasi Drive</p> <p className="text-[#0D1922]">{currentApartment.Project_Name}</p>
</div> </div>
<div className="flex justify-between text-m"> <div className="flex justify-between text-m">
<p className="text-[#73787C]">Section</p> <p className="text-[#73787C]">Section</p>
<p className="text-[#0D1922]">East Wing</p> <p className="text-[#0D1922]">{wing}</p>
</div> </div>
<div className="flex justify-between text-m"> <div className="flex justify-between text-m">
<p className="text-[#73787C]">Floor</p> <p className="text-[#73787C]">Floor</p>
<p className="text-[#0D1922]">11</p> <p className="text-[#0D1922]">{currentApartment.Floor}</p>
</div> </div>
<div className="flex justify-between text-m"> <div className="flex justify-between text-m">
<p className="text-[#73787C]">Number</p> <p className="text-[#73787C]">Number</p>
<p className="text-[#0D1922]">213</p> <p className="text-[#0D1922]">{unitNo}</p>
</div> </div>
<div className="flex justify-between text-m"> <div className="flex justify-between text-m">
<p className="text-[#73787C]">Size</p> <p className="text-[#73787C]">Size</p>
<p className="text-[#0D1922]">609 Sqft</p> <p className="text-[#0D1922]">
{currentApartment.Total_Area_Sqft} Sqft
</p>
</div> </div>
</div> </div>
</div> </div>
<div className="rounded-2xl bg-white flex flex-col p-6 gap-4 flex-1 lg:flex-none justify-between"> <div className="rounded-2xl bg-white flex flex-col p-6 gap-4 flex-1 lg:flex-none justify-between">
<p className="text-[#00BED7] font-semibold text-subheadline-s leading-7"> <p className="text-[#00BED7] font-semibold text-subheadline-s leading-7">
AED {formatNumber(1668888, ",", 3, 1)} Unvailiable
{/* AED {formatNumber(1668888, ",", 3, 1)} */}
</p> </p>
<div className="flex gap-2"> <div className="flex gap-2">
<Button <Button
+2 -1
View File
@@ -35,6 +35,7 @@ const Button = ({
const border = borders[buttonType]; const border = borders[buttonType];
const padding = paddings[buttonType]; const padding = paddings[buttonType];
const rounded = isCircleRounded ? "rounded-full" : "rounded-lg"; const rounded = isCircleRounded ? "rounded-full" : "rounded-lg";
const disabledStyle = disabled ? "bg-[#0D192214] text-gray-400" : "";
return ( return (
<button <button
@@ -43,7 +44,7 @@ const Button = ({
onClick={onClick} onClick={onClick}
className={`min-w-10 max-h-10 ${rounded} ${ className={`min-w-10 max-h-10 ${rounded} ${
icon && !text ? "p-[10px]" : padding icon && !text ? "p-[10px]" : padding
} transition-all duration-300 ease-in-out text-s pointer-events-auto flex gap-1 items-center align-middle h-fit ${backgroundColor} ${textColor} ${border} ${ } transition-all duration-300 ease-in-out text-s pointer-events-auto flex gap-1 items-center align-middle h-fit ${backgroundColor} ${textColor} ${border} ${disabledStyle} ${
className ? className : "" className ? className : ""
}`} }`}
> >
+1 -1
View File
@@ -93,7 +93,7 @@ const MultiRangeSlider = ({
max={multirangeSlider.maxValue} max={multirangeSlider.maxValue}
value={[multirangeSlider.startValue, multirangeSlider.endValue]} value={[multirangeSlider.startValue, multirangeSlider.endValue]}
className={`${ className={`${
isDisabled ? "pointer-events-none text" : "" isDisabled ? "pointer-events-none text disabled" : ""
} absolute -bottom-3 left-0 w-[calc(100%-16px)] z-20`} } absolute -bottom-3 left-0 w-[calc(100%-16px)] z-20`}
onInput={handleOnRangeInputChange} onInput={handleOnRangeInputChange}
/> />
@@ -151,6 +151,9 @@ function SequenceSlider({ path }: SequenceSliderProps) {
setLeft(_left); setLeft(_left);
} }
} }
function handleOnSequenceClick(): void {
navigate("./wing");
}
useEffect(() => { useEffect(() => {
handleResize(); handleResize();
@@ -158,10 +161,6 @@ function SequenceSlider({ path }: SequenceSliderProps) {
return () => window.removeEventListener("resize", handleResize); return () => window.removeEventListener("resize", handleResize);
}, []); }, []);
function handleOnSequenceClick(): void {
navigate("./wing");
}
return ( return (
<div <div
{...handlers} {...handlers}
@@ -276,12 +275,22 @@ function SequenceSlider({ path }: SequenceSliderProps) {
> >
{(state) => ( {(state) => (
<div <div
className={`absolute top-0 left-0 w-full h-full flex items-center justify-center bg-neutral-950 z-50 transition-opacity duration-300 ${state}`} className={`absolute z-[99999999] top-0 left-0 w-screen bg-[#F3F3F2] h-screen flex justify-center items-center flex-col ${state}`}
> >
<h2 className="text-2xl font-tenor text-white whitespace-nowrap"> <div className="animate-spin">
Loading... {Math.round((100 / arrayLength) * loadedImages)} % <img src="/images/loader.png" alt="" />
</h2> </div>
<div className="text-[#00BED7] text-m">
{Math.round((100 / arrayLength) * loadedImages)} %
</div>
</div> </div>
// <div
// className={`absolute top-0 left-0 w-full h-full flex items-center justify-center bg-neutral-950 z-50 transition-opacity duration-300 ${state}`}
// >
// <h2 className="text-2xl font-tenor text-white whitespace-nowrap">
// Loading... {Math.round((100 / arrayLength) * loadedImages)} %
// </h2>
// </div>
)} )}
</Transition> </Transition>
</div> </div>
@@ -1,5 +1,6 @@
import { IAparmentRes } from "../../../types/apartmentsRes"; import { IAparmentRes } from "../../../types/apartmentsRes";
import VirtualTourIcon from "../../icons/VirtualTourIcon"; import VirtualTourIcon from "../../icons/VirtualTourIcon";
import { apartmentsWithoutVirtualTour } from "../../../consts/apartmentsWithoutVirtualTour";
interface ApartmentDescriptionProps { interface ApartmentDescriptionProps {
isVisible: boolean; isVisible: boolean;
@@ -48,16 +49,20 @@ const ApartmentDescription = ({
{/* <p className="font-semibold text-[#00BED7] text-subheadline-s"> {/* <p className="font-semibold text-[#00BED7] text-subheadline-s">
AED 1,668,888 AED 1,668,888
</p> */} </p> */}
<div {!apartmentsWithoutVirtualTour.some(
className={`bg-[#30B21614] text-[#30B216] px-2 py-[6px] flex gap-1 items-center rounded-lg ${ (aprt) => aprt.type === hoveredApartment.Unit_Type
is3DTourAvailable ? "opacity-100" : "opacity-0" ) && (
}`} <div
> className={`bg-[#30B21614] text-[#30B216] px-2 py-[6px] flex gap-1 items-center rounded-lg ${
<VirtualTourIcon /> is3DTourAvailable ? "opacity-100" : "opacity-0"
<p className="text-caption-m font-semibold text-[#30B216]"> }`}
3D-tour >
</p> <VirtualTourIcon />
</div> <p className="text-caption-m font-semibold text-[#30B216]">
3D-tour
</p>
</div>
)}
</div> </div>
<div className="w-0 h-0 border-transparent border-t-[14px] border-x-[6px] border-b-0 absolute left-6 -bottom-[13px] border-t-white"></div> <div className="w-0 h-0 border-transparent border-t-[14px] border-x-[6px] border-b-0 absolute left-6 -bottom-[13px] border-t-white"></div>
</div> </div>
@@ -1,4 +1,4 @@
interface FloorWestWingHighlightingProps { interface EastWingHighlightingProps {
handleOnMouseOut: handleOnMouseOut:
| (() => void) | (() => void)
| ((event: React.MouseEvent<SVGSVGElement, MouseEvent>) => void); | ((event: React.MouseEvent<SVGSVGElement, MouseEvent>) => void);
@@ -10,11 +10,11 @@ interface FloorWestWingHighlightingProps {
) => void; ) => void;
} }
const FloorWestWingHighlighting = ({ const EastWingHighlighting = ({
handleOnMouseOut, handleOnMouseOut,
handleOnMouseOver, handleOnMouseOver,
handleOnApartmentClick, handleOnApartmentClick,
}: FloorWestWingHighlightingProps) => { }: EastWingHighlightingProps) => {
return ( return (
<> <>
<svg <svg
@@ -51,6 +51,7 @@ const FloorWestWingHighlighting = ({
</svg> </svg>
<svg <svg
data-type="1 BR U1 Left"
className="opacity-0 hover:opacity-100 ease-in-out duration-300 transition-opacity cursor-pointer" className="opacity-0 hover:opacity-100 ease-in-out duration-300 transition-opacity cursor-pointer"
onMouseOut={handleOnMouseOut} onMouseOut={handleOnMouseOut}
onMouseOver={handleOnMouseOver} onMouseOver={handleOnMouseOver}
@@ -388,6 +389,7 @@ const FloorWestWingHighlighting = ({
></path> ></path>
</svg> </svg>
<svg <svg
data-type="1 BR U1 Left"
className="opacity-0 hover:opacity-100 ease-in-out duration-300 transition-opacity cursor-pointer" className="opacity-0 hover:opacity-100 ease-in-out duration-300 transition-opacity cursor-pointer"
onMouseOut={handleOnMouseOut} onMouseOut={handleOnMouseOut}
onMouseOver={handleOnMouseOver} onMouseOver={handleOnMouseOver}
@@ -412,6 +414,7 @@ const FloorWestWingHighlighting = ({
></path> ></path>
</svg> </svg>
<svg <svg
data-type="1 BR U1 Right"
className="opacity-0 hover:opacity-100 ease-in-out duration-300 transition-opacity cursor-pointer" className="opacity-0 hover:opacity-100 ease-in-out duration-300 transition-opacity cursor-pointer"
onMouseOut={handleOnMouseOut} onMouseOut={handleOnMouseOut}
onMouseOver={handleOnMouseOver} onMouseOver={handleOnMouseOver}
@@ -440,4 +443,4 @@ const FloorWestWingHighlighting = ({
); );
}; };
export default FloorWestWingHighlighting; export default EastWingHighlighting;
@@ -1,4 +1,4 @@
function FloorWestWingLayout() { function EastWingLayout() {
return ( return (
<> <>
<path <path
@@ -441,4 +441,4 @@ function FloorWestWingLayout() {
); );
} }
export default FloorWestWingLayout; export default EastWingLayout;
@@ -1,19 +1,16 @@
import { useState, useEffect, useRef } from "react"; import { useState, useEffect, useRef } from "react";
import { IDesctiptionFloor } from "../../../types/descriptionFloor"; import { IDesctiptionFloor } from "../../../types/descriptionFloor";
import ApartmentDescription from "./ApartmentDescription"; import ApartmentDescription from "./ApartmentDescription";
import FloorWestWingHighlighting from "./FloorWestWingHighlighting"; import EastWingHighlighting from "./EastWingHighlighting";
import FloorWestWingLayout from "./FloorWestWingLayout"; import EastWingLayout from "./EastWingLayout";
import FloorEastWingHighlighting from "./FloorEastWingHighlighting"; import WestWingHighlighting from "./WestWingHighlighting";
import FloorEastWingLayout from "./FloorEastWingLayout"; import WestWingLayout from "./WestWingLayout";
import useModal from "../../../store/useModal"; import useModal from "../../../store/useModal";
import AboutComplexModal from "../../modals/AboutComplexModal"; import AboutComplexModal from "../../modals/AboutComplexModal";
import { IAparmentRes } from "../../../types/apartmentsRes"; import { IAparmentRes } from "../../../types/apartmentsRes";
import FloorEastWingTopLayout from "./FloorEastWingTopLayout"; import WestWingTopLevelsLayout from "./WestWingTopLevelsLayout";
import FloorEastWingTopHighlighting from "./FloorEastWingTopHighlighting"; import WestWingTopLevelsHighlighting from "./WestWingTopLevelsHighlighting";
import { apartmentsWithoutVirtualTour } from "../../../consts/apartmentsWithoutVirtualTour";
// import _appartment from "../../../data/appartments.json";
// import { IAppartmentComplex } from "../../../types/apartmentSphere";
// const appartments = _appartment as IAppartmentComplex[];
interface IFloorSidebarProps { interface IFloorSidebarProps {
currentFloor: IDesctiptionFloor | null; currentFloor: IDesctiptionFloor | null;
@@ -31,6 +28,9 @@ const FloorSidebar = ({
const [hoveredApartment, setHoveredApartment] = useState<IAparmentRes | null>( const [hoveredApartment, setHoveredApartment] = useState<IAparmentRes | null>(
null null
); );
const [defaultApartments, setDefaultApartments] = useState<IAparmentRes[]>(
[]
);
const [is3DTourAvailable] = useState(true); const [is3DTourAvailable] = useState(true);
const { setModal } = useModal(); const { setModal } = useModal();
const descRef = useRef(null); const descRef = useRef(null);
@@ -46,7 +46,7 @@ const FloorSidebar = ({
event: React.MouseEvent<SVGSVGElement, MouseEvent> event: React.MouseEvent<SVGSVGElement, MouseEvent>
) { ) {
const apartmentType = event.currentTarget.dataset.type; const apartmentType = event.currentTarget.dataset.type;
const apartment = floorApartments.find( const apartment = defaultApartments.find(
(aprt) => aprt.Unit_Type === apartmentType (aprt) => aprt.Unit_Type === apartmentType
); );
if (apartment) { if (apartment) {
@@ -58,11 +58,12 @@ const FloorSidebar = ({
function handleOnMouseOut(): void { function handleOnMouseOut(): void {
setIsDescVisible(false); setIsDescVisible(false);
} }
function handleOnMouseOver( function handleOnMouseOver(
event: React.MouseEvent<SVGSVGElement, MouseEvent> event: React.MouseEvent<SVGSVGElement, MouseEvent>
): void { ): void {
const apartmentType = event.currentTarget.dataset.type; const apartmentType = event.currentTarget.dataset.type;
const _hoveredApartment = floorApartments.find( const _hoveredApartment = defaultApartments.find(
(apart) => apart.Unit_Type === apartmentType (apart) => apart.Unit_Type === apartmentType
); );
if (_hoveredApartment) { if (_hoveredApartment) {
@@ -81,6 +82,34 @@ const FloorSidebar = ({
}; };
}, []); }, []);
useEffect(() => {
if (!currentFloor) return;
const _defaultApartment: IAparmentRes[] = apartmentsWithoutVirtualTour.map(
(aprt, index) => {
const unitNo = `${currentFloor?.wing.slice(1)}-${index}`;
return {
id: unitNo,
Floor: currentFloor.floor,
Property_Status: "Available",
Unit_Type: aprt.type,
Project_Name: "Rove Home Marasi Drive",
Suite_Area_Sqft: 0,
Balcony_Area_Sqft: 0,
No_Of_Bedrooms: 1,
Unit_No: unitNo,
Total_Area_Sqft: 0,
No_of_Bathrooms: 0,
Property_Name: "-",
Unit_View: "-",
};
}
);
setDefaultApartments([..._defaultApartment, ...floorApartments]);
return () => {};
}, [currentFloor, currentFloor?.floor, currentFloor?.wing, floorApartments]);
return ( return (
<> <>
<div <div
@@ -135,6 +164,54 @@ const FloorSidebar = ({
<div className="px-10 bg-white flex gap-6 font-semibold text-caption-m rounded-2xl justify-center items-center flex-1 py-4"> <div className="px-10 bg-white flex gap-6 font-semibold text-caption-m rounded-2xl justify-center items-center flex-1 py-4">
{currentFloor?.wing === "West Wing" ? ( {currentFloor?.wing === "West Wing" ? (
currentFloor && currentFloor.floor <= 21 ? (
<svg
xmlns="http://www.w3.org/2000/svg"
width="204"
height="588"
fill="none"
viewBox="0 0 204 588"
>
<WestWingLayout />
<WestWingHighlighting
handleOnApartmentClick={handleOnApartmentClick}
handleOnMouseOut={handleOnMouseOut}
handleOnMouseOver={handleOnMouseOver}
/>
</svg>
) : (
<svg
xmlns="http://www.w3.org/2000/svg"
width="205"
height="588"
fill="none"
viewBox="0 0 205 588"
>
<WestWingTopLevelsLayout />
<WestWingTopLevelsHighlighting
handleOnApartmentClick={handleOnApartmentClick}
handleOnMouseOut={handleOnMouseOut}
handleOnMouseOver={handleOnMouseOver}
/>
</svg>
)
) : (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
width="672"
height="280"
viewBox="0 0 672 280"
>
<EastWingLayout />
<EastWingHighlighting
handleOnApartmentClick={handleOnApartmentClick}
handleOnMouseOut={handleOnMouseOut}
handleOnMouseOver={handleOnMouseOver}
/>
</svg>
)}
{/* {currentFloor?.wing === "West Wing" ? (
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
fill="none" fill="none"
@@ -149,37 +226,7 @@ const FloorSidebar = ({
handleOnMouseOver={handleOnMouseOver} handleOnMouseOver={handleOnMouseOver}
/> />
</svg> </svg>
) : currentFloor && currentFloor.floor <= 21 ? ( ) : } */}
<svg
xmlns="http://www.w3.org/2000/svg"
width="204"
height="588"
fill="none"
viewBox="0 0 204 588"
>
<FloorEastWingLayout />
<FloorEastWingHighlighting
handleOnApartmentClick={handleOnApartmentClick}
handleOnMouseOut={handleOnMouseOut}
handleOnMouseOver={handleOnMouseOver}
/>
</svg>
) : (
<svg
xmlns="http://www.w3.org/2000/svg"
width="205"
height="588"
fill="none"
viewBox="0 0 205 588"
>
<FloorEastWingTopLayout />
<FloorEastWingTopHighlighting
handleOnApartmentClick={handleOnApartmentClick}
handleOnMouseOut={handleOnMouseOut}
handleOnMouseOver={handleOnMouseOver}
/>
</svg>
)}
</div> </div>
</div> </div>
</> </>
@@ -10,7 +10,7 @@ interface FloorEastWingHighlightingProps {
) => void; ) => void;
} }
function FloorEastWingHighlighting({ function WestWingHighlighting({
handleOnMouseOut, handleOnMouseOut,
handleOnMouseOver, handleOnMouseOver,
handleOnApartmentClick, handleOnApartmentClick,
@@ -79,6 +79,7 @@ function FloorEastWingHighlighting({
/> />
</svg> </svg>
<svg <svg
data-type="1 BR U2 Left"
onMouseOut={handleOnMouseOut} onMouseOut={handleOnMouseOut}
onMouseOver={handleOnMouseOver} onMouseOver={handleOnMouseOver}
onClick={handleOnApartmentClick} onClick={handleOnApartmentClick}
@@ -153,6 +154,7 @@ function FloorEastWingHighlighting({
/> />
</svg> </svg>
<svg <svg
data-type="1 BR U2 Right"
onMouseOut={handleOnMouseOut} onMouseOut={handleOnMouseOut}
onMouseOver={handleOnMouseOver} onMouseOver={handleOnMouseOver}
onClick={handleOnApartmentClick} onClick={handleOnApartmentClick}
@@ -473,4 +475,4 @@ function FloorEastWingHighlighting({
); );
} }
export default FloorEastWingHighlighting; export default WestWingHighlighting;
@@ -1,4 +1,4 @@
const FloorEastWingLayout = () => { const WestWingLayout = () => {
return ( return (
<> <>
<path <path
@@ -459,4 +459,4 @@ const FloorEastWingLayout = () => {
); );
}; };
export default FloorEastWingLayout; export default WestWingLayout;
@@ -1,4 +1,4 @@
interface FloorEastWingTopHighlightingProps { interface WestWingTopLevelsHighlightingProps {
handleOnMouseOut: handleOnMouseOut:
| (() => void) | (() => void)
| ((event: React.MouseEvent<SVGSVGElement, MouseEvent>) => void); | ((event: React.MouseEvent<SVGSVGElement, MouseEvent>) => void);
@@ -10,11 +10,11 @@ interface FloorEastWingTopHighlightingProps {
) => void; ) => void;
} }
function FloorEastWingTopHighlighting({ function WestWingTopLevelsHighlighting({
handleOnMouseOut, handleOnMouseOut,
handleOnMouseOver, handleOnMouseOver,
handleOnApartmentClick, handleOnApartmentClick,
}: FloorEastWingTopHighlightingProps) { }: WestWingTopLevelsHighlightingProps) {
return ( return (
<> <>
<svg <svg
@@ -72,6 +72,7 @@ function FloorEastWingTopHighlighting({
/> />
</svg> </svg>
<svg <svg
data-type="1 BR U2 Right"
onMouseOut={handleOnMouseOut} onMouseOut={handleOnMouseOut}
onMouseOver={handleOnMouseOver} onMouseOver={handleOnMouseOver}
onClick={handleOnApartmentClick} onClick={handleOnApartmentClick}
@@ -96,6 +97,7 @@ function FloorEastWingTopHighlighting({
/> />
</svg> </svg>
<svg <svg
data-type="1 BR U2 Left"
onMouseOut={handleOnMouseOut} onMouseOut={handleOnMouseOut}
onMouseOver={handleOnMouseOver} onMouseOver={handleOnMouseOver}
onClick={handleOnApartmentClick} onClick={handleOnApartmentClick}
@@ -220,6 +222,7 @@ function FloorEastWingTopHighlighting({
/> />
</svg> </svg>
<svg <svg
data-type="1 BR U2 Left"
onMouseOut={handleOnMouseOut} onMouseOut={handleOnMouseOut}
onMouseOver={handleOnMouseOver} onMouseOver={handleOnMouseOver}
onClick={handleOnApartmentClick} onClick={handleOnApartmentClick}
@@ -244,6 +247,7 @@ function FloorEastWingTopHighlighting({
/> />
</svg> </svg>
<svg <svg
data-type="1 BR U2 Right"
onMouseOut={handleOnMouseOut} onMouseOut={handleOnMouseOut}
onMouseOver={handleOnMouseOver} onMouseOver={handleOnMouseOver}
onClick={handleOnApartmentClick} onClick={handleOnApartmentClick}
@@ -379,8 +383,33 @@ function FloorEastWingTopHighlighting({
fillOpacity="0.2" fillOpacity="0.2"
/> />
</svg> </svg>
<svg
data-type="Studio Squared"
onMouseOut={handleOnMouseOut}
onMouseOver={handleOnMouseOver}
onClick={handleOnApartmentClick}
className="opacity-0 hover:opacity-100 ease-in-out duration-300 transition-opacity cursor-pointer"
x={99}
y={310}
width="78"
height="33"
viewBox="0 0 78 33"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5.9351 32.593H59.7103V1.90207H19.0635V0.658203H4.00961V5.53797H0.624023V7.06293V16.1567V26.9562H5.9351V32.593Z"
fill="#00BED7"
fillOpacity="0.2"
/>
<path
d="M77.4163 32.593V6.01846H60.0418V32.593H77.4163Z"
fill="#00BED7"
fillOpacity="0.2"
/>
</svg>
</> </>
); );
} }
export default FloorEastWingTopHighlighting; export default WestWingTopLevelsHighlighting;
@@ -1,4 +1,4 @@
const FloorEastWingTopLayout = () => { const WestWingTopLevelsLayout = () => {
return ( return (
<> <>
<path <path
@@ -414,4 +414,4 @@ const FloorEastWingTopLayout = () => {
); );
}; };
export default FloorEastWingTopLayout; export default WestWingTopLevelsLayout;
@@ -12,9 +12,14 @@ import {
mobileWidht, mobileWidht,
descriptions, descriptions,
} from "../../consts/masterplan"; } from "../../consts/masterplan";
import { getApartments } from "../../api/apartments";
import { updateAccessToken } from "../../api/updateAccessToken"; import { updateAccessToken } from "../../api/updateAccessToken";
import { IAparmentRes, IApartmentsRes } from "../../types/apartmentsRes"; import { IAparmentRes } from "../../types/apartmentsRes";
import useMasterplanFilters from "../../store/useMasterplanFilters";
import { initialRoveHomeCheckboxes } from "../../consts/initialMasterplanFilters";
import { pageInitial } from "../../consts/initialMasterplanFilters";
import { useDebounce } from "@uidotdev/usehooks";
import { getFilteredApartments } from "../../calc/getFilteredApartments";
import MasterplanLoaderModal from "../modals/MasterplanLoaderModal";
const skyGardenFloor = 22; const skyGardenFloor = 22;
@@ -27,6 +32,7 @@ const SequenceWing = () => {
const [mousePos, setMousePos] = useState<[number, number]>([0, 0]); const [mousePos, setMousePos] = useState<[number, number]>([0, 0]);
const [currentHoveredFloor, setHoverCurrentFloor] = const [currentHoveredFloor, setHoverCurrentFloor] =
useState<null | IDesctiptionFloor>(null); useState<null | IDesctiptionFloor>(null);
const [isLoading, setIsLoading] = useState(true);
const [currentFloor, setCurrentFloor] = useState<IDesctiptionFloor | null>( const [currentFloor, setCurrentFloor] = useState<IDesctiptionFloor | null>(
null null
); );
@@ -41,6 +47,14 @@ const SequenceWing = () => {
const [selectedApartments, setSelectedApartments] = useState<IAparmentRes[]>( const [selectedApartments, setSelectedApartments] = useState<IAparmentRes[]>(
[] []
); );
const {
apartmentTypeCheckboxes,
switchers,
multirangeSliders,
viewCheckboxes,
sortList,
} = useMasterplanFilters();
const debouncedSliders = useDebounce(multirangeSliders, 300);
function handleResize() { function handleResize() {
const screenWidth = window.innerWidth; const screenWidth = window.innerWidth;
@@ -149,25 +163,60 @@ const SequenceWing = () => {
useEffect(() => { useEffect(() => {
const zohoToken = localStorage.getItem("ACCESS_TOKEN"); const zohoToken = localStorage.getItem("ACCESS_TOKEN");
setIsLoading(true);
getApartments(zohoToken) getFilteredApartments(
zohoToken,
setApartments,
initialRoveHomeCheckboxes,
apartmentTypeCheckboxes,
debouncedSliders,
switchers,
viewCheckboxes,
sortList,
pageInitial,
1000
)
.catch((error) => { .catch((error) => {
const errorStatus = error.response.status; const errorStatus = error.response.status;
if (errorStatus === 401) { if (errorStatus === 401) {
updateAccessToken().then((token) => { updateAccessToken().then((token) => {
if (token) { if (token) {
getApartments(token); getFilteredApartments(
token,
setApartments,
initialRoveHomeCheckboxes,
apartmentTypeCheckboxes,
debouncedSliders,
switchers,
viewCheckboxes,
sortList,
pageInitial,
1000
);
} }
}); });
} }
}) })
.then((data) => { .finally(() => {
const apartmentsData = (data as IApartmentsRes).apartments; setIsLoading(false);
const updatedApartments = [...apartmentsData];
setApartments(updatedApartments);
}); });
}, []); }, [
apartmentTypeCheckboxes,
debouncedSliders,
sortList,
switchers,
viewCheckboxes,
]);
useEffect(() => {
if (isLoading) {
setModal(<MasterplanLoaderModal />);
} else {
setModal(null);
}
}, [isLoading, setModal]);
return ( return (
<div className="absolute left-0 overflow-hidden h-screen w-screen select-none "> <div className="absolute left-0 overflow-hidden h-screen w-screen select-none ">
@@ -9,6 +9,7 @@ import { MobileModalWrapper } from "../modals/mobile/MobileModalWrapper";
import SendEnquiryMobileModal from "../modals/mobile/SendEnquiryMobileModal"; import SendEnquiryMobileModal from "../modals/mobile/SendEnquiryMobileModal";
import { IAparmentRes } from "../../types/apartmentsRes"; import { IAparmentRes } from "../../types/apartmentsRes";
import useFavorites from "../../store/useFavorites"; import useFavorites from "../../store/useFavorites";
import { apartmentRoutes } from "../../consts/apartmentsRoutes";
interface FavoriteAppartmentCardProps { interface FavoriteAppartmentCardProps {
card: IAparmentRes; card: IAparmentRes;
@@ -19,6 +20,9 @@ const FavoriteAppartmentCard = ({ card }: FavoriteAppartmentCardProps) => {
const wing = Unit_No.split("-")[0] === "E" ? "East" : "West"; const wing = Unit_No.split("-")[0] === "E" ? "East" : "West";
const navigate = useNavigate(); const navigate = useNavigate();
const { setFavorites } = useFavorites(); const { setFavorites } = useFavorites();
const layoutImage = apartmentRoutes.find(
(apr) => apr.type === card.Unit_Type
)?.layout;
const { setModal } = useModal(); const { setModal } = useModal();
@@ -95,7 +99,11 @@ const FavoriteAppartmentCard = ({ card }: FavoriteAppartmentCardProps) => {
/> />
</div> </div>
<div className="w-full aspect-square rounded-lg"> <div className="w-full aspect-square rounded-lg">
<img src="/images/layout-1.png" alt="" className="h-full" /> <img
src={layoutImage}
alt=""
className="w-full aspect-square object-contain"
/>
</div> </div>
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
<div className="flex flex-col gap-1"> <div className="flex flex-col gap-1">
@@ -1,4 +1,5 @@
// import { formatNumber } from "../../calc/formatNumber"; // import { formatNumber } from "../../calc/formatNumber";
import { apartmentRoutes } from "../../consts/apartmentsRoutes";
import useFavorites from "../../store/useFavorites"; import useFavorites from "../../store/useFavorites";
import { IAparmentRes } from "../../types/apartmentsRes"; import { IAparmentRes } from "../../types/apartmentsRes";
import Button from "../Button"; import Button from "../Button";
@@ -13,6 +14,9 @@ interface FavoriteSliderCardProps {
const FavoriteSliderCard = ({ card, elementRef }: FavoriteSliderCardProps) => { const FavoriteSliderCard = ({ card, elementRef }: FavoriteSliderCardProps) => {
const wing = card.Unit_No.split("-")[0] === "E" ? "East" : "West"; const wing = card.Unit_No.split("-")[0] === "E" ? "East" : "West";
const { setFavorites } = useFavorites(); const { setFavorites } = useFavorites();
const layoutImage = apartmentRoutes.find(
(apr) => apr.type === card.Unit_Type
)?.layout;
const handleOnAddFavoriteClick = ( const handleOnAddFavoriteClick = (
e: React.MouseEvent<HTMLButtonElement, MouseEvent> e: React.MouseEvent<HTMLButtonElement, MouseEvent>
@@ -58,9 +62,9 @@ const FavoriteSliderCard = ({ card, elementRef }: FavoriteSliderCardProps) => {
/> />
</div> </div>
<img <img
src="/images/layout-1.png" src={layoutImage}
alt="" alt=""
className="w-full pointer-events-none select-none" className="w-full object-contain aspect-square pointer-events-none select-none"
/> />
</div> </div>
<div className="flex flex-col gap-1 pb-6 border-b"> <div className="flex flex-col gap-1 pb-6 border-b">
@@ -12,7 +12,7 @@ const Navbar = () => {
const [tabs, setTabs] = useState(_tabs); const [tabs, setTabs] = useState(_tabs);
const location = useLocation(); const location = useLocation();
const navigate = useNavigate(); const navigate = useNavigate();
const { favorites } = useFavorites(); const { favorites, setFavorites } = useFavorites();
const onTabClick = (tab: Tab) => { const onTabClick = (tab: Tab) => {
setSelectedTab(tab); setSelectedTab(tab);
@@ -30,6 +30,13 @@ const Navbar = () => {
} }
}, [location.pathname]); }, [location.pathname]);
useEffect(() => {
const _favorites = localStorage.getItem("Favorites");
if (!_favorites) return;
const convertedFavorute = JSON.parse(_favorites);
setFavorites(convertedFavorute);
}, [setFavorites]);
useEffect(() => { useEffect(() => {
const updatedTabs = _tabs.map((tab) => { const updatedTabs = _tabs.map((tab) => {
if (tab.value === "Favorites") { if (tab.value === "Favorites") {
@@ -0,0 +1,31 @@
const LoadingIcon = () => {
return (
<svg
width="64"
height="64"
viewBox="0 0 64 64"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M52.267 32.0001C52.8561 32.0001 53.3364 31.5221 53.307 30.9338C53.0735 26.2653 51.3116 21.7914 48.2774 18.21C45.0129 14.3567 40.4871 11.7865 35.5055 10.9567C30.5238 10.1269 25.4094 11.0913 21.072 13.6784C16.7347 16.2655 13.4558 20.3074 11.8188 25.085C10.1818 29.8626 10.2928 35.0661 12.1321 39.7695C13.9714 44.473 17.4196 48.3714 21.8633 50.7711C26.307 53.1709 31.458 53.9163 36.3997 52.8749C40.9928 51.9069 45.1282 49.4536 48.1757 45.9094C48.5598 45.4627 48.4735 44.7906 48.0082 44.4293C47.5429 44.068 46.875 44.1546 46.4884 44.5991C43.7524 47.7455 40.0586 49.9235 35.9598 50.7874C31.5122 51.7247 26.8764 51.0538 22.877 48.894C18.8777 46.7343 15.7743 43.2257 14.1189 38.9926C12.4636 34.7595 12.3637 30.0764 13.837 25.7765C15.3103 21.4767 18.2613 17.839 22.1649 15.5106C26.0685 13.1822 30.6715 12.3142 35.155 13.061C39.6385 13.8078 43.7116 16.121 46.6497 19.589C49.3574 22.785 50.9393 26.7708 51.1707 30.9339C51.2034 31.522 51.6779 32.0001 52.267 32.0001Z"
fill="url(#paint0_angular_1498_24245)"
/>
<defs>
<radialGradient
id="paint0_angular_1498_24245"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(32.0003 32.0001) rotate(45) scale(21.1189)"
>
<stop offset="0.874517" stopColor="#00BED7" />
<stop offset="0.982613" stopColor="#00BED7" stopOpacity="0" />
</radialGradient>
</defs>
</svg>
);
};
export default LoadingIcon;
@@ -8,35 +8,8 @@ import SwitchToggle from "../SwitchToggle";
import HeartIcon from "../icons/Heart"; import HeartIcon from "../icons/Heart";
import LeftArrowSliderIcon from "../icons/LeftArrowSliderIcon"; import LeftArrowSliderIcon from "../icons/LeftArrowSliderIcon";
import { IAparmentRes } from "../../types/apartmentsRes"; import { IAparmentRes } from "../../types/apartmentsRes";
import { apartmentsWithoutVirtualTour } from "../../consts/apartmentsWithoutVirtualTour";
interface IApartmentRoute { import { apartmentRoutes } from "../../consts/apartmentsRoutes";
type: string;
virtualTour: string;
id: string;
}
const apartmentRoute: IApartmentRoute[] = [
{
type: "1 BR Squared",
virtualTour: "apartments-studio-3",
id: "1",
},
{
type: "Studio Squared",
virtualTour: "apartments-studio-2",
id: "2",
},
{
type: "2 BR Squared",
virtualTour: "apartments-studio-4",
id: "3",
},
{
type: "Studio Flex",
virtualTour: "apartments-studio-1",
id: "4",
},
];
interface AboutComplexModalProps { interface AboutComplexModalProps {
apartment: IAparmentRes; apartment: IAparmentRes;
@@ -48,6 +21,15 @@ const AboutComplexModal = ({ apartment }: AboutComplexModalProps) => {
const navigate = useNavigate(); const navigate = useNavigate();
const unitNumber = apartment.Unit_No.split("-")[1]; const unitNumber = apartment.Unit_No.split("-")[1];
const wing = apartment.Unit_No.split("-")[0] === "E" ? "East" : "West"; const wing = apartment.Unit_No.split("-")[0] === "E" ? "East" : "West";
const isVirtualTourAvailialbe = !apartmentsWithoutVirtualTour.some(
(aprt) => aprt.type === apartment.Unit_Type
);
const layoutWithoutVirtualTour = isVirtualTourAvailialbe
? apartmentRoutes.find((aprt) => aprt.type === apartment.Unit_Type)?.layout
: apartmentsWithoutVirtualTour.find(
(aprt) => aprt.type === apartment.Unit_Type
)?.layout;
const handleOnBackClick = () => { const handleOnBackClick = () => {
setModal(false); setModal(false);
@@ -59,7 +41,7 @@ const AboutComplexModal = ({ apartment }: AboutComplexModalProps) => {
const handleOn3DTourClick = () => { const handleOn3DTourClick = () => {
setModal(null); setModal(null);
const virtualTour = apartmentRoute.find( const virtualTour = apartmentRoutes.find(
(route) => route.type === apartment.Unit_Type (route) => route.type === apartment.Unit_Type
); );
@@ -99,10 +81,10 @@ const AboutComplexModal = ({ apartment }: AboutComplexModalProps) => {
</div> </div>
{/* Layout */} {/* Layout */}
<div className="p-10 rounded-2xl bg-white flex flex-col items-center gap-8 relative justify-center h-full"> <div className="p-10 rounded-2xl bg-white flex flex-col items-center gap-8 relative justify-center h-full">
<div className="w-full flex justify-center h-full"> <div className="flex justify-center h-full">
<img <img
className="object-cover h-full" className="object-cover h-full"
src="/images/layout-1.png" src={`${layoutWithoutVirtualTour}`}
alt="" alt=""
/> />
</div> </div>
@@ -172,6 +154,7 @@ const AboutComplexModal = ({ apartment }: AboutComplexModalProps) => {
text="3D Tour" text="3D Tour"
buttonType="secondary" buttonType="secondary"
className="w-full flex justify-center" className="w-full flex justify-center"
disabled={!isVirtualTourAvailialbe}
/> />
<Button <Button
text="Send Enquiry" text="Send Enquiry"
@@ -1,4 +1,3 @@
import { useState } from "react";
import useModal from "../../store/useModal"; import useModal from "../../store/useModal";
import Button from "../Button"; import Button from "../Button";
import CrossIcon from "../icons/CrossIcon"; import CrossIcon from "../icons/CrossIcon";
@@ -6,38 +5,38 @@ import ResetIcon from "../icons/ResetIcon";
import Checkbox from "../Checkbox"; import Checkbox from "../Checkbox";
import Switch from "../Switch"; import Switch from "../Switch";
import MultiRangeSlider from "../MultiRangeSlider"; import MultiRangeSlider from "../MultiRangeSlider";
import { ICheckbox } from "../../types/checkbox";
import { IMultirangeSlider } from "../../types/multirangeSlider";
import { ISwitcher } from "../../types/switcher";
import { import {
initialAparmentTypeCheckboxes, initialAparmentTypeCheckboxes,
initialSliders, initialSliders,
initialSwitchers, initialSwitchers,
initialViewCheckboxes, initialViewCheckboxes,
} from "../../consts/initialMasterplanFilters"; } from "../../consts/initialMasterplanFilters";
import useMasterplanFilters from "../../store/useMasterplanFilters";
const MasterplanFilters = () => { const MasterplanFilters = () => {
const { setModal } = useModal(); const { setModal } = useModal();
const [apartmentTypeCheckbox, setAparmentTypeCheckboxes] = useState< const {
ICheckbox[] apartmentTypeCheckboxes,
>(initialAparmentTypeCheckboxes); setApartmentTypeCheckboxes,
const [viewCheckboxes, setViewCheckboxes] = useState<ICheckbox[]>( viewCheckboxes,
initialViewCheckboxes setViewCheckboxes,
); multirangeSliders,
const [sliders, setSliders] = useState<IMultirangeSlider[]>(initialSliders); setMultirangeSliders,
const [switchers, setSwitchers] = useState<ISwitcher[]>(initialSwitchers); switchers,
setSwitchers,
} = useMasterplanFilters();
const handleOnCloseClick = () => setModal(null); const handleOnCloseClick = () => setModal(null);
const handleOnApartmentTypeCheckboxClick = (checkboxId: string) => { const handleOnApartmentTypeCheckboxClick = (checkboxId: string) => {
const updatedCheckboxes = apartmentTypeCheckbox.map((cbox) => { const updatedCheckboxes = apartmentTypeCheckboxes.map((cbox) => {
if (checkboxId !== cbox.id) return cbox; if (checkboxId !== cbox.id) return cbox;
const isSelected = !cbox.selected; const isSelected = !cbox.selected;
return { ...cbox, selected: isSelected }; return { ...cbox, selected: isSelected };
}); });
setAparmentTypeCheckboxes(updatedCheckboxes); setApartmentTypeCheckboxes(updatedCheckboxes);
}; };
const handleOnViewCheckboxClick = (checkboxId: string) => { const handleOnViewCheckboxClick = (checkboxId: string) => {
@@ -55,7 +54,7 @@ const MasterplanFilters = () => {
sliderId: string, sliderId: string,
e: [a: number, b: number] e: [a: number, b: number]
) => { ) => {
const updatedSliders = sliders.map((slider) => { const updatedSliders = multirangeSliders.map((slider) => {
if (sliderId !== slider.id) return slider; if (sliderId !== slider.id) return slider;
return { return {
@@ -65,7 +64,7 @@ const MasterplanFilters = () => {
}; };
}); });
setSliders(updatedSliders); setMultirangeSliders(updatedSliders);
}; };
const handleOnSwitcherClick = (switcherId: string) => { const handleOnSwitcherClick = (switcherId: string) => {
@@ -80,14 +79,14 @@ const MasterplanFilters = () => {
}; };
const handleOnResetClick = () => { const handleOnResetClick = () => {
setAparmentTypeCheckboxes(initialAparmentTypeCheckboxes); setApartmentTypeCheckboxes(initialAparmentTypeCheckboxes);
setViewCheckboxes(initialViewCheckboxes); setViewCheckboxes(initialViewCheckboxes);
setSliders(initialSliders); setMultirangeSliders(initialSliders);
setSwitchers(initialSwitchers); setSwitchers(initialSwitchers);
}; };
return ( return (
<div className="absolute z-[99999901] top-0 left-0 w-screen bg-[#0D192266] h-screen backdrop-blur-[6px] items-center "> <div className="absolute z-[99999901] top-0 left-0 w-screen bg-[#0D192266] h-screen backdrop-blur-[6px] items-center select-none">
<div className="h-screen bg-[#F3F3F2] flex flex-col items-center justify-between w-[360px] overflow-y-scroll"> <div className="h-screen bg-[#F3F3F2] flex flex-col items-center justify-between w-[360px] overflow-y-scroll">
<div className="w-full py-6 px-6 flex flex-col items-center"> <div className="w-full py-6 px-6 flex flex-col items-center">
<div className="flex justify-between border-b border-[#E2E2DC] w-full pb-4"> <div className="flex justify-between border-b border-[#E2E2DC] w-full pb-4">
@@ -102,7 +101,7 @@ const MasterplanFilters = () => {
<div className="flex flex-col pt-6 w-full"> <div className="flex flex-col pt-6 w-full">
<p className="text-[#0D1922] text-s pb-4">Apartment type</p> <p className="text-[#0D1922] text-s pb-4">Apartment type</p>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
{apartmentTypeCheckbox.map((checkbox) => ( {apartmentTypeCheckboxes.map((checkbox) => (
<Checkbox <Checkbox
checkbox={checkbox} checkbox={checkbox}
key={checkbox.id} key={checkbox.id}
@@ -112,7 +111,7 @@ const MasterplanFilters = () => {
</div> </div>
</div> </div>
<div className="flex flex-col pt-6 w-full gap-8"> <div className="flex flex-col pt-6 w-full gap-8">
{sliders.map((slider) => ( {multirangeSliders.map((slider) => (
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<p className="text-[#0D1922] text-s ">{slider.title}</p> <p className="text-[#0D1922] text-s ">{slider.title}</p>
@@ -0,0 +1,11 @@
const MasterplanLoaderModal = () => {
return (
<div className="absolute z-[99999] top-0 left-0 w-screen bg-[#F3F3F2] h-screen flex justify-center items-center">
<div className="animate-spin">
<img src="/images/loader.png" alt="" />
</div>
</div>
);
};
export default MasterplanLoaderModal;
@@ -0,0 +1,11 @@
const SearchLoaderModal = () => {
return (
<div className="absolute z-[99] top-0 left-0 w-screen bg-[#F3F3F2] h-screen flex justify-center items-center">
<div className="animate-spin">
<img src="/images/loader.png" alt="" />
</div>
</div>
);
};
export default SearchLoaderModal;
@@ -0,0 +1,32 @@
import useModal from "../../store/useModal";
import CrossIcon from "../icons/CrossIcon";
interface VirtualTourVideoModalProps {
videoHref: string;
}
const VirtualTourVideoModal = ({ videoHref }: VirtualTourVideoModalProps) => {
const { setModal } = useModal();
const handleOnCloseClick = () => {
setModal(null);
};
return (
<div className="absolute z-[99999999] top-0 left-0 w-screen bg-[#0D192266] h-screen backdrop-blur-[6px] flex justify-center items-center">
<div
className="aspect-video xl:h-[768px] xl:w-auto w-screen relative select-none cursor-pointer"
onClick={handleOnCloseClick}
>
<div className="absolute top-[10px] right-[10px] text-white">
<CrossIcon />
</div>
<video autoPlay muted className="w-full" playsInline preload="metadata">
<source src={videoHref} type="video/mp4" />
</video>
</div>
</div>
);
};
export default VirtualTourVideoModal;
@@ -29,6 +29,16 @@
border-radius: 50%; border-radius: 50%;
background: #00bed7; background: #00bed7;
} }
/* .range-slider .range-slider__thumb .disabled {
position: absolute;
z-index: 3;
top: 50%;
width: 16px;
height: 16px;
transform: translate(-50%, -50%);
border-radius: 50%;
background: #0d192266;
} */
.range-slider .range-slider__thumb:focus-visible { .range-slider .range-slider__thumb:focus-visible {
outline: 0; outline: 0;
} }
@@ -38,6 +48,7 @@
.range-slider .range-slider__thumb[data-disabled] { .range-slider .range-slider__thumb[data-disabled] {
z-index: 2; z-index: 2;
} }
.range-slider .range-slider__range { .range-slider .range-slider__range {
position: absolute; position: absolute;
z-index: 1; z-index: 1;
@@ -47,6 +58,17 @@
height: 100%; height: 100%;
background: #00bed7; background: #00bed7;
} }
/* .range-slider .range-slider__range .disabled {
position: absolute;
z-index: 1;
transform: translate(0, -50%);
top: 50%;
width: 100%;
height: 100%;
background: white;
} */
.range-slider[data-vertical] .range-slider__range { .range-slider[data-vertical] .range-slider__range {
left: 50%; left: 50%;
transform: translate(-50%, 0); transform: translate(-50%, 0);
@@ -1,24 +1,33 @@
import { useState } from "react"; import { useState } from "react";
import { ISwitchLabel } from "../../types/switchLabel"; import { ISwitchLabel } from "../../types/switchLabel";
import SwitchToggle from "../SwitchToggle"; import SwitchToggle from "../SwitchToggle";
import { IAparmentRes } from "../../types/apartmentsRes";
import { apartmentRoutes } from "../../consts/apartmentsRoutes";
const apartmentLayouts: ISwitchLabel[] = [ const apartmentLayouts: ISwitchLabel[] = [
{ id: "1", label: "Layout" }, { id: "1", label: "Layout" },
{ id: "2", label: "On the floor" }, { id: "2", label: "On the floor" },
]; ];
const ApartmentLayout = () => { interface ApartmentLayoutProps {
currentApartment: IAparmentRes;
}
const ApartmentLayout = ({ currentApartment }: ApartmentLayoutProps) => {
const [currentLabel, setCurrentLabel] = useState(apartmentLayouts[0]); const [currentLabel, setCurrentLabel] = useState(apartmentLayouts[0]);
const handleOnSwitchClick = (label: ISwitchLabel) => { const handleOnSwitchClick = (label: ISwitchLabel) => {
setCurrentLabel(label); setCurrentLabel(label);
}; };
const imageLayout = apartmentRoutes.find(
(aprt) => aprt.type === currentApartment.Unit_Type
)?.layout;
return ( return (
<div className="p-10 pt-6 rounded-2xl bg-white flex flex-col items-center gap-8 relative h-full"> <div className="p-10 pt-6 rounded-2xl bg-white flex flex-col items-center gap-8 relative h-full ">
<div className="w-full xl:px-[304px] sm:px-24 h-full"> <div className="w-full xl:px-[304px] sm:px-24 h-full max-h-[888px]">
<img <img
className="w-full h-full object-cover" className="w-full h-full object-cover"
src="/images/layout-1.png" src={imageLayout ? imageLayout : "/images/layout-1.png"}
alt="" alt=""
/> />
</div> </div>
@@ -2,9 +2,15 @@ import { useNavigate } from "react-router-dom";
import Button from "../Button"; import Button from "../Button";
import HeartIcon from "../icons/Heart"; import HeartIcon from "../icons/Heart";
import LeftArrowSliderIcon from "../icons/LeftArrowSliderIcon"; import LeftArrowSliderIcon from "../icons/LeftArrowSliderIcon";
import { IAparmentRes } from "../../types/apartmentsRes";
const ButtonPanel = () => { interface ButtonPanelProps {
currentApartment: IAparmentRes;
}
const ButtonPanel = ({ currentApartment }: ButtonPanelProps) => {
const navigate = useNavigate(); const navigate = useNavigate();
const unitNo = currentApartment.Unit_No.split("-")[1];
const handleOnBackClick = () => { const handleOnBackClick = () => {
navigate(-1); navigate(-1);
@@ -19,9 +25,11 @@ const ButtonPanel = () => {
onClick={handleOnBackClick} onClick={handleOnBackClick}
/> />
<div className="flex flex-col"> <div className="flex flex-col">
<p className="text-[#73787C] text-caption-m font-semibold"> 213</p> <p className="text-[#73787C] text-caption-m font-semibold">
{unitNo}
</p>
<h2 className="text-subheadline-s font-semibold text-[#0D1922]"> <h2 className="text-subheadline-s font-semibold text-[#0D1922]">
1 bedroom apartment {currentApartment.Unit_Type}
</h2> </h2>
</div> </div>
</div> </div>
@@ -1,25 +1,17 @@
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { ILayoutCard } from "../../types/layoutCard"; // import { formatNumber } from "../../calc/formatNumber";
import { formatNumber } from "../../calc/formatNumber"; import { IAparmentRes } from "../../types/apartmentsRes";
interface LayoutCardProps { interface LayoutCardProps {
layoutCard: ILayoutCard; layoutCard: IAparmentRes;
elementRef: React.MutableRefObject<HTMLDivElement | null>; elementRef: React.MutableRefObject<HTMLDivElement | null>;
} }
const SimilarAppartmentCard = ({ layoutCard, elementRef }: LayoutCardProps) => { const SimilarAppartmentCard = ({ layoutCard, elementRef }: LayoutCardProps) => {
const { const { Floor, Unit_Type, Project_Name, Total_Area_Sqft, Unit_No, id } =
floorEnd, layoutCard;
floorStart,
apartmentType,
roveHome,
wing,
units,
square,
cost,
id,
} = layoutCard;
const navigate = useNavigate(); const navigate = useNavigate();
const wing = Unit_No.split("-")[0] === "E" ? "East Wing" : "West Wing";
const handleOnClick = () => { const handleOnClick = () => {
navigate(`${id}`); navigate(`${id}`);
@@ -33,19 +25,17 @@ const SimilarAppartmentCard = ({ layoutCard, elementRef }: LayoutCardProps) => {
> >
<div className="flex gap-4 justify-between"> <div className="flex gap-4 justify-between">
<div className="flex gap-1 flex-col"> <div className="flex gap-1 flex-col">
<p className="text-[#00BED7] text-s leading-5"> <p className="text-[#00BED7] text-s leading-5">{Project_Name}</p>
Rove Home {roveHome}
</p>
<div className="text-[#73787C] flex gap-2 items-center w-fit"> <div className="text-[#73787C] flex gap-2 items-center w-fit">
<p className="text-caption-m font-semibold leading-4">{wing}</p> <p className="text-caption-m font-semibold leading-4">{wing}</p>
<div className="w-1 h-1 bg-[#E2E2DC] rounded-full"></div> <div className="w-1 h-1 bg-[#E2E2DC] rounded-full"></div>
<p className="text-caption-m font-semibold leading-4"> <p className="text-caption-m font-semibold leading-4">
Floor {floorStart}-{floorEnd} Floor {Floor}
</p> </p>
</div> </div>
</div> </div>
<div className="bg-[#00BED7] text-white text-caption-m font-semibold rounded-full py-[3px] px-2 self-start text-nowrap"> <div className="bg-[#00BED7] text-white text-caption-m font-semibold rounded-full py-[3px] px-2 self-start text-nowrap">
{units} units {Total_Area_Sqft} units
</div> </div>
</div> </div>
<div className="w-full aspect-square rounded-lg"> <div className="w-full aspect-square rounded-lg">
@@ -53,10 +43,11 @@ const SimilarAppartmentCard = ({ layoutCard, elementRef }: LayoutCardProps) => {
</div> </div>
<div className="flex flex-col"> <div className="flex flex-col">
<p className="text[#0D1922] text-s"> <p className="text[#0D1922] text-s">
{apartmentType}, {square} Sqft {Unit_Type}, {Total_Area_Sqft} Sqft
</p> </p>
<p className="text-[#00BED7] text-m font-bold"> <p className="text-[#00BED7] text-m font-bold">
AED {formatNumber(cost, ",", 3, 1)} {/* AED {formatNumber(cost, ",", 3, 1)} */}
Unavailiable
</p> </p>
</div> </div>
</div> </div>
@@ -85,7 +85,7 @@ const SimilarSlider = () => {
}} }}
> >
<div className="flex w-fit gap-4 "> <div className="flex w-fit gap-4 ">
{Array.from({ length: Math.floor(cards.length / cols) }).map( {Array.from({ length: Math.round(cards.length / cols) }).map(
(_, index) => { (_, index) => {
return ( return (
<div <div
@@ -4,6 +4,7 @@ import HeartIcon from "../icons/Heart";
import { IAparmentRes } from "../../types/apartmentsRes"; import { IAparmentRes } from "../../types/apartmentsRes";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import useFavorites from "../../store/useFavorites"; import useFavorites from "../../store/useFavorites";
import { apartmentRoutes } from "../../consts/apartmentsRoutes";
interface LayoutCardProps { interface LayoutCardProps {
apartmentCard: IAparmentRes; apartmentCard: IAparmentRes;
@@ -24,6 +25,9 @@ const LayoutCard = ({ apartmentCard }: LayoutCardProps) => {
const totalArea = `${_totalArea}`.split(".").join(","); const totalArea = `${_totalArea}`.split(".").join(",");
const [isFavorite, setIsFavorite] = useState(false); const [isFavorite, setIsFavorite] = useState(false);
const { setFavorites } = useFavorites(); const { setFavorites } = useFavorites();
const layoutImage = apartmentRoutes.find(
(apr) => apr.type === unitType
)?.layout;
const navigate = useNavigate(); const navigate = useNavigate();
@@ -102,8 +106,12 @@ const LayoutCard = ({ apartmentCard }: LayoutCardProps) => {
isCircleRounded isCircleRounded
/> />
</div> </div>
<div className="w-full aspect-square rounded-lg pt-6"> <div className="w-full aspect-square rounded-lg pt-6 ">
<img src="/images/layout-1.png" alt="" className="h-full" /> <img
src={`${layoutImage}`}
alt=""
className="w-full aspect-square object-contain"
/>
</div> </div>
<div className="flex flex-col gap-1 pt-6"> <div className="flex flex-col gap-1 pt-6">
<p className="text-[#0D1922] text-s"> <p className="text-[#0D1922] text-s">
@@ -1,5 +1,5 @@
/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable react-hooks/exhaustive-deps */
import { useEffect } from "react"; import { useEffect, useState } from "react";
import LayoutCard from "./LayoutCard"; import LayoutCard from "./LayoutCard";
import SortButton from "./SortButton"; import SortButton from "./SortButton";
import SearchIcon from "../icons/SearchIcon"; import SearchIcon from "../icons/SearchIcon";
@@ -17,9 +17,11 @@ import {
pageInitial, pageInitial,
} from "../../consts/initialMasterplanFilters"; } from "../../consts/initialMasterplanFilters";
import { getFilteredApartments } from "../../calc/getFilteredApartments"; import { getFilteredApartments } from "../../calc/getFilteredApartments";
import SearchLoader from "./SearchLoader";
const LayoutOptions = () => { const LayoutOptions = () => {
const { apartments, setApartments } = useApartments(); const { apartments, setApartments } = useApartments();
const [isLoading, setIsLoading] = useState(false);
const { setModal } = useModal(); const { setModal } = useModal();
const { const {
@@ -63,6 +65,7 @@ const LayoutOptions = () => {
useEffect(() => { useEffect(() => {
const zohoToken = localStorage.getItem("ACCESS_TOKEN"); const zohoToken = localStorage.getItem("ACCESS_TOKEN");
setIsLoading(true);
getFilteredApartments( getFilteredApartments(
zohoToken, zohoToken,
@@ -75,28 +78,32 @@ const LayoutOptions = () => {
sortList, sortList,
pageInitial, pageInitial,
perPage perPage
).catch((error) => { )
const errorStatus = error.response.status; .catch((error) => {
const errorStatus = error.response.status;
if (errorStatus === 401) { if (errorStatus === 401) {
updateAccessToken().then((token) => { updateAccessToken().then((token) => {
if (token) { if (token) {
getFilteredApartments( getFilteredApartments(
token, token,
setApartments, setApartments,
roveHomeTypeCheckboxes, roveHomeTypeCheckboxes,
apartmentTypeCheckboxes, apartmentTypeCheckboxes,
debouncedSliders, debouncedSliders,
switchers, switchers,
viewCheckboxes, viewCheckboxes,
sortList, sortList,
pageInitial, pageInitial,
perPage perPage
); );
} }
}); });
} }
}); })
.finally(() => {
setIsLoading(false);
});
}, [ }, [
setApartments, setApartments,
roveHomeTypeCheckboxes, roveHomeTypeCheckboxes,
@@ -129,12 +136,16 @@ const LayoutOptions = () => {
/> />
</div> </div>
</div> </div>
<div className="grid 2xl:grid-cols-4 xl:grid-cols-3 grid-cols-2 gap-4 pt-6"> {isLoading ? (
{apartments && <SearchLoader />
apartments.map((apartment) => ( ) : (
<LayoutCard apartmentCard={apartment} key={apartment.id} /> <div className="grid 2xl:grid-cols-4 xl:grid-cols-3 grid-cols-2 gap-4 pt-6">
))} {apartments &&
</div> apartments.map((apartment) => (
<LayoutCard apartmentCard={apartment} key={apartment.id} />
))}
</div>
)}
<div <div
className="bg-white rounded-lg mt-4 py-[10px] flex justify-center select-none cursor-pointer items-center gap-2" className="bg-white rounded-lg mt-4 py-[10px] flex justify-center select-none cursor-pointer items-center gap-2"
onClick={handleOnShowMoreBtnClick} onClick={handleOnShowMoreBtnClick}
@@ -0,0 +1,11 @@
const SearchLoader = () => {
return (
<div className="h-full w-full flex justify-center pt-[120px]">
<div className="w-fit h-fit animate-spin">
<img src="/images/loader.png" alt="" />
</div>
</div>
);
};
export default SearchLoader;
@@ -1,16 +1,25 @@
import useModal from "../../store/useModal";
import { ISphereLink } from "../../types/apartmentSphere"; import { ISphereLink } from "../../types/apartmentSphere";
import VideoIcon from "../icons/VideoIcon"; import VideoIcon from "../icons/VideoIcon";
import VirtualTourVideoModal from "../modals/VirtualTourVideoModal";
interface VideoMarkerProps { interface VideoMarkerProps {
sphereLink: ISphereLink; sphereLink: ISphereLink;
} }
const VideoMarker = ({ sphereLink }: VideoMarkerProps) => { const VideoMarker = ({ sphereLink }: VideoMarkerProps) => {
const { setModal } = useModal();
const handleOnClick = () => {
sphereLink.video &&
setModal(<VirtualTourVideoModal videoHref={sphereLink.video} />);
};
return ( return (
<div className="relative"> <div className="relative">
<div <div
className="bg-white w-9 h-9 rounded-full text-[#00BED7] flex items-center justify-center cursor-pointer peer" className="bg-white w-9 h-9 rounded-full text-[#00BED7] flex items-center justify-center cursor-pointer peer"
// onClick={handleOnClick} onClick={handleOnClick}
> >
<VideoIcon /> <VideoIcon />
</div> </div>
+30
View File
@@ -0,0 +1,30 @@
import { IApartmentRoute } from "../types/apartmentRoute";
const apartmentRoutes: IApartmentRoute[] = [
{
type: "1 BR Squared",
virtualTour: "apartments-studio-3",
id: "1",
layout: "/images/layouts/layout-2.jpg",
},
{
type: "Studio Squared",
virtualTour: "apartments-studio-2",
id: "2",
layout: "/images/layouts/layout-4.jpg",
},
{
type: "2 BR Squared",
virtualTour: "apartments-studio-4",
id: "3",
layout: "/images/layouts/layout-3.jpg",
},
{
type: "Studio Flex",
virtualTour: "apartments-studio-1",
id: "4",
layout: "/images/layouts/layout-1.jpg",
},
];
export { apartmentRoutes };
@@ -0,0 +1,14 @@
interface IApartmentWithoutVirtualTour {
type: string;
layout: string;
id: string;
}
const apartmentsWithoutVirtualTour: IApartmentWithoutVirtualTour[] = [
{ type: "1 BR U1 Left", layout: "/images/layouts/layout-5.jpg", id: "1" },
{ type: "1 BR U1 Right", layout: "/images/layouts/layout-6.jpg", id: "2" },
{ type: "1 BR U2 Left", layout: "/images/layouts/layout-7.jpg", id: "3" },
{ type: "1 BR U2 Right", layout: "/images/layouts/layout-8.jpg", id: "4" },
];
export { apartmentsWithoutVirtualTour };
+91 -120
View File
@@ -1,137 +1,108 @@
import { ILayoutCard } from "../types/layoutCard"; import { IAparmentRes } from "../types/apartmentsRes";
const layoutsCards: ILayoutCard[] = [ // Property_Status: string;
// Unit_Type: string;
// Project_Name: string;
// Suite_Area_Sqft: number;
// Balcony_Area_Sqft: number;
// No_Of_Bedrooms: number;
// Unit_No: string;
// id: string;
// Total_Area_Sqft: number;
// No_of_Bathrooms: number;
// Property_Name: string;
// Unit_View: string;
const layoutsCards: IAparmentRes[] = [
{ {
id: "1", id: "1",
roveHome: "Marasi Drive", Property_Status: "",
apartmentType: "Studio Flex", Unit_Type: "",
wing: "East Wing", Project_Name: "Rove Home Marasi Drive",
floorStart: 11, Floor: 5,
floorEnd: 35, Balcony_Area_Sqft: 77.5,
units: 234, No_of_Bathrooms: 1,
cost: 10488888, No_Of_Bedrooms: 1,
square: 619, Total_Area_Sqft: 402,
}, Property_Name: "",
{ Unit_View: "Canal / Amenities",
id: "2", Suite_Area_Sqft: 0,
roveHome: "Marasi Drive", Unit_No: "W-502",
apartmentType: "1 Bedroom",
wing: "East Wing",
floorStart: 11,
floorEnd: 35,
units: 234,
cost: 1668888,
square: 619,
},
{
id: "3",
roveHome: "Marasi Drive",
apartmentType: "1 Bedroom",
wing: "East Wing",
floorStart: 11,
floorEnd: 35,
units: 234,
cost: 1668888,
square: 609,
},
{
id: "4",
roveHome: "Marasi Drive",
apartmentType: "1 Bedroom",
wing: "East Wing",
floorStart: 11,
floorEnd: 35,
units: 234,
cost: 1138888,
square: 609,
},
{
id: "5",
roveHome: "Marasi Drive",
apartmentType: "Studio Flex",
wing: "East Wing",
floorStart: 11,
floorEnd: 35,
units: 234,
cost: 10488888,
square: 609,
}, },
{ {
id: "6", id: "6",
roveHome: "Marasi Drive", Property_Status: "",
apartmentType: "1 Bedroom", Unit_Type: "",
wing: "East Wing", Project_Name: "Rove Home Marasi Drive",
floorStart: 11, Floor: 5,
floorEnd: 35, Balcony_Area_Sqft: 77.5,
units: 234, No_of_Bathrooms: 1,
cost: 1668888, No_Of_Bedrooms: 1,
square: 609, Total_Area_Sqft: 402,
Property_Name: "",
Unit_View: "Canal / Amenities",
Suite_Area_Sqft: 0,
Unit_No: "W-502",
}, },
{ {
id: "7", id: "2",
roveHome: "Marasi Drive", Property_Status: "",
apartmentType: "1 Bedroom", Unit_Type: "",
wing: "East Wing", Project_Name: "Rove Home Marasi Drive",
floorStart: 11, Floor: 5,
floorEnd: 35, Balcony_Area_Sqft: 77.5,
units: 234, No_of_Bathrooms: 1,
cost: 1668888, No_Of_Bedrooms: 1,
square: 609, Total_Area_Sqft: 402,
Property_Name: "",
Unit_View: "Canal / Amenities",
Suite_Area_Sqft: 0,
Unit_No: "W-502",
}, },
{ {
id: "8", id: "3",
roveHome: "Marasi Drive", Property_Status: "",
apartmentType: "1 Bedroom", Unit_Type: "",
wing: "East Wing", Project_Name: "Rove Home Marasi Drive",
floorStart: 11, Floor: 5,
floorEnd: 35, Balcony_Area_Sqft: 77.5,
units: 234, No_of_Bathrooms: 1,
cost: 1138888, No_Of_Bedrooms: 1,
square: 609, Total_Area_Sqft: 402,
Property_Name: "",
Unit_View: "Canal / Amenities",
Suite_Area_Sqft: 0,
Unit_No: "W-502",
}, },
{ {
id: "9", id: "4",
roveHome: "Marasi Drive", Property_Status: "",
apartmentType: "Studio Flex", Unit_Type: "",
wing: "East Wing", Project_Name: "Rove Home Marasi Drive",
floorStart: 11, Floor: 5,
floorEnd: 35, Balcony_Area_Sqft: 77.5,
units: 234, No_of_Bathrooms: 1,
cost: 10488888, No_Of_Bedrooms: 1,
square: 609, Total_Area_Sqft: 402,
Property_Name: "",
Unit_View: "Canal / Amenities",
Suite_Area_Sqft: 0,
Unit_No: "W-502",
}, },
{ {
id: "10", id: "5",
roveHome: "Marasi Drive", Property_Status: "",
apartmentType: "1 Bedroom", Unit_Type: "",
wing: "East Wing", Project_Name: "Rove Home Marasi Drive",
floorStart: 11, Floor: 5,
floorEnd: 35, Balcony_Area_Sqft: 77.5,
units: 234, No_of_Bathrooms: 1,
cost: 1668888, No_Of_Bedrooms: 1,
square: 609, Total_Area_Sqft: 402,
}, Property_Name: "",
{ Unit_View: "Canal / Amenities",
id: "11", Suite_Area_Sqft: 0,
roveHome: "Marasi Drive", Unit_No: "W-502",
apartmentType: "1 Bedroom",
wing: "East Wing",
floorStart: 11,
floorEnd: 35,
units: 234,
cost: 1668888,
square: 609,
},
{
id: "12",
roveHome: "Marasi Drive",
apartmentType: "1 Bedroom",
wing: "East Wing",
floorStart: 11,
floorEnd: 35,
units: 234,
cost: 1138888,
square: 609,
}, },
]; ];
+1 -1
View File
@@ -56,7 +56,7 @@
{ {
"id": "studio-1_video-1", "id": "studio-1_video-1",
"type": "video", "type": "video",
"video": "", "video": "/videos/studio_flex_bed.mp4",
"videoTitle": "Cloud Bed", "videoTitle": "Cloud Bed",
"labelPosition": [-5, 0, 36.11] "labelPosition": [-5, 0, 36.11]
} }
+1 -1
View File
@@ -46,7 +46,7 @@ const router = createBrowserRouter([
element: <Search />, element: <Search />,
}, },
{ {
path: "/search/:apartmentType", path: "/search/:id",
element: <SearchApartment />, element: <SearchApartment />,
}, },
// { // {
+76 -8
View File
@@ -2,26 +2,94 @@ import Footer from "../components/Footer";
import ButtonPanel from "../components/searchApartment/ButtonPanel"; import ButtonPanel from "../components/searchApartment/ButtonPanel";
import ApartmentLayout from "../components/searchApartment/ApartmentLayout"; import ApartmentLayout from "../components/searchApartment/ApartmentLayout";
import ApartmentSidebar from "../components/ApartmentSidebar"; import ApartmentSidebar from "../components/ApartmentSidebar";
import SimilarSlider from "../components/searchApartment/SimilarSlider"; // import SimilarSlider from "../components/searchApartment/SimilarSlider";
import StudioDescriptionSection from "../components/searchApartment/StudioDescriptionSection"; import StudioDescriptionSection from "../components/searchApartment/StudioDescriptionSection";
import { useEffect, useState } from "react";
import { getApartments } from "../api/apartments";
import { updateAccessToken } from "../api/updateAccessToken";
import { IAparmentRes, IApartmentsRes } from "../types/apartmentsRes";
import { useNavigate, useParams } from "react-router-dom";
import useModal from "../store/useModal";
import SearchLoaderModal from "../components/modals/SearchLoaderModal";
const SearchApartment = () => { const SearchApartment = () => {
const { id } = useParams();
const [currentApartment, setCurrentApartment] = useState<IAparmentRes>();
const [isLoading, setIsLoading] = useState(true);
const { setModal } = useModal();
const navigate = useNavigate();
useEffect(() => {
setIsLoading(true);
const zohoToken = localStorage.getItem("ACCESS_TOKEN");
getApartments(zohoToken)
.then((data) => {
const apartmentsData = (data as IApartmentsRes).apartments;
const _currentApartment = apartmentsData.find((aprt) => aprt.id === id);
if (_currentApartment) {
setCurrentApartment(_currentApartment);
} else {
navigate(-1);
}
})
.catch((error) => {
const errorStatus = error.response.status;
if (errorStatus === 401) {
updateAccessToken().then((token) => {
if (token) {
getApartments(zohoToken).then((data) => {
const apartmentsData = (data as IApartmentsRes).apartments;
const _currentApartment = apartmentsData.find(
(aprt) => aprt.id === id
);
if (_currentApartment) {
setCurrentApartment(_currentApartment);
} else {
navigate(-1);
}
});
}
});
}
})
.finally(() => {
setIsLoading(false);
});
}, [id, navigate]);
useEffect(() => {
if (isLoading) {
setModal(<SearchLoaderModal />);
} else {
setModal(null);
}
}, [isLoading, setModal]);
return ( return (
<div className="overflow-scroll h-screen w-screen pt-14"> <div className="overflow-scroll h-screen w-screen pt-14">
<div className="grid grid-cols-9 px-4 pt-6 pb-16 gap-4"> <div className="grid grid-cols-9 px-4 pt-6 pb-16 gap-4">
<div className="flex flex-col lg:col-span-7 col-span-full"> <div className="flex flex-col lg:col-span-7 col-span-full">
<ButtonPanel /> {currentApartment && (
<ApartmentLayout /> <ButtonPanel currentApartment={currentApartment} />
</div> )}
<div className="lg:col-span-2 rounded-lg col-span-full"> {currentApartment && (
<ApartmentSidebar /> <ApartmentLayout currentApartment={currentApartment} />
)}
</div> </div>
{currentApartment && (
<div className="lg:col-span-2 rounded-lg col-span-full">
<ApartmentSidebar currentApartment={currentApartment} />
</div>
)}
<div className="col-span-full"> <div className="col-span-full">
<StudioDescriptionSection /> <StudioDescriptionSection />
</div> </div>
<div className="col-span-full"> {/* <div className="col-span-full">
<SimilarSlider /> <SimilarSlider />
</div> </div> */}
</div> </div>
<Footer /> <Footer />
</div> </div>
+58
View File
@@ -0,0 +1,58 @@
import { create } from "zustand";
import { ICheckbox } from "../types/checkbox";
import {
initialAparmentTypeCheckboxes,
initialSliders,
initialSwitchers,
initialViewCheckboxes,
initialRoveHomeCheckboxes,
initialSortList,
} from "../consts/initialMasterplanFilters";
import { IMultirangeSlider } from "../types/multirangeSlider";
import { ISwitcher } from "../types/switcher";
import { ISort } from "../types/sortType";
import { perPageInitial } from "../consts/initialMasterplanFilters";
interface Store {
apartmentTypeCheckboxes: ICheckbox[];
viewCheckboxes: ICheckbox[];
sortList: ISort[];
page: number;
perPage: number;
setPage: (page: number) => void;
setPerPage: (perPage: number) => void;
setSortList: (sortList: ISort[]) => void;
setApartmentTypeCheckboxes: (typeCheckboxes: ICheckbox[]) => void;
setViewCheckboxes: (checkboxes: ICheckbox[]) => void;
roveHomeTypeCheckboxes: ICheckbox[];
setRoveHomeTypeCheckboxes: (typeCheckboxes: ICheckbox[]) => void;
multirangeSliders: IMultirangeSlider[];
setMultirangeSliders: (multirangeSliders: IMultirangeSlider[]) => void;
switchers: ISwitcher[];
setSwitchers: (switchers: ISwitcher[]) => void;
}
const useMasterplanFilters = create<Store>((set) => ({
apartmentTypeCheckboxes: initialAparmentTypeCheckboxes,
viewCheckboxes: initialViewCheckboxes,
roveHomeTypeCheckboxes: initialRoveHomeCheckboxes,
multirangeSliders: initialSliders,
switchers: initialSwitchers,
sortList: initialSortList,
page: 1,
perPage: perPageInitial,
setPerPage: (perPage) => set(() => ({ perPage: perPage })),
setPage: (page) => set(() => ({ page: page })),
setSortList: (sortList) => set(() => ({ sortList: sortList })),
setApartmentTypeCheckboxes: (typeCheckboxes) =>
set(() => ({ apartmentTypeCheckboxes: typeCheckboxes })),
setViewCheckboxes: (typeCheckboxes) =>
set(() => ({ viewCheckboxes: typeCheckboxes })),
setRoveHomeTypeCheckboxes: (typeCheckboxes) =>
set(() => ({ roveHomeTypeCheckboxes: typeCheckboxes })),
setMultirangeSliders: (multirangeSliders) =>
set(() => ({ multirangeSliders: multirangeSliders })),
setSwitchers: (switchers) => set(() => ({ switchers: switchers })),
}));
export default useMasterplanFilters;
+8
View File
@@ -0,0 +1,8 @@
interface IApartmentRoute {
type: string;
virtualTour: string;
id: string;
layout: string;
}
export type { IApartmentRoute };
+1
View File
@@ -24,6 +24,7 @@ app.use(json());
app.use(morgan("combined", { stream: accessLogStream })); app.use(morgan("combined", { stream: accessLogStream }));
app.use("/apartments", apartmentsRoute); app.use("/apartments", apartmentsRoute);
app.use("/apartments/:id", apartmentsRoute);
app.use("/updateAccessToken", updateAccessToken); app.use("/updateAccessToken", updateAccessToken);
app.listen(port, () => { app.listen(port, () => {
+48
View File
@@ -276,6 +276,54 @@ router.get("/", async (req, res) => {
console.log("error", error); console.log("error", error);
} }
}); });
// router.get("/:id", async (req, res) => {
// const accessToken = req?.headers?.authorization;
// const {id} = req.params;
// try {
// const response = await fetch(`${aparmentsApi}&page=${page}&per_page=200`, {
// headers: {
// Authorization: accessToken,
// },
// });
// if (!accessToken)
// return res
// .status(401)
// .json({ message: "Отсутсвует access token", code: 401 });
// try {
// res.status(200).json({
// message: "ok",
// apartments: slicedApartments,
// code: 200,
// });
// return;
// } catch (error) {
// if (
// (error as Error).message === "invalid oauth token" ||
// (error as Error).message === "INVALID_TOKEN"
// ) {
// console.log("error", error);
// logger.error(error);
// return res
// .status(401)
// .json({ message: "Неправильный токен или токен устарел", code: 401 });
// }
// console.log("error", error);
// logger.error(error);
// return res.status(500).json({ message: "Server Error", code: 500 });
// }
// } catch (error) {
// logger.error(error);
// console.log("error", error);
// }
// });
const apartmentsRoute = router; const apartmentsRoute = router;