mirror of
https://github.com/vercel/commerce.git
synced 2025-05-16 14:36:59 +00:00
385 lines
10 KiB
TypeScript
385 lines
10 KiB
TypeScript
import { Layout } from '@components/common'
|
|
import commerce from '@lib/api/commerce'
|
|
import {
|
|
GetStaticPathsContext,
|
|
GetStaticPropsContext,
|
|
InferGetStaticPropsType,
|
|
} from 'next'
|
|
import { Viewer } from 'photo-sphere-viewer'
|
|
import { GyroscopePlugin } from 'photo-sphere-viewer/dist/plugins/gyroscope'
|
|
import { MarkersPlugin } from 'photo-sphere-viewer/dist/plugins/markers'
|
|
import { GalleryPlugin } from 'photo-sphere-viewer/dist/plugins/gallery'
|
|
import 'photo-sphere-viewer/dist/plugins/markers.css'
|
|
import 'photo-sphere-viewer/dist/plugins/gallery.css'
|
|
import { StereoPlugin } from 'photo-sphere-viewer/dist/plugins/stereo'
|
|
import { VirtualTourPlugin } from 'photo-sphere-viewer/dist/plugins/virtual-tour'
|
|
import { VisibleRangePlugin } from 'photo-sphere-viewer/dist/plugins/visible-range'
|
|
import { useEffect, useRef, useState } from 'react'
|
|
import { useRouter } from 'next/router'
|
|
|
|
import RegionsDataJson from '../../../static_data/navBarMenuData.json'
|
|
import MarkerCardModal from '@components/common/Room/MarkerCardModal/MarkerCardModal'
|
|
import { useDisclosure } from '@chakra-ui/react'
|
|
|
|
import decadesManifest from '../../../static_data/decadesManifest.json'
|
|
import {
|
|
MarkerData,
|
|
MarkerJson,
|
|
} from '@components/common/Room/RoomTypes/RoomTypes'
|
|
import { getNodes, getRecursiveMarkers } from 'workers/DecadeWorker'
|
|
import screenfull from 'screenfull'
|
|
|
|
export async function getStaticPaths({ locales }: GetStaticPathsContext) {
|
|
const decadesPaths = RegionsDataJson.regions
|
|
.filter((region) => region.enabled)
|
|
.flatMap((region) => {
|
|
let regionDecadesPath = new Array<string>()
|
|
for (let key in decadesManifest) {
|
|
if (decadesManifest[key as keyof typeof decadesManifest].enabled) {
|
|
Array.from(Array(7).keys()).forEach((nodeId: number) =>
|
|
regionDecadesPath.push(region.href + '/' + key + '/' + nodeId)
|
|
)
|
|
}
|
|
}
|
|
return regionDecadesPath
|
|
})
|
|
|
|
return {
|
|
paths: locales
|
|
? locales.reduce<string[]>((arr, locale) => {
|
|
// Add a decade path for every locale
|
|
decadesPaths.forEach((path: any) => {
|
|
arr.push(`/${locale}${path}`)
|
|
})
|
|
return arr
|
|
}, [])
|
|
: decadesPaths,
|
|
fallback: 'blocking',
|
|
}
|
|
}
|
|
|
|
export async function getStaticProps({
|
|
params,
|
|
locale,
|
|
locales,
|
|
preview,
|
|
}: GetStaticPropsContext<{ region: string; decade: string; start: string }>) {
|
|
const config = { locale, locales }
|
|
let products = new Array()
|
|
let decadeManifest = (
|
|
await import(
|
|
`../../../static_data/regions/${params?.region}/${params?.decade}/manifest.json`
|
|
)
|
|
).rooms
|
|
let region = params?.region
|
|
let decade = params?.decade
|
|
let startNode = params?.start
|
|
|
|
//sunrise sunset api to retreive Rome rise/set times
|
|
const sunriseSunsetAPI =
|
|
'https://api.sunrise-sunset.org/json?lat=41.9027835&lng=12.4963655'
|
|
const [sunriseTime, sunsetTime] = await fetch(sunriseSunsetAPI)
|
|
.then((response) => {
|
|
if (!response.ok) {
|
|
throw Error(response.statusText)
|
|
}
|
|
return response.json()
|
|
})
|
|
.then((data) => data.results)
|
|
.then((data) => [
|
|
parseInt(data.sunrise.split(':')[0]),
|
|
parseInt(data.sunset.split(':')[0]),
|
|
])
|
|
.catch((error) => [7, 7])
|
|
|
|
const time =
|
|
new Date().getUTCHours() >= sunsetTime + 12 ||
|
|
new Date().getUTCHours() <= sunriseTime
|
|
? 'night'
|
|
: 'day'
|
|
|
|
for (const roomMeta of decadeManifest) {
|
|
let roomMarkers
|
|
|
|
try {
|
|
roomMarkers = await import(
|
|
`../../../static_data/regions/abruzzo/${decade}/${time}/${
|
|
roomMeta.filename.split('.')[0]
|
|
}.json`
|
|
)
|
|
} catch (e) {
|
|
continue
|
|
}
|
|
|
|
for (const productMarker of roomMarkers.markers.filter(
|
|
(marker: MarkerJson) => marker.markerType == 'product'
|
|
)) {
|
|
if (
|
|
products.find(({ product }) =>
|
|
product.slug?.includes(productMarker.markerSource)
|
|
)
|
|
)
|
|
continue
|
|
|
|
const productPromise = commerce.getProduct({
|
|
variables: {
|
|
slug: productMarker.markerSource,
|
|
withMetafields: [
|
|
{ namespace: 'custom', key: 'nazionalit_' },
|
|
{ namespace: 'custom', key: 'descrizione_tecnica' },
|
|
{ namespace: 'custom', key: 'descrizione_storica' },
|
|
],
|
|
},
|
|
config,
|
|
preview,
|
|
})
|
|
|
|
products.push(await productPromise)
|
|
}
|
|
}
|
|
|
|
if (!products) {
|
|
throw new Error(`Products associated with markers not found`)
|
|
}
|
|
|
|
return {
|
|
props: {
|
|
products,
|
|
decadeManifest,
|
|
region,
|
|
decade,
|
|
startNode,
|
|
time,
|
|
},
|
|
revalidate: 200,
|
|
}
|
|
}
|
|
|
|
export default function RoomPage({
|
|
products,
|
|
decadeManifest,
|
|
region,
|
|
decade,
|
|
startNode,
|
|
time,
|
|
}: InferGetStaticPropsType<typeof getStaticProps>) {
|
|
const {
|
|
isOpen: isOpenModal,
|
|
onOpen: onOpenModal,
|
|
onClose: onCloseModal,
|
|
} = useDisclosure()
|
|
const [currentMarkerInModal, setCurrentMarkerInModal] = useState<MarkerData>()
|
|
const [recursiveMarkers] = useState<any>(
|
|
getRecursiveMarkers(decade!, decadeManifest, time)
|
|
)
|
|
const [virtualTourNodes] = useState<Array<any>>(
|
|
getNodes(products, decadeManifest, region!, decade!, time)
|
|
)
|
|
|
|
const [audioPlayer, setAudioPlayer] = useState<HTMLAudioElement>()
|
|
const [isAudioInBackground, setIsAudioInBackground] = useState<boolean>(false)
|
|
const [isNodeChanged, setIsNodeChanged] = useState<boolean>(false)
|
|
|
|
const router = useRouter()
|
|
const audioPlayerRef = useRef<HTMLAudioElement | undefined>(audioPlayer)
|
|
|
|
let navbarArray = new Array(
|
|
'autorotate',
|
|
'zoom',
|
|
'move',
|
|
'markers',
|
|
'markersList',
|
|
'gallery',
|
|
'stereo',
|
|
'gyroscope',
|
|
'fullscreen'
|
|
)
|
|
|
|
navbarArray = navbarArray.concat(
|
|
recursiveMarkers.map((recursiveMarker: any) => {
|
|
return {
|
|
id: recursiveMarker.name,
|
|
content: recursiveMarker.name,
|
|
title: recursiveMarker.name,
|
|
className: 'custom-button',
|
|
visible: false,
|
|
onClick: (viewer: any) => {
|
|
changeToRecursiveRoom(recursiveMarker, viewer)
|
|
},
|
|
}
|
|
})
|
|
)
|
|
|
|
const changeToRecursiveRoom = (recursiveMarker: any, viewer: any) => {
|
|
const virtualTour = viewer.getPlugin(VirtualTourPlugin)
|
|
const destNode = virtualTourNodes.find(
|
|
(node: any) => node.name === recursiveMarker.name
|
|
)
|
|
virtualTour.setCurrentNode(destNode.id)
|
|
}
|
|
|
|
useEffect(() => {
|
|
const shperePlayerInstance = new Viewer({
|
|
container: 'roomViewer',
|
|
plugins: [
|
|
[
|
|
VisibleRangePlugin,
|
|
{
|
|
longitudeRange: [null],
|
|
latitudeRange: [-Math.PI / 2, Math.PI / 4], //Restrict range so you can't see the top of the pano
|
|
},
|
|
],
|
|
[GyroscopePlugin, StereoPlugin],
|
|
MarkersPlugin,
|
|
[
|
|
GalleryPlugin,
|
|
{
|
|
thumbnailSize: { width: 100, height: 100 },
|
|
},
|
|
],
|
|
[
|
|
VirtualTourPlugin,
|
|
{
|
|
positionMode: VirtualTourPlugin.MODE_3D,
|
|
renderMode: VirtualTourPlugin.MODE_MARKERS,
|
|
nodes: virtualTourNodes,
|
|
startNodeId: startNode,
|
|
},
|
|
],
|
|
],
|
|
touchmoveTwoFingers: true,
|
|
mousewheelCtrlKey: true,
|
|
navbar: navbarArray,
|
|
})
|
|
|
|
const markersPlugin = shperePlayerInstance.getPlugin(MarkersPlugin)
|
|
const virtualTourPlugin = shperePlayerInstance.getPlugin(VirtualTourPlugin)
|
|
|
|
markersPlugin?.on('select-marker', (e, marker) => {
|
|
if (marker.id.includes('tour-link')) {
|
|
return
|
|
}
|
|
|
|
if (screenfull.isEnabled) {
|
|
screenfull.exit()
|
|
}
|
|
|
|
if (marker.data.markerType === 'room') {
|
|
virtualTourPlugin?.setCurrentNode(
|
|
decadeManifest.find(
|
|
(room: any) =>
|
|
room.name === marker.data.markerPayload.resourceSource
|
|
).id
|
|
)
|
|
return
|
|
}
|
|
|
|
setCurrentMarkerInModal(marker.data)
|
|
onOpenModal()
|
|
})
|
|
|
|
virtualTourPlugin?.on('node-changed', (e, nodeId, data) => {
|
|
setIsNodeChanged(true)
|
|
recursiveMarkers.forEach((recursive: any) =>
|
|
shperePlayerInstance.navbar.getButton(recursive.name).hide()
|
|
)
|
|
const originNode = virtualTourNodes.find(
|
|
(node: any) => node.id === nodeId
|
|
)
|
|
const originRoom = recursiveMarkers.find((recursive: any) =>
|
|
originNode.panorama.includes(recursive.panorama)
|
|
)
|
|
if (originRoom != undefined) {
|
|
shperePlayerInstance.navbar.getButton(originRoom.name).show()
|
|
}
|
|
})
|
|
|
|
router.events.on('routeChangeStart', () => {
|
|
if (audioPlayerRef.current && !audioPlayerRef.current?.paused) {
|
|
audioPlayerRef.current!.pause()
|
|
audioPlayerRef.current!.src = ''
|
|
}
|
|
})
|
|
|
|
// unmount component instructions
|
|
return () => {
|
|
shperePlayerInstance.destroy()
|
|
router.events.off('routeChangeStart', () => {
|
|
if (audioPlayerRef.current && !audioPlayerRef.current?.paused) {
|
|
audioPlayerRef.current!.pause()
|
|
audioPlayerRef.current!.src = ''
|
|
}
|
|
})
|
|
}
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
if (isAudioInBackground === true) {
|
|
setTimeout(() => {
|
|
audioPlayer!.play()
|
|
}, 500)
|
|
setTimeout(() => {
|
|
audioPlayer?.pause()
|
|
setIsAudioInBackground(false)
|
|
}, audioPlayer!.duration - audioPlayer!.currentTime)
|
|
}
|
|
}, [isAudioInBackground])
|
|
|
|
useEffect(() => {
|
|
if (
|
|
currentMarkerInModal != undefined &&
|
|
currentMarkerInModal.markerType === 'video' &&
|
|
!audioPlayer?.paused
|
|
) {
|
|
audioPlayer?.pause()
|
|
}
|
|
}, [currentMarkerInModal])
|
|
|
|
const onAudioPlay = (player: HTMLAudioElement) => {
|
|
if (!audioPlayer?.paused) {
|
|
audioPlayer?.pause()
|
|
}
|
|
setAudioPlayer(player)
|
|
}
|
|
|
|
useEffect(() => {
|
|
audioPlayerRef.current = audioPlayer
|
|
}, [audioPlayer])
|
|
|
|
useEffect(() => {
|
|
if (isNodeChanged && !audioPlayer?.paused) {
|
|
audioPlayer?.pause()
|
|
setIsNodeChanged(false)
|
|
}
|
|
}, [isNodeChanged])
|
|
|
|
return (
|
|
<>
|
|
{currentMarkerInModal != undefined ? (
|
|
currentMarkerInModal.markerType === 'audio' ? (
|
|
<MarkerCardModal
|
|
decade={decade!}
|
|
marker={currentMarkerInModal}
|
|
onModalClose={onCloseModal}
|
|
isOpen={isOpenModal}
|
|
onAudioPlayerPause={() => setIsAudioInBackground(true)}
|
|
onAudioPlayerPlay={onAudioPlay}
|
|
/>
|
|
) : (
|
|
<MarkerCardModal
|
|
decade={decade!}
|
|
marker={currentMarkerInModal}
|
|
onModalClose={onCloseModal}
|
|
isOpen={isOpenModal}
|
|
/>
|
|
)
|
|
) : (
|
|
<></>
|
|
)}
|
|
<div style={{ height: '90vh' }} id="roomViewer" />
|
|
</>
|
|
)
|
|
}
|
|
|
|
RoomPage.Layout = Layout
|