virtual tour sidebar info

This commit is contained in:
2024-06-27 14:36:11 +05:00
parent 9737340da7
commit d499a1dd13
19 changed files with 395 additions and 145 deletions
+18 -3
View File
@@ -1,5 +1,6 @@
import { apartmentsApi } from "./urls";
import { apartmentsApi, currentApartmentApi } from "./urls";
import ky from "ky";
import { IApartmentRes, IApartmentsRes } from "../types/apartmentsRes";
async function getApartments(
token: string | null,
@@ -11,7 +12,7 @@ async function getApartments(
sortBy?: string | undefined,
page?: number,
perPage?: number
) {
): Promise<IApartmentsRes> {
const roveHomeQuery =
roveHomeFilters && roveHomeFilters.length !== 0
? `rove_home=${roveHomeFilters.join(",")}`
@@ -61,4 +62,18 @@ async function getApartments(
return res.json();
}
export { getApartments };
async function getCurrentApartment(
token: string | null,
id: string
): Promise<IApartmentRes> {
const url = `${currentApartmentApi}/${id}`;
const res = await ky.get(url, {
headers: {
Authorization: `Zoho-oauthtoken ${token}`,
},
});
return res.json();
}
export { getApartments, getCurrentApartment };
+3 -1
View File
@@ -3,6 +3,8 @@ const serverApi = import.meta.env.VITE_SERVER_API;
const apartmentsApi = `${serverApi}/apartments`;
const currentApartmentApi = `${serverApi}/apartment`;
const updateAccessTokenApi = `${serverApi}/updateAccessToken`;
export { apartmentsApi, updateAccessTokenApi };
export { apartmentsApi, updateAccessTokenApi, currentApartmentApi };
+1 -5
View File
@@ -2,7 +2,6 @@ import { useNavigate } from "react-router-dom";
import Button from "./Button";
// import { formatNumber } from "../calc/formatNumber";
import { IAparmentRes } from "../types/apartmentsRes";
import { apartmentRoutes } from "../consts/apartmentsRoutes";
interface ApartmentSidebarProps {
currentApartment: IAparmentRes;
@@ -10,15 +9,12 @@ interface ApartmentSidebarProps {
const ApartmentSidebar = ({ currentApartment }: ApartmentSidebarProps) => {
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 = () => {
navigate(`../virtual-tour/${route ? route : "apartments-studio-1"}`);
navigate(`../virtual-tour/${currentApartment.id}`);
};
return (
@@ -3,6 +3,8 @@ import Button from "../Button";
import HeartIcon from "../icons/Heart";
import LeftArrowSliderIcon from "../icons/LeftArrowSliderIcon";
import { IAparmentRes } from "../../types/apartmentsRes";
import useFavorites from "../../store/useFavorites";
import { useEffect, useState } from "react";
interface ButtonPanelProps {
currentApartment: IAparmentRes;
@@ -11,11 +13,55 @@ interface ButtonPanelProps {
const ButtonPanel = ({ currentApartment }: ButtonPanelProps) => {
const navigate = useNavigate();
const unitNo = currentApartment.Unit_No.split("-")[1];
const [isFavorite, setIsFavorite] = useState(false);
const { setFavorites } = useFavorites();
const handleOnBackClick = () => {
navigate(-1);
navigate("../search");
};
const handleOnFavoriteClick = (
e: React.MouseEvent<HTMLButtonElement, MouseEvent>
) => {
e.stopPropagation();
const favorites = localStorage.getItem("Favorites");
if (!favorites) {
setIsFavorite(true);
const updatedFavorites = JSON.stringify([currentApartment]);
localStorage.setItem("Favorites", updatedFavorites);
} else {
const _favorites = JSON.parse(favorites) as IAparmentRes[];
if (_favorites.some((apart) => apart.id === currentApartment.id)) {
setIsFavorite(false);
const updatedFavorites = [..._favorites].filter(
(apart) => apart.id !== currentApartment.id
);
const convertedFavorites = JSON.stringify(updatedFavorites);
setFavorites(updatedFavorites);
localStorage.setItem("Favorites", convertedFavorites);
} else {
setIsFavorite(true);
const updatedFavorites = [..._favorites, currentApartment];
setFavorites(updatedFavorites);
const convertedFavorites = JSON.stringify(updatedFavorites);
localStorage.setItem("Favorites", convertedFavorites);
}
}
};
useEffect(() => {
const favorites = localStorage.getItem("Favorites");
if (favorites) {
const _isFavorite = (JSON.parse(favorites) as IAparmentRes[]).some(
(apart) => apart.id === currentApartment.id
);
setIsFavorite(_isFavorite);
}
}, [currentApartment.id]);
return (
<div className="flex justify-between w-full gap-4 items-center pb-3">
<div className="flex gap-4 items-center ">
@@ -33,7 +79,12 @@ const ButtonPanel = ({ currentApartment }: ButtonPanelProps) => {
</h2>
</div>
</div>
<Button buttonType="favorite" icon={<HeartIcon />} isCircleRounded />
<Button
buttonType="favorite"
icon={<HeartIcon isFilled={isFavorite} />}
isCircleRounded
onClick={handleOnFavoriteClick}
/>
</div>
);
};
@@ -19,7 +19,7 @@ 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";
import LoaderModal from "../modals/LoaderModal";
const skyGardenFloor = 22;
@@ -219,7 +219,7 @@ const SequenceWing = () => {
useEffect(() => {
if (isLoading) {
setModal(<MasterplanLoaderModal />);
setModal(<LoaderModal />);
} else {
setModal(null);
}
@@ -26,7 +26,6 @@ const FavoriteAppartmentCard = ({ card }: FavoriteAppartmentCardProps) => {
const layoutImage = isLayoutType
? apartmentLayoutImages[Unit_Type]
: apartmentRoutes.find((apr) => apr.type === card.Unit_Type)?.layout;
console.log("card", card);
const { setModal } = useModal();
@@ -1,4 +1,4 @@
const MasterplanLoaderModal = () => {
const LoaderModal = () => {
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">
@@ -8,4 +8,4 @@ const MasterplanLoaderModal = () => {
);
};
export default MasterplanLoaderModal;
export default LoaderModal;
@@ -82,8 +82,7 @@ const LayoutOptions = () => {
setIsLoading(true);
getApartments(localStorageToken)
.then((res) => {
console.log("first2", res);
.then(() => {
setIsLoading(false);
})
.catch((error) => {
@@ -1,4 +1,4 @@
import { useState } from "react";
import { useEffect, useState } from "react";
import useSphere from "../../store/useSphere";
import { IAppartmentComplex, ISphere } from "../../types/apartmentSphere";
import Button from "../Button";
@@ -12,17 +12,28 @@ import InfoIcon from "../icons/InfoIcon";
import { useNavigate } from "react-router-dom";
import useModal from "../../store/useModal";
import { SendEnquiryModal } from "../modals/SendEnquryModal";
import { IAparmentRes } from "../../types/apartmentsRes";
import useFavorites from "../../store/useFavorites";
interface VirtualTourSidebarProps {
currentAppartment: null | IAppartmentComplex;
appartmentSphere: null | IAppartmentComplex;
apartment: null | IAparmentRes;
}
const VirtualTourSidebar = ({ currentAppartment }: VirtualTourSidebarProps) => {
const VirtualTourSidebar = ({
appartmentSphere,
apartment,
}: VirtualTourSidebarProps) => {
const { currentCompassRotate } = useCompass();
const [isActive, setIsActive] = useState(false);
const { setSelectedSphere, selectedSphere } = useSphere();
const { setModal } = useModal();
const navigate = useNavigate();
const wing =
apartment?.Unit_No.split("-")[0] === "W" ? "West Wing" : "East Wing";
const [isFavorite, setIsFavorite] = useState(false);
const { setFavorites } = useFavorites();
const handleOnShowClick = () => {
setIsActive((prev) => !prev);
@@ -37,13 +48,59 @@ const VirtualTourSidebar = ({ currentAppartment }: VirtualTourSidebarProps) => {
};
const handleAboutComplexClick = () => {
navigate(`../aboutComplex`);
if (!apartment) return;
navigate(`../search/${apartment?.id}`);
};
const handleOnSendEnquiryClick = () => {
setModal(<SendEnquiryModal />);
};
const handleOnFavoriteClick = (
e: React.MouseEvent<HTMLButtonElement, MouseEvent>
) => {
e.stopPropagation();
console.log("apartment", apartment);
if (!apartment) return;
const favorites = localStorage.getItem("Favorites");
if (!favorites) {
setIsFavorite(true);
const updatedFavorites = JSON.stringify([apartment]);
localStorage.setItem("Favorites", updatedFavorites);
} else {
const _favorites = JSON.parse(favorites) as IAparmentRes[];
if (_favorites.some((apart) => apart.id === apartment.id)) {
setIsFavorite(false);
const updatedFavorites = [..._favorites].filter(
(apart) => apart.id !== apartment.id
);
const convertedFavorites = JSON.stringify(updatedFavorites);
setFavorites(updatedFavorites);
localStorage.setItem("Favorites", convertedFavorites);
} else {
setIsFavorite(true);
const updatedFavorites = [..._favorites, apartment];
setFavorites(updatedFavorites);
const convertedFavorites = JSON.stringify(updatedFavorites);
localStorage.setItem("Favorites", convertedFavorites);
}
}
};
useEffect(() => {
if (!apartment) return;
const favorites = localStorage.getItem("Favorites");
if (favorites) {
const _isFavorite = (JSON.parse(favorites) as IAparmentRes[]).some(
(apart) => apart.id === apartment.id
);
setIsFavorite(_isFavorite);
}
}, [apartment, apartment?.id]);
return (
<div className="absolute w-screen h-screen grid z-[99999997] pointer-events-none select-none">
<div className="h-screen py-[72px] px-3 w-[360px]">
@@ -55,27 +112,32 @@ const VirtualTourSidebar = ({ currentAppartment }: VirtualTourSidebarProps) => {
className="w-fit"
onClick={handleOnBackClick}
/>
{/* <p className="text-[#0D1922] font-semibold leading-6 text-left text-xl"> */}
<p className="text-[#0D1922] font-semibold text-subheadline-s leading-6 text-left">
1 BR Squared, 609 Sqft
{apartment
? `${apartment?.Unit_Type}, ${Math.round(
apartment?.Total_Area_Sqft
)} Sqft`
: "1 BR Squared, 609 Sqft"}
</p>
</div>
<div className="pt-3">
<div className="flex gap-2 items-center">
<div className="flex flex-col">
<p className="text-[#00BED7] text-caption-m font-medium">
Rove Home Marasi Drive{" "}
{apartment?.Project_Name || "Rove Home Marasi Drive"}
</p>
<div className="text-[#73787C] flex gap-2 items-center w-fit pt-1">
<p className="text-caption-m font-semibold leading-4">
East Wing
{wing}
</p>
<div className="w-1 h-1 bg-[#E2E2DC] rounded-full"></div>
<p className="text-caption-m font-semibold leading-4">
Floor 11
Floor {apartment?.Floor || 11}
</p>
<div className="w-1 h-1 bg-[#E2E2DC] rounded-full"></div>
<p className="text-caption-m font-semibold leading-4">
213
{apartment?.Unit_No || 213}
</p>
</div>
</div>
@@ -91,7 +153,7 @@ const VirtualTourSidebar = ({ currentAppartment }: VirtualTourSidebarProps) => {
} relative flex justify-center`}
>
<img
src={currentAppartment?.map}
src={appartmentSphere?.map}
alt=""
className="max-h-[300px]"
/>
@@ -110,11 +172,15 @@ const VirtualTourSidebar = ({ currentAppartment }: VirtualTourSidebarProps) => {
<div className="flex flex-col gap-3">
<div className="flex justify-between text-m">
<p className="text-[#73787C]">Size</p>
<p className="text-[#0D1922]">609 Sqft</p>
<p className="text-[#0D1922]">
{apartment?.Total_Area_Sqft || 609} Sqft
</p>
</div>
<div className="flex justify-between text-m">
<p className="text-[#73787C]">Status</p>
<p className="text-[#0D1922]">Available</p>
<p className="text-[#0D1922]">
{apartment?.Property_Status || "Available"}
</p>
</div>
</div>
</div>
@@ -136,14 +202,18 @@ const VirtualTourSidebar = ({ currentAppartment }: VirtualTourSidebarProps) => {
buttonType="secondary"
onClick={handleAboutComplexClick}
/>
<Button icon={<HeartIcon />} buttonType="secondary" />
<Button
icon={<HeartIcon isFilled={isFavorite} />}
buttonType="secondary"
onClick={handleOnFavoriteClick}
/>
</div>
</div>
</div>
<div className="h-14 absolute -bottom-14 left-0 w-full flex justify-between">
<div className="flex gap-1 py-2 items-start flex-wrap pr-[9px]">
{currentAppartment &&
currentAppartment.spheres.map((sphere) => {
{appartmentSphere &&
appartmentSphere.spheres.map((sphere) => {
return (
<div
onClick={() => handleOnLabelClick(sphere)}
@@ -1,18 +1,18 @@
import useModal from "../../store/useModal";
// import useModal from "../../store/useModal";
import Button from "../Button";
import HintIcon from "../icons/HintIcon";
import ResizeIcon from "../icons/ResizeIcon";
import HelpModal from "../modals/HelpModal";
// import HelpModal from "../modals/HelpModal";
import useFullScreen from "../../store/useFullScreen";
import ActiveResizeIcon from "../icons/ActiveResizeIcon";
const VirtualTourTopPanel = () => {
const { setModal } = useModal();
// const { setModal } = useModal();
const { onFullscreen, isFullscreen, setIsFullscreen } = useFullScreen();
const handleOnHelpClick = () => {
setModal(<HelpModal />);
};
// const handleOnHelpClick = () => {
// setModal(<HelpModal />);
// };
const handleOnFullScreenClick = () => {
if (!onFullscreen) return;
@@ -47,7 +47,7 @@ const VirtualTourTopPanel = () => {
<Button
buttonType="fab"
icon={<HintIcon />}
onClick={handleOnHelpClick}
// onClick={handleOnHelpClick}
/>
</div>
</div>
+4 -4
View File
@@ -1,6 +1,6 @@
[
{
"id": "apartments-studio-1",
"id": "Studio Flex",
"map": "/images/virtual-tour/STD-FLEX_13/map.jpg",
"spheres": [
{
@@ -98,7 +98,7 @@
]
},
{
"id": "apartments-studio-2",
"id": "Studio Squared",
"map": "/images/virtual-tour/STD-2_31/map.jpg",
"spheres": [
{
@@ -189,7 +189,7 @@
]
},
{
"id": "apartments-studio-3",
"id": "1 BR Squared",
"map": "/images/virtual-tour/BDR-1-C_31/map.jpg",
"spheres": [
{
@@ -397,7 +397,7 @@
]
},
{
"id": "apartments-studio-4",
"id": "2 BR Squared",
"map": "/images/virtual-tour/BDR-2-B_21/map.jpg",
"spheres": [
{
+19 -22
View File
@@ -1,13 +1,13 @@
import { useEffect, useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import Footer from "../components/Footer";
import ButtonPanel from "../components/apartmentPage/ButtonPanel";
import ApartmentLayout from "../components/apartmentPage/ApartmentLayout";
import ApartmentSidebar from "../components/ApartmentSidebar";
import StudioDescriptionSection from "../components/apartmentPage/StudioDescriptionSection";
import { useEffect, useState } from "react";
import { getApartments } from "../api/apartments";
import { getCurrentApartment } from "../api/apartments";
import { updateAccessToken } from "../api/updateAccessToken";
import { IAparmentRes, IApartmentsRes } from "../types/apartmentsRes";
import { useNavigate, useParams } from "react-router-dom";
import { IAparmentRes } from "../types/apartmentsRes";
import useModal from "../store/useModal";
import SearchLoaderModal from "../components/modals/SearchLoaderModal";
@@ -23,47 +23,44 @@ const ApartmentPage = () => {
setIsLoading(true);
const zohoToken = localStorage.getItem("ACCESS_TOKEN");
getApartments(zohoToken)
if (!id) return;
getCurrentApartment(zohoToken, id)
.then((data) => {
const apartmentsData = (data as IApartmentsRes).apartments;
const _currentApartment = apartmentsData.find((aprt) => aprt.id === id);
if (_currentApartment) {
setCurrentApartment(_currentApartment);
} else {
console.log("Apartment not found");
navigate(-1);
}
const _currentApartment = data.apartment;
setCurrentApartment(_currentApartment);
setIsLoading(false);
})
.catch((error) => {
const errorStatus = error.response.status;
if (errorStatus === 401) {
updateAccessToken().then((token) => {
return updateAccessToken().then((token) => {
if (token) {
getApartments(token)
getCurrentApartment(token, id)
.then((data) => {
const apartmentsData = (data as IApartmentsRes).apartments;
const _currentApartment = apartmentsData.find(
(aprt) => aprt.id === id
);
const _currentApartment = data.apartment;
if (_currentApartment) {
setCurrentApartment(_currentApartment);
} else {
navigate(-1);
}
setIsLoading(false);
})
.catch(() => {
console.error("error", error);
})
.finally(() => {
setIsLoading(false);
});
}
});
} else if (errorStatus === 404) {
console.log("Apartment not found");
navigate(-1);
} else {
console.error("error", error);
setIsLoading(false);
navigate(-1);
}
setIsLoading(false);
});
}, [id, navigate]);
+80 -12
View File
@@ -1,40 +1,108 @@
import { useEffect, useState } from "react";
import { Canvas } from "@react-three/fiber";
import { useParams } from "react-router-dom";
import { useNavigate, useParams } from "react-router-dom";
import VirtualTourWrapper from "../components/virtualTour/VirtualTourWrapper";
import { IAppartmentComplex } from "../types/apartmentSphere";
import VirtualTourTopPanel from "../components/virtualTour/VirtualTourTopPanel";
import ButtomPanelCompassVirtualTour from "../components/virtualTour/ButtomPanelCompassVirualTour";
import VirtualTourSidebar from "../components/virtualTour/VirtualTourSidebar";
import _appartment from "../data/appartments.json";
import { getCurrentApartment } from "../api/apartments";
import { updateAccessToken } from "../api/updateAccessToken";
import { IAparmentRes } from "../types/apartmentsRes";
import useModal from "../store/useModal";
import LoaderModal from "../components/modals/LoaderModal";
const appartments = _appartment as IAppartmentComplex[];
const defaultApartment = appartments[0];
const VirtualTour = () => {
const [currentAppartment, setCurrentAppartment] =
const [currentAppartmentSphere, setCurrentAppartmentSphere] =
useState<null | IAppartmentComplex>(null);
const [isLoading, setIsLoading] = useState(false);
const [currentApartment, setCurrentApartment] = useState<IAparmentRes | null>(
null
);
const navigate = useNavigate();
const { appartmentTypeId } = useParams();
const { setModal } = useModal();
useEffect(() => {
const _currentAppartment = appartments.find(
(app) => app.id === appartmentTypeId
setIsLoading(true);
const zohoToken = localStorage.getItem("ACCESS_TOKEN");
if (!appartmentTypeId) return;
getCurrentApartment(zohoToken, appartmentTypeId)
.then((data) => {
const _currentApartment = data.apartment;
setCurrentApartment(_currentApartment);
setIsLoading(false);
})
.catch((error) => {
const errorStatus = error.response.status;
if (errorStatus === 401) {
return updateAccessToken().then((token) => {
if (token) {
getCurrentApartment(token, appartmentTypeId)
.then((data) => {
const _currentApartment = data.apartment;
if (_currentApartment) {
setCurrentApartment(_currentApartment);
}
})
.catch(() => {
console.error("error", error);
})
.finally(() => {
setIsLoading(false);
});
}
});
} else if (errorStatus === 404) {
console.log("Apartment not found");
navigate(-1);
} else {
console.error("error", error);
setIsLoading(false);
navigate(-1);
}
setIsLoading(false);
});
}, [appartmentTypeId, navigate]);
useEffect(() => {
if (!currentApartment) return;
const _currentAppartmentSphere = appartments.find(
(app) => app.id === currentApartment.Unit_Type
);
if (_currentAppartment) {
setCurrentAppartment(_currentAppartment);
if (_currentAppartmentSphere) {
setCurrentAppartmentSphere(_currentAppartmentSphere);
} else {
setCurrentAppartment(defaultApartment);
setCurrentAppartmentSphere(defaultApartment);
}
}, [appartmentTypeId]);
}, [appartmentTypeId, currentApartment]);
useEffect(() => {
if (isLoading) {
setModal(<LoaderModal />);
} else {
setModal(null);
}
}, [isLoading, setModal]);
return (
<div className="overflow-hidden h-screen w-screen select-none">
<VirtualTourTopPanel />
<VirtualTourSidebar currentAppartment={currentAppartment} />
<VirtualTourSidebar
appartmentSphere={currentAppartmentSphere}
apartment={currentApartment}
/>
<Canvas camera={{ fov: 90 }}>
{currentAppartment && (
<VirtualTourWrapper appartment={currentAppartment} />
{currentAppartmentSphere && (
<VirtualTourWrapper appartment={currentAppartmentSphere} />
)}
</Canvas>
<ButtomPanelCompassVirtualTour />
+8 -1
View File
@@ -29,6 +29,13 @@ type InfoRes = null | {
interface IApartmentsRes {
message: string;
apartments: IAparmentRes[];
code: number;
}
export type { IApartmentsRes, IAparmentRes, InfoRes };
interface IApartmentRes {
message: string;
apartment: IAparmentRes;
code: number;
}
export type { IApartmentsRes, IAparmentRes, InfoRes, IApartmentRes };