This commit is contained in:
2026-02-11 18:32:29 +05:00
parent 13f7ac4dc0
commit 96ddfc6e4a
27 changed files with 1100 additions and 597 deletions
+3 -3
View File
@@ -1,5 +1,5 @@
# VITE_API_URL=http://localhost:4002 # VITE_API_URL=http://192.168.1.224:4002
VITE_API_URL=http://192.168.1.35:4002 # VITE_API_URL=http://192.168.1.35:4002
# VITE_API_URL=http://194.26.138.94:4002 # VITE_API_URL=http://194.26.138.94:4002
# VITE_API_URL=https://irthtest.online/api VITE_API_URL=https://irthtest.online/api
# VITE_API_URL=https://irth.graff.estate/api # VITE_API_URL=https://irth.graff.estate/api
+2 -1
View File
@@ -11,6 +11,7 @@ lerna-debug.log*
node_modules node_modules
dist dist
dist-ssr dist-ssr
dist.zip
*.local *.local
public/virtual-tours public/virtual-tours
@@ -24,4 +25,4 @@ public/virtual-tours
*.ntvs* *.ntvs*
*.njsproj *.njsproj
*.sln *.sln
*.sw? *.sw?
Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 385 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 287 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 334 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 385 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 287 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.
+83 -83
View File
@@ -32,7 +32,7 @@ const constrainPosition = (
position: Position, position: Position,
containerSize: Size, containerSize: Size,
imageSize: Size, imageSize: Size,
zoom: number, zoom: number
): Position => { ): Position => {
const scaledWidth = imageSize.width * zoom; const scaledWidth = imageSize.width * zoom;
const scaledHeight = imageSize.height * zoom; const scaledHeight = imageSize.height * zoom;
@@ -58,7 +58,7 @@ const constrainPosition = (
}; };
const getEventPosition = ( const getEventPosition = (
e: MouseEvent | TouchEvent | React.MouseEvent | React.TouchEvent, e: MouseEvent | TouchEvent | React.MouseEvent | React.TouchEvent
): Position => { ): Position => {
if ("touches" in e) if ("touches" in e)
return { return {
@@ -83,7 +83,7 @@ const calculateMinZoom = (containerSize: Size, imageSize: Size): number => {
const calculateCenterPosition = ( const calculateCenterPosition = (
containerSize: Size, containerSize: Size,
imageSize: Size, imageSize: Size,
zoom: number, zoom: number
): Position => { ): Position => {
const scaledWidth = imageSize.width * zoom; const scaledWidth = imageSize.width * zoom;
const scaledHeight = imageSize.height * zoom; const scaledHeight = imageSize.height * zoom;
@@ -161,7 +161,7 @@ function FloorSelect({
newPosition, newPosition,
{ width: containerRect.width, height: containerRect.height }, { width: containerRect.width, height: containerRect.height },
originalSize, originalSize,
newZoom, newZoom
); );
setImagePosition(constrainedPosition); setImagePosition(constrainedPosition);
@@ -194,7 +194,7 @@ function FloorSelect({
// Check if we've moved beyond the threshold // Check if we've moved beyond the threshold
const distanceMoved = Math.hypot( const distanceMoved = Math.hypot(
x - dragStartPosition.current.x, x - dragStartPosition.current.x,
y - dragStartPosition.current.y, y - dragStartPosition.current.y
); );
if (distanceMoved > dragThreshold) { if (distanceMoved > dragThreshold) {
@@ -251,7 +251,7 @@ function FloorSelect({
const touch2 = e.touches[1]; const touch2 = e.touches[1];
const distance = Math.hypot( const distance = Math.hypot(
touch1.clientX - touch2.clientX, touch1.clientX - touch2.clientX,
touch1.clientY - touch2.clientY, touch1.clientY - touch2.clientY
); );
initialTouchDistance.current = distance; initialTouchDistance.current = distance;
previousTouchDistance.current = distance; previousTouchDistance.current = distance;
@@ -285,7 +285,7 @@ function FloorSelect({
const touch2 = e.touches[1]; const touch2 = e.touches[1];
const distance = Math.hypot( const distance = Math.hypot(
touch1.clientX - touch2.clientX, touch1.clientX - touch2.clientX,
touch1.clientY - touch2.clientY, touch1.clientY - touch2.clientY
); );
if (initialTouchDistance.current === null) { if (initialTouchDistance.current === null) {
@@ -311,7 +311,7 @@ function FloorSelect({
const newZoom = Math.min( const newZoom = Math.min(
maxZoomRef.current, maxZoomRef.current,
Math.max(minZoomRef.current, zoom * zoomFactor), Math.max(minZoomRef.current, zoom * zoomFactor)
); );
// Prevent zoom if at limits or change is too small // Prevent zoom if at limits or change is too small
@@ -353,7 +353,7 @@ function FloorSelect({
// Check if we've moved beyond the threshold // Check if we've moved beyond the threshold
const distanceMoved = Math.hypot( const distanceMoved = Math.hypot(
x - dragStartPosition.current.x, x - dragStartPosition.current.x,
y - dragStartPosition.current.y, y - dragStartPosition.current.y
); );
if (distanceMoved > dragThreshold) { if (distanceMoved > dragThreshold) {
@@ -426,7 +426,7 @@ function FloorSelect({
const newZoom = Math.min( const newZoom = Math.min(
maxZoomRef.current, maxZoomRef.current,
Math.max(minZoomRef.current, zoom * zoomFactor), Math.max(minZoomRef.current, zoom * zoomFactor)
); );
// Prevent zoom if at limits or change is too small // Prevent zoom if at limits or change is too small
@@ -459,7 +459,7 @@ function FloorSelect({
const centerPosition = calculateCenterPosition( const centerPosition = calculateCenterPosition(
{ width, height }, { width, height },
originalSize, originalSize,
newMinZoom, // Сбрасываем к минимальному зуму (изображение на всю высоту) newMinZoom // Сбрасываем к минимальному зуму (изображение на всю высоту)
); );
setZoom(newMinZoom); setZoom(newMinZoom);
@@ -493,7 +493,7 @@ function FloorSelect({
const centerPosition = calculateCenterPosition( const centerPosition = calculateCenterPosition(
{ width, height }, { width, height },
originalSize, originalSize,
newMinZoom, // Используем вычисленный минимальный зум newMinZoom // Используем вычисленный минимальный зум
); );
setZoom(newMinZoom); setZoom(newMinZoom);
setImagePosition(centerPosition); setImagePosition(centerPosition);
@@ -583,11 +583,7 @@ function FloorSelect({
const { data } = useQuery({ const { data } = useQuery({
queryKey: ["floors-data", complexName], queryKey: ["floors-data", complexName],
queryFn: () => queryFn: () =>
api api.get(`units/get-floors-data/${complexName}`).json<FloorsData[]>(),
.get(
`units/get-floors-data/${complexName}`,
)
.json<FloorsData[]>(),
}); });
function handleFloorClick(floor: string) { function handleFloorClick(floor: string) {
@@ -606,7 +602,7 @@ function FloorSelect({
data.some( data.some(
(floorData) => (floorData) =>
floorData.floor === +floor!.split(" ").at(-1)! || floorData.floor === +floor!.split(" ").at(-1)! ||
floorData.floor === +floor!.split(" ").at(-1)!.split("-")[0], floorData.floor === +floor!.split(" ").at(-1)!.split("-")[0]
) || ) ||
SPECIAL_FLOORS.includes(floor) SPECIAL_FLOORS.includes(floor)
) )
@@ -618,11 +614,11 @@ function FloorSelect({
data.find( data.find(
(floorData) => (floorData) =>
floorData.floor === +floor!.split(" ").at(-1)! || floorData.floor === +floor!.split(" ").at(-1)! ||
floorData.floor === +floor!.split(" ").at(-1)!.split("-")[0], floorData.floor === +floor!.split(" ").at(-1)!.split("-")[0]
)! )!
} }
onSelect={handleFloorClick} onSelect={handleFloorClick}
/>, />
); );
} }
@@ -647,7 +643,7 @@ function FloorSelect({
<div <div
className={clsx( className={clsx(
"overflow-hidden h-full w-full relative transition-transform duration-300", "overflow-hidden h-full w-full relative transition-transform duration-300",
selectedFloor && "2xl:-translate-x-1/4", selectedFloor && "2xl:-translate-x-1/4"
)} )}
ref={rootRef} ref={rootRef}
> >
@@ -661,7 +657,7 @@ function FloorSelect({
"touch-none absolute inset-0 select-none will-change-[opacity,scale,transform] transition-opacity duration-300", "touch-none absolute inset-0 select-none will-change-[opacity,scale,transform] transition-opacity duration-300",
isImageLoaded && originalSize.width !== 0 isImageLoaded && originalSize.width !== 0
? "opacity-100" ? "opacity-100"
: "opacity-0", : "opacity-0"
)} )}
style={{ style={{
cursor: isMobile ? (isDragging ? "grabbing" : "grab") : "default", cursor: isMobile ? (isDragging ? "grabbing" : "grab") : "default",
@@ -702,60 +698,64 @@ function FloorSelect({
/> />
<g ref={ref}> <g ref={ref}>
{Object.entries(enumerationMasks[complexName]).map( {Object.entries(enumerationMasks[complexName]).map(
([floorTitle, { x, y, width, height, d }]) => ([floorTitle, mask]) =>
Array.isArray(d) && Array.isArray(x) ? ( Array.isArray(mask) ? (
<Fragment key={floorTitle}> mask.map(({ x, y, width, height, d }) => (
<rect <Fragment
x={x[0]} key={`${floorTitle}-${x}-${y}-${width}-${height}-${d}`}
y={y} >
width={width} <rect
height={height} x={x}
rx={complexName === "marasi-drive" ? 14.2 : 10} y={y}
fillOpacity={0.4} width={width}
className={clsx( height={height}
"transition-[fill] pointer-events-none", rx={height / 2}
((hoveredFloor && fillOpacity={0.4}
floorTitle === className={clsx(
(complexName === "dubai-marina" "transition-[fill] pointer-events-none",
? hoveredFloor ((hoveredFloor &&
: SPECIAL_FLOORS.includes(hoveredFloor) floorTitle ===
? hoveredFloor (complexName === "dubai-marina"
: hoveredFloor.split(" ").at(-1)!)) || ? hoveredFloor
selectedFloor?.split(" ").at(-1) === floorTitle) && : SPECIAL_FLOORS.includes(hoveredFloor)
"fill-[#00BED7]", ? hoveredFloor
)} : hoveredFloor.split(" ").at(-1)!)) ||
/> selectedFloor?.split(" ").at(-1) === floorTitle) &&
<path d={d[0]} className="pointer-events-none fill-white" /> "fill-[#00BED7]"
<rect )}
x={x[1]} />
y={y} <path d={d} className="fill-white pointer-events-none" />
width={width} </Fragment>
height={height} ))
rx={complexName === "marasi-drive" ? 14.2 : 10}
fillOpacity={0.4}
className={clsx(
"transition-[fill] pointer-events-none",
((hoveredFloor &&
floorTitle ===
(complexName === "dubai-marina"
? hoveredFloor
: SPECIAL_FLOORS.includes(hoveredFloor)
? hoveredFloor
: hoveredFloor.split(" ").at(-1)!)) ||
selectedFloor?.split(" ").at(-1) === floorTitle) &&
"fill-[#00BED7]",
)}
/>
<path d={d[1]} className="pointer-events-none fill-white" />
</Fragment>
) : ( ) : (
// <rect
// x={x[1]}
// y={y[1]}
// width={width[1]}
// height={height[1]}
// rx={complexName === "marasi-drive" ? 14.2 : 10}
// fillOpacity={0.4}
// className={clsx(
// "transition-[fill] pointer-events-none",
// ((hoveredFloor &&
// floorTitle ===
// (complexName === "dubai-marina"
// ? hoveredFloor
// : SPECIAL_FLOORS.includes(hoveredFloor)
// ? hoveredFloor
// : hoveredFloor.split(" ").at(-1)!)) ||
// selectedFloor?.split(" ").at(-1) === floorTitle) &&
// "fill-[#00BED7]"
// )}
// />
// <path d={d[1]} className="fill-white pointer-events-none" />
<Fragment key={floorTitle}> <Fragment key={floorTitle}>
<rect <rect
x={Array.isArray(x) ? x[0] : x} x={mask.x}
y={y} y={mask.y}
width={width} width={mask.width}
height={height} height={mask.height}
rx={complexName === "marasi-drive" ? 14.2 : 10} rx={mask.height / 2}
fillOpacity={0.4} fillOpacity={0.4}
className={clsx( className={clsx(
"transition-[fill] pointer-events-none", "transition-[fill] pointer-events-none",
@@ -767,18 +767,18 @@ function FloorSelect({
? hoveredFloor ? hoveredFloor
: hoveredFloor.split(" ").at(-1)!)) || : hoveredFloor.split(" ").at(-1)!)) ||
selectedFloor?.split(" ").at(-1) === floorTitle) && selectedFloor?.split(" ").at(-1) === floorTitle) &&
"fill-[#00BED7]", "fill-[#00BED7]"
)} )}
/> />
<path <path
d={d as string} d={mask.d}
className="pointer-events-none fill-white" className="fill-white pointer-events-none"
/> />
</Fragment> </Fragment>
), )
)} )}
{Object.entries( {Object.entries(
floorsMasks[complexName as keyof typeof floorsMasks], floorsMasks[complexName as keyof typeof floorsMasks]
).map(([floorTitle, d]) => ( ).map(([floorTitle, d]) => (
<path <path
onMouseMove={!isMobile ? handleFloorMouseMove : undefined} onMouseMove={!isMobile ? handleFloorMouseMove : undefined}
@@ -802,7 +802,7 @@ function FloorSelect({
SPECIAL_FLOORS.includes(floorTitle) || SPECIAL_FLOORS.includes(floorTitle) ||
complexName === "marasi-drive" complexName === "marasi-drive"
? floorTitle ? floorTitle
: floorTitle.split(" ").at(-1)!, : floorTitle.split(" ").at(-1)!
); );
openPopup( openPopup(
@@ -810,7 +810,7 @@ function FloorSelect({
!SPECIAL_FLOORS.includes(floorTitle) && !SPECIAL_FLOORS.includes(floorTitle) &&
complexName === "marasi-drive" complexName === "marasi-drive"
? (floorTitle.split(" ")[0] as "West" | "East") ? (floorTitle.split(" ")[0] as "West" | "East")
: undefined, : undefined
); );
} }
}} }}
@@ -819,7 +819,7 @@ function FloorSelect({
SPECIAL_FLOORS.includes(floorTitle) || SPECIAL_FLOORS.includes(floorTitle) ||
complexName === "marasi-drive" complexName === "marasi-drive"
? floorTitle ? floorTitle
: floorTitle.split(" ").at(-1)!, : floorTitle.split(" ").at(-1)!
); );
if (!isMobile) if (!isMobile)
openPopup( openPopup(
@@ -827,7 +827,7 @@ function FloorSelect({
!SPECIAL_FLOORS.includes(floorTitle) && !SPECIAL_FLOORS.includes(floorTitle) &&
complexName === "marasi-drive" complexName === "marasi-drive"
? (floorTitle.split(" ")[0] as "West" | "East") ? (floorTitle.split(" ")[0] as "West" | "East")
: undefined, : undefined
); );
}} }}
onMouseLeave={() => { onMouseLeave={() => {
@@ -851,7 +851,7 @@ function FloorSelect({
? floorTitle ? floorTitle
: floorTitle.split(" ").at(-1)!) : floorTitle.split(" ").at(-1)!)
? "opacity-60" ? "opacity-60"
: "opacity-20", : "opacity-20"
)} )}
/> />
))} ))}
+988 -507
View File
File diff suppressed because it is too large Load Diff
+24 -3
View File
@@ -25,9 +25,7 @@ function UnitPage() {
queryKey: ["unit", params.complexName, params.unitNumber], queryKey: ["unit", params.complexName, params.unitNumber],
queryFn: () => queryFn: () =>
api api
.get( .get(`units/${params.unitNumber}?project=${params.complexName}`)
`units/${params.unitNumber}?project=${params.complexName}`
)
.json<Unit>(), .json<Unit>(),
}); });
@@ -270,6 +268,29 @@ function UnitPage() {
{/* <Button disabled variant="cta" size="large"> {/* <Button disabled variant="cta" size="large">
Book Book
</Button> */} </Button> */}
{/* videos for hq units */}
{unit.projectSlug === "hq" &&
[
"loft-edge",
"penthouse-loft",
"presidential-loft",
"studio",
].includes(unit.unitTypeVariantSlug) && (
<Button
variant="cta"
size="large"
onClick={() =>
setModal(
<VideoModal
src={`/videos/unit-types/hq/${unit.unitTypeVariantSlug}.mp4`}
/>
)
}
>
Video tour
</Button>
)}
</div> </div>
</div> </div>
</div> </div>