virtual tour sidebar info
This commit is contained in:
@@ -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,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 };
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
+2
-2
@@ -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>
|
||||
|
||||
@@ -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": [
|
||||
{
|
||||
|
||||
@@ -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]);
|
||||
|
||||
|
||||
@@ -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 />
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -11,6 +11,8 @@ const aparmentsApi =
|
||||
const searchApartmentApi =
|
||||
"https://www.zohoapis.com/crm/v6/Apartments/search?fields=Floor,Property_Status,Project_Name,Balcony_Area_Sqft,Unit_Type,Suite_Area_Sqft,No_Of_Bedrooms,Total_Area_Sqft,No_of_Bathrooms,Property_Name,Unit_View,Balcony_Area_Sqft,Unit_No,Suite_Area_Sqft";
|
||||
|
||||
const searchCurrentApartmentApi = "https://www.zohoapis.com/crm/v6/Apartments";
|
||||
|
||||
export {
|
||||
updateAccessTokenApi,
|
||||
aparmentsApi,
|
||||
@@ -19,4 +21,5 @@ export {
|
||||
clientSecret,
|
||||
grantType,
|
||||
searchApartmentApi,
|
||||
searchCurrentApartmentApi,
|
||||
};
|
||||
|
||||
+2
-1
@@ -6,6 +6,7 @@ import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import morgan from "morgan";
|
||||
import apartmentsRoute from "./routes/apartments.js";
|
||||
import apartmentRoute from "./routes/apartment.js";
|
||||
import updateAccessToken from "./routes/zohoAccessToken.js";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
@@ -24,7 +25,7 @@ app.use(json());
|
||||
app.use(morgan("combined", { stream: accessLogStream }));
|
||||
|
||||
app.use("/apartments", apartmentsRoute);
|
||||
app.use("/apartments/:id", apartmentsRoute);
|
||||
app.use("/apartment", apartmentRoute);
|
||||
app.use("/updateAccessToken", updateAccessToken);
|
||||
|
||||
app.listen(port, () => {
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
import { Router } from "express";
|
||||
import { searchCurrentApartmentApi } from "../consts.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { IApartment } from "../types/apartment.js";
|
||||
|
||||
const router = Router();
|
||||
|
||||
function ConvertApartmentRes(apartment: IApartment) {
|
||||
const convertedApartment: IApartment = {
|
||||
Balcony_Area_Sqft: apartment.Balcony_Area_Sqft,
|
||||
Floor: apartment.Floor,
|
||||
Property_Status: apartment.Property_Status,
|
||||
Unit_Type: apartment.Unit_Type,
|
||||
Project_Name: apartment.Project_Name,
|
||||
Suite_Area_Sqft: apartment.Suite_Area_Sqft,
|
||||
No_Of_Bedrooms: apartment.No_Of_Bedrooms,
|
||||
Unit_No: apartment.Unit_No,
|
||||
id: apartment.id,
|
||||
Total_Area_Sqft: apartment.Total_Area_Sqft,
|
||||
No_of_Bathrooms: apartment.No_of_Bathrooms,
|
||||
Property_Name: apartment.Property_Name,
|
||||
Unit_View: apartment.Unit_View,
|
||||
};
|
||||
|
||||
return convertedApartment;
|
||||
}
|
||||
|
||||
router.get("/:id", async (req, res) => {
|
||||
const accessToken = req?.headers?.authorization;
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
const url = `${searchCurrentApartmentApi}/${id}`;
|
||||
const requestHeaders: HeadersInit = new Headers();
|
||||
requestHeaders.set("Authorization", `${accessToken}`);
|
||||
const response = await fetch(url, {
|
||||
headers: requestHeaders,
|
||||
});
|
||||
|
||||
if (response.status === 404) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ message: "Квартира не найдена", code: 404 });
|
||||
}
|
||||
if (response.status === 401) {
|
||||
return res
|
||||
.status(401)
|
||||
.json({ message: "Неправильный токен или токен устарел", code: 401 });
|
||||
}
|
||||
const result = await response.json();
|
||||
|
||||
const convertedApartment = ConvertApartmentRes(result.data[0]);
|
||||
|
||||
return res.status(200).json({
|
||||
message: "ok",
|
||||
apartment: convertedApartment,
|
||||
code: 200,
|
||||
});
|
||||
} 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 });
|
||||
}
|
||||
if (
|
||||
(error as Error).message ===
|
||||
"Please check if the URL trying to access is a correct one"
|
||||
) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ message: "Квартира не найдена", code: 404 });
|
||||
}
|
||||
console.log("error", error);
|
||||
logger.error(error);
|
||||
|
||||
return res.status(500).json({ message: "Server Error", code: 500 });
|
||||
}
|
||||
});
|
||||
|
||||
const apartmentRoute = router;
|
||||
|
||||
export default apartmentRoute;
|
||||
@@ -1,22 +1,7 @@
|
||||
import { Router } from "express";
|
||||
import { aparmentsApi, searchApartmentApi } from "../consts.js";
|
||||
import { aparmentsApi, searchCurrentApartmentApi } from "../consts.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
|
||||
interface IApartment {
|
||||
Floor: number;
|
||||
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;
|
||||
}
|
||||
import { IApartment } from "../types/apartment.js";
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -276,54 +261,6 @@ router.get("/", async (req, res) => {
|
||||
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;
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
interface IApartment {
|
||||
Floor: number;
|
||||
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;
|
||||
}
|
||||
|
||||
export type { IApartment };
|
||||
Reference in New Issue
Block a user