touch functionality

This commit is contained in:
2024-07-01 17:58:09 +05:00
parent 87d78f3f78
commit 497cb6aa44
24 changed files with 843 additions and 264 deletions
@@ -1,11 +1,11 @@
interface EastWingHighlightingProps {
handleOnMouseOut:
handleOnMouseOut?:
| (() => void)
| ((event: React.MouseEvent<SVGSVGElement, MouseEvent>) => void);
handleOnMouseOver: (
handleOnMouseOver?: (
event: React.MouseEvent<SVGSVGElement, MouseEvent>
) => void;
handleOnApartmentClick: (
handleOnApartmentClick?: (
e: React.MouseEvent<SVGSVGElement, MouseEvent>
) => void;
}
@@ -1,11 +1,11 @@
interface FloorEastWingHighlightingProps {
handleOnMouseOut:
handleOnMouseOut?:
| (() => void)
| ((event: React.MouseEvent<SVGSVGElement, MouseEvent>) => void);
handleOnMouseOver: (
handleOnMouseOver?: (
event: React.MouseEvent<SVGSVGElement, MouseEvent>
) => void | (() => void);
handleOnApartmentClick: (
handleOnApartmentClick?: (
event: React.MouseEvent<SVGSVGElement, MouseEvent>
) => void;
}
@@ -1,11 +1,11 @@
interface WestWingTopLevelsHighlightingProps {
handleOnMouseOut:
handleOnMouseOut?:
| (() => void)
| ((event: React.MouseEvent<SVGSVGElement, MouseEvent>) => void);
handleOnMouseOver:
handleOnMouseOver?:
| (() => void)
| ((event: React.MouseEvent<SVGSVGElement, MouseEvent>) => void);
handleOnApartmentClick: (
handleOnApartmentClick?: (
event: React.MouseEvent<SVGSVGElement, MouseEvent>
) => void;
}
@@ -0,0 +1,110 @@
import { apartmentsWithoutVirtualTour } from "../../consts/apartmentsWithoutVirtualTour";
import { IAparmentRes } from "../../types/apartmentsRes";
import Button from "../Button";
import RightArrowSliderIcon from "../icons/RightArrowSliderIcon";
import VirtualTourIcon from "../icons/VirtualTourIcon";
import useModal from "../../store/useModal";
import { MobileModalWrapper } from "../modals/mobile/MobileModalWrapper";
import AboutComplexMobileModal from "../modals/mobile/AboutCompexMobileModal/AboutComplexMobileModal";
import { IDesctiptionFloor } from "../../types/descriptionFloor";
interface MobileApartmentDescriptionProps {
apartment: IAparmentRes | null;
apartments: IAparmentRes[];
apartmentDataType: string | null;
floor: IDesctiptionFloor | null;
}
const MobileApartmentDescription = ({
apartment,
apartmentDataType,
apartments,
floor,
}: MobileApartmentDescriptionProps) => {
const wing =
apartment && apartment.Unit_No.split("-")[0] === "E"
? "East Wing"
: "West Wing";
const isVirtualTourAvailiable =
apartment &&
!apartmentsWithoutVirtualTour.some(
(aprt) =>
aprt.type === apartment.Unit_Type || aprt.type === apartmentDataType
);
const { setModal } = useModal();
const handleOnExploreClick = (
event: React.MouseEvent<HTMLButtonElement, MouseEvent>
) => {
event.preventDefault();
if (!apartment) return;
setModal(null);
const timeout = setTimeout(() => {
setModal(
<MobileModalWrapper isHeightScreen>
<AboutComplexMobileModal
currentApartment={apartment}
apartments={apartments}
floor={floor}
/>
</MobileModalWrapper>
);
clearTimeout(timeout);
}, 300);
};
return (
<>
{apartment && (
<div className="p-6 py-3">
<div
className={`bg-white rounded-2xl p-6 flex flex-col text-subheadline-s relative text-nowrap desc-shadow py-2 duration-300 ease-in-out transition-opacity min-w-[344px]`}
>
<h2 className="text-[#0D1922] font-semibold pt-6">
{apartment?.Unit_Type},{" "}
{apartment && Math.round(apartment?.Total_Area_Sqft)} Sqft
</h2>
<div className="flex gap-2 items-center text-caption-m font-semibold pt-1 border-b pb-4 justify-start">
<p className="text-[#0D1922B2]">{wing}</p>
<div className="w-1 h-1 bg-[#E2E2DC] rounded-full"></div>
<p className="text-[#0D1922B2]">Floor {apartment.Floor}</p>
<div className="w-1 h-1 bg-[#E2E2DC] rounded-full"></div>
<p className="text-[#0D1922B2]">{apartment.Unit_No}</p>
</div>
<div className="flex justify-between items-center pt-4 gap-14 pb-4">
<p className="font-semibold text-[#00BED7] text-subheadline-s">
Unvailiable
</p>
{/* <p className="font-semibold text-[#00BED7] text-subheadline-s">
AED 1,668,888
</p> */}
{isVirtualTourAvailiable && (
<div
className={`bg-[#30B21614] text-[#30B216] px-2 py-[6px] flex gap-1 items-center rounded-lg opacity-100`}
>
<VirtualTourIcon />
<p className="text-caption-m font-semibold text-[#30B216]">
3D-tour
</p>
</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-full pb-6 ">
<Button
buttonType="cta"
className="justify-center w-full"
text="Explore"
icon={<RightArrowSliderIcon />}
iconPos="right"
onClick={handleOnExploreClick}
/>
</div>
</div>
</div>
)}
</>
);
};
export default MobileApartmentDescription;
@@ -3,8 +3,8 @@ import { MouseEvent } from "react";
import { IDesctiptionFloor } from "../../../types/descriptionFloor";
interface FloorsHighlightingProps {
handleOnFloorClick: () => void;
handleOnSkygardenClick: () => void;
handleOnFloorClick: (e: MouseEvent | any) => void;
handleOnSkygardenClick: (e: React.MouseEvent) => void;
handleOnWingWrapperMouseEnter: (e: React.MouseEvent<SVGSVGElement>) => void;
handleOnFloorMouseEnter:
| ((
@@ -7,9 +7,7 @@ import RightArrowSliderIcon from "../../icons/RightArrowSliderIcon";
interface MobileFloorDescriptionProps {
descriptionFloor: IDesctiptionFloor | null;
floorApartments: IAparmentRes[];
onClick: (
e: React.MouseEvent<Element, React.MouseEvent<Element, MouseEvent>>
) => void;
onClick: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
}
const MobileFloorDescription = ({
@@ -0,0 +1,63 @@
import Button from "../../Button";
import CrossIcon from "../../icons/CrossIcon";
import RightArrowSliderIcon from "../../icons/RightArrowSliderIcon";
interface MobileSkygardenDescriptionProps {
onClick: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
}
const MobileSkygardenDescription = ({
onClick,
}: MobileSkygardenDescriptionProps) => {
return (
<>
<div
className={`bg-white rounded-2xl p-6 flex flex-col gap-4 w-[344px] absolute left-[414px] transition-opacity duration-300 desc-shadow h-[240px] pointer-events-auto`}
>
<div className="relative">
<div className="flex justify-between border-b pb-4">
<div className="flex flex-col">
<p
className={`text-[#0D1922] font-semibold text-[20px] duration-300 ease-in-out text-subheadline-s`}
>
Sky Garden
</p>
</div>
<Button buttonType="tertiary" icon={<CrossIcon />} />
</div>
<div className="flex flex-col gap-4 pt-4">
<div className="flex items-center justify-between gap-8">
<div className="flex gap-2 items-center">
<div className="min-w-6 min-h-6 rounded-full bg-[#00BED7] text-white text-xs font-semibold">
<p className="p-1 flex justify-center items-center">8</p>
</div>
<p className="text-s text-[#73787C] w-full">Indoor</p>
</div>
<p className="text-s text-[#0D1922] text-nowrap">3 amenties</p>
</div>
<div className="flex items-center justify-between gap-8">
<div className="flex gap-2 items-center">
<div className="min-w-6 min-h-6 rounded-full bg-[#00BED7] text-white text-xs font-semibold">
<p className="p-1 flex justify-center items-center">8</p>
</div>
<p className="text-s text-[#73787C] w-full">Studio</p>
</div>
<p className="text-s text-[#0D1922] text-nowrap">14 amenties</p>
</div>
<Button
buttonType="cta"
className="justify-center"
text="Explore"
icon={<RightArrowSliderIcon />}
iconPos="right"
onClick={onClick}
/>
</div>
<div className="w-0 h-0 border-t-0 border-r-[6px] border-b-[14px] border-l-[6px] border-transparent border-b-white absolute -top-[35px] left-[0px]"></div>
</div>
</div>
</>
);
};
export default MobileSkygardenDescription;
@@ -1,10 +1,7 @@
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { MouseEvent, useEffect, useState } from "react";
import FloorDescription from "../FloorDescription";
import { IDesctiptionFloor } from "../../../types/descriptionFloor";
import SkygardenDescription from "../SkygardenDescription";
import FloorSidebar from "../FloorSidebar/FloorSidebar";
import SkygardenSidebar from "../SkygardenSidebar/SkygardenSidebar";
import useWingSidebar from "../../../store/useWingSidebar";
import useModal from "../../../store/useModal";
import {
@@ -26,14 +23,15 @@ import { isMobile } from "react-device-detect";
import FloorsHighlighting from "./FloorsHighlighting";
import MobileFloorDescription from "./MobileFloorDescription";
import WingFloorModal from "../../modals/mobile/WingFloorModal";
import MobileSkygardenDescription from "./MobileSkygardenDescription";
import SkygardenModal from "../../modals/mobile/SkygardenModal";
const skyGardenFloor = 22;
// const skyGardenFloor = 22;
const SequenceWing = () => {
const [width, setWidth] = useState<number>(0);
const [top, setTop] = useState<number>(0);
const [left, setLeft] = useState<number>(0);
// const leftWingRef = useRef(null);
const { isSidebar, setIsSidebar } = useWingSidebar();
const [mousePos, setMousePos] = useState<[number, number]>([0, 0]);
const [currentHoveredFloor, setHoverCurrentFloor] =
@@ -42,7 +40,7 @@ const SequenceWing = () => {
const [currentFloor, setCurrentFloor] = useState<IDesctiptionFloor | null>(
null
);
const [isWrapperHovered, setIsWrapperHovered] = useState(false);
const [, setIsWrapperHovered] = useState(false);
const [isSkygardenSidebar, setIsSkygardenSidebar] = useState(false);
const [isFloorSidebar, setIsFloorSidebar] = useState(false);
const { setModal } = useModal();
@@ -50,12 +48,10 @@ const SequenceWing = () => {
const [currentHoveredApartments, setCurrentHoveredApartments] = useState<
IAparmentRes[]
>([]);
const [selectedApartments, setSelectedApartments] = useState<IAparmentRes[]>(
[]
);
const [isDescriptionFloorMobile, setIsDescriptionFloorMobile] =
useState(false);
const [isDescriptionSkygarden, setIsDescriptionSkygarden] = useState(false);
const {
apartmentTypeCheckboxes,
@@ -96,60 +92,17 @@ const SequenceWing = () => {
setIsWrapperHovered(false);
};
const handleOnFloorClick = (e: MouseEvent | any) => {
const isFloorClicked = Boolean(e.currentTarget.dataset.id);
if (isFloorClicked) {
// detect mouse pos
const screenWidth = window.innerWidth;
const screenHeight = window.innerHeight;
// >1072
if (screenWidth > laptopWidth) {
const _top = screenWidth / 2 - screenHeight / 2;
setMousePos([e.clientX - 384, e.clientY + Math.abs(_top) - 20]);
} else {
// 640-1072
if (screenWidth > mobileWidht) {
const _top = screenHeight / 4;
const _left = laptopWidth - screenWidth;
setMousePos([
e.clientX - 440 + _left,
e.clientY + Math.abs(_top) + 20,
]);
// <640
} else {
const _top = screenHeight / 2.5;
const _left = laptopWidth - screenWidth;
setMousePos([
e.clientX - 440 + _left,
e.clientY + Math.abs(_top) + 20,
]);
}
}
//detect currentFloor, current sidebar and apartment on floor
if (!currentHoveredFloor && !currentHoveredApartments) return;
setSelectedApartments(currentHoveredApartments);
setCurrentFloor(currentHoveredFloor);
if (!isMobile) {
setIsFloorSidebar(true);
setIsSkygardenSidebar(false);
setIsSidebar(true);
} else {
setIsDescriptionFloorMobile(true);
}
} else {
setIsDescriptionFloorMobile(false);
}
const handleOnFloorClick = () => {
setIsDescriptionSkygarden(false);
//detect currentFloor
if (!currentHoveredFloor && !currentHoveredApartments) return;
setCurrentFloor(currentHoveredFloor);
};
const handleOnSkygardenClick = () => {
if (!isMobile) {
setIsSkygardenSidebar(true);
setIsFloorSidebar(false);
setIsSidebar(true);
} else {
// setModal(<WingFloorModal />);
}
setCurrentFloor(null);
setIsDescriptionFloorMobile(false);
setIsDescriptionSkygarden(true);
};
function handleMouseMove(
@@ -195,7 +148,6 @@ const SequenceWing = () => {
//detect currentFloor, current sidebar and apartment on floor
if (!currentHoveredFloor && !currentHoveredApartments) return;
setSelectedApartments(currentHoveredApartments);
setCurrentFloor(currentHoveredFloor);
if (!isMobile) {
setIsFloorSidebar(true);
@@ -203,6 +155,7 @@ const SequenceWing = () => {
setIsSidebar(true);
} else {
setIsDescriptionFloorMobile(true);
setCurrentFloor(null);
}
}
}
@@ -233,11 +186,25 @@ const SequenceWing = () => {
}
}
const handleOnExploreClick = (
e: MouseEvent<Element, MouseEvent<Element, MouseEvent>>
const handleOnExploreFloorClick = (
e: MouseEvent<Element, MouseEvent<Element, MouseEvent>> | any
) => {
e.stopPropagation();
setModal(<WingFloorModal />);
if (!currentHoveredFloor) return;
setModal(
<WingFloorModal
currentFloor={currentHoveredFloor}
floorApartments={apartments}
/>
);
setIsDescriptionFloorMobile(false);
};
const handleOnExploreSkygardenClick = (
e: MouseEvent<Element, MouseEvent<Element, MouseEvent>> | any
) => {
e.stopPropagation();
setIsDescriptionSkygarden(false);
setModal(<SkygardenModal />);
setIsDescriptionFloorMobile(false);
};
@@ -313,33 +280,16 @@ const SequenceWing = () => {
sortList,
]);
// useEffect(() => {
// if (isLoading) {
// setModal(<LoaderModal />);
// } else {
// setModal(null);
// }
// }, [isLoading, setModal]);
useEffect(() => {
if (isLoading) {
setModal(<LoaderModal />);
} else {
setModal(null);
}
}, [isLoading, setModal]);
return (
<div className="absolute left-0 overflow-hidden h-screen w-screen select-none ">
<div
className=" absolute h-[calc(100vh-56px)] right-0 w-1/2 duration-300 transition-all "
style={{ right: `${isFloorSidebar ? "0" : "-50%"}` }}
>
<FloorSidebar
floorApartments={selectedApartments}
currentFloor={currentFloor}
onMouseEnter={handleOnWingWrapperMouseLeave}
/>
</div>
<div
className=" absolute h-[calc(100vh-56px)] right-0 w-1/2 duration-300 transition-all"
style={{ right: `${isSkygardenSidebar ? "0" : "-50%"}` }}
>
<SkygardenSidebar onMouseEnter={handleOnWingWrapperMouseLeave} />
</div>
<div
className="absolute left-0 transition-[left]"
style={{
@@ -351,60 +301,29 @@ const SequenceWing = () => {
}`,
}}
>
<div
className={`absolute z-40 top-0 left-0 transition-opacity duration-300 ease-in-out lg:flex hidden ${
currentHoveredFloor?.floor === skyGardenFloor && isWrapperHovered
? "opacity-100"
: "opacity-0"
}`}
style={{
top: mousePos[1] - 25,
left: `${
isSkygardenSidebar || isFloorSidebar
? `calc(${mousePos[0]}px + 25%)`
: `${mousePos[0]}px`
}`,
}}
>
<SkygardenDescription />
</div>
<div
className={`absolute z-40 top-0 left-0 transition-opacity duration-300 ease-in-out lg:flex hidden ${
currentHoveredFloor?.floor !== skyGardenFloor &&
currentHoveredFloor &&
isWrapperHovered
? "opacity-100"
: "opacity-0"
}`}
style={{
top: mousePos[1],
left: `${
isSkygardenSidebar || isFloorSidebar
? `calc(${mousePos[0]}px + 25%)`
: `${mousePos[0]}px`
}`,
}}
>
<FloorDescription
descriptionFloor={currentHoveredFloor}
floorApartments={currentHoveredApartments}
/>
</div>
{/* */}
<div
className={`absolute z-40 top-0 left-0 transition-opacity duration-300 ease-in-out ${
isDescriptionFloorMobile ? "opacity-100" : "opacity-0"
isDescriptionSkygarden ? "" : "hidden"
}`}
style={{
top: `${mousePos[1]}px`,
left: `${mousePos[0]}px`,
}}
>
<MobileSkygardenDescription onClick={handleOnExploreSkygardenClick} />
</div>
<div
className={`absolute z-40 top-0 left-0 transition-opacity duration-300 ease-in-out ${
isDescriptionFloorMobile ? "" : "hidden"
}`}
style={{
top: `${mousePos[1]}px`,
left: `${mousePos[0]}px`,
// top: `${mousePos[1] + 140}px`,
// left: `${mousePos[0] + 366}px`,
}}
>
<MobileFloorDescription
onClick={handleOnExploreClick}
onClick={handleOnExploreFloorClick}
descriptionFloor={currentHoveredFloor}
floorApartments={currentHoveredApartments}
/>
@@ -1,5 +1,5 @@
import { useState } from "react";
// import { useSwipeable } from "react-swipeable";
import { useSwipeable } from "react-swipeable";
import SkygardenIndoorLayout from "./SkygardenIndoorLayout";
import { ISwitchLabel } from "../../../types/switchLabel";
import SwitchToggle from "../../SwitchToggle";
@@ -14,13 +14,18 @@ const LayoutSlider = () => {
const [currentLabel, setCurrentLabel] = useState<ISwitchLabel>(
skygardenLayouts[0]
);
const handlers = useSwipeable({
onSwipedLeft: () => setCurrentLabel(skygardenLayouts[1]),
onSwipedRight: () => setCurrentLabel(skygardenLayouts[0]),
trackMouse: true,
});
const handleOnSwitchClick = (label: ISwitchLabel) => {
setCurrentLabel(label);
};
return (
<div className="flex flex-col items-center">
<div className="select-none flex flex-col items-center" {...handlers}>
<SwitchToggle
labels={skygardenLayouts}
currentLabel={currentLabel}