@uniai-fe/uds-templates 0.4.28 → 0.4.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/styles.css +3 -0
- package/package.json +6 -6
- package/src/auth/login/types/api.ts +15 -0
- package/src/cctv/components/video/Container.tsx +8 -1
- package/src/cctv/components/video/Template.tsx +1 -1
- package/src/cctv/hooks/useRtcStream.ts +15 -1
- package/src/cctv/styles/video.scss +7 -0
- package/src/cctv/utils/video-state.ts +2 -1
package/dist/styles.css
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniai-fe/uds-templates",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.30",
|
|
4
4
|
"description": "UNIAI Design System; UI Templates Package",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@svgr/webpack": "^8.1.0",
|
|
73
|
-
"@tanstack/react-query": "^5.
|
|
73
|
+
"@tanstack/react-query": "^5.97.0",
|
|
74
74
|
"@types/node": "^24.10.2",
|
|
75
75
|
"@types/react": "^19.2.14",
|
|
76
76
|
"@types/react-dom": "^19.2.3",
|
|
@@ -86,11 +86,11 @@
|
|
|
86
86
|
"@uniai-fe/util-next": "workspace:*",
|
|
87
87
|
"@uniai-fe/util-rtc": "workspace:*",
|
|
88
88
|
"eslint": "^9.39.2",
|
|
89
|
-
"jotai": "^2.19.
|
|
89
|
+
"jotai": "^2.19.1",
|
|
90
90
|
"next": "^15.5.11",
|
|
91
|
-
"prettier": "^3.8.
|
|
92
|
-
"react-hook-form": "^7.72.
|
|
93
|
-
"sass": "^1.
|
|
91
|
+
"prettier": "^3.8.2",
|
|
92
|
+
"react-hook-form": "^7.72.1",
|
|
93
|
+
"sass": "^1.99.0",
|
|
94
94
|
"typescript": "~5.9.3"
|
|
95
95
|
}
|
|
96
96
|
}
|
|
@@ -24,6 +24,9 @@ export interface API_Req_Login {
|
|
|
24
24
|
* @property {string} name 농장명
|
|
25
25
|
* @property {string} farm_code 농장 식별번호
|
|
26
26
|
* @property {string} user_access_role 계정 권한/직책 코드 (OWNER: 농장주, EMPLOYEE: 농장직원, REGIONAL_MANAGER: 지역소장)
|
|
27
|
+
* @property {string} address 농장주소
|
|
28
|
+
* @property {number} latitude 농장좌표 위도
|
|
29
|
+
* @property {number} longitude 농장좌표 경도
|
|
27
30
|
*/
|
|
28
31
|
export interface API_Res_LoginUserFarm {
|
|
29
32
|
/**
|
|
@@ -49,6 +52,18 @@ export interface API_Res_LoginUserFarm {
|
|
|
49
52
|
* - REGIONAL_MANAGER: 지역소장
|
|
50
53
|
*/
|
|
51
54
|
user_access_role: string;
|
|
55
|
+
/**
|
|
56
|
+
* 농장 주소
|
|
57
|
+
*/
|
|
58
|
+
address: string;
|
|
59
|
+
/**
|
|
60
|
+
* 농장 좌표; 위도
|
|
61
|
+
*/
|
|
62
|
+
latitude: number;
|
|
63
|
+
/**
|
|
64
|
+
* 농장 좌표; 경도
|
|
65
|
+
*/
|
|
66
|
+
longitude: number;
|
|
52
67
|
}
|
|
53
68
|
|
|
54
69
|
/**
|
|
@@ -3,11 +3,18 @@ import clsx from "clsx";
|
|
|
3
3
|
export default function CCTVVideoContainer({
|
|
4
4
|
className,
|
|
5
5
|
children,
|
|
6
|
+
isError,
|
|
6
7
|
}: {
|
|
7
8
|
className?: string;
|
|
8
9
|
children: React.ReactNode;
|
|
10
|
+
isError?: boolean;
|
|
9
11
|
}) {
|
|
10
12
|
return (
|
|
11
|
-
<div
|
|
13
|
+
<div
|
|
14
|
+
className={clsx("cctv-video-container", className)}
|
|
15
|
+
data-error={isError ? "true" : undefined}
|
|
16
|
+
>
|
|
17
|
+
{children}
|
|
18
|
+
</div>
|
|
12
19
|
);
|
|
13
20
|
}
|
|
@@ -32,7 +32,7 @@ const CCTVVideoTemplate = forwardRef<HTMLVideoElement, CctvVideoTemplateProps>(
|
|
|
32
32
|
ref,
|
|
33
33
|
) => {
|
|
34
34
|
return (
|
|
35
|
-
<CCTVVideoContainer className={className}>
|
|
35
|
+
<CCTVVideoContainer className={className} isError={isError}>
|
|
36
36
|
<CCTVVideoContents ref={ref} muted />
|
|
37
37
|
<CCTVVideoOverlayContainer>
|
|
38
38
|
<CCTVVideoOverlayHeader {...headerOptions} />
|
|
@@ -84,6 +84,12 @@ export function useCctvRtcStream({
|
|
|
84
84
|
useEffect(() => {
|
|
85
85
|
const currentVideo = videoRef.current;
|
|
86
86
|
|
|
87
|
+
// 토큰/카메라 에러로 전환되면 직전 MediaStream이 화면에 남지 않도록 비운다.
|
|
88
|
+
if (tokenQuery.isError || !cam?.cam_online) {
|
|
89
|
+
if (currentVideo) currentVideo.srcObject = null;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
87
93
|
// 필수 값이 없으면 스트림을 시작하지 않는다.
|
|
88
94
|
if (!tokenQuery.data?.token || !endpoint || !currentVideo) return;
|
|
89
95
|
|
|
@@ -110,6 +116,8 @@ export function useCctvRtcStream({
|
|
|
110
116
|
handle = streamHandle;
|
|
111
117
|
})
|
|
112
118
|
.catch(error => {
|
|
119
|
+
// 스트림 실패 시에도 이전 프레임이 에러 오버레이 뒤에 남지 않도록 정리한다.
|
|
120
|
+
currentVideo.srcObject = null;
|
|
113
121
|
// Error 객체 여부에 따라 메시지를 정규화한다.
|
|
114
122
|
setStreamError(
|
|
115
123
|
error instanceof Error
|
|
@@ -129,7 +137,13 @@ export function useCctvRtcStream({
|
|
|
129
137
|
handle = null;
|
|
130
138
|
currentVideo.srcObject = null;
|
|
131
139
|
};
|
|
132
|
-
}, [
|
|
140
|
+
}, [
|
|
141
|
+
endpoint,
|
|
142
|
+
tokenQuery.data?.token,
|
|
143
|
+
tokenQuery.isError,
|
|
144
|
+
cam?.cam_id,
|
|
145
|
+
cam?.cam_online,
|
|
146
|
+
]);
|
|
133
147
|
|
|
134
148
|
const liveState = useMemo(
|
|
135
149
|
() =>
|
|
@@ -40,9 +40,10 @@ export function getOverlayMessage({
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
if (!cam.cam_online) return CCTV_MESSAGE.offline;
|
|
43
|
-
|
|
43
|
+
// 에러 상태가 준비 상태와 겹칠 때는 에러 문구가 최종 표시 계약을 우선한다.
|
|
44
44
|
if (isTokenError) return CCTV_MESSAGE.tokenError;
|
|
45
45
|
if (streamError) return streamError;
|
|
46
|
+
if (isTokenLoading || isStreaming) return CCTV_MESSAGE.preparing;
|
|
46
47
|
return null;
|
|
47
48
|
}
|
|
48
49
|
|