diff --git a/src/app/mobile/webcam/[key]/page.tsx b/src/app/mobile/webcam/[key]/page.tsx
new file mode 100644
index 0000000..8a0da76
--- /dev/null
+++ b/src/app/mobile/webcam/[key]/page.tsx
@@ -0,0 +1,20 @@
+import { redirect } from 'next/navigation';
+import React from 'react';
+import WebcamMobileMapPage from '@/pages/webcam/ui/webcam-mobile-map-page';
+import { JISAN } from '@/entities/slop/model';
+
+const domainMap = {
+ jisan: JISAN,
+};
+
+const Page = ({ params }: { params: { key: string } }) => {
+ if (!(params.key in domainMap)) {
+ redirect('/not-found');
+ }
+
+ const domain = domainMap[params.key as keyof typeof domainMap];
+
+ return ;
+};
+
+export default Page;
diff --git a/src/app/mobile/webcam/page.tsx b/src/app/mobile/webcam/page.tsx
deleted file mode 100644
index d65b865..0000000
--- a/src/app/mobile/webcam/page.tsx
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from '@/pages/webcam/ui/webcam-mobile-map-page';
diff --git a/src/entities/slop/model/jisan.tsx b/src/entities/slop/model/jisan.tsx
index 5699cbc..38a4d4b 100644
--- a/src/entities/slop/model/jisan.tsx
+++ b/src/entities/slop/model/jisan.tsx
@@ -1,3 +1,5 @@
+'use client';
+
import BlueLiftPath from '../image/jisan/blue-lift-path';
import Lemon1Sub1LiftPath from '../image/jisan/lemon1-1-lift-path';
import Lemon1LiftPath from '../image/jisan/lemon1-lift-path';
@@ -17,138 +19,129 @@ export const JISAN: ResortInfo = {
level: 'BEGINNER',
name: '레몬 리프트 1',
Element: Lemon1LiftPath,
- webcam: {
- id: 'lemon-station',
- name: '레몬 탑승장',
- position: {
- top: 'top-[84%]',
- left: 'left-[20%]',
- },
- scale: 2,
- },
+ webcamId: 'lemon-station',
isOpen: true,
- isDayOpen: false,
- isNightOpen: false,
- isLateNightOpen: false,
},
{
id: 'lemon1-1-lift',
level: 'BEGINNER',
name: '레몬 리프트 1-1',
Element: Lemon1Sub1LiftPath,
- webcam: null,
isOpen: false,
- isDayOpen: false,
- isNightOpen: false,
- isLateNightOpen: false,
},
{
id: 'orange2-lift',
level: 'INTERMEDIATE',
name: '오렌지 리프트 2',
Element: Orange2LiftPath,
- webcam: {
- id: 'orange-station',
- name: '오렌지 탑승장',
- position: {
- top: 'top-[69%]',
- left: 'left-[29%]',
- },
- scale: 1,
- src: 'http://konjiam.live.cdn.cloudn.co.kr/konjiam/cam01.stream/playlist.m3u8',
- },
+ webcamId: 'orange-station',
isOpen: true,
- isDayOpen: false,
- isNightOpen: false,
- isLateNightOpen: false,
},
{
id: 'orange3-lift',
level: 'INTERMEDIATE',
name: '오렌지 리프트 3',
Element: Orange3LiftPath,
- webcam: {
- id: 'new-orange-station',
- name: '뉴오렌지 탑승장',
- position: {
- top: 'top-[64%]',
- left: 'left-[38%]',
- },
- scale: 2,
- src: 'http://konjiam.live.cdn.cloudn.co.kr/konjiam/cam01.stream/playlist.m3u8',
- },
+ webcamId: 'new-orange-station',
isOpen: true,
- isDayOpen: false,
- isNightOpen: false,
- isLateNightOpen: false,
},
{
id: 'new-orange-lift',
level: 'ADVANCED',
name: '뉴오렌지 리프트',
Element: NewOrangeLiftPath,
- webcam: null,
isOpen: true,
- isDayOpen: false,
- isNightOpen: false,
- isLateNightOpen: false,
},
{
id: 'blue-lift',
level: 'ADVANCED',
name: '블루 리프트 5',
Element: BlueLiftPath,
- webcam: {
- id: 'blue-station',
- name: '블루 탑승장',
- scale: 2,
- position: {
- top: 'top-[69%]',
- left: 'left-[56%]',
- },
- },
+ webcamId: 'blue-station',
isOpen: true,
- isDayOpen: false,
- isNightOpen: false,
- isLateNightOpen: false,
},
{
id: 'silver6-lift',
level: 'EXPERT',
name: '실버 리프트 6',
Element: Silver6LiftPath,
- webcam: {
- id: '5-station',
- name: '5번 슬로프',
- scale: 1,
- position: {
- top: 'top-[47%]',
- left: 'left-[37%]',
- },
- },
+ webcamId: '5-station',
isOpen: true,
- isDayOpen: false,
- isNightOpen: false,
- isLateNightOpen: false,
},
{
id: 'silver7-lift',
level: 'UPPER_INTERMEDIATE',
name: '실버 리프트 7',
Element: Silver7LiftPath,
- webcam: {
- id: 'silver-station',
- name: '실버 탑승장',
- scale: 1,
- position: {
- top: 'top-[72%]',
- left: 'left-[68%]',
- },
- },
+ webcamId: 'silver-station',
isOpen: true,
- isDayOpen: false,
- isNightOpen: false,
- isLateNightOpen: false,
+ },
+ ],
+ webcams: [
+ {
+ id: 'lemon-station',
+ name: '레몬 탑승장',
+ position: {
+ top: 'top-[84%]',
+ left: 'left-[20%]',
+ },
+ scale: 1,
+ },
+ {
+ id: 'orange-station',
+ name: '오렌지 탑승장',
+ position: {
+ top: 'top-[69%]',
+ left: 'left-[29%]',
+ },
+ scale: 1,
+ src: 'http://konjiam.live.cdn.cloudn.co.kr/konjiam/cam01.stream/playlist.m3u8',
+ },
+ {
+ id: 'blue-station',
+ name: '블루 탑승장',
+ scale: 1,
+ position: {
+ top: 'top-[69%]',
+ left: 'left-[56%]',
+ },
+ },
+ {
+ id: 'silver-station',
+ name: '실버 탑승장',
+ scale: 1,
+ position: {
+ top: 'top-[72%]',
+ left: 'left-[68%]',
+ },
+ },
+ {
+ id: '5-station',
+ name: '5번 슬로프',
+ scale: 1,
+
+ position: {
+ top: 'top-[47%]',
+ left: 'left-[37%]',
+ },
+ },
+ {
+ id: 'new-orange-station',
+ name: '뉴오렌지 탑승장',
+ scale: 1,
+ position: {
+ top: 'top-[64%]',
+ left: 'left-[38%]',
+ },
+ },
+ {
+ id: 'jisan-overview',
+ name: '지산 전경',
+ scale: 1,
+ position: {
+ top: 'top-[38%]',
+ left: 'left-[52%]',
+ },
},
],
};
diff --git a/src/entities/slop/model/model.d.ts b/src/entities/slop/model/model.d.ts
index ef2c144..2fe417a 100644
--- a/src/entities/slop/model/model.d.ts
+++ b/src/entities/slop/model/model.d.ts
@@ -9,6 +9,7 @@ export type Level =
export type ResortInfo = {
MapComponent: ComponentType;
slops: Slop[];
+ webcams: Webcam[];
};
export type Webcam = {
@@ -27,12 +28,8 @@ export type Slop = {
level: Level;
name: string;
Element: React.FC;
+ webcamId?: string;
isOpen: boolean;
- isDayOpen: boolean;
- isNightOpen: boolean;
- isLateNightOpen: boolean;
-
- webcam: Webcam | null;
};
export type Position = {
diff --git a/src/features/slop/ui/slop-camera.tsx b/src/features/slop/ui/slop-camera.tsx
index 550bb6b..c7fb6aa 100644
--- a/src/features/slop/ui/slop-camera.tsx
+++ b/src/features/slop/ui/slop-camera.tsx
@@ -27,13 +27,12 @@ const SlopCamera = ({
const cameraRef = useRef(null);
useEffect(() => {
- console.log(updateCameraPosition);
cameraRef.current &&
updateCameraPosition(id, {
x: cameraRef.current.getBoundingClientRect().x,
y: cameraRef.current.getBoundingClientRect().y,
});
- }, [id, updateCameraPosition]);
+ }, [id, updateCameraPosition, cameraRef]);
const toggleVideo = () => {
setIsVideoOpen((pre) => !pre);
diff --git a/src/pages/webcam/ui/webcam-mobile-map-page.tsx b/src/pages/webcam/ui/webcam-mobile-map-page.tsx
index 2ff1b6d..6ae8fa9 100644
--- a/src/pages/webcam/ui/webcam-mobile-map-page.tsx
+++ b/src/pages/webcam/ui/webcam-mobile-map-page.tsx
@@ -4,13 +4,10 @@ import React, { useCallback, useState } from 'react';
import { WebcamMap, WebcamSlopList } from '@/widgets/webcam/ui';
import useMapPinch from '@/features/slop/hooks/useMapPinch';
import calculateWebcamPosition from '@/features/slop/lib/calculateWebcamPosition';
-import { JISAN } from '@/entities/slop/model';
-import type { Position } from '@/entities/slop/model/model';
+import type { Position, ResortInfo } from '@/entities/slop/model/model';
import { cn } from '@/shared/lib';
-const WebCamMobileMapPage = () => {
- const DUMMY2 = JISAN;
-
+const WebCamMobileMapPage = ({ data }: { data: ResortInfo }) => {
const [cameraPositions, setCameraPositions] = useState<{
[key: string]: Position;
}>({});
@@ -39,12 +36,17 @@ const WebCamMobileMapPage = () => {
ref={ref}
style={style}
containerRef={containerRef}
- slops={DUMMY2.slops}
- MapComponent={DUMMY2.MapComponent}
+ slops={data.slops}
+ webcams={data.webcams}
+ MapComponent={data.MapComponent}
onCameraClick={handleFocusSlopCamClick}
updateCameraPosition={updateCameraPosition}
/>
-
+
);
};
diff --git a/src/widgets/webcam/ui/webcam-map.tsx b/src/widgets/webcam/ui/webcam-map.tsx
index 121ed03..8775aad 100644
--- a/src/widgets/webcam/ui/webcam-map.tsx
+++ b/src/widgets/webcam/ui/webcam-map.tsx
@@ -18,30 +18,29 @@ interface WebcamMapProps extends ResortInfo {
}
const WebcamMap = forwardRef(
- ({ slops, style, MapComponent, onCameraClick, containerRef, updateCameraPosition }, ref) => {
+ (
+ { slops, webcams, style, MapComponent, onCameraClick, containerRef, updateCameraPosition },
+ ref
+ ) => {
const { selectedSlop } = useSlopStore();
return (
- {slops
- .filter(
- (
- slop
- ): slop is WebcamMapProps['slops'][number] & {
- webcam: NonNullable;
- } => slop.webcam !== null
- )
- .map(({ id, webcam }) => (
+ {webcams.map((webcam) => {
+ const slop = slops.find((slop) => slop.webcamId === webcam.id);
+
+ return (
- ))}
+ );
+ })}
);
diff --git a/src/widgets/webcam/ui/webcam-slop-list.tsx b/src/widgets/webcam/ui/webcam-slop-list.tsx
index 4641eee..c5e4379 100644
--- a/src/widgets/webcam/ui/webcam-slop-list.tsx
+++ b/src/widgets/webcam/ui/webcam-slop-list.tsx
@@ -1,6 +1,6 @@
import React from 'react';
import useSlopStore from '@/features/slop/hooks/useSlopStore';
-import type { Slop } from '@/entities/slop/model/model';
+import type { Slop, Webcam } from '@/entities/slop/model/model';
import LevelChip from '@/entities/slop/ui/level-chip';
import { cn } from '@/shared/lib';
import CameraButton from '@/shared/ui/cam-button';
@@ -8,10 +8,11 @@ import CameraButton from '@/shared/ui/cam-button';
interface WebcamSlopListProps {
className?: string;
list: Slop[];
+ webcams: Webcam[];
onItemClick: ({ scale, id }: { scale: number; id: string }) => void;
}
-const WebcamSlopList = ({ className, list, onItemClick }: WebcamSlopListProps) => {
+const WebcamSlopList = ({ className, list, webcams, onItemClick }: WebcamSlopListProps) => {
const { selectedSlop, setSelectedSlop } = useSlopStore();
return (
@@ -31,17 +32,19 @@ const WebcamSlopList = ({ className, list, onItemClick }: WebcamSlopListProps) =
} else {
setSelectedSlop(item.id);
}
- if (item.webcam) {
+ if (item.webcamId) {
+ const webcam = webcams.find((webcam) => webcam.id === item.webcamId);
+ if (!webcam) return;
onItemClick({
- scale: item.webcam.scale,
- id: item.webcam.id,
+ scale: webcam.scale,
+ id: webcam.id,
});
}
}}
>
{item.name}
- {item.webcam &&
}
+ {item.webcamId &&
}