From 8c7faf13baf0f09d38240ee17f5f07893664155f Mon Sep 17 00:00:00 2001 From: zero0205 Date: Tue, 14 Jan 2025 16:35:05 +0900 Subject: [PATCH 01/11] =?UTF-8?q?:bug:=20[Fix]:=20=EC=BA=90=EB=A6=AD?= =?UTF-8?q?=ED=84=B0=EA=B0=80=20=EC=B4=88=EA=B8=B0=20=EB=A1=9C=EB=94=A9=20?= =?UTF-8?q?=EC=8B=9C=20=EC=9D=98=EB=8F=84=EC=99=80=20=EB=8B=A4=EB=A5=B4?= =?UTF-8?q?=EA=B2=8C=20=EB=B3=B4=EC=9D=B4=EB=8A=94=20=ED=98=84=EC=83=81=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 모든 애니메이션에 `begin=0s` 속성 추가 - 모든 path와 shape 요소에 초기값을 명확하게 설정 - transform의 초기값 설정 --- .../src/components/Icons/MoveCharacter.tsx | 74 +++++++++++++------ 1 file changed, 50 insertions(+), 24 deletions(-) diff --git a/apps/client/src/components/Icons/MoveCharacter.tsx b/apps/client/src/components/Icons/MoveCharacter.tsx index 1479135d..1f3e4e30 100644 --- a/apps/client/src/components/Icons/MoveCharacter.tsx +++ b/apps/client/src/components/Icons/MoveCharacter.tsx @@ -1,7 +1,8 @@ function MoveCharacter() { return ( - + {/* Initial transform to set starting position */} + - + {/* Shadow with initial path */} + + {/* Body */} - + - + {/* Arms with initial positions */} + - + + {/* Antennae group */} + {/* Left antenna */} - - - + + + + {/* Right antenna */} - - - + + + + {/* Face elements */} - - + {/* Legs with initial positions */} + + - + From 2e833dc66a8230a310edfc655c458f3bf45cd3f6 Mon Sep 17 00:00:00 2001 From: zero0205 Date: Tue, 14 Jan 2025 16:53:53 +0900 Subject: [PATCH 02/11] =?UTF-8?q?:bug:=20[Fix]:=20=EB=B2=84=ED=8A=BC=20?= =?UTF-8?q?=EC=95=88=EC=97=90=20=EB=B2=84=ED=8A=BC=20=EB=84=A3=EC=96=B4?= =?UTF-8?q?=EC=84=9C=20=EB=B0=9C=EC=83=9D=ED=95=98=EB=8A=94=20=EA=B2=BD?= =?UTF-8?q?=EA=B3=A0=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client/src/pages/Home/Bookmark.tsx | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/client/src/pages/Home/Bookmark.tsx b/apps/client/src/pages/Home/Bookmark.tsx index 3e86c7f2..89b8e242 100644 --- a/apps/client/src/pages/Home/Bookmark.tsx +++ b/apps/client/src/pages/Home/Bookmark.tsx @@ -79,20 +79,25 @@ function Bookmark() {
{bookmarkList && bookmarkList.map(data => ( - - +
))} {bookmarkList.length < 5 && ( From 9b96bb7d50160ddc979adebbc650d2ad478bf408 Mon Sep 17 00:00:00 2001 From: zero0205 Date: Tue, 14 Jan 2025 17:25:37 +0900 Subject: [PATCH 03/11] =?UTF-8?q?:recycle:=20[Refactor]:=20fSD=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EC=A0=81=EC=9A=A9=20-=201.=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=EB=A5=BC=20pages=20=EB=8B=A8=EC=9C=84=EB=A1=9C=20=EB=B6=84?= =?UTF-8?q?=ED=95=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client/src/Router.tsx | 20 +- apps/client/src/pages/Auth/AuthPage.tsx | 43 ++++ apps/client/src/pages/Auth/index.tsx | 46 +--- .../src/pages/Broadcast/BroadcastPage.tsx | 222 +++++++++++++++++ apps/client/src/pages/Broadcast/index.tsx | 225 +----------------- apps/client/src/pages/Home/HomePage.tsx | 11 + apps/client/src/pages/Home/index.tsx | 12 +- apps/client/src/pages/Live/LivePage.tsx | 83 +++++++ apps/client/src/pages/Live/index.tsx | 84 +------ apps/client/src/pages/Profile/ProfilePage.tsx | 92 +++++++ apps/client/src/pages/Profile/index.tsx | 93 +------- 11 files changed, 466 insertions(+), 465 deletions(-) create mode 100644 apps/client/src/pages/Auth/AuthPage.tsx create mode 100644 apps/client/src/pages/Broadcast/BroadcastPage.tsx create mode 100644 apps/client/src/pages/Home/HomePage.tsx create mode 100644 apps/client/src/pages/Live/LivePage.tsx create mode 100644 apps/client/src/pages/Profile/ProfilePage.tsx diff --git a/apps/client/src/Router.tsx b/apps/client/src/Router.tsx index 56ce88f5..ea92d95b 100644 --- a/apps/client/src/Router.tsx +++ b/apps/client/src/Router.tsx @@ -1,9 +1,9 @@ import { createBrowserRouter } from 'react-router-dom'; -import Home from '@pages/Home'; -import Profile from '@pages/Profile'; -import Live from '@pages/Live'; -import Broadcast from '@pages/Broadcast'; -import Auth from '@pages/Auth'; +import { HomePage } from '@pages/Home'; +import { ProfilePage } from '@pages/Profile'; +import { LivePage } from '@pages/Live'; +import { BroadcastPage } from '@pages/Broadcast'; +import { AuthPage } from '@pages/Auth'; import Record from '@pages/Record'; import App from './App'; import ProtectedRoute from './ProtectedRoute'; @@ -27,15 +27,15 @@ const router = createBrowserRouter( children: [ { path: '', - element: , + element: , }, { path: 'live/:liveId', - element: , + element: , }, { path: 'auth', - element: , + element: , }, { path: '', @@ -43,7 +43,7 @@ const router = createBrowserRouter( children: [ { path: 'profile', - element: , + element: , }, { @@ -60,7 +60,7 @@ const router = createBrowserRouter( children: [ { path: '', - element: , + element: , }, ], }, diff --git a/apps/client/src/pages/Auth/AuthPage.tsx b/apps/client/src/pages/Auth/AuthPage.tsx new file mode 100644 index 00000000..8c54f2f8 --- /dev/null +++ b/apps/client/src/pages/Auth/AuthPage.tsx @@ -0,0 +1,43 @@ +import ErrorCharacter from '@components/ErrorCharacter'; +import { useAuth } from '@hooks/useAuth'; +import { useEffect, useState } from 'react'; +import { useNavigate, useSearchParams } from 'react-router-dom'; + +export function AuthPage() { + const [searchParams] = useSearchParams(); + const { setLogIn } = useAuth(); + const navigate = useNavigate(); + const [error, setError] = useState(null); + + useEffect(() => { + try { + const accessToken = searchParams.get('accessToken'); + const isNecessaryInfo = searchParams.get('isNecessaryInfo'); + if (!accessToken) { + throw new Error('액세스 토큰을 받지 못했습니다.'); + } + + setLogIn(accessToken); + if (isNecessaryInfo === 'true') navigate('/', { replace: true }); + else navigate('/profile', { replace: true }); + } catch (err) { + setError(err instanceof Error ? err : new Error('로그인 처리 중 오류')); + setTimeout(() => { + navigate('/', { replace: true }); + }, 3000); + } + }, [navigate, searchParams, setLogIn]); + + return ( +
+ {error ? ( + + ) : ( +
+

로그인 처리 중입니다.

+

잠시만 기다려주세요!!!!

+
+ )} +
+ ); +} diff --git a/apps/client/src/pages/Auth/index.tsx b/apps/client/src/pages/Auth/index.tsx index 8836b8c1..8a909a2b 100644 --- a/apps/client/src/pages/Auth/index.tsx +++ b/apps/client/src/pages/Auth/index.tsx @@ -1,45 +1 @@ -import ErrorCharacter from '@components/ErrorCharacter'; -import { useAuth } from '@hooks/useAuth'; -import { useEffect, useState } from 'react'; -import { useNavigate, useSearchParams } from 'react-router-dom'; - -function Auth() { - const [searchParams] = useSearchParams(); - const { setLogIn } = useAuth(); - const navigate = useNavigate(); - const [error, setError] = useState(null); - - useEffect(() => { - try { - const accessToken = searchParams.get('accessToken'); - const isNecessaryInfo = searchParams.get('isNecessaryInfo'); - if (!accessToken) { - throw new Error('액세스 토큰을 받지 못했습니다.'); - } - - setLogIn(accessToken); - if (isNecessaryInfo === 'true') navigate('/', { replace: true }); - else navigate('/profile', { replace: true }); - } catch (err) { - setError(err instanceof Error ? err : new Error('로그인 처리 중 오류')); - setTimeout(() => { - navigate('/', { replace: true }); - }, 3000); - } - }, [navigate, searchParams, setLogIn]); - - return ( -
- {error ? ( - - ) : ( -
-

로그인 처리 중입니다.

-

잠시만 기다려주세요!!!!

-
- )} -
- ); -} - -export default Auth; +export { AuthPage } from './AuthPage'; diff --git a/apps/client/src/pages/Broadcast/BroadcastPage.tsx b/apps/client/src/pages/Broadcast/BroadcastPage.tsx new file mode 100644 index 00000000..78f96058 --- /dev/null +++ b/apps/client/src/pages/Broadcast/BroadcastPage.tsx @@ -0,0 +1,222 @@ +import ChatContainer from '@components/ChatContainer'; +import ErrorCharacter from '@components/ErrorCharacter'; +import { useProducer } from '@hooks/useProducer'; +import { useRoom } from '@hooks/useRoom'; +import { useSocket } from '@hooks/useSocket'; +import { useTransport } from '@hooks/useTransport'; +import { Button } from '@components/ui/button'; +import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'; +import { + MicrophoneOffIcon, + MicrophoneOnIcon, + VideoOffIcon, + VideoOnIcon, + ScreenShareIcon, + ScreenShareIconOff, +} from '@/components/Icons'; +import BroadcastTitle from './BroadcastTitle'; +import useScreenShare from '@/hooks/useScreenShare'; +import BroadcastPlayer from './BroadcastPlayer'; +import { Tracks } from '@/types/mediasoupTypes'; +import RecordButton from './RecordButton'; +import axiosInstance from '@/services/axios'; +import { useMedia } from '@/hooks/useMedia'; +import { useTheme } from '@/hooks/useTheme'; + +const mediaServerUrl = import.meta.env.VITE_MEDIASERVER_URL; + +export function BroadcastPage() { + // 미디어 스트림(비디오, 오디오) + const { + mediaStream, + mediaStreamError, + isMediaStreamReady, + isAudioEnabled, + isVideoEnabled, + toggleAudio, + toggleVideo, + } = useMedia(); + + // 화면 공유 + const { screenStream, isScreenSharing, screenShareError, toggleScreenShare } = useScreenShare(); + // 송출 정보 + const tracksRef = useRef({ video: undefined, mediaAudio: undefined, screenAudio: undefined }); + const [isStreamReady, setIsStreamReady] = useState(false); + // 방송 송출 + const { socket, isConnected, socketError } = useSocket(mediaServerUrl); + const { roomId, roomError } = useRoom(socket, isConnected, isMediaStreamReady); + const { transportInfo, device, transportError } = useTransport({ socket, roomId, isProducer: true }); + const { + transport, + error: mediasoupError, + producers, + } = useProducer({ + socket, + mediaStream, + isMediaStreamReady, + transportInfo, + device, + roomId, + }); + // 방송 정보 + const [title, setTitle] = useState(''); + // 테마 + const { theme } = useTheme(); + + useLayoutEffect(() => { + if (theme === 'light') { + document.querySelector('html')?.setAttribute('data-theme', 'light'); + } else { + document.querySelector('html')?.removeAttribute('data-theme'); + } + }, [theme]); + + const stopBroadcast = useCallback( + (e?: BeforeUnloadEvent) => { + if (e) { + e.preventDefault(); + e.returnValue = ''; + } + if (socket) { + socket.emit('stopBroadcast', { roomId }); + socket.disconnect(); + mediaStream?.getTracks().forEach(track => { + track.stop(); + }); + } + transport?.close(); + }, + [socket, mediaStream, roomId, transport], + ); + + const handleCheckout = () => { + stopBroadcast(); + window.close(); + }; + + const handleBroadcastTitle = (newTitle: string) => { + setTitle(newTitle); + }; + + const playPauseAudio = () => { + if (isAudioEnabled) { + producers.get('mediaAudio')?.pause(); + if (tracksRef.current.mediaAudio) tracksRef.current.mediaAudio.enabled = false; + } else { + producers.get('mediaAudio')?.resume(); + if (tracksRef.current.mediaAudio) tracksRef.current.mediaAudio.enabled = true; + } + }; + + useEffect(() => { + tracksRef.current.mediaAudio = mediaStream?.getAudioTracks()[0]; + + axiosInstance.get('/v1/members/info').then(response => { + if (response.data.success) { + setTitle(`${response.data.data.camperId}님의 방송`); + } + }); + + window.addEventListener('beforeunload', stopBroadcast); + return () => { + window.removeEventListener('beforeunload', stopBroadcast); + }; + }, [mediaStream, stopBroadcast]); + + useEffect(() => { + const changeTrack = async () => { + const currentProducer = producers.get('video'); + if (!currentProducer) return; + + currentProducer.pause(); + + let newTrack = null; + + if (isVideoEnabled && isScreenSharing) { + newTrack = tracksRef.current.video || null; + } else if (isVideoEnabled && !isScreenSharing) { + newTrack = mediaStream?.getVideoTracks()[0] || null; + } else if (!isVideoEnabled && isScreenSharing) { + newTrack = screenStream?.getVideoTracks()[0] || null; + } + + if (isVideoEnabled && mediaStream) mediaStream.getVideoTracks()[0].enabled = true; + if (isScreenSharing && screenStream) screenStream.getVideoTracks()[0].enabled = true; + + await currentProducer.replaceTrack({ track: newTrack }); + + if (newTrack) { + currentProducer.resume(); + } + }; + + changeTrack(); + }, [isVideoEnabled, isScreenSharing, mediaStream, screenStream, producers]); + + if (socketError || roomError || transportError || screenShareError) { + mediaStream?.getTracks().forEach((track: MediaStreamTrack) => track.stop()); + return ( +
+ +
+ ); + } + + return ( +
+ {mediaStreamError || mediasoupError ? ( + <> +

Error

+ {mediaStreamError &&
{mediaStreamError.message}
} + {mediasoupError &&
{mediasoupError.message}
} + + ) : ( + <> + +
+ +
+
+ + +
+ +
+ + + +
+
+
+ + + )} +
+ ); +} diff --git a/apps/client/src/pages/Broadcast/index.tsx b/apps/client/src/pages/Broadcast/index.tsx index d6cc0c8f..d99b7143 100644 --- a/apps/client/src/pages/Broadcast/index.tsx +++ b/apps/client/src/pages/Broadcast/index.tsx @@ -1,224 +1 @@ -import ChatContainer from '@components/ChatContainer'; -import ErrorCharacter from '@components/ErrorCharacter'; -import { useProducer } from '@hooks/useProducer'; -import { useRoom } from '@hooks/useRoom'; -import { useSocket } from '@hooks/useSocket'; -import { useTransport } from '@hooks/useTransport'; -import { Button } from '@components/ui/button'; -import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'; -import { - MicrophoneOffIcon, - MicrophoneOnIcon, - VideoOffIcon, - VideoOnIcon, - ScreenShareIcon, - ScreenShareIconOff, -} from '@/components/Icons'; -import BroadcastTitle from './BroadcastTitle'; -import useScreenShare from '@/hooks/useScreenShare'; -import BroadcastPlayer from './BroadcastPlayer'; -import { Tracks } from '@/types/mediasoupTypes'; -import RecordButton from './RecordButton'; -import axiosInstance from '@/services/axios'; -import { useMedia } from '@/hooks/useMedia'; -import { useTheme } from '@/hooks/useTheme'; - -const mediaServerUrl = import.meta.env.VITE_MEDIASERVER_URL; - -function Broadcast() { - // 미디어 스트림(비디오, 오디오) - const { - mediaStream, - mediaStreamError, - isMediaStreamReady, - isAudioEnabled, - isVideoEnabled, - toggleAudio, - toggleVideo, - } = useMedia(); - - // 화면 공유 - const { screenStream, isScreenSharing, screenShareError, toggleScreenShare } = useScreenShare(); - // 송출 정보 - const tracksRef = useRef({ video: undefined, mediaAudio: undefined, screenAudio: undefined }); - const [isStreamReady, setIsStreamReady] = useState(false); - // 방송 송출 - const { socket, isConnected, socketError } = useSocket(mediaServerUrl); - const { roomId, roomError } = useRoom(socket, isConnected, isMediaStreamReady); - const { transportInfo, device, transportError } = useTransport({ socket, roomId, isProducer: true }); - const { - transport, - error: mediasoupError, - producers, - } = useProducer({ - socket, - mediaStream, - isMediaStreamReady, - transportInfo, - device, - roomId, - }); - // 방송 정보 - const [title, setTitle] = useState(''); - // 테마 - const { theme } = useTheme(); - - useLayoutEffect(() => { - if (theme === 'light') { - document.querySelector('html')?.setAttribute('data-theme', 'light'); - } else { - document.querySelector('html')?.removeAttribute('data-theme'); - } - }, [theme]); - - const stopBroadcast = useCallback( - (e?: BeforeUnloadEvent) => { - if (e) { - e.preventDefault(); - e.returnValue = ''; - } - if (socket) { - socket.emit('stopBroadcast', { roomId }); - socket.disconnect(); - mediaStream?.getTracks().forEach(track => { - track.stop(); - }); - } - transport?.close(); - }, - [socket, mediaStream, roomId, transport], - ); - - const handleCheckout = () => { - stopBroadcast(); - window.close(); - }; - - const handleBroadcastTitle = (newTitle: string) => { - setTitle(newTitle); - }; - - const playPauseAudio = () => { - if (isAudioEnabled) { - producers.get('mediaAudio')?.pause(); - if (tracksRef.current.mediaAudio) tracksRef.current.mediaAudio.enabled = false; - } else { - producers.get('mediaAudio')?.resume(); - if (tracksRef.current.mediaAudio) tracksRef.current.mediaAudio.enabled = true; - } - }; - - useEffect(() => { - tracksRef.current.mediaAudio = mediaStream?.getAudioTracks()[0]; - - axiosInstance.get('/v1/members/info').then(response => { - if (response.data.success) { - setTitle(`${response.data.data.camperId}님의 방송`); - } - }); - - window.addEventListener('beforeunload', stopBroadcast); - return () => { - window.removeEventListener('beforeunload', stopBroadcast); - }; - }, [mediaStream, stopBroadcast]); - - useEffect(() => { - const changeTrack = async () => { - const currentProducer = producers.get('video'); - if (!currentProducer) return; - - currentProducer.pause(); - - let newTrack = null; - - if (isVideoEnabled && isScreenSharing) { - newTrack = tracksRef.current.video || null; - } else if (isVideoEnabled && !isScreenSharing) { - newTrack = mediaStream?.getVideoTracks()[0] || null; - } else if (!isVideoEnabled && isScreenSharing) { - newTrack = screenStream?.getVideoTracks()[0] || null; - } - - if (isVideoEnabled && mediaStream) mediaStream.getVideoTracks()[0].enabled = true; - if (isScreenSharing && screenStream) screenStream.getVideoTracks()[0].enabled = true; - - await currentProducer.replaceTrack({ track: newTrack }); - - if (newTrack) { - currentProducer.resume(); - } - }; - - changeTrack(); - }, [isVideoEnabled, isScreenSharing, mediaStream, screenStream, producers]); - - if (socketError || roomError || transportError || screenShareError) { - mediaStream?.getTracks().forEach((track: MediaStreamTrack) => track.stop()); - return ( -
- -
- ); - } - - return ( -
- {mediaStreamError || mediasoupError ? ( - <> -

Error

- {mediaStreamError &&
{mediaStreamError.message}
} - {mediasoupError &&
{mediasoupError.message}
} - - ) : ( - <> - -
- -
-
- - -
- -
- - - -
-
-
- - - )} -
- ); -} - -export default Broadcast; +export { BroadcastPage } from './BroadcastPage'; diff --git a/apps/client/src/pages/Home/HomePage.tsx b/apps/client/src/pages/Home/HomePage.tsx new file mode 100644 index 00000000..3e8198f2 --- /dev/null +++ b/apps/client/src/pages/Home/HomePage.tsx @@ -0,0 +1,11 @@ +import LiveList from '@pages/Home/LiveList'; +import Banner from './Banner'; + +export function HomePage() { + return ( +
+ + +
+ ); +} diff --git a/apps/client/src/pages/Home/index.tsx b/apps/client/src/pages/Home/index.tsx index 3418f376..0799f479 100644 --- a/apps/client/src/pages/Home/index.tsx +++ b/apps/client/src/pages/Home/index.tsx @@ -1,11 +1 @@ -import LiveList from '@pages/Home/LiveList'; -import Banner from './Banner'; - -export default function Home() { - return ( -
- - -
- ); -} +export { HomePage } from './HomePage'; diff --git a/apps/client/src/pages/Live/LivePage.tsx b/apps/client/src/pages/Live/LivePage.tsx new file mode 100644 index 00000000..50f2e901 --- /dev/null +++ b/apps/client/src/pages/Live/LivePage.tsx @@ -0,0 +1,83 @@ +import ChatContainer from '@components/ChatContainer'; +import ErrorCharacter from '@components/ErrorCharacter'; +import { useConsumer } from '@hooks/useConsumer'; +import { useSocket } from '@hooks/useSocket'; +import { useTransport } from '@hooks/useTransport'; +import { useEffect } from 'react'; +import { useParams } from 'react-router-dom'; +import LivePlayer from './LivePlayer'; +import LiveCamperInfo from './LiveCamperInfo'; + +const socketUrl = import.meta.env.VITE_MEDIASERVER_URL; + +export function LivePage() { + const { liveId } = useParams<{ liveId: string }>(); + const { socket, isConnected, socketError } = useSocket(socketUrl); + const { transportInfo, device, transportError } = useTransport({ + socket, + roomId: liveId, + isProducer: false, + }); + const { + transport, + mediastream: mediaStream, + error: consumerError, + } = useConsumer({ + socket, + device, + roomId: liveId, + transportInfo, + isConnected, + }); + + useEffect(() => { + if (!socket || !liveId || !transportInfo || !transport) return undefined; + + const handleLeaveLive = () => { + if (socket && liveId && transportInfo) { + socket.emit('leaveBroadcast', { transportId: transportInfo.transportId, roomId: liveId }); + } + + socket?.disconnect(); + transport?.close(); + }; + + const preventClose = (e: BeforeUnloadEvent) => { + e.preventDefault(); + handleLeaveLive(); + e.returnValue = ''; + }; + + window.addEventListener('beforeunload', preventClose); + + return () => { + handleLeaveLive(); + window.removeEventListener('beforeunload', preventClose); + }; + }, [socket, liveId, transportInfo, transport]); + + return ( +
+ {!liveId ? ( + + ) : ( + <> +
+ +
+ +
+
+
+ +
+ + )} +
+ ); +} diff --git a/apps/client/src/pages/Live/index.tsx b/apps/client/src/pages/Live/index.tsx index 0fb14a88..31ed0446 100644 --- a/apps/client/src/pages/Live/index.tsx +++ b/apps/client/src/pages/Live/index.tsx @@ -1,83 +1 @@ -import ChatContainer from '@components/ChatContainer'; -import ErrorCharacter from '@components/ErrorCharacter'; -import { useConsumer } from '@hooks/useConsumer'; -import { useSocket } from '@hooks/useSocket'; -import { useTransport } from '@hooks/useTransport'; -import { useEffect } from 'react'; -import { useParams } from 'react-router-dom'; -import LivePlayer from './LivePlayer'; -import LiveCamperInfo from './LiveCamperInfo'; - -const socketUrl = import.meta.env.VITE_MEDIASERVER_URL; - -export default function Live() { - const { liveId } = useParams<{ liveId: string }>(); - const { socket, isConnected, socketError } = useSocket(socketUrl); - const { transportInfo, device, transportError } = useTransport({ - socket, - roomId: liveId, - isProducer: false, - }); - const { - transport, - mediastream: mediaStream, - error: consumerError, - } = useConsumer({ - socket, - device, - roomId: liveId, - transportInfo, - isConnected, - }); - - useEffect(() => { - if (!socket || !liveId || !transportInfo || !transport) return undefined; - - const handleLeaveLive = () => { - if (socket && liveId && transportInfo) { - socket.emit('leaveBroadcast', { transportId: transportInfo.transportId, roomId: liveId }); - } - - socket?.disconnect(); - transport?.close(); - }; - - const preventClose = (e: BeforeUnloadEvent) => { - e.preventDefault(); - handleLeaveLive(); - e.returnValue = ''; - }; - - window.addEventListener('beforeunload', preventClose); - - return () => { - handleLeaveLive(); - window.removeEventListener('beforeunload', preventClose); - }; - }, [socket, liveId, transportInfo, transport]); - - return ( -
- {!liveId ? ( - - ) : ( - <> -
- -
- -
-
-
- -
- - )} -
- ); -} +export { LivePage } from './LivePage'; diff --git a/apps/client/src/pages/Profile/ProfilePage.tsx b/apps/client/src/pages/Profile/ProfilePage.tsx new file mode 100644 index 00000000..66487a8f --- /dev/null +++ b/apps/client/src/pages/Profile/ProfilePage.tsx @@ -0,0 +1,92 @@ +import { useEffect, useState } from 'react'; +import Attendance from './Attendance'; +import UserInfo from './UserInfo'; +import EditUserInfo from './EditUserInfo'; +import axiosInstance from '@/services/axios'; +import { Field } from '@/types/liveTypes'; +import ErrorCharacter from '@/components/ErrorCharacter'; +import LoadingCharacter from '@/components/LoadingCharacter'; + +export type Contacts = { + email: string; + github: string; + blog: string; + linkedIn: string; +}; + +export type UserData = { + id: number; + camperId: string; + name: string; + field: Field; + contacts: Contacts; + profileImage: string; +}; + +export function ProfilePage() { + const [userData, setUserData] = useState(null); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); + const [isEditing, setIsEditing] = useState(false); + const [showLoading, setShowLoading] = useState(true); + + useEffect(() => { + axiosInstance + .get('/v1/members/info') + .then(response => { + if (response.data.success) { + setUserData(response.data.data); + } else { + setError(new Error(response.data.message)); + } + }) + .catch(err => setError(err instanceof Error ? err : new Error(err))) + .finally(() => setIsLoading(false)); + }, [isEditing]); + + useEffect(() => { + if (!userData) return; + if (!userData.camperId || !userData.name || !userData.field) { + if (!isEditing) setIsEditing(true); + } + }, [userData, isEditing]); + + useEffect(() => { + const timeoutId = setTimeout(() => { + setShowLoading(false); + }, 250); + + return () => clearTimeout(timeoutId); + }, []); + + const toggleEditing = () => { + setIsEditing(prev => !prev); + }; + + if (showLoading && isLoading) { + return ( +
+ +
+ ); + } + + if (error || !userData) { + return ( +
+ +
+ ); + } + + if (isEditing) { + return ; + } + + return ( + <> + + + + ); +} diff --git a/apps/client/src/pages/Profile/index.tsx b/apps/client/src/pages/Profile/index.tsx index 1649a1de..93d254ee 100644 --- a/apps/client/src/pages/Profile/index.tsx +++ b/apps/client/src/pages/Profile/index.tsx @@ -1,92 +1 @@ -import { useEffect, useState } from 'react'; -import Attendance from './Attendance'; -import UserInfo from './UserInfo'; -import EditUserInfo from './EditUserInfo'; -import axiosInstance from '@/services/axios'; -import { Field } from '@/types/liveTypes'; -import ErrorCharacter from '@/components/ErrorCharacter'; -import LoadingCharacter from '@/components/LoadingCharacter'; - -export type Contacts = { - email: string; - github: string; - blog: string; - linkedIn: string; -}; - -export type UserData = { - id: number; - camperId: string; - name: string; - field: Field; - contacts: Contacts; - profileImage: string; -}; - -export default function Profile() { - const [userData, setUserData] = useState(null); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); - const [isEditing, setIsEditing] = useState(false); - const [showLoading, setShowLoading] = useState(true); - - useEffect(() => { - axiosInstance - .get('/v1/members/info') - .then(response => { - if (response.data.success) { - setUserData(response.data.data); - } else { - setError(new Error(response.data.message)); - } - }) - .catch(err => setError(err instanceof Error ? err : new Error(err))) - .finally(() => setIsLoading(false)); - }, [isEditing]); - - useEffect(() => { - if (!userData) return; - if (!userData.camperId || !userData.name || !userData.field) { - if (!isEditing) setIsEditing(true); - } - }, [userData, isEditing]); - - useEffect(() => { - const timeoutId = setTimeout(() => { - setShowLoading(false); - }, 250); - - return () => clearTimeout(timeoutId); - }, []); - - const toggleEditing = () => { - setIsEditing(prev => !prev); - }; - - if (showLoading && isLoading) { - return ( -
- -
- ); - } - - if (error || !userData) { - return ( -
- -
- ); - } - - if (isEditing) { - return ; - } - - return ( - <> - - - - ); -} +export { ProfilePage } from './ProfilePage'; From 9924b10af75ff3ec2422ced15e941821fa969f74 Mon Sep 17 00:00:00 2001 From: zero0205 Date: Tue, 14 Jan 2025 17:25:37 +0900 Subject: [PATCH 04/11] =?UTF-8?q?:recycle:=20[Refactor]:=20FSD=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EC=A0=81=EC=9A=A9=20-=201.=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=EB=A5=BC=20pages=20=EB=8B=A8=EC=9C=84=EB=A1=9C=20=EB=B6=84?= =?UTF-8?q?=ED=95=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client/src/Router.tsx | 20 +- apps/client/src/pages/Auth/AuthPage.tsx | 43 ++++ apps/client/src/pages/Auth/index.tsx | 46 +--- .../src/pages/Broadcast/BroadcastPage.tsx | 222 +++++++++++++++++ apps/client/src/pages/Broadcast/index.tsx | 225 +----------------- apps/client/src/pages/Home/HomePage.tsx | 11 + apps/client/src/pages/Home/index.tsx | 12 +- apps/client/src/pages/Live/LivePage.tsx | 83 +++++++ apps/client/src/pages/Live/index.tsx | 84 +------ apps/client/src/pages/Profile/ProfilePage.tsx | 92 +++++++ apps/client/src/pages/Profile/index.tsx | 93 +------- 11 files changed, 466 insertions(+), 465 deletions(-) create mode 100644 apps/client/src/pages/Auth/AuthPage.tsx create mode 100644 apps/client/src/pages/Broadcast/BroadcastPage.tsx create mode 100644 apps/client/src/pages/Home/HomePage.tsx create mode 100644 apps/client/src/pages/Live/LivePage.tsx create mode 100644 apps/client/src/pages/Profile/ProfilePage.tsx diff --git a/apps/client/src/Router.tsx b/apps/client/src/Router.tsx index 56ce88f5..ea92d95b 100644 --- a/apps/client/src/Router.tsx +++ b/apps/client/src/Router.tsx @@ -1,9 +1,9 @@ import { createBrowserRouter } from 'react-router-dom'; -import Home from '@pages/Home'; -import Profile from '@pages/Profile'; -import Live from '@pages/Live'; -import Broadcast from '@pages/Broadcast'; -import Auth from '@pages/Auth'; +import { HomePage } from '@pages/Home'; +import { ProfilePage } from '@pages/Profile'; +import { LivePage } from '@pages/Live'; +import { BroadcastPage } from '@pages/Broadcast'; +import { AuthPage } from '@pages/Auth'; import Record from '@pages/Record'; import App from './App'; import ProtectedRoute from './ProtectedRoute'; @@ -27,15 +27,15 @@ const router = createBrowserRouter( children: [ { path: '', - element: , + element: , }, { path: 'live/:liveId', - element: , + element: , }, { path: 'auth', - element: , + element: , }, { path: '', @@ -43,7 +43,7 @@ const router = createBrowserRouter( children: [ { path: 'profile', - element: , + element: , }, { @@ -60,7 +60,7 @@ const router = createBrowserRouter( children: [ { path: '', - element: , + element: , }, ], }, diff --git a/apps/client/src/pages/Auth/AuthPage.tsx b/apps/client/src/pages/Auth/AuthPage.tsx new file mode 100644 index 00000000..8c54f2f8 --- /dev/null +++ b/apps/client/src/pages/Auth/AuthPage.tsx @@ -0,0 +1,43 @@ +import ErrorCharacter from '@components/ErrorCharacter'; +import { useAuth } from '@hooks/useAuth'; +import { useEffect, useState } from 'react'; +import { useNavigate, useSearchParams } from 'react-router-dom'; + +export function AuthPage() { + const [searchParams] = useSearchParams(); + const { setLogIn } = useAuth(); + const navigate = useNavigate(); + const [error, setError] = useState(null); + + useEffect(() => { + try { + const accessToken = searchParams.get('accessToken'); + const isNecessaryInfo = searchParams.get('isNecessaryInfo'); + if (!accessToken) { + throw new Error('액세스 토큰을 받지 못했습니다.'); + } + + setLogIn(accessToken); + if (isNecessaryInfo === 'true') navigate('/', { replace: true }); + else navigate('/profile', { replace: true }); + } catch (err) { + setError(err instanceof Error ? err : new Error('로그인 처리 중 오류')); + setTimeout(() => { + navigate('/', { replace: true }); + }, 3000); + } + }, [navigate, searchParams, setLogIn]); + + return ( +
+ {error ? ( + + ) : ( +
+

로그인 처리 중입니다.

+

잠시만 기다려주세요!!!!

+
+ )} +
+ ); +} diff --git a/apps/client/src/pages/Auth/index.tsx b/apps/client/src/pages/Auth/index.tsx index 8836b8c1..8a909a2b 100644 --- a/apps/client/src/pages/Auth/index.tsx +++ b/apps/client/src/pages/Auth/index.tsx @@ -1,45 +1 @@ -import ErrorCharacter from '@components/ErrorCharacter'; -import { useAuth } from '@hooks/useAuth'; -import { useEffect, useState } from 'react'; -import { useNavigate, useSearchParams } from 'react-router-dom'; - -function Auth() { - const [searchParams] = useSearchParams(); - const { setLogIn } = useAuth(); - const navigate = useNavigate(); - const [error, setError] = useState(null); - - useEffect(() => { - try { - const accessToken = searchParams.get('accessToken'); - const isNecessaryInfo = searchParams.get('isNecessaryInfo'); - if (!accessToken) { - throw new Error('액세스 토큰을 받지 못했습니다.'); - } - - setLogIn(accessToken); - if (isNecessaryInfo === 'true') navigate('/', { replace: true }); - else navigate('/profile', { replace: true }); - } catch (err) { - setError(err instanceof Error ? err : new Error('로그인 처리 중 오류')); - setTimeout(() => { - navigate('/', { replace: true }); - }, 3000); - } - }, [navigate, searchParams, setLogIn]); - - return ( -
- {error ? ( - - ) : ( -
-

로그인 처리 중입니다.

-

잠시만 기다려주세요!!!!

-
- )} -
- ); -} - -export default Auth; +export { AuthPage } from './AuthPage'; diff --git a/apps/client/src/pages/Broadcast/BroadcastPage.tsx b/apps/client/src/pages/Broadcast/BroadcastPage.tsx new file mode 100644 index 00000000..78f96058 --- /dev/null +++ b/apps/client/src/pages/Broadcast/BroadcastPage.tsx @@ -0,0 +1,222 @@ +import ChatContainer from '@components/ChatContainer'; +import ErrorCharacter from '@components/ErrorCharacter'; +import { useProducer } from '@hooks/useProducer'; +import { useRoom } from '@hooks/useRoom'; +import { useSocket } from '@hooks/useSocket'; +import { useTransport } from '@hooks/useTransport'; +import { Button } from '@components/ui/button'; +import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'; +import { + MicrophoneOffIcon, + MicrophoneOnIcon, + VideoOffIcon, + VideoOnIcon, + ScreenShareIcon, + ScreenShareIconOff, +} from '@/components/Icons'; +import BroadcastTitle from './BroadcastTitle'; +import useScreenShare from '@/hooks/useScreenShare'; +import BroadcastPlayer from './BroadcastPlayer'; +import { Tracks } from '@/types/mediasoupTypes'; +import RecordButton from './RecordButton'; +import axiosInstance from '@/services/axios'; +import { useMedia } from '@/hooks/useMedia'; +import { useTheme } from '@/hooks/useTheme'; + +const mediaServerUrl = import.meta.env.VITE_MEDIASERVER_URL; + +export function BroadcastPage() { + // 미디어 스트림(비디오, 오디오) + const { + mediaStream, + mediaStreamError, + isMediaStreamReady, + isAudioEnabled, + isVideoEnabled, + toggleAudio, + toggleVideo, + } = useMedia(); + + // 화면 공유 + const { screenStream, isScreenSharing, screenShareError, toggleScreenShare } = useScreenShare(); + // 송출 정보 + const tracksRef = useRef({ video: undefined, mediaAudio: undefined, screenAudio: undefined }); + const [isStreamReady, setIsStreamReady] = useState(false); + // 방송 송출 + const { socket, isConnected, socketError } = useSocket(mediaServerUrl); + const { roomId, roomError } = useRoom(socket, isConnected, isMediaStreamReady); + const { transportInfo, device, transportError } = useTransport({ socket, roomId, isProducer: true }); + const { + transport, + error: mediasoupError, + producers, + } = useProducer({ + socket, + mediaStream, + isMediaStreamReady, + transportInfo, + device, + roomId, + }); + // 방송 정보 + const [title, setTitle] = useState(''); + // 테마 + const { theme } = useTheme(); + + useLayoutEffect(() => { + if (theme === 'light') { + document.querySelector('html')?.setAttribute('data-theme', 'light'); + } else { + document.querySelector('html')?.removeAttribute('data-theme'); + } + }, [theme]); + + const stopBroadcast = useCallback( + (e?: BeforeUnloadEvent) => { + if (e) { + e.preventDefault(); + e.returnValue = ''; + } + if (socket) { + socket.emit('stopBroadcast', { roomId }); + socket.disconnect(); + mediaStream?.getTracks().forEach(track => { + track.stop(); + }); + } + transport?.close(); + }, + [socket, mediaStream, roomId, transport], + ); + + const handleCheckout = () => { + stopBroadcast(); + window.close(); + }; + + const handleBroadcastTitle = (newTitle: string) => { + setTitle(newTitle); + }; + + const playPauseAudio = () => { + if (isAudioEnabled) { + producers.get('mediaAudio')?.pause(); + if (tracksRef.current.mediaAudio) tracksRef.current.mediaAudio.enabled = false; + } else { + producers.get('mediaAudio')?.resume(); + if (tracksRef.current.mediaAudio) tracksRef.current.mediaAudio.enabled = true; + } + }; + + useEffect(() => { + tracksRef.current.mediaAudio = mediaStream?.getAudioTracks()[0]; + + axiosInstance.get('/v1/members/info').then(response => { + if (response.data.success) { + setTitle(`${response.data.data.camperId}님의 방송`); + } + }); + + window.addEventListener('beforeunload', stopBroadcast); + return () => { + window.removeEventListener('beforeunload', stopBroadcast); + }; + }, [mediaStream, stopBroadcast]); + + useEffect(() => { + const changeTrack = async () => { + const currentProducer = producers.get('video'); + if (!currentProducer) return; + + currentProducer.pause(); + + let newTrack = null; + + if (isVideoEnabled && isScreenSharing) { + newTrack = tracksRef.current.video || null; + } else if (isVideoEnabled && !isScreenSharing) { + newTrack = mediaStream?.getVideoTracks()[0] || null; + } else if (!isVideoEnabled && isScreenSharing) { + newTrack = screenStream?.getVideoTracks()[0] || null; + } + + if (isVideoEnabled && mediaStream) mediaStream.getVideoTracks()[0].enabled = true; + if (isScreenSharing && screenStream) screenStream.getVideoTracks()[0].enabled = true; + + await currentProducer.replaceTrack({ track: newTrack }); + + if (newTrack) { + currentProducer.resume(); + } + }; + + changeTrack(); + }, [isVideoEnabled, isScreenSharing, mediaStream, screenStream, producers]); + + if (socketError || roomError || transportError || screenShareError) { + mediaStream?.getTracks().forEach((track: MediaStreamTrack) => track.stop()); + return ( +
+ +
+ ); + } + + return ( +
+ {mediaStreamError || mediasoupError ? ( + <> +

Error

+ {mediaStreamError &&
{mediaStreamError.message}
} + {mediasoupError &&
{mediasoupError.message}
} + + ) : ( + <> + +
+ +
+
+ + +
+ +
+ + + +
+
+
+ + + )} +
+ ); +} diff --git a/apps/client/src/pages/Broadcast/index.tsx b/apps/client/src/pages/Broadcast/index.tsx index d6cc0c8f..d99b7143 100644 --- a/apps/client/src/pages/Broadcast/index.tsx +++ b/apps/client/src/pages/Broadcast/index.tsx @@ -1,224 +1 @@ -import ChatContainer from '@components/ChatContainer'; -import ErrorCharacter from '@components/ErrorCharacter'; -import { useProducer } from '@hooks/useProducer'; -import { useRoom } from '@hooks/useRoom'; -import { useSocket } from '@hooks/useSocket'; -import { useTransport } from '@hooks/useTransport'; -import { Button } from '@components/ui/button'; -import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'; -import { - MicrophoneOffIcon, - MicrophoneOnIcon, - VideoOffIcon, - VideoOnIcon, - ScreenShareIcon, - ScreenShareIconOff, -} from '@/components/Icons'; -import BroadcastTitle from './BroadcastTitle'; -import useScreenShare from '@/hooks/useScreenShare'; -import BroadcastPlayer from './BroadcastPlayer'; -import { Tracks } from '@/types/mediasoupTypes'; -import RecordButton from './RecordButton'; -import axiosInstance from '@/services/axios'; -import { useMedia } from '@/hooks/useMedia'; -import { useTheme } from '@/hooks/useTheme'; - -const mediaServerUrl = import.meta.env.VITE_MEDIASERVER_URL; - -function Broadcast() { - // 미디어 스트림(비디오, 오디오) - const { - mediaStream, - mediaStreamError, - isMediaStreamReady, - isAudioEnabled, - isVideoEnabled, - toggleAudio, - toggleVideo, - } = useMedia(); - - // 화면 공유 - const { screenStream, isScreenSharing, screenShareError, toggleScreenShare } = useScreenShare(); - // 송출 정보 - const tracksRef = useRef({ video: undefined, mediaAudio: undefined, screenAudio: undefined }); - const [isStreamReady, setIsStreamReady] = useState(false); - // 방송 송출 - const { socket, isConnected, socketError } = useSocket(mediaServerUrl); - const { roomId, roomError } = useRoom(socket, isConnected, isMediaStreamReady); - const { transportInfo, device, transportError } = useTransport({ socket, roomId, isProducer: true }); - const { - transport, - error: mediasoupError, - producers, - } = useProducer({ - socket, - mediaStream, - isMediaStreamReady, - transportInfo, - device, - roomId, - }); - // 방송 정보 - const [title, setTitle] = useState(''); - // 테마 - const { theme } = useTheme(); - - useLayoutEffect(() => { - if (theme === 'light') { - document.querySelector('html')?.setAttribute('data-theme', 'light'); - } else { - document.querySelector('html')?.removeAttribute('data-theme'); - } - }, [theme]); - - const stopBroadcast = useCallback( - (e?: BeforeUnloadEvent) => { - if (e) { - e.preventDefault(); - e.returnValue = ''; - } - if (socket) { - socket.emit('stopBroadcast', { roomId }); - socket.disconnect(); - mediaStream?.getTracks().forEach(track => { - track.stop(); - }); - } - transport?.close(); - }, - [socket, mediaStream, roomId, transport], - ); - - const handleCheckout = () => { - stopBroadcast(); - window.close(); - }; - - const handleBroadcastTitle = (newTitle: string) => { - setTitle(newTitle); - }; - - const playPauseAudio = () => { - if (isAudioEnabled) { - producers.get('mediaAudio')?.pause(); - if (tracksRef.current.mediaAudio) tracksRef.current.mediaAudio.enabled = false; - } else { - producers.get('mediaAudio')?.resume(); - if (tracksRef.current.mediaAudio) tracksRef.current.mediaAudio.enabled = true; - } - }; - - useEffect(() => { - tracksRef.current.mediaAudio = mediaStream?.getAudioTracks()[0]; - - axiosInstance.get('/v1/members/info').then(response => { - if (response.data.success) { - setTitle(`${response.data.data.camperId}님의 방송`); - } - }); - - window.addEventListener('beforeunload', stopBroadcast); - return () => { - window.removeEventListener('beforeunload', stopBroadcast); - }; - }, [mediaStream, stopBroadcast]); - - useEffect(() => { - const changeTrack = async () => { - const currentProducer = producers.get('video'); - if (!currentProducer) return; - - currentProducer.pause(); - - let newTrack = null; - - if (isVideoEnabled && isScreenSharing) { - newTrack = tracksRef.current.video || null; - } else if (isVideoEnabled && !isScreenSharing) { - newTrack = mediaStream?.getVideoTracks()[0] || null; - } else if (!isVideoEnabled && isScreenSharing) { - newTrack = screenStream?.getVideoTracks()[0] || null; - } - - if (isVideoEnabled && mediaStream) mediaStream.getVideoTracks()[0].enabled = true; - if (isScreenSharing && screenStream) screenStream.getVideoTracks()[0].enabled = true; - - await currentProducer.replaceTrack({ track: newTrack }); - - if (newTrack) { - currentProducer.resume(); - } - }; - - changeTrack(); - }, [isVideoEnabled, isScreenSharing, mediaStream, screenStream, producers]); - - if (socketError || roomError || transportError || screenShareError) { - mediaStream?.getTracks().forEach((track: MediaStreamTrack) => track.stop()); - return ( -
- -
- ); - } - - return ( -
- {mediaStreamError || mediasoupError ? ( - <> -

Error

- {mediaStreamError &&
{mediaStreamError.message}
} - {mediasoupError &&
{mediasoupError.message}
} - - ) : ( - <> - -
- -
-
- - -
- -
- - - -
-
-
- - - )} -
- ); -} - -export default Broadcast; +export { BroadcastPage } from './BroadcastPage'; diff --git a/apps/client/src/pages/Home/HomePage.tsx b/apps/client/src/pages/Home/HomePage.tsx new file mode 100644 index 00000000..3e8198f2 --- /dev/null +++ b/apps/client/src/pages/Home/HomePage.tsx @@ -0,0 +1,11 @@ +import LiveList from '@pages/Home/LiveList'; +import Banner from './Banner'; + +export function HomePage() { + return ( +
+ + +
+ ); +} diff --git a/apps/client/src/pages/Home/index.tsx b/apps/client/src/pages/Home/index.tsx index 3418f376..0799f479 100644 --- a/apps/client/src/pages/Home/index.tsx +++ b/apps/client/src/pages/Home/index.tsx @@ -1,11 +1 @@ -import LiveList from '@pages/Home/LiveList'; -import Banner from './Banner'; - -export default function Home() { - return ( -
- - -
- ); -} +export { HomePage } from './HomePage'; diff --git a/apps/client/src/pages/Live/LivePage.tsx b/apps/client/src/pages/Live/LivePage.tsx new file mode 100644 index 00000000..50f2e901 --- /dev/null +++ b/apps/client/src/pages/Live/LivePage.tsx @@ -0,0 +1,83 @@ +import ChatContainer from '@components/ChatContainer'; +import ErrorCharacter from '@components/ErrorCharacter'; +import { useConsumer } from '@hooks/useConsumer'; +import { useSocket } from '@hooks/useSocket'; +import { useTransport } from '@hooks/useTransport'; +import { useEffect } from 'react'; +import { useParams } from 'react-router-dom'; +import LivePlayer from './LivePlayer'; +import LiveCamperInfo from './LiveCamperInfo'; + +const socketUrl = import.meta.env.VITE_MEDIASERVER_URL; + +export function LivePage() { + const { liveId } = useParams<{ liveId: string }>(); + const { socket, isConnected, socketError } = useSocket(socketUrl); + const { transportInfo, device, transportError } = useTransport({ + socket, + roomId: liveId, + isProducer: false, + }); + const { + transport, + mediastream: mediaStream, + error: consumerError, + } = useConsumer({ + socket, + device, + roomId: liveId, + transportInfo, + isConnected, + }); + + useEffect(() => { + if (!socket || !liveId || !transportInfo || !transport) return undefined; + + const handleLeaveLive = () => { + if (socket && liveId && transportInfo) { + socket.emit('leaveBroadcast', { transportId: transportInfo.transportId, roomId: liveId }); + } + + socket?.disconnect(); + transport?.close(); + }; + + const preventClose = (e: BeforeUnloadEvent) => { + e.preventDefault(); + handleLeaveLive(); + e.returnValue = ''; + }; + + window.addEventListener('beforeunload', preventClose); + + return () => { + handleLeaveLive(); + window.removeEventListener('beforeunload', preventClose); + }; + }, [socket, liveId, transportInfo, transport]); + + return ( +
+ {!liveId ? ( + + ) : ( + <> +
+ +
+ +
+
+
+ +
+ + )} +
+ ); +} diff --git a/apps/client/src/pages/Live/index.tsx b/apps/client/src/pages/Live/index.tsx index 0fb14a88..31ed0446 100644 --- a/apps/client/src/pages/Live/index.tsx +++ b/apps/client/src/pages/Live/index.tsx @@ -1,83 +1 @@ -import ChatContainer from '@components/ChatContainer'; -import ErrorCharacter from '@components/ErrorCharacter'; -import { useConsumer } from '@hooks/useConsumer'; -import { useSocket } from '@hooks/useSocket'; -import { useTransport } from '@hooks/useTransport'; -import { useEffect } from 'react'; -import { useParams } from 'react-router-dom'; -import LivePlayer from './LivePlayer'; -import LiveCamperInfo from './LiveCamperInfo'; - -const socketUrl = import.meta.env.VITE_MEDIASERVER_URL; - -export default function Live() { - const { liveId } = useParams<{ liveId: string }>(); - const { socket, isConnected, socketError } = useSocket(socketUrl); - const { transportInfo, device, transportError } = useTransport({ - socket, - roomId: liveId, - isProducer: false, - }); - const { - transport, - mediastream: mediaStream, - error: consumerError, - } = useConsumer({ - socket, - device, - roomId: liveId, - transportInfo, - isConnected, - }); - - useEffect(() => { - if (!socket || !liveId || !transportInfo || !transport) return undefined; - - const handleLeaveLive = () => { - if (socket && liveId && transportInfo) { - socket.emit('leaveBroadcast', { transportId: transportInfo.transportId, roomId: liveId }); - } - - socket?.disconnect(); - transport?.close(); - }; - - const preventClose = (e: BeforeUnloadEvent) => { - e.preventDefault(); - handleLeaveLive(); - e.returnValue = ''; - }; - - window.addEventListener('beforeunload', preventClose); - - return () => { - handleLeaveLive(); - window.removeEventListener('beforeunload', preventClose); - }; - }, [socket, liveId, transportInfo, transport]); - - return ( -
- {!liveId ? ( - - ) : ( - <> -
- -
- -
-
-
- -
- - )} -
- ); -} +export { LivePage } from './LivePage'; diff --git a/apps/client/src/pages/Profile/ProfilePage.tsx b/apps/client/src/pages/Profile/ProfilePage.tsx new file mode 100644 index 00000000..66487a8f --- /dev/null +++ b/apps/client/src/pages/Profile/ProfilePage.tsx @@ -0,0 +1,92 @@ +import { useEffect, useState } from 'react'; +import Attendance from './Attendance'; +import UserInfo from './UserInfo'; +import EditUserInfo from './EditUserInfo'; +import axiosInstance from '@/services/axios'; +import { Field } from '@/types/liveTypes'; +import ErrorCharacter from '@/components/ErrorCharacter'; +import LoadingCharacter from '@/components/LoadingCharacter'; + +export type Contacts = { + email: string; + github: string; + blog: string; + linkedIn: string; +}; + +export type UserData = { + id: number; + camperId: string; + name: string; + field: Field; + contacts: Contacts; + profileImage: string; +}; + +export function ProfilePage() { + const [userData, setUserData] = useState(null); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); + const [isEditing, setIsEditing] = useState(false); + const [showLoading, setShowLoading] = useState(true); + + useEffect(() => { + axiosInstance + .get('/v1/members/info') + .then(response => { + if (response.data.success) { + setUserData(response.data.data); + } else { + setError(new Error(response.data.message)); + } + }) + .catch(err => setError(err instanceof Error ? err : new Error(err))) + .finally(() => setIsLoading(false)); + }, [isEditing]); + + useEffect(() => { + if (!userData) return; + if (!userData.camperId || !userData.name || !userData.field) { + if (!isEditing) setIsEditing(true); + } + }, [userData, isEditing]); + + useEffect(() => { + const timeoutId = setTimeout(() => { + setShowLoading(false); + }, 250); + + return () => clearTimeout(timeoutId); + }, []); + + const toggleEditing = () => { + setIsEditing(prev => !prev); + }; + + if (showLoading && isLoading) { + return ( +
+ +
+ ); + } + + if (error || !userData) { + return ( +
+ +
+ ); + } + + if (isEditing) { + return ; + } + + return ( + <> + + + + ); +} diff --git a/apps/client/src/pages/Profile/index.tsx b/apps/client/src/pages/Profile/index.tsx index 1649a1de..93d254ee 100644 --- a/apps/client/src/pages/Profile/index.tsx +++ b/apps/client/src/pages/Profile/index.tsx @@ -1,92 +1 @@ -import { useEffect, useState } from 'react'; -import Attendance from './Attendance'; -import UserInfo from './UserInfo'; -import EditUserInfo from './EditUserInfo'; -import axiosInstance from '@/services/axios'; -import { Field } from '@/types/liveTypes'; -import ErrorCharacter from '@/components/ErrorCharacter'; -import LoadingCharacter from '@/components/LoadingCharacter'; - -export type Contacts = { - email: string; - github: string; - blog: string; - linkedIn: string; -}; - -export type UserData = { - id: number; - camperId: string; - name: string; - field: Field; - contacts: Contacts; - profileImage: string; -}; - -export default function Profile() { - const [userData, setUserData] = useState(null); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); - const [isEditing, setIsEditing] = useState(false); - const [showLoading, setShowLoading] = useState(true); - - useEffect(() => { - axiosInstance - .get('/v1/members/info') - .then(response => { - if (response.data.success) { - setUserData(response.data.data); - } else { - setError(new Error(response.data.message)); - } - }) - .catch(err => setError(err instanceof Error ? err : new Error(err))) - .finally(() => setIsLoading(false)); - }, [isEditing]); - - useEffect(() => { - if (!userData) return; - if (!userData.camperId || !userData.name || !userData.field) { - if (!isEditing) setIsEditing(true); - } - }, [userData, isEditing]); - - useEffect(() => { - const timeoutId = setTimeout(() => { - setShowLoading(false); - }, 250); - - return () => clearTimeout(timeoutId); - }, []); - - const toggleEditing = () => { - setIsEditing(prev => !prev); - }; - - if (showLoading && isLoading) { - return ( -
- -
- ); - } - - if (error || !userData) { - return ( -
- -
- ); - } - - if (isEditing) { - return ; - } - - return ( - <> - - - - ); -} +export { ProfilePage } from './ProfilePage'; From 62eaf428d44ccf094c5d4d04e2de969af2da92ee Mon Sep 17 00:00:00 2001 From: zero0205 Date: Wed, 15 Jan 2025 00:54:10 +0900 Subject: [PATCH 05/11] =?UTF-8?q?:recycle:=20[Refactor]:=20FSD=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EC=A0=81=EC=9A=A9=20-=202.=20=EB=AA=A8=EB=93=A0=20?= =?UTF-8?q?=EA=B2=83=EC=9D=84=20=ED=8E=98=EC=9D=B4=EC=A7=80=EC=97=90?= =?UTF-8?q?=EC=84=9C=EB=B6=80=ED=84=B0=20=EB=B6=84=EB=A6=AC=ED=95=98?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client/.eslintignore | 2 +- apps/client/src/App.css | 4 --- apps/client/src/App.tsx | 24 --------------- apps/client/src/app/layouts/Layout.tsx | 21 +++++++++++++ apps/client/src/app/layouts/index.tsx | 1 + .../src/{ => app/routes}/ProtectedRoute.tsx | 2 +- apps/client/src/app/routes/index.tsx | 1 + .../src/{Router.tsx => app/routes/router.tsx} | 8 ++--- apps/client/src/components/ui/input.tsx | 20 ------------ apps/client/src/components/ui/toaster.tsx | 22 ------------- apps/client/src/main.tsx | 2 +- apps/client/src/pages/Auth/AuthPage.tsx | 24 ++++++--------- .../src/pages/Broadcast/BroadcastPage.tsx | 26 ++++++++-------- .../src/pages/Broadcast/BroadcastPlayer.tsx | 4 +-- .../src/pages/Broadcast/BroadcastTitle.tsx | 4 +-- .../src/pages/Broadcast/RecordButton.tsx | 4 +-- apps/client/src/pages/Home/Banner.tsx | 2 +- apps/client/src/pages/Home/Bookmark.tsx | 12 ++++---- apps/client/src/pages/Home/FieldFilter.tsx | 4 +-- apps/client/src/pages/Home/LiveList.tsx | 8 ++--- apps/client/src/pages/Home/Search.tsx | 4 +-- apps/client/src/pages/Live/LiveCamperInfo.tsx | 16 +++++----- apps/client/src/pages/Live/LivePage.tsx | 10 +++--- apps/client/src/pages/Live/LivePlayer.tsx | 6 ++-- apps/client/src/pages/Profile/Attendance.tsx | 8 ++--- .../client/src/pages/Profile/EditUserInfo.tsx | 12 ++++---- apps/client/src/pages/Profile/ProfilePage.tsx | 8 ++--- apps/client/src/pages/Profile/UserInfo.tsx | 10 +++--- apps/client/src/pages/Record/RecordList.tsx | 6 ++-- apps/client/src/pages/Record/RecordPlayer.tsx | 2 +- .../assets/fonts/PretendardVariable.woff2 | Bin .../components/ChatContainer/ChatEndModal.tsx | 2 +- .../components/ChatContainer/index.tsx | 12 ++++---- .../components/ErrorCharacter/index.tsx | 0 .../components/FloatingButton/index.tsx | 6 ++-- .../{ => shared}/components/Footer/index.tsx | 0 .../components/Header/LogInButton.tsx | 12 ++++---- .../{ => shared}/components/Header/index.tsx | 12 ++++---- .../components/IconButton/index.tsx | 0 .../components/Icons/BlogIcon.tsx | 0 .../components/Icons/Character.tsx | 0 .../components/Icons/CloseIcon.tsx | 0 .../components/Icons/EditIcon.tsx | 0 .../components/Icons/ExpandIcon.tsx | 0 .../components/Icons/GithubIcon.tsx | 0 .../components/Icons/GoogleIcon.tsx | 0 .../components/Icons/LinkedInIcon.tsx | 0 .../{ => shared}/components/Icons/Logo.tsx | 0 .../components/Icons/MailIcon.tsx | 0 .../components/Icons/MicrophoneOffIcon.tsx | 0 .../components/Icons/MicrophoneOnIcon.tsx | 0 .../components/Icons/MoveCharacter.tsx | 0 .../components/Icons/PauseIcon.tsx | 0 .../components/Icons/PlayIcon.tsx | 0 .../components/Icons/ScreenShareIcon.tsx | 0 .../components/Icons/ScreenShareOffIcon.tsx | 0 .../components/Icons/SearchIcon.tsx | 0 .../components/Icons/SmileIcon.tsx | 0 .../components/Icons/ThemeIcon.tsx | 0 .../components/Icons/VideoOffIcon.tsx | 0 .../components/Icons/VideoOnIcon.tsx | 0 .../components/Icons/VolumeOffIcon.tsx | 0 .../components/Icons/VolumeOnIcon.tsx | 0 .../{ => shared}/components/Icons/index.ts | 0 .../components/LoadingCharacter/index.tsx | 0 .../{ => shared}/components/Modal/index.tsx | 2 +- .../components/WelcomeCharacter/index.tsx | 0 .../src/{ => shared}/components/ui/avatar.tsx | 2 +- .../src/{ => shared}/components/ui/badge.tsx | 2 +- .../src/{ => shared}/components/ui/button.tsx | 2 +- .../src/{ => shared}/components/ui/card.tsx | 2 +- .../client/src/shared/components/ui/input.tsx | 20 ++++++++++++ .../components/ui/scroll-area.tsx | 2 +- .../src/{ => shared}/components/ui/select.tsx | 2 +- .../src/{ => shared}/components/ui/toast.tsx | 6 ++-- .../src/shared/components/ui/toaster.tsx | 29 ++++++++++++++++++ .../{ => shared}/constants/videoOptions.ts | 0 .../src/{ => shared}/contexts/AuthContext.tsx | 0 .../{ => shared}/contexts/ThemeContext.tsx | 0 apps/client/src/{ => shared}/hooks/useAPI.ts | 2 +- apps/client/src/{ => shared}/hooks/useAuth.ts | 2 +- .../src/{ => shared}/hooks/useConsumer.ts | 4 +-- .../src/{ => shared}/hooks/useIntersect.ts | 0 .../client/src/{ => shared}/hooks/useMedia.ts | 0 .../src/{ => shared}/hooks/useProducer.ts | 6 ++-- apps/client/src/{ => shared}/hooks/useRoom.ts | 0 .../src/{ => shared}/hooks/useScreenShare.ts | 0 .../src/{ => shared}/hooks/useSocket.ts | 0 .../client/src/{ => shared}/hooks/useTheme.ts | 2 +- .../client/src/{ => shared}/hooks/useToast.ts | 2 +- .../src/{ => shared}/hooks/useTransport.ts | 4 +-- .../client/src/{ => shared}/services/axios.ts | 0 .../src/{ => shared}/types/homeTypes.ts | 0 .../src/{ => shared}/types/liveTypes.ts | 0 .../src/{ => shared}/types/mediasoupTypes.ts | 0 apps/client/src/{ => shared}/utils/utils.ts | 0 apps/client/tsconfig.json | 10 +++--- 97 files changed, 210 insertions(+), 212 deletions(-) delete mode 100644 apps/client/src/App.css delete mode 100644 apps/client/src/App.tsx create mode 100644 apps/client/src/app/layouts/Layout.tsx create mode 100644 apps/client/src/app/layouts/index.tsx rename apps/client/src/{ => app/routes}/ProtectedRoute.tsx (84%) create mode 100644 apps/client/src/app/routes/index.tsx rename apps/client/src/{Router.tsx => app/routes/router.tsx} (92%) delete mode 100644 apps/client/src/components/ui/input.tsx delete mode 100644 apps/client/src/components/ui/toaster.tsx rename apps/client/src/{ => shared}/assets/fonts/PretendardVariable.woff2 (100%) rename apps/client/src/{ => shared}/components/ChatContainer/ChatEndModal.tsx (94%) rename apps/client/src/{ => shared}/components/ChatContainer/index.tsx (94%) rename apps/client/src/{ => shared}/components/ErrorCharacter/index.tsx (100%) rename apps/client/src/{ => shared}/components/FloatingButton/index.tsx (70%) rename apps/client/src/{ => shared}/components/Footer/index.tsx (100%) rename apps/client/src/{ => shared}/components/Header/LogInButton.tsx (88%) rename apps/client/src/{ => shared}/components/Header/index.tsx (89%) rename apps/client/src/{ => shared}/components/IconButton/index.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/BlogIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/Character.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/CloseIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/EditIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/ExpandIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/GithubIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/GoogleIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/LinkedInIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/Logo.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/MailIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/MicrophoneOffIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/MicrophoneOnIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/MoveCharacter.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/PauseIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/PlayIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/ScreenShareIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/ScreenShareOffIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/SearchIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/SmileIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/ThemeIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/VideoOffIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/VideoOnIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/VolumeOffIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/VolumeOnIcon.tsx (100%) rename apps/client/src/{ => shared}/components/Icons/index.ts (100%) rename apps/client/src/{ => shared}/components/LoadingCharacter/index.tsx (100%) rename apps/client/src/{ => shared}/components/Modal/index.tsx (96%) rename apps/client/src/{ => shared}/components/WelcomeCharacter/index.tsx (100%) rename apps/client/src/{ => shared}/components/ui/avatar.tsx (96%) rename apps/client/src/{ => shared}/components/ui/badge.tsx (96%) rename apps/client/src/{ => shared}/components/ui/button.tsx (97%) rename apps/client/src/{ => shared}/components/ui/card.tsx (97%) create mode 100644 apps/client/src/shared/components/ui/input.tsx rename apps/client/src/{ => shared}/components/ui/scroll-area.tsx (97%) rename apps/client/src/{ => shared}/components/ui/select.tsx (99%) rename apps/client/src/{ => shared}/components/ui/toast.tsx (95%) create mode 100644 apps/client/src/shared/components/ui/toaster.tsx rename apps/client/src/{ => shared}/constants/videoOptions.ts (100%) rename apps/client/src/{ => shared}/contexts/AuthContext.tsx (100%) rename apps/client/src/{ => shared}/contexts/ThemeContext.tsx (100%) rename apps/client/src/{ => shared}/hooks/useAPI.ts (93%) rename apps/client/src/{ => shared}/hooks/useAuth.ts (92%) rename apps/client/src/{ => shared}/hooks/useConsumer.ts (96%) rename apps/client/src/{ => shared}/hooks/useIntersect.ts (100%) rename apps/client/src/{ => shared}/hooks/useMedia.ts (100%) rename apps/client/src/{ => shared}/hooks/useProducer.ts (95%) rename apps/client/src/{ => shared}/hooks/useRoom.ts (100%) rename apps/client/src/{ => shared}/hooks/useScreenShare.ts (100%) rename apps/client/src/{ => shared}/hooks/useSocket.ts (100%) rename apps/client/src/{ => shared}/hooks/useTheme.ts (91%) rename apps/client/src/{ => shared}/hooks/useToast.ts (97%) rename apps/client/src/{ => shared}/hooks/useTransport.ts (96%) rename apps/client/src/{ => shared}/services/axios.ts (100%) rename apps/client/src/{ => shared}/types/homeTypes.ts (100%) rename apps/client/src/{ => shared}/types/liveTypes.ts (100%) rename apps/client/src/{ => shared}/types/mediasoupTypes.ts (100%) rename apps/client/src/{ => shared}/utils/utils.ts (100%) diff --git a/apps/client/.eslintignore b/apps/client/.eslintignore index cdc980d0..4213f614 100644 --- a/apps/client/.eslintignore +++ b/apps/client/.eslintignore @@ -1,5 +1,5 @@ # shadcn/ui 컴포넌트 폴더 무시 -src/components/ui/* +src/shared/components/ui/* # node_modules는 기본적으로 무시되지만, 명시적으로 추가할 수도 있습니다 node_modules/ diff --git a/apps/client/src/App.css b/apps/client/src/App.css deleted file mode 100644 index ee7ff7d6..00000000 --- a/apps/client/src/App.css +++ /dev/null @@ -1,4 +0,0 @@ -main { - padding-top: 74px; - height: 100%; -} diff --git a/apps/client/src/App.tsx b/apps/client/src/App.tsx deleted file mode 100644 index 3256a8a7..00000000 --- a/apps/client/src/App.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { Outlet } from 'react-router-dom'; -import Header from '@components/Header'; -import './App.css'; -import { AuthProvider } from '@contexts/AuthContext'; -import { Toaster } from '@components/ui/toaster'; -import FloatingButton from '@components/FloatingButton'; -import { ThemeProvider } from './contexts/ThemeContext'; - -function App() { - return ( - - -
-
- -
- - - - - ); -} - -export default App; diff --git a/apps/client/src/app/layouts/Layout.tsx b/apps/client/src/app/layouts/Layout.tsx new file mode 100644 index 00000000..f3d8615b --- /dev/null +++ b/apps/client/src/app/layouts/Layout.tsx @@ -0,0 +1,21 @@ +import { Outlet } from 'react-router-dom'; +import Header from '@/shared/components/Header'; +import { AuthProvider } from '@/shared/contexts/AuthContext'; +import { Toaster } from '@/shared/components/ui/toaster'; +import FloatingButton from '@/shared/components/FloatingButton'; +import { ThemeProvider } from '@/shared/contexts/ThemeContext'; + +export function Layout() { + return ( + + +
+
+ +
+ + + + + ); +} diff --git a/apps/client/src/app/layouts/index.tsx b/apps/client/src/app/layouts/index.tsx new file mode 100644 index 00000000..9fc685e2 --- /dev/null +++ b/apps/client/src/app/layouts/index.tsx @@ -0,0 +1 @@ +export { Layout } from './Layout'; diff --git a/apps/client/src/ProtectedRoute.tsx b/apps/client/src/app/routes/ProtectedRoute.tsx similarity index 84% rename from apps/client/src/ProtectedRoute.tsx rename to apps/client/src/app/routes/ProtectedRoute.tsx index 48d7b79f..e4e0acb9 100644 --- a/apps/client/src/ProtectedRoute.tsx +++ b/apps/client/src/app/routes/ProtectedRoute.tsx @@ -1,6 +1,6 @@ import { useContext } from 'react'; -import { AuthContext } from '@contexts/AuthContext'; import { Navigate, Outlet } from 'react-router-dom'; +import { AuthContext } from '@/shared/contexts/AuthContext'; function ProtectedRoute() { const { isLoggedIn } = useContext(AuthContext); diff --git a/apps/client/src/app/routes/index.tsx b/apps/client/src/app/routes/index.tsx new file mode 100644 index 00000000..b5259a1a --- /dev/null +++ b/apps/client/src/app/routes/index.tsx @@ -0,0 +1 @@ +export { router } from './router'; diff --git a/apps/client/src/Router.tsx b/apps/client/src/app/routes/router.tsx similarity index 92% rename from apps/client/src/Router.tsx rename to apps/client/src/app/routes/router.tsx index ea92d95b..8c2df908 100644 --- a/apps/client/src/Router.tsx +++ b/apps/client/src/app/routes/router.tsx @@ -5,7 +5,7 @@ import { LivePage } from '@pages/Live'; import { BroadcastPage } from '@pages/Broadcast'; import { AuthPage } from '@pages/Auth'; import Record from '@pages/Record'; -import App from './App'; +import { Layout } from '@/app/layouts'; import ProtectedRoute from './ProtectedRoute'; const routerOptions = { @@ -19,11 +19,11 @@ const routerOptions = { }, }; -const router = createBrowserRouter( +export const router = createBrowserRouter( [ { path: '/', - element: , + element: , children: [ { path: '', @@ -67,5 +67,3 @@ const router = createBrowserRouter( ], routerOptions, ); - -export default router; diff --git a/apps/client/src/components/ui/input.tsx b/apps/client/src/components/ui/input.tsx deleted file mode 100644 index d78d7233..00000000 --- a/apps/client/src/components/ui/input.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import * as React from 'react'; - -import { cn } from '@/utils/utils'; - -const Input = React.forwardRef>( - ({ className, type, ...props }, ref) => ( - - ), -); -Input.displayName = 'Input'; - -export { Input }; diff --git a/apps/client/src/components/ui/toaster.tsx b/apps/client/src/components/ui/toaster.tsx deleted file mode 100644 index 622b5eb1..00000000 --- a/apps/client/src/components/ui/toaster.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { useToast } from '@/hooks/useToast'; -import { Toast, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport } from '@/components/ui/toast'; - -export function Toaster() { - const { toasts } = useToast(); - - return ( - - {toasts.map(({ id, title, description, action, ...props }) => ( - -
- {title && {title}} - {description && {description}} -
- {action} - -
- ))} - -
- ); -} diff --git a/apps/client/src/main.tsx b/apps/client/src/main.tsx index 21390861..07116fa8 100644 --- a/apps/client/src/main.tsx +++ b/apps/client/src/main.tsx @@ -1,6 +1,6 @@ import { createRoot } from 'react-dom/client'; import './index.css'; import { RouterProvider } from 'react-router-dom'; -import router from './Router'; +import { router } from '@/app/routes'; createRoot(document.getElementById('root')!).render(); diff --git a/apps/client/src/pages/Auth/AuthPage.tsx b/apps/client/src/pages/Auth/AuthPage.tsx index 8c54f2f8..3c296b11 100644 --- a/apps/client/src/pages/Auth/AuthPage.tsx +++ b/apps/client/src/pages/Auth/AuthPage.tsx @@ -1,7 +1,7 @@ -import ErrorCharacter from '@components/ErrorCharacter'; -import { useAuth } from '@hooks/useAuth'; import { useEffect, useState } from 'react'; import { useNavigate, useSearchParams } from 'react-router-dom'; +import ErrorCharacter from '@/shared/components/ErrorCharacter'; +import { useAuth } from '@/shared/hooks/useAuth'; export function AuthPage() { const [searchParams] = useSearchParams(); @@ -10,22 +10,18 @@ export function AuthPage() { const [error, setError] = useState(null); useEffect(() => { - try { - const accessToken = searchParams.get('accessToken'); - const isNecessaryInfo = searchParams.get('isNecessaryInfo'); - if (!accessToken) { - throw new Error('액세스 토큰을 받지 못했습니다.'); - } - - setLogIn(accessToken); - if (isNecessaryInfo === 'true') navigate('/', { replace: true }); - else navigate('/profile', { replace: true }); - } catch (err) { - setError(err instanceof Error ? err : new Error('로그인 처리 중 오류')); + const accessToken = searchParams.get('accessToken'); + const isNecessaryInfo = searchParams.get('isNecessaryInfo'); + if (!accessToken) { + setError(new Error('액세스 토큰을 받지 못했습니다.')); setTimeout(() => { navigate('/', { replace: true }); }, 3000); + return; } + + setLogIn(accessToken); + navigate(isNecessaryInfo === 'true' ? '/' : '/profile', { replace: true }); }, [navigate, searchParams, setLogIn]); return ( diff --git a/apps/client/src/pages/Broadcast/BroadcastPage.tsx b/apps/client/src/pages/Broadcast/BroadcastPage.tsx index 78f96058..03e211c5 100644 --- a/apps/client/src/pages/Broadcast/BroadcastPage.tsx +++ b/apps/client/src/pages/Broadcast/BroadcastPage.tsx @@ -1,11 +1,11 @@ -import ChatContainer from '@components/ChatContainer'; -import ErrorCharacter from '@components/ErrorCharacter'; -import { useProducer } from '@hooks/useProducer'; -import { useRoom } from '@hooks/useRoom'; -import { useSocket } from '@hooks/useSocket'; -import { useTransport } from '@hooks/useTransport'; -import { Button } from '@components/ui/button'; import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'; +import ChatContainer from '@/shared/components/ChatContainer'; +import ErrorCharacter from '@/shared/components/ErrorCharacter'; +import { useProducer } from '@/shared/hooks/useProducer'; +import { useRoom } from '@/shared/hooks/useRoom'; +import { useSocket } from '@/shared/hooks/useSocket'; +import { useTransport } from '@/shared/hooks/useTransport'; +import { Button } from '@/shared/components/ui/button'; import { MicrophoneOffIcon, MicrophoneOnIcon, @@ -13,15 +13,15 @@ import { VideoOnIcon, ScreenShareIcon, ScreenShareIconOff, -} from '@/components/Icons'; +} from '@/shared/components/Icons'; import BroadcastTitle from './BroadcastTitle'; -import useScreenShare from '@/hooks/useScreenShare'; +import useScreenShare from '@/shared/hooks/useScreenShare'; import BroadcastPlayer from './BroadcastPlayer'; -import { Tracks } from '@/types/mediasoupTypes'; +import { Tracks } from '@/shared/types/mediasoupTypes'; import RecordButton from './RecordButton'; -import axiosInstance from '@/services/axios'; -import { useMedia } from '@/hooks/useMedia'; -import { useTheme } from '@/hooks/useTheme'; +import axiosInstance from '@/shared/services/axios'; +import { useMedia } from '@/shared/hooks/useMedia'; +import { useTheme } from '@/shared/hooks/useTheme'; const mediaServerUrl = import.meta.env.VITE_MEDIASERVER_URL; diff --git a/apps/client/src/pages/Broadcast/BroadcastPlayer.tsx b/apps/client/src/pages/Broadcast/BroadcastPlayer.tsx index 2d19ae59..6e982d64 100644 --- a/apps/client/src/pages/Broadcast/BroadcastPlayer.tsx +++ b/apps/client/src/pages/Broadcast/BroadcastPlayer.tsx @@ -1,6 +1,6 @@ import { useEffect, useRef } from 'react'; -import { RESOLUTION_OPTIONS } from '@/constants/videoOptions'; -import { Tracks } from '@/types/mediasoupTypes'; +import { RESOLUTION_OPTIONS } from '@/shared/constants/videoOptions'; +import { Tracks } from '@/shared/types/mediasoupTypes'; type BroadcastPlayerProps = { mediaStream: MediaStream | null; diff --git a/apps/client/src/pages/Broadcast/BroadcastTitle.tsx b/apps/client/src/pages/Broadcast/BroadcastTitle.tsx index eccadc9a..7ecbeca9 100644 --- a/apps/client/src/pages/Broadcast/BroadcastTitle.tsx +++ b/apps/client/src/pages/Broadcast/BroadcastTitle.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import { useForm, SubmitHandler } from 'react-hook-form'; -import { Button } from '@components/ui/button'; -import axiosInstance from '@services/axios'; +import { Button } from '@/shared/components/ui/button'; +import axiosInstance from '@/shared/services/axios'; type Inputs = { title: string; diff --git a/apps/client/src/pages/Broadcast/RecordButton.tsx b/apps/client/src/pages/Broadcast/RecordButton.tsx index 12e5a12f..056e1a10 100644 --- a/apps/client/src/pages/Broadcast/RecordButton.tsx +++ b/apps/client/src/pages/Broadcast/RecordButton.tsx @@ -2,8 +2,8 @@ import { useEffect, useState } from 'react'; import { createPortal } from 'react-dom'; import { useForm } from 'react-hook-form'; import { Socket } from 'socket.io-client'; -import { Button } from '@/components/ui/button'; -import Modal from '@/components/Modal'; +import { Button } from '@/shared/components/ui/button'; +import Modal from '@/shared/components/Modal'; type FormInput = { title: string; diff --git a/apps/client/src/pages/Home/Banner.tsx b/apps/client/src/pages/Home/Banner.tsx index f6ffae8f..63b6cefc 100644 --- a/apps/client/src/pages/Home/Banner.tsx +++ b/apps/client/src/pages/Home/Banner.tsx @@ -1,4 +1,4 @@ -import MoveCharacter from '@/components/Icons/MoveCharacter'; +import MoveCharacter from '@/shared/components/Icons/MoveCharacter'; import Bookmark from './Bookmark'; function Banner() { diff --git a/apps/client/src/pages/Home/Bookmark.tsx b/apps/client/src/pages/Home/Bookmark.tsx index 89b8e242..07b997ac 100644 --- a/apps/client/src/pages/Home/Bookmark.tsx +++ b/apps/client/src/pages/Home/Bookmark.tsx @@ -1,12 +1,12 @@ -import Modal from '@components/Modal'; -import { Button } from '@components/ui/button'; import { createPortal } from 'react-dom'; import { useForm } from 'react-hook-form'; -import { useToast } from '@hooks/useToast'; -import { AuthContext } from '@contexts/AuthContext'; -import axiosInstance from '@services/axios'; import { useContext, useEffect, useState } from 'react'; -import { CloseIcon } from '@components/Icons'; +import Modal from '@/shared/components/Modal'; +import { Button } from '@/shared/components/ui/button'; +import { useToast } from '@/shared/hooks/useToast'; +import { AuthContext } from '@/shared/contexts/AuthContext'; +import axiosInstance from '@/shared/services/axios'; +import { CloseIcon } from '@/shared/components/Icons'; type BookmarkData = { bookmarkId: number; diff --git a/apps/client/src/pages/Home/FieldFilter.tsx b/apps/client/src/pages/Home/FieldFilter.tsx index 277d8297..43be438a 100644 --- a/apps/client/src/pages/Home/FieldFilter.tsx +++ b/apps/client/src/pages/Home/FieldFilter.tsx @@ -1,6 +1,6 @@ import { useState } from 'react'; -import { Button } from '@/components/ui/button'; -import { Field } from '@/types/liveTypes'; +import { Button } from '@/shared/components/ui/button'; +import { Field } from '@/shared/types/liveTypes'; const fields: Field[] = ['WEB', 'AND', 'IOS']; diff --git a/apps/client/src/pages/Home/LiveList.tsx b/apps/client/src/pages/Home/LiveList.tsx index 1f7a22ce..d900df74 100644 --- a/apps/client/src/pages/Home/LiveList.tsx +++ b/apps/client/src/pages/Home/LiveList.tsx @@ -1,11 +1,11 @@ import { useCallback, useEffect, useState } from 'react'; -import axiosInstance from '@services/axios'; +import axiosInstance from '@/shared/services/axios'; import FieldFilter from './FieldFilter'; import LiveCard from './LiveCard'; -import { LivePreviewInfo } from '@/types/homeTypes'; +import { LivePreviewInfo } from '@/shared/types/homeTypes'; import Search from './Search'; -import { Field } from '@/types/liveTypes'; -import { useIntersect } from '@/hooks/useIntersect'; +import { Field } from '@/shared/types/liveTypes'; +import { useIntersect } from '@/shared/hooks/useIntersect'; const LIMIT = 12; diff --git a/apps/client/src/pages/Home/Search.tsx b/apps/client/src/pages/Home/Search.tsx index 5b65e95f..7791ce1c 100644 --- a/apps/client/src/pages/Home/Search.tsx +++ b/apps/client/src/pages/Home/Search.tsx @@ -1,6 +1,6 @@ import { useForm } from 'react-hook-form'; -import IconButton from '@/components/IconButton'; -import { SearchIcon } from '@/components/Icons'; +import IconButton from '@/shared/components/IconButton'; +import { SearchIcon } from '@/shared/components/Icons'; type SearchProps = { onSearch: (keyword: string) => void; diff --git a/apps/client/src/pages/Live/LiveCamperInfo.tsx b/apps/client/src/pages/Live/LiveCamperInfo.tsx index 32d2b7a5..0ac6d751 100644 --- a/apps/client/src/pages/Live/LiveCamperInfo.tsx +++ b/apps/client/src/pages/Live/LiveCamperInfo.tsx @@ -1,11 +1,11 @@ -import { Avatar, AvatarFallback, AvatarImage } from '@components/ui/avatar'; -import { Badge } from '@components/ui/badge'; -import IconButton from '@components/IconButton'; -import { useAPI } from '@hooks/useAPI'; -import LoadingCharacter from '@components/LoadingCharacter'; -import ErrorCharacter from '@components/ErrorCharacter'; -import { LiveInfo } from '@/types/liveTypes'; -import { MailIcon, GithubIcon, BlogIcon, LinkedInIcon } from '@/components/Icons'; +import { Avatar, AvatarFallback, AvatarImage } from '@/shared/components/ui/avatar'; +import { Badge } from '@/shared/components/ui/badge'; +import IconButton from '@/shared/components/IconButton'; +import { useAPI } from '@/shared/hooks/useAPI'; +import LoadingCharacter from '@/shared/components/LoadingCharacter'; +import ErrorCharacter from '@/shared/components/ErrorCharacter'; +import { LiveInfo } from '@/shared/types/liveTypes'; +import { MailIcon, GithubIcon, BlogIcon, LinkedInIcon } from '@/shared/components/Icons'; function LiveCamperInfo({ liveId }: { liveId: string }) { const { data, isLoading, error } = useAPI({ url: `v1/broadcasts/${liveId}/info` }); diff --git a/apps/client/src/pages/Live/LivePage.tsx b/apps/client/src/pages/Live/LivePage.tsx index 50f2e901..e7a6feb3 100644 --- a/apps/client/src/pages/Live/LivePage.tsx +++ b/apps/client/src/pages/Live/LivePage.tsx @@ -1,10 +1,10 @@ -import ChatContainer from '@components/ChatContainer'; -import ErrorCharacter from '@components/ErrorCharacter'; -import { useConsumer } from '@hooks/useConsumer'; -import { useSocket } from '@hooks/useSocket'; -import { useTransport } from '@hooks/useTransport'; import { useEffect } from 'react'; import { useParams } from 'react-router-dom'; +import ChatContainer from '@/shared/components/ChatContainer'; +import ErrorCharacter from '@/shared/components/ErrorCharacter'; +import { useConsumer } from '@/shared/hooks/useConsumer'; +import { useSocket } from '@/shared/hooks/useSocket'; +import { useTransport } from '@/shared/hooks/useTransport'; import LivePlayer from './LivePlayer'; import LiveCamperInfo from './LiveCamperInfo'; diff --git a/apps/client/src/pages/Live/LivePlayer.tsx b/apps/client/src/pages/Live/LivePlayer.tsx index 8168136b..1c3cb3ee 100644 --- a/apps/client/src/pages/Live/LivePlayer.tsx +++ b/apps/client/src/pages/Live/LivePlayer.tsx @@ -1,8 +1,8 @@ import { useEffect, useRef, useState } from 'react'; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@components/ui/select'; import { Socket } from 'socket.io-client'; -import { PlayIcon, PauseIcon, VolumeOffIcon, VolumeOnIcon, ExpandIcon } from '@/components/Icons'; -import ErrorCharacter from '@/components/ErrorCharacter'; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/shared/components/ui/select'; +import { PlayIcon, PauseIcon, VolumeOffIcon, VolumeOnIcon, ExpandIcon } from '@/shared/components/Icons'; +import ErrorCharacter from '@/shared/components/ErrorCharacter'; type Errors = { socketError: Error | null; diff --git a/apps/client/src/pages/Profile/Attendance.tsx b/apps/client/src/pages/Profile/Attendance.tsx index 895066fb..770693f7 100644 --- a/apps/client/src/pages/Profile/Attendance.tsx +++ b/apps/client/src/pages/Profile/Attendance.tsx @@ -1,9 +1,9 @@ import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import ErrorCharacter from '@/components/ErrorCharacter'; -import { PlayIcon } from '@/components/Icons'; -import LoadingCharacter from '@/components/LoadingCharacter'; -import axiosInstance from '@/services/axios'; +import ErrorCharacter from '@/shared/components/ErrorCharacter'; +import { PlayIcon } from '@/shared/components/Icons'; +import LoadingCharacter from '@/shared/components/LoadingCharacter'; +import axiosInstance from '@/shared/services/axios'; type AttendanceData = { attendanceId: number; diff --git a/apps/client/src/pages/Profile/EditUserInfo.tsx b/apps/client/src/pages/Profile/EditUserInfo.tsx index d1829389..63b1e009 100644 --- a/apps/client/src/pages/Profile/EditUserInfo.tsx +++ b/apps/client/src/pages/Profile/EditUserInfo.tsx @@ -1,11 +1,11 @@ import { useForm } from 'react-hook-form'; import { useState } from 'react'; -import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; -import { UserData } from '.'; -import { Field } from '@/types/liveTypes'; -import { Button } from '@/components/ui/button'; -import axiosInstance from '@/services/axios'; -import { useToast } from '@/hooks/useToast'; +import { Avatar, AvatarFallback, AvatarImage } from '@/shared/components/ui/avatar'; +import { UserData } from './ProfilePage'; +import { Field } from '@/shared/types/liveTypes'; +import { Button } from '@/shared/components/ui/button'; +import axiosInstance from '@/shared/services/axios'; +import { useToast } from '@/shared/hooks/useToast'; type EditUserInfoProps = { userData: UserData | undefined; diff --git a/apps/client/src/pages/Profile/ProfilePage.tsx b/apps/client/src/pages/Profile/ProfilePage.tsx index 66487a8f..3f4810a1 100644 --- a/apps/client/src/pages/Profile/ProfilePage.tsx +++ b/apps/client/src/pages/Profile/ProfilePage.tsx @@ -2,10 +2,10 @@ import { useEffect, useState } from 'react'; import Attendance from './Attendance'; import UserInfo from './UserInfo'; import EditUserInfo from './EditUserInfo'; -import axiosInstance from '@/services/axios'; -import { Field } from '@/types/liveTypes'; -import ErrorCharacter from '@/components/ErrorCharacter'; -import LoadingCharacter from '@/components/LoadingCharacter'; +import axiosInstance from '@/shared/services/axios'; +import { Field } from '@/shared/types/liveTypes'; +import ErrorCharacter from '@/shared/components/ErrorCharacter'; +import LoadingCharacter from '@/shared/components/LoadingCharacter'; export type Contacts = { email: string; diff --git a/apps/client/src/pages/Profile/UserInfo.tsx b/apps/client/src/pages/Profile/UserInfo.tsx index 28151973..9d7fb649 100644 --- a/apps/client/src/pages/Profile/UserInfo.tsx +++ b/apps/client/src/pages/Profile/UserInfo.tsx @@ -1,9 +1,9 @@ import { useEffect, useState } from 'react'; -import ErrorCharacter from '@/components/ErrorCharacter'; -import { BlogIcon, EditIcon, GithubIcon, LinkedInIcon, MailIcon } from '@/components/Icons'; -import LoadingCharacter from '@/components/LoadingCharacter'; -import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; -import { UserData } from '.'; +import ErrorCharacter from '@/shared/components/ErrorCharacter'; +import { BlogIcon, EditIcon, GithubIcon, LinkedInIcon, MailIcon } from '@/shared/components/Icons'; +import LoadingCharacter from '@/shared/components/LoadingCharacter'; +import { Avatar, AvatarFallback, AvatarImage } from '@/shared/components/ui/avatar'; +import { UserData } from './ProfilePage'; type UserInfoProps = { userData: UserData | undefined; diff --git a/apps/client/src/pages/Record/RecordList.tsx b/apps/client/src/pages/Record/RecordList.tsx index 4d660be4..30b297cd 100644 --- a/apps/client/src/pages/Record/RecordList.tsx +++ b/apps/client/src/pages/Record/RecordList.tsx @@ -1,9 +1,9 @@ import { useEffect, useState } from 'react'; import { useParams } from 'react-router-dom'; -import { PlayIcon } from '@/components/Icons'; +import { PlayIcon } from '@/shared/components/Icons'; import { RecordData } from '.'; -import axiosInstance from '@/services/axios'; -import ErrorCharacter from '@/components/ErrorCharacter'; +import axiosInstance from '@/shared/services/axios'; +import ErrorCharacter from '@/shared/components/ErrorCharacter'; type RecordListProps = { onClickList: (data: RecordData) => void; diff --git a/apps/client/src/pages/Record/RecordPlayer.tsx b/apps/client/src/pages/Record/RecordPlayer.tsx index b3bf3e36..d8127473 100644 --- a/apps/client/src/pages/Record/RecordPlayer.tsx +++ b/apps/client/src/pages/Record/RecordPlayer.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; import ReactPlayer from 'react-player'; -import LoadingCharacter from '@/components/LoadingCharacter'; +import LoadingCharacter from '@/shared/components/LoadingCharacter'; type RecordPlayerProps = { video: string; diff --git a/apps/client/src/assets/fonts/PretendardVariable.woff2 b/apps/client/src/shared/assets/fonts/PretendardVariable.woff2 similarity index 100% rename from apps/client/src/assets/fonts/PretendardVariable.woff2 rename to apps/client/src/shared/assets/fonts/PretendardVariable.woff2 diff --git a/apps/client/src/components/ChatContainer/ChatEndModal.tsx b/apps/client/src/shared/components/ChatContainer/ChatEndModal.tsx similarity index 94% rename from apps/client/src/components/ChatContainer/ChatEndModal.tsx rename to apps/client/src/shared/components/ChatContainer/ChatEndModal.tsx index 327fda81..beb1663d 100644 --- a/apps/client/src/components/ChatContainer/ChatEndModal.tsx +++ b/apps/client/src/shared/components/ChatContainer/ChatEndModal.tsx @@ -1,5 +1,5 @@ -import Modal from '@components/Modal'; import { useNavigate } from 'react-router-dom'; +import Modal from '@/shared/components/Modal'; type ChatEndModalProps = { setShowModal: (b: boolean) => void; diff --git a/apps/client/src/components/ChatContainer/index.tsx b/apps/client/src/shared/components/ChatContainer/index.tsx similarity index 94% rename from apps/client/src/components/ChatContainer/index.tsx rename to apps/client/src/shared/components/ChatContainer/index.tsx index 39202d90..996aa1f9 100644 --- a/apps/client/src/components/ChatContainer/index.tsx +++ b/apps/client/src/shared/components/ChatContainer/index.tsx @@ -1,11 +1,11 @@ import { useState, useEffect, useRef, useContext } from 'react'; -import { Card, CardHeader, CardTitle, CardContent, CardFooter } from '@components/ui/card'; -import { Input } from '@components/ui/input'; -import { useSocket } from '@hooks/useSocket'; -import ErrorCharacter from '@components/ErrorCharacter'; import { createPortal } from 'react-dom'; -import { AuthContext } from '@/contexts/AuthContext'; -import { SmileIcon } from '@/components/Icons'; +import { Card, CardHeader, CardTitle, CardContent, CardFooter } from '@/shared/components/ui/card'; +import { Input } from '@/shared/components/ui/input'; +import { useSocket } from '@/shared/hooks/useSocket'; +import ErrorCharacter from '@/shared/components/ErrorCharacter'; +import { AuthContext } from '@/shared/contexts/AuthContext'; +import { SmileIcon } from '@/shared/components/Icons'; import ChatEndModal from './ChatEndModal'; type Chat = { diff --git a/apps/client/src/components/ErrorCharacter/index.tsx b/apps/client/src/shared/components/ErrorCharacter/index.tsx similarity index 100% rename from apps/client/src/components/ErrorCharacter/index.tsx rename to apps/client/src/shared/components/ErrorCharacter/index.tsx diff --git a/apps/client/src/components/FloatingButton/index.tsx b/apps/client/src/shared/components/FloatingButton/index.tsx similarity index 70% rename from apps/client/src/components/FloatingButton/index.tsx rename to apps/client/src/shared/components/FloatingButton/index.tsx index c111154c..b974753f 100644 --- a/apps/client/src/components/FloatingButton/index.tsx +++ b/apps/client/src/shared/components/FloatingButton/index.tsx @@ -1,6 +1,6 @@ -import { Button } from '@components/ui/button'; -import { ThemeIcon } from '@components/Icons'; -import { useTheme } from '@/hooks/useTheme'; +import { Button } from '@/shared/components/ui/button'; +import { ThemeIcon } from '@/shared/components/Icons'; +import { useTheme } from '@/shared/hooks/useTheme'; function FloatingButton() { const { convertTheme } = useTheme(); diff --git a/apps/client/src/components/Footer/index.tsx b/apps/client/src/shared/components/Footer/index.tsx similarity index 100% rename from apps/client/src/components/Footer/index.tsx rename to apps/client/src/shared/components/Footer/index.tsx diff --git a/apps/client/src/components/Header/LogInButton.tsx b/apps/client/src/shared/components/Header/LogInButton.tsx similarity index 88% rename from apps/client/src/components/Header/LogInButton.tsx rename to apps/client/src/shared/components/Header/LogInButton.tsx index 43dc4f40..5e2fd758 100644 --- a/apps/client/src/components/Header/LogInButton.tsx +++ b/apps/client/src/shared/components/Header/LogInButton.tsx @@ -1,11 +1,11 @@ import { useState } from 'react'; -import WelcomeCharacter from '@components/WelcomeCharacter'; -import { Button } from '@components/ui/button'; import { createPortal } from 'react-dom'; -import Modal from '@components/Modal'; -import { GithubIcon, GoogleIcon } from '@components/Icons'; -import { useAuth } from '@/hooks/useAuth'; -import axiosInstance from '@/services/axios'; +import WelcomeCharacter from '@/shared/components/WelcomeCharacter'; +import { Button } from '@/shared/components/ui/button'; +import Modal from '@/shared/components/Modal'; +import { GithubIcon, GoogleIcon } from '@/shared/components/Icons'; +import { useAuth } from '@/shared/hooks/useAuth'; +import axiosInstance from '@/shared/services/axios'; function LogInButton() { const [showModal, setShowModal] = useState(false); diff --git a/apps/client/src/components/Header/index.tsx b/apps/client/src/shared/components/Header/index.tsx similarity index 89% rename from apps/client/src/components/Header/index.tsx rename to apps/client/src/shared/components/Header/index.tsx index ef262751..04cdd0c7 100644 --- a/apps/client/src/components/Header/index.tsx +++ b/apps/client/src/shared/components/Header/index.tsx @@ -1,13 +1,13 @@ import { useContext, useEffect, useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import { Character, Logo } from '@components/Icons'; -import { Avatar, AvatarFallback, AvatarImage } from '@components/ui/avatar'; -import { cn } from '@utils/utils'; -import { AuthContext } from '@/contexts/AuthContext'; -import axiosInstance from '@/services/axios'; +import { Character, Logo } from '@/shared/components/Icons'; +import { Avatar, AvatarFallback, AvatarImage } from '@/shared/components/ui/avatar'; +import { cn } from '@/shared/utils/utils'; +import { AuthContext } from '@/shared/contexts/AuthContext'; +import axiosInstance from '@/shared/services/axios'; import LogInButton from './LogInButton'; import { Button } from '../ui/button'; -import { useAuth } from '@/hooks/useAuth'; +import { useAuth } from '@/shared/hooks/useAuth'; function Header() { const [isCheckedIn, setIsCheckedIn] = useState(false); diff --git a/apps/client/src/components/IconButton/index.tsx b/apps/client/src/shared/components/IconButton/index.tsx similarity index 100% rename from apps/client/src/components/IconButton/index.tsx rename to apps/client/src/shared/components/IconButton/index.tsx diff --git a/apps/client/src/components/Icons/BlogIcon.tsx b/apps/client/src/shared/components/Icons/BlogIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/BlogIcon.tsx rename to apps/client/src/shared/components/Icons/BlogIcon.tsx diff --git a/apps/client/src/components/Icons/Character.tsx b/apps/client/src/shared/components/Icons/Character.tsx similarity index 100% rename from apps/client/src/components/Icons/Character.tsx rename to apps/client/src/shared/components/Icons/Character.tsx diff --git a/apps/client/src/components/Icons/CloseIcon.tsx b/apps/client/src/shared/components/Icons/CloseIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/CloseIcon.tsx rename to apps/client/src/shared/components/Icons/CloseIcon.tsx diff --git a/apps/client/src/components/Icons/EditIcon.tsx b/apps/client/src/shared/components/Icons/EditIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/EditIcon.tsx rename to apps/client/src/shared/components/Icons/EditIcon.tsx diff --git a/apps/client/src/components/Icons/ExpandIcon.tsx b/apps/client/src/shared/components/Icons/ExpandIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/ExpandIcon.tsx rename to apps/client/src/shared/components/Icons/ExpandIcon.tsx diff --git a/apps/client/src/components/Icons/GithubIcon.tsx b/apps/client/src/shared/components/Icons/GithubIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/GithubIcon.tsx rename to apps/client/src/shared/components/Icons/GithubIcon.tsx diff --git a/apps/client/src/components/Icons/GoogleIcon.tsx b/apps/client/src/shared/components/Icons/GoogleIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/GoogleIcon.tsx rename to apps/client/src/shared/components/Icons/GoogleIcon.tsx diff --git a/apps/client/src/components/Icons/LinkedInIcon.tsx b/apps/client/src/shared/components/Icons/LinkedInIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/LinkedInIcon.tsx rename to apps/client/src/shared/components/Icons/LinkedInIcon.tsx diff --git a/apps/client/src/components/Icons/Logo.tsx b/apps/client/src/shared/components/Icons/Logo.tsx similarity index 100% rename from apps/client/src/components/Icons/Logo.tsx rename to apps/client/src/shared/components/Icons/Logo.tsx diff --git a/apps/client/src/components/Icons/MailIcon.tsx b/apps/client/src/shared/components/Icons/MailIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/MailIcon.tsx rename to apps/client/src/shared/components/Icons/MailIcon.tsx diff --git a/apps/client/src/components/Icons/MicrophoneOffIcon.tsx b/apps/client/src/shared/components/Icons/MicrophoneOffIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/MicrophoneOffIcon.tsx rename to apps/client/src/shared/components/Icons/MicrophoneOffIcon.tsx diff --git a/apps/client/src/components/Icons/MicrophoneOnIcon.tsx b/apps/client/src/shared/components/Icons/MicrophoneOnIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/MicrophoneOnIcon.tsx rename to apps/client/src/shared/components/Icons/MicrophoneOnIcon.tsx diff --git a/apps/client/src/components/Icons/MoveCharacter.tsx b/apps/client/src/shared/components/Icons/MoveCharacter.tsx similarity index 100% rename from apps/client/src/components/Icons/MoveCharacter.tsx rename to apps/client/src/shared/components/Icons/MoveCharacter.tsx diff --git a/apps/client/src/components/Icons/PauseIcon.tsx b/apps/client/src/shared/components/Icons/PauseIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/PauseIcon.tsx rename to apps/client/src/shared/components/Icons/PauseIcon.tsx diff --git a/apps/client/src/components/Icons/PlayIcon.tsx b/apps/client/src/shared/components/Icons/PlayIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/PlayIcon.tsx rename to apps/client/src/shared/components/Icons/PlayIcon.tsx diff --git a/apps/client/src/components/Icons/ScreenShareIcon.tsx b/apps/client/src/shared/components/Icons/ScreenShareIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/ScreenShareIcon.tsx rename to apps/client/src/shared/components/Icons/ScreenShareIcon.tsx diff --git a/apps/client/src/components/Icons/ScreenShareOffIcon.tsx b/apps/client/src/shared/components/Icons/ScreenShareOffIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/ScreenShareOffIcon.tsx rename to apps/client/src/shared/components/Icons/ScreenShareOffIcon.tsx diff --git a/apps/client/src/components/Icons/SearchIcon.tsx b/apps/client/src/shared/components/Icons/SearchIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/SearchIcon.tsx rename to apps/client/src/shared/components/Icons/SearchIcon.tsx diff --git a/apps/client/src/components/Icons/SmileIcon.tsx b/apps/client/src/shared/components/Icons/SmileIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/SmileIcon.tsx rename to apps/client/src/shared/components/Icons/SmileIcon.tsx diff --git a/apps/client/src/components/Icons/ThemeIcon.tsx b/apps/client/src/shared/components/Icons/ThemeIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/ThemeIcon.tsx rename to apps/client/src/shared/components/Icons/ThemeIcon.tsx diff --git a/apps/client/src/components/Icons/VideoOffIcon.tsx b/apps/client/src/shared/components/Icons/VideoOffIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/VideoOffIcon.tsx rename to apps/client/src/shared/components/Icons/VideoOffIcon.tsx diff --git a/apps/client/src/components/Icons/VideoOnIcon.tsx b/apps/client/src/shared/components/Icons/VideoOnIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/VideoOnIcon.tsx rename to apps/client/src/shared/components/Icons/VideoOnIcon.tsx diff --git a/apps/client/src/components/Icons/VolumeOffIcon.tsx b/apps/client/src/shared/components/Icons/VolumeOffIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/VolumeOffIcon.tsx rename to apps/client/src/shared/components/Icons/VolumeOffIcon.tsx diff --git a/apps/client/src/components/Icons/VolumeOnIcon.tsx b/apps/client/src/shared/components/Icons/VolumeOnIcon.tsx similarity index 100% rename from apps/client/src/components/Icons/VolumeOnIcon.tsx rename to apps/client/src/shared/components/Icons/VolumeOnIcon.tsx diff --git a/apps/client/src/components/Icons/index.ts b/apps/client/src/shared/components/Icons/index.ts similarity index 100% rename from apps/client/src/components/Icons/index.ts rename to apps/client/src/shared/components/Icons/index.ts diff --git a/apps/client/src/components/LoadingCharacter/index.tsx b/apps/client/src/shared/components/LoadingCharacter/index.tsx similarity index 100% rename from apps/client/src/components/LoadingCharacter/index.tsx rename to apps/client/src/shared/components/LoadingCharacter/index.tsx diff --git a/apps/client/src/components/Modal/index.tsx b/apps/client/src/shared/components/Modal/index.tsx similarity index 96% rename from apps/client/src/components/Modal/index.tsx rename to apps/client/src/shared/components/Modal/index.tsx index bcc6cefb..ef1cda19 100644 --- a/apps/client/src/components/Modal/index.tsx +++ b/apps/client/src/shared/components/Modal/index.tsx @@ -1,5 +1,5 @@ -import { CloseIcon } from '@components/Icons'; import { useEffect, useRef } from 'react'; +import { CloseIcon } from '@/shared/components/Icons'; type ModalProps = { children: React.ReactNode; diff --git a/apps/client/src/components/WelcomeCharacter/index.tsx b/apps/client/src/shared/components/WelcomeCharacter/index.tsx similarity index 100% rename from apps/client/src/components/WelcomeCharacter/index.tsx rename to apps/client/src/shared/components/WelcomeCharacter/index.tsx diff --git a/apps/client/src/components/ui/avatar.tsx b/apps/client/src/shared/components/ui/avatar.tsx similarity index 96% rename from apps/client/src/components/ui/avatar.tsx rename to apps/client/src/shared/components/ui/avatar.tsx index 6807a16f..516d8235 100644 --- a/apps/client/src/components/ui/avatar.tsx +++ b/apps/client/src/shared/components/ui/avatar.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import * as AvatarPrimitive from '@radix-ui/react-avatar'; -import { cn } from '@/utils/utils'; +import { cn } from '@/shared/utils/utils'; const Avatar = React.forwardRef< React.ElementRef, diff --git a/apps/client/src/components/ui/badge.tsx b/apps/client/src/shared/components/ui/badge.tsx similarity index 96% rename from apps/client/src/components/ui/badge.tsx rename to apps/client/src/shared/components/ui/badge.tsx index 74d3a0ff..843166d1 100644 --- a/apps/client/src/components/ui/badge.tsx +++ b/apps/client/src/shared/components/ui/badge.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { cva, type VariantProps } from 'class-variance-authority'; -import { cn } from '@/utils/utils'; +import { cn } from '@/shared/utils/utils'; const badgeVariants = cva( 'inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', diff --git a/apps/client/src/components/ui/button.tsx b/apps/client/src/shared/components/ui/button.tsx similarity index 97% rename from apps/client/src/components/ui/button.tsx rename to apps/client/src/shared/components/ui/button.tsx index 466585c7..51d50f08 100644 --- a/apps/client/src/components/ui/button.tsx +++ b/apps/client/src/shared/components/ui/button.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { Slot } from '@radix-ui/react-slot'; import { cva, type VariantProps } from 'class-variance-authority'; -import { cn } from '@/utils/utils'; +import { cn } from '@/shared/utils/utils'; const buttonVariants = cva( 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-xl text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', diff --git a/apps/client/src/components/ui/card.tsx b/apps/client/src/shared/components/ui/card.tsx similarity index 97% rename from apps/client/src/components/ui/card.tsx rename to apps/client/src/shared/components/ui/card.tsx index d140013f..276d2fcb 100644 --- a/apps/client/src/components/ui/card.tsx +++ b/apps/client/src/shared/components/ui/card.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -import { cn } from '@/utils/utils'; +import { cn } from '@/shared/utils/utils'; const Card = React.forwardRef>(({ className, ...props }, ref) => (
diff --git a/apps/client/src/shared/components/ui/input.tsx b/apps/client/src/shared/components/ui/input.tsx new file mode 100644 index 00000000..4b2ed315 --- /dev/null +++ b/apps/client/src/shared/components/ui/input.tsx @@ -0,0 +1,20 @@ +import * as React from 'react'; + +import { cn } from '@/shared/utils/utils'; + +const Input = React.forwardRef>( + ({ className, type, ...props }, ref) => ( + + ), +); +Input.displayName = 'Input'; + +export { Input }; diff --git a/apps/client/src/components/ui/scroll-area.tsx b/apps/client/src/shared/components/ui/scroll-area.tsx similarity index 97% rename from apps/client/src/components/ui/scroll-area.tsx rename to apps/client/src/shared/components/ui/scroll-area.tsx index abf0f1d2..ee9db212 100644 --- a/apps/client/src/components/ui/scroll-area.tsx +++ b/apps/client/src/shared/components/ui/scroll-area.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'; -import { cn } from '@/utils/utils'; +import { cn } from '@/shared/utils/utils'; const ScrollArea = React.forwardRef< React.ElementRef, diff --git a/apps/client/src/components/ui/select.tsx b/apps/client/src/shared/components/ui/select.tsx similarity index 99% rename from apps/client/src/components/ui/select.tsx rename to apps/client/src/shared/components/ui/select.tsx index dd1cf276..c8093e4d 100644 --- a/apps/client/src/components/ui/select.tsx +++ b/apps/client/src/shared/components/ui/select.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import * as SelectPrimitive from '@radix-ui/react-select'; import { Check, ChevronDown, ChevronUp } from 'lucide-react'; -import { cn } from '@/utils/utils'; +import { cn } from '@/shared/utils/utils'; const Select = SelectPrimitive.Root; diff --git a/apps/client/src/components/ui/toast.tsx b/apps/client/src/shared/components/ui/toast.tsx similarity index 95% rename from apps/client/src/components/ui/toast.tsx rename to apps/client/src/shared/components/ui/toast.tsx index e27ae6cc..e8a7079b 100644 --- a/apps/client/src/components/ui/toast.tsx +++ b/apps/client/src/shared/components/ui/toast.tsx @@ -3,7 +3,7 @@ import * as ToastPrimitives from '@radix-ui/react-toast'; import { cva, type VariantProps } from 'class-variance-authority'; import { X } from 'lucide-react'; -import { cn } from '@utils/utils'; +import { cn } from '@/shared/utils/utils'; const ToastProvider = ToastPrimitives.Provider; @@ -40,7 +40,9 @@ const toastVariants = cva( const Toast = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & VariantProps ->(({ className, variant, ...props }, ref) => ); +>(({ className, variant, ...props }, ref) => ( + +)); Toast.displayName = ToastPrimitives.Root.displayName; const ToastAction = React.forwardRef< diff --git a/apps/client/src/shared/components/ui/toaster.tsx b/apps/client/src/shared/components/ui/toaster.tsx new file mode 100644 index 00000000..82544ccd --- /dev/null +++ b/apps/client/src/shared/components/ui/toaster.tsx @@ -0,0 +1,29 @@ +import { useToast } from '@/shared/hooks/useToast'; +import { + Toast, + ToastClose, + ToastDescription, + ToastProvider, + ToastTitle, + ToastViewport, +} from '@/shared/components/ui/toast'; + +export function Toaster() { + const { toasts } = useToast(); + + return ( + + {toasts.map(({ id, title, description, action, ...props }) => ( + +
+ {title && {title}} + {description && {description}} +
+ {action} + +
+ ))} + +
+ ); +} diff --git a/apps/client/src/constants/videoOptions.ts b/apps/client/src/shared/constants/videoOptions.ts similarity index 100% rename from apps/client/src/constants/videoOptions.ts rename to apps/client/src/shared/constants/videoOptions.ts diff --git a/apps/client/src/contexts/AuthContext.tsx b/apps/client/src/shared/contexts/AuthContext.tsx similarity index 100% rename from apps/client/src/contexts/AuthContext.tsx rename to apps/client/src/shared/contexts/AuthContext.tsx diff --git a/apps/client/src/contexts/ThemeContext.tsx b/apps/client/src/shared/contexts/ThemeContext.tsx similarity index 100% rename from apps/client/src/contexts/ThemeContext.tsx rename to apps/client/src/shared/contexts/ThemeContext.tsx diff --git a/apps/client/src/hooks/useAPI.ts b/apps/client/src/shared/hooks/useAPI.ts similarity index 93% rename from apps/client/src/hooks/useAPI.ts rename to apps/client/src/shared/hooks/useAPI.ts index da524011..b0bf7ce2 100644 --- a/apps/client/src/hooks/useAPI.ts +++ b/apps/client/src/shared/hooks/useAPI.ts @@ -1,6 +1,6 @@ -import axiosInstance from '@services/axios'; import { AxiosRequestConfig } from 'axios'; import { useEffect, useState } from 'react'; +import axiosInstance from '@/shared/services/axios'; type APIQueryState = { data: T | null; diff --git a/apps/client/src/hooks/useAuth.ts b/apps/client/src/shared/hooks/useAuth.ts similarity index 92% rename from apps/client/src/hooks/useAuth.ts rename to apps/client/src/shared/hooks/useAuth.ts index 4ff13a01..2fa91ff8 100644 --- a/apps/client/src/hooks/useAuth.ts +++ b/apps/client/src/shared/hooks/useAuth.ts @@ -1,6 +1,6 @@ -import { AuthContext } from '@contexts/AuthContext'; import { useContext, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; +import { AuthContext } from '@/shared/contexts/AuthContext'; export const useAuth = () => { const navigate = useNavigate(); diff --git a/apps/client/src/hooks/useConsumer.ts b/apps/client/src/shared/hooks/useConsumer.ts similarity index 96% rename from apps/client/src/hooks/useConsumer.ts rename to apps/client/src/shared/hooks/useConsumer.ts index d1eba123..c0da4c1a 100644 --- a/apps/client/src/hooks/useConsumer.ts +++ b/apps/client/src/shared/hooks/useConsumer.ts @@ -1,8 +1,8 @@ import { useEffect, useRef, useState } from 'react'; import { Transport, Device, MediaKind } from 'mediasoup-client/lib/types'; import { Socket } from 'socket.io-client'; -import { checkDependencies } from '@utils/utils'; -import { ConnectTransportResponse, TransportInfo } from '@/types/mediasoupTypes'; +import { checkDependencies } from '@/shared/utils/utils'; +import { ConnectTransportResponse, TransportInfo } from '@/shared/types/mediasoupTypes'; type UseConsumerProps = { socket: Socket | null; diff --git a/apps/client/src/hooks/useIntersect.ts b/apps/client/src/shared/hooks/useIntersect.ts similarity index 100% rename from apps/client/src/hooks/useIntersect.ts rename to apps/client/src/shared/hooks/useIntersect.ts diff --git a/apps/client/src/hooks/useMedia.ts b/apps/client/src/shared/hooks/useMedia.ts similarity index 100% rename from apps/client/src/hooks/useMedia.ts rename to apps/client/src/shared/hooks/useMedia.ts diff --git a/apps/client/src/hooks/useProducer.ts b/apps/client/src/shared/hooks/useProducer.ts similarity index 95% rename from apps/client/src/hooks/useProducer.ts rename to apps/client/src/shared/hooks/useProducer.ts index 9dac3f8b..9dc1e3e2 100644 --- a/apps/client/src/hooks/useProducer.ts +++ b/apps/client/src/shared/hooks/useProducer.ts @@ -1,9 +1,9 @@ import { useEffect, useRef, useState } from 'react'; import { Transport, Device, Producer } from 'mediasoup-client/lib/types'; import { Socket } from 'socket.io-client'; -import { ConnectTransportResponse, TransportInfo } from '@/types/mediasoupTypes'; -import { checkDependencies } from '@/utils/utils'; -import { ENCODING_OPTIONS } from '@/constants/videoOptions'; +import { ConnectTransportResponse, TransportInfo } from '@/shared/types/mediasoupTypes'; +import { checkDependencies } from '@/shared/utils/utils'; +import { ENCODING_OPTIONS } from '@/shared/constants/videoOptions'; type UseProducerProps = { socket: Socket | null; diff --git a/apps/client/src/hooks/useRoom.ts b/apps/client/src/shared/hooks/useRoom.ts similarity index 100% rename from apps/client/src/hooks/useRoom.ts rename to apps/client/src/shared/hooks/useRoom.ts diff --git a/apps/client/src/hooks/useScreenShare.ts b/apps/client/src/shared/hooks/useScreenShare.ts similarity index 100% rename from apps/client/src/hooks/useScreenShare.ts rename to apps/client/src/shared/hooks/useScreenShare.ts diff --git a/apps/client/src/hooks/useSocket.ts b/apps/client/src/shared/hooks/useSocket.ts similarity index 100% rename from apps/client/src/hooks/useSocket.ts rename to apps/client/src/shared/hooks/useSocket.ts diff --git a/apps/client/src/hooks/useTheme.ts b/apps/client/src/shared/hooks/useTheme.ts similarity index 91% rename from apps/client/src/hooks/useTheme.ts rename to apps/client/src/shared/hooks/useTheme.ts index d8ec706b..9a321e19 100644 --- a/apps/client/src/hooks/useTheme.ts +++ b/apps/client/src/shared/hooks/useTheme.ts @@ -1,5 +1,5 @@ import { useContext, useLayoutEffect } from 'react'; -import { ThemeContext } from '@/contexts/ThemeContext'; +import { ThemeContext } from '@/shared/contexts/ThemeContext'; export const useTheme = () => { const { theme, setTheme } = useContext(ThemeContext); diff --git a/apps/client/src/hooks/useToast.ts b/apps/client/src/shared/hooks/useToast.ts similarity index 97% rename from apps/client/src/hooks/useToast.ts rename to apps/client/src/shared/hooks/useToast.ts index f2ed6f0e..969b307e 100644 --- a/apps/client/src/hooks/useToast.ts +++ b/apps/client/src/shared/hooks/useToast.ts @@ -4,7 +4,7 @@ // Inspired by react-hot-toast library import * as React from 'react'; -import type { ToastActionElement, ToastProps } from '@/components/ui/toast'; +import type { ToastActionElement, ToastProps } from '@/shared/components/ui/toast'; const TOAST_LIMIT = 1; const TOAST_REMOVE_DELAY = 1000000; diff --git a/apps/client/src/hooks/useTransport.ts b/apps/client/src/shared/hooks/useTransport.ts similarity index 96% rename from apps/client/src/hooks/useTransport.ts rename to apps/client/src/shared/hooks/useTransport.ts index 2ee03313..39ed4d54 100644 --- a/apps/client/src/hooks/useTransport.ts +++ b/apps/client/src/shared/hooks/useTransport.ts @@ -3,8 +3,8 @@ import { useEffect, useState, useRef } from 'react'; import { RtpCapabilities } from 'mediasoup-client/lib/RtpParameters'; import { Device } from 'mediasoup-client/lib/types'; import { Socket } from 'socket.io-client'; -import { checkDependencies } from '@/utils/utils'; -import { TransportInfo } from '@/types/mediasoupTypes'; +import { checkDependencies } from '@/shared/utils/utils'; +import { TransportInfo } from '@/shared/types/mediasoupTypes'; type UseTransportProps = { socket: Socket | null; diff --git a/apps/client/src/services/axios.ts b/apps/client/src/shared/services/axios.ts similarity index 100% rename from apps/client/src/services/axios.ts rename to apps/client/src/shared/services/axios.ts diff --git a/apps/client/src/types/homeTypes.ts b/apps/client/src/shared/types/homeTypes.ts similarity index 100% rename from apps/client/src/types/homeTypes.ts rename to apps/client/src/shared/types/homeTypes.ts diff --git a/apps/client/src/types/liveTypes.ts b/apps/client/src/shared/types/liveTypes.ts similarity index 100% rename from apps/client/src/types/liveTypes.ts rename to apps/client/src/shared/types/liveTypes.ts diff --git a/apps/client/src/types/mediasoupTypes.ts b/apps/client/src/shared/types/mediasoupTypes.ts similarity index 100% rename from apps/client/src/types/mediasoupTypes.ts rename to apps/client/src/shared/types/mediasoupTypes.ts diff --git a/apps/client/src/utils/utils.ts b/apps/client/src/shared/utils/utils.ts similarity index 100% rename from apps/client/src/utils/utils.ts rename to apps/client/src/shared/utils/utils.ts diff --git a/apps/client/tsconfig.json b/apps/client/tsconfig.json index cc54801b..19770d9d 100644 --- a/apps/client/tsconfig.json +++ b/apps/client/tsconfig.json @@ -20,12 +20,12 @@ "@/*": ["./src/*"], "@assets/*": ["./src/assets/*"], "@components/*": ["./src/components/*"], - "@contexts/*": ["./src/contexts/*"], - "@hooks/*": ["./src/hooks/*"], - "@services/*": ["./src/services/*"], + "@contexts/*": ["src/shared/contexts/*"], + "@hooks/*": ["src/shared/hooks/*"], + "@services/*": ["src/shared/services/*"], "@pages/*": ["./src/pages/*"], - "@utils/*": ["./src/utils/*"], - "@constants/*": ["./src/constants/*"] + "@utils/*": ["src/shared/utils/*"], + "@constants/*": ["src/shared/constants/*"] }, "outDir": "./dist" }, From bff4ded73848f98baed5c806b0b7d4c0d0ca6e1d Mon Sep 17 00:00:00 2001 From: zero0205 Date: Wed, 15 Jan 2025 02:12:57 +0900 Subject: [PATCH 06/11] =?UTF-8?q?:recycle:=20[Refactor]:=20FSD=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EC=A0=81=EC=9A=A9=20-=204.=20shared=20=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EC=96=B4=20unpack?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client/.eslintignore | 2 +- .../fonts/PretendardVariable.woff2 | Bin apps/client/src/app/layouts/Layout.tsx | 27 +++++++--------- .../src/app/providers/auth/AuthContext.tsx | 9 ++++++ .../src/app/providers/auth/AuthProvider.tsx | 8 +++++ apps/client/src/app/providers/auth/types.ts | 4 +++ apps/client/src/app/providers/index.tsx | 10 ++++++ .../src/app/providers/theme/ThemeContext.tsx | 9 ++++++ .../src/app/providers/theme/ThemeProvider.tsx | 9 ++++++ apps/client/src/app/providers/theme/types.ts | 6 ++++ apps/client/src/app/routes/ProtectedRoute.tsx | 2 +- .../src/app/routes/config/routerOptions.ts | 10 ++++++ apps/client/src/app/routes/router.tsx | 16 ++-------- apps/client/src/index.css | 2 +- apps/client/src/pages/Auth/AuthPage.tsx | 4 +-- .../src/pages/Broadcast/BroadcastPage.tsx | 30 +++++++++--------- .../Broadcast/{ => ui}/BroadcastPlayer.tsx | 2 +- .../Broadcast/{ => ui}/BroadcastTitle.tsx | 4 +-- .../pages/Broadcast/{ => ui}/RecordButton.tsx | 4 +-- apps/client/src/pages/Home/HomePage.tsx | 4 +-- .../client/src/pages/Home/{ => ui}/Banner.tsx | 2 +- .../src/pages/Home/{ => ui}/Bookmark.tsx | 12 +++---- .../src/pages/Home/{ => ui}/FieldFilter.tsx | 2 +- .../src/pages/Home/{ => ui}/LiveCard.tsx | 0 .../src/pages/Home/{ => ui}/LiveList.tsx | 4 +-- .../client/src/pages/Home/{ => ui}/Search.tsx | 4 +-- apps/client/src/pages/Live/LivePage.tsx | 14 ++++---- .../pages/Live/{ => ui}/LiveCamperInfo.tsx | 14 ++++---- .../src/pages/Live/{ => ui}/LivePlayer.tsx | 6 ++-- apps/client/src/pages/Profile/ProfilePage.tsx | 12 +++---- .../src/pages/Profile/{ => ui}/Attendance.tsx | 8 ++--- .../pages/Profile/{ => ui}/EditUserInfo.tsx | 10 +++--- .../src/pages/Profile/{ => ui}/UserInfo.tsx | 10 +++--- apps/client/src/pages/Record/RecordPage.tsx | 27 ++++++++++++++++ apps/client/src/pages/Record/index.tsx | 30 +----------------- .../src/pages/Record/{ => ui}/RecordInfo.tsx | 0 .../src/pages/Record/{ => ui}/RecordList.tsx | 8 ++--- .../pages/Record/{ => ui}/RecordPlayer.tsx | 2 +- .../src/shared/{services => api}/axios.ts | 0 .../src/shared/components/Footer/index.tsx | 12 ------- .../{constants => config}/videoOptions.ts | 0 .../src/shared/contexts/AuthContext.tsx | 19 ----------- .../src/shared/contexts/ThemeContext.tsx | 21 ------------ .../{hooks => lib/mediasoup}/useConsumer.ts | 2 +- .../{hooks => lib/mediasoup}/useProducer.ts | 4 +-- .../{hooks => lib/mediasoup}/useRoom.ts | 0 .../{hooks => lib/mediasoup}/useTransport.ts | 2 +- .../shared/{hooks => lib/socket}/useSocket.ts | 0 .../shared/{hooks => lib/toast}/useToast.ts | 2 +- .../src/shared/{hooks => lib}/useAPI.ts | 2 +- .../src/shared/{hooks => lib}/useAuth.ts | 2 +- .../src/shared/{hooks => lib}/useIntersect.ts | 0 .../src/shared/{hooks => lib}/useMedia.ts | 0 .../shared/{hooks => lib}/useScreenShare.ts | 0 .../src/shared/{hooks => lib}/useTheme.ts | 2 +- .../src/shared/{ => lib}/utils/utils.ts | 0 .../ChatContainer/ChatEndModal.tsx | 2 +- .../ChatContainer/index.tsx | 12 +++---- .../ErrorCharacter/index.tsx | 0 .../FloatingButton/index.tsx | 6 ++-- .../{components => ui}/Header/LogInButton.tsx | 12 +++---- .../{components => ui}/Header/index.tsx | 14 ++++---- .../{components => ui}/IconButton/index.tsx | 0 .../{components => ui}/Icons/BlogIcon.tsx | 0 .../{components => ui}/Icons/Character.tsx | 0 .../{components => ui}/Icons/CloseIcon.tsx | 0 .../{components => ui}/Icons/EditIcon.tsx | 0 .../{components => ui}/Icons/ExpandIcon.tsx | 0 .../{components => ui}/Icons/GithubIcon.tsx | 0 .../{components => ui}/Icons/GoogleIcon.tsx | 0 .../{components => ui}/Icons/LinkedInIcon.tsx | 0 .../shared/{components => ui}/Icons/Logo.tsx | 0 .../{components => ui}/Icons/MailIcon.tsx | 0 .../Icons/MicrophoneOffIcon.tsx | 0 .../Icons/MicrophoneOnIcon.tsx | 0 .../Icons/MoveCharacter.tsx | 0 .../{components => ui}/Icons/PauseIcon.tsx | 0 .../{components => ui}/Icons/PlayIcon.tsx | 0 .../Icons/ScreenShareIcon.tsx | 0 .../Icons/ScreenShareOffIcon.tsx | 0 .../{components => ui}/Icons/SearchIcon.tsx | 0 .../{components => ui}/Icons/SmileIcon.tsx | 0 .../{components => ui}/Icons/ThemeIcon.tsx | 0 .../{components => ui}/Icons/VideoOffIcon.tsx | 0 .../{components => ui}/Icons/VideoOnIcon.tsx | 0 .../Icons/VolumeOffIcon.tsx | 0 .../{components => ui}/Icons/VolumeOnIcon.tsx | 0 .../shared/{components => ui}/Icons/index.ts | 0 .../LoadingCharacter/index.tsx | 0 .../shared/{components => ui}/Modal/index.tsx | 2 +- .../WelcomeCharacter/index.tsx | 0 .../{components/ui => ui/shadcn}/avatar.tsx | 2 +- .../{components/ui => ui/shadcn}/badge.tsx | 2 +- .../{components/ui => ui/shadcn}/button.tsx | 2 +- .../{components/ui => ui/shadcn}/card.tsx | 2 +- .../{components/ui => ui/shadcn}/input.tsx | 2 +- .../ui => ui/shadcn}/scroll-area.tsx | 2 +- .../{components/ui => ui/shadcn}/select.tsx | 2 +- .../{components/ui => ui/shadcn}/toast.tsx | 2 +- .../{components/ui => ui/shadcn}/toaster.tsx | 4 +-- apps/client/tsconfig.json | 6 ++-- 101 files changed, 234 insertions(+), 235 deletions(-) rename apps/client/{src/shared/assets => public}/fonts/PretendardVariable.woff2 (100%) create mode 100644 apps/client/src/app/providers/auth/AuthContext.tsx create mode 100644 apps/client/src/app/providers/auth/AuthProvider.tsx create mode 100644 apps/client/src/app/providers/auth/types.ts create mode 100644 apps/client/src/app/providers/index.tsx create mode 100644 apps/client/src/app/providers/theme/ThemeContext.tsx create mode 100644 apps/client/src/app/providers/theme/ThemeProvider.tsx create mode 100644 apps/client/src/app/providers/theme/types.ts create mode 100644 apps/client/src/app/routes/config/routerOptions.ts rename apps/client/src/pages/Broadcast/{ => ui}/BroadcastPlayer.tsx (98%) rename apps/client/src/pages/Broadcast/{ => ui}/BroadcastTitle.tsx (95%) rename apps/client/src/pages/Broadcast/{ => ui}/RecordButton.tsx (96%) rename apps/client/src/pages/Home/{ => ui}/Banner.tsx (91%) rename apps/client/src/pages/Home/{ => ui}/Bookmark.tsx (94%) rename apps/client/src/pages/Home/{ => ui}/FieldFilter.tsx (94%) rename apps/client/src/pages/Home/{ => ui}/LiveCard.tsx (100%) rename apps/client/src/pages/Home/{ => ui}/LiveList.tsx (96%) rename apps/client/src/pages/Home/{ => ui}/Search.tsx (89%) rename apps/client/src/pages/Live/{ => ui}/LiveCamperInfo.tsx (87%) rename apps/client/src/pages/Live/{ => ui}/LivePlayer.tsx (96%) rename apps/client/src/pages/Profile/{ => ui}/Attendance.tsx (93%) rename apps/client/src/pages/Profile/{ => ui}/EditUserInfo.tsx (96%) rename apps/client/src/pages/Profile/{ => ui}/UserInfo.tsx (92%) create mode 100644 apps/client/src/pages/Record/RecordPage.tsx rename apps/client/src/pages/Record/{ => ui}/RecordInfo.tsx (100%) rename apps/client/src/pages/Record/{ => ui}/RecordList.tsx (90%) rename apps/client/src/pages/Record/{ => ui}/RecordPlayer.tsx (93%) rename apps/client/src/shared/{services => api}/axios.ts (100%) delete mode 100644 apps/client/src/shared/components/Footer/index.tsx rename apps/client/src/shared/{constants => config}/videoOptions.ts (100%) delete mode 100644 apps/client/src/shared/contexts/AuthContext.tsx delete mode 100644 apps/client/src/shared/contexts/ThemeContext.tsx rename apps/client/src/shared/{hooks => lib/mediasoup}/useConsumer.ts (98%) rename apps/client/src/shared/{hooks => lib/mediasoup}/useProducer.ts (97%) rename apps/client/src/shared/{hooks => lib/mediasoup}/useRoom.ts (100%) rename apps/client/src/shared/{hooks => lib/mediasoup}/useTransport.ts (98%) rename apps/client/src/shared/{hooks => lib/socket}/useSocket.ts (100%) rename apps/client/src/shared/{hooks => lib/toast}/useToast.ts (97%) rename apps/client/src/shared/{hooks => lib}/useAPI.ts (93%) rename apps/client/src/shared/{hooks => lib}/useAuth.ts (92%) rename apps/client/src/shared/{hooks => lib}/useIntersect.ts (100%) rename apps/client/src/shared/{hooks => lib}/useMedia.ts (100%) rename apps/client/src/shared/{hooks => lib}/useScreenShare.ts (100%) rename apps/client/src/shared/{hooks => lib}/useTheme.ts (90%) rename apps/client/src/shared/{ => lib}/utils/utils.ts (100%) rename apps/client/src/shared/{components => ui}/ChatContainer/ChatEndModal.tsx (94%) rename apps/client/src/shared/{components => ui}/ChatContainer/index.tsx (94%) rename apps/client/src/shared/{components => ui}/ErrorCharacter/index.tsx (100%) rename apps/client/src/shared/{components => ui}/FloatingButton/index.tsx (70%) rename apps/client/src/shared/{components => ui}/Header/LogInButton.tsx (88%) rename apps/client/src/shared/{components => ui}/Header/index.tsx (88%) rename apps/client/src/shared/{components => ui}/IconButton/index.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/BlogIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/Character.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/CloseIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/EditIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/ExpandIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/GithubIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/GoogleIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/LinkedInIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/Logo.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/MailIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/MicrophoneOffIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/MicrophoneOnIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/MoveCharacter.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/PauseIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/PlayIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/ScreenShareIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/ScreenShareOffIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/SearchIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/SmileIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/ThemeIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/VideoOffIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/VideoOnIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/VolumeOffIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/VolumeOnIcon.tsx (100%) rename apps/client/src/shared/{components => ui}/Icons/index.ts (100%) rename apps/client/src/shared/{components => ui}/LoadingCharacter/index.tsx (100%) rename apps/client/src/shared/{components => ui}/Modal/index.tsx (96%) rename apps/client/src/shared/{components => ui}/WelcomeCharacter/index.tsx (100%) rename apps/client/src/shared/{components/ui => ui/shadcn}/avatar.tsx (96%) rename apps/client/src/shared/{components/ui => ui/shadcn}/badge.tsx (95%) rename apps/client/src/shared/{components/ui => ui/shadcn}/button.tsx (97%) rename apps/client/src/shared/{components/ui => ui/shadcn}/card.tsx (97%) rename apps/client/src/shared/{components/ui => ui/shadcn}/input.tsx (93%) rename apps/client/src/shared/{components/ui => ui/shadcn}/scroll-area.tsx (97%) rename apps/client/src/shared/{components/ui => ui/shadcn}/select.tsx (99%) rename apps/client/src/shared/{components/ui => ui/shadcn}/toast.tsx (99%) rename apps/client/src/shared/{components/ui => ui/shadcn}/toaster.tsx (87%) diff --git a/apps/client/.eslintignore b/apps/client/.eslintignore index 4213f614..9f76e33a 100644 --- a/apps/client/.eslintignore +++ b/apps/client/.eslintignore @@ -1,5 +1,5 @@ # shadcn/ui 컴포넌트 폴더 무시 -src/shared/components/ui/* +src/shared/ui/shadcn/* # node_modules는 기본적으로 무시되지만, 명시적으로 추가할 수도 있습니다 node_modules/ diff --git a/apps/client/src/shared/assets/fonts/PretendardVariable.woff2 b/apps/client/public/fonts/PretendardVariable.woff2 similarity index 100% rename from apps/client/src/shared/assets/fonts/PretendardVariable.woff2 rename to apps/client/public/fonts/PretendardVariable.woff2 diff --git a/apps/client/src/app/layouts/Layout.tsx b/apps/client/src/app/layouts/Layout.tsx index f3d8615b..bd82bdb5 100644 --- a/apps/client/src/app/layouts/Layout.tsx +++ b/apps/client/src/app/layouts/Layout.tsx @@ -1,21 +1,18 @@ import { Outlet } from 'react-router-dom'; -import Header from '@/shared/components/Header'; -import { AuthProvider } from '@/shared/contexts/AuthContext'; -import { Toaster } from '@/shared/components/ui/toaster'; -import FloatingButton from '@/shared/components/FloatingButton'; -import { ThemeProvider } from '@/shared/contexts/ThemeContext'; +import Header from '@/shared/ui/Header'; +import { Toaster } from '@/shared/ui/shadcn/toaster'; +import FloatingButton from '@/shared/ui/FloatingButton'; +import { Providers } from '../providers'; export function Layout() { return ( - - -
-
- -
- - - - + +
+
+ +
+ + + ); } diff --git a/apps/client/src/app/providers/auth/AuthContext.tsx b/apps/client/src/app/providers/auth/AuthContext.tsx new file mode 100644 index 00000000..92e9406c --- /dev/null +++ b/apps/client/src/app/providers/auth/AuthContext.tsx @@ -0,0 +1,9 @@ +import { createContext } from 'react'; +import { AuthContextValue } from './types'; + +const initialState = { + isLoggedIn: !!localStorage.getItem('accessToken'), + setIsLoggedIn: () => {}, +}; + +export const AuthContext = createContext(initialState); diff --git a/apps/client/src/app/providers/auth/AuthProvider.tsx b/apps/client/src/app/providers/auth/AuthProvider.tsx new file mode 100644 index 00000000..a912a189 --- /dev/null +++ b/apps/client/src/app/providers/auth/AuthProvider.tsx @@ -0,0 +1,8 @@ +import { useMemo, useState } from 'react'; +import { AuthContext } from './AuthContext'; + +export function AuthProvider({ children }: { children: React.ReactNode }) { + const [isLoggedIn, setIsLoggedIn] = useState(() => !!localStorage.getItem('accessToken')); + const value = useMemo(() => ({ isLoggedIn, setIsLoggedIn }), [isLoggedIn, setIsLoggedIn]); + return {children}; +} diff --git a/apps/client/src/app/providers/auth/types.ts b/apps/client/src/app/providers/auth/types.ts new file mode 100644 index 00000000..41ffba88 --- /dev/null +++ b/apps/client/src/app/providers/auth/types.ts @@ -0,0 +1,4 @@ +export type AuthContextValue = { + isLoggedIn: boolean; + setIsLoggedIn: React.Dispatch>; +}; diff --git a/apps/client/src/app/providers/index.tsx b/apps/client/src/app/providers/index.tsx new file mode 100644 index 00000000..eea4db24 --- /dev/null +++ b/apps/client/src/app/providers/index.tsx @@ -0,0 +1,10 @@ +import { ThemeProvider } from '@/app/providers/theme/ThemeProvider'; +import { AuthProvider } from '@/app/providers/auth/AuthProvider'; + +export function Providers({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} diff --git a/apps/client/src/app/providers/theme/ThemeContext.tsx b/apps/client/src/app/providers/theme/ThemeContext.tsx new file mode 100644 index 00000000..fd4ff99d --- /dev/null +++ b/apps/client/src/app/providers/theme/ThemeContext.tsx @@ -0,0 +1,9 @@ +import { createContext } from 'react'; +import { Theme, ThemeContextValue } from './types'; + +const currentTheme = localStorage.getItem('theme') ?? null; + +export const ThemeContext = createContext({ + theme: currentTheme as Theme, + setTheme: () => null, +}); diff --git a/apps/client/src/app/providers/theme/ThemeProvider.tsx b/apps/client/src/app/providers/theme/ThemeProvider.tsx new file mode 100644 index 00000000..3221d946 --- /dev/null +++ b/apps/client/src/app/providers/theme/ThemeProvider.tsx @@ -0,0 +1,9 @@ +import { useMemo, useState } from 'react'; +import { Theme } from './types'; +import { ThemeContext } from './ThemeContext'; + +export function ThemeProvider({ children }: { children: React.ReactNode }) { + const [theme, setTheme] = useState(() => (localStorage.getItem('theme') as Theme) ?? null); + const value = useMemo(() => ({ theme, setTheme }), [theme, setTheme]); + return {children}; +} diff --git a/apps/client/src/app/providers/theme/types.ts b/apps/client/src/app/providers/theme/types.ts new file mode 100644 index 00000000..083c5825 --- /dev/null +++ b/apps/client/src/app/providers/theme/types.ts @@ -0,0 +1,6 @@ +export type Theme = 'light' | 'dark' | null; + +export type ThemeContextValue = { + theme: Theme; + setTheme: React.Dispatch>; +}; diff --git a/apps/client/src/app/routes/ProtectedRoute.tsx b/apps/client/src/app/routes/ProtectedRoute.tsx index e4e0acb9..c85fcf41 100644 --- a/apps/client/src/app/routes/ProtectedRoute.tsx +++ b/apps/client/src/app/routes/ProtectedRoute.tsx @@ -1,6 +1,6 @@ import { useContext } from 'react'; import { Navigate, Outlet } from 'react-router-dom'; -import { AuthContext } from '@/shared/contexts/AuthContext'; +import { AuthContext } from '@/app/providers/auth/AuthContext'; function ProtectedRoute() { const { isLoggedIn } = useContext(AuthContext); diff --git a/apps/client/src/app/routes/config/routerOptions.ts b/apps/client/src/app/routes/config/routerOptions.ts new file mode 100644 index 00000000..9e6604ab --- /dev/null +++ b/apps/client/src/app/routes/config/routerOptions.ts @@ -0,0 +1,10 @@ +export const routerOptions = { + future: { + v7_startTransition: true, + v7_relativeSplatPath: true, + v7_fetcherPersist: true, + v7_normalizeFormMethod: true, + v7_partialHydration: true, + v7_skipActionErrorRevalidation: true, + }, +}; diff --git a/apps/client/src/app/routes/router.tsx b/apps/client/src/app/routes/router.tsx index 8c2df908..8783d2a0 100644 --- a/apps/client/src/app/routes/router.tsx +++ b/apps/client/src/app/routes/router.tsx @@ -4,20 +4,10 @@ import { ProfilePage } from '@pages/Profile'; import { LivePage } from '@pages/Live'; import { BroadcastPage } from '@pages/Broadcast'; import { AuthPage } from '@pages/Auth'; -import Record from '@pages/Record'; +import { RecordPage } from '@pages/Record'; import { Layout } from '@/app/layouts'; import ProtectedRoute from './ProtectedRoute'; - -const routerOptions = { - future: { - v7_startTransition: true, - v7_relativeSplatPath: true, - v7_fetcherPersist: true, - v7_normalizeFormMethod: true, - v7_partialHydration: true, - v7_skipActionErrorRevalidation: true, - }, -}; +import { routerOptions } from './config/routerOptions'; export const router = createBrowserRouter( [ @@ -48,7 +38,7 @@ export const router = createBrowserRouter( { path: 'record/:attendanceId', - element: , + element: , }, ], }, diff --git a/apps/client/src/index.css b/apps/client/src/index.css index edd9eefb..0626b23c 100644 --- a/apps/client/src/index.css +++ b/apps/client/src/index.css @@ -4,7 +4,7 @@ @font-face { font-family: 'Pretendard'; - src: url('./assets/fonts/PretendardVariable.woff2') format('woff2'); + src: url('/fonts/PretendardVariable.woff2') format('woff2'); font-weight: 100 900; font-style: normal; } diff --git a/apps/client/src/pages/Auth/AuthPage.tsx b/apps/client/src/pages/Auth/AuthPage.tsx index 3c296b11..606d3077 100644 --- a/apps/client/src/pages/Auth/AuthPage.tsx +++ b/apps/client/src/pages/Auth/AuthPage.tsx @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react'; import { useNavigate, useSearchParams } from 'react-router-dom'; -import ErrorCharacter from '@/shared/components/ErrorCharacter'; -import { useAuth } from '@/shared/hooks/useAuth'; +import ErrorCharacter from '@/shared/ui/ErrorCharacter'; +import { useAuth } from '@/shared/lib/useAuth'; export function AuthPage() { const [searchParams] = useSearchParams(); diff --git a/apps/client/src/pages/Broadcast/BroadcastPage.tsx b/apps/client/src/pages/Broadcast/BroadcastPage.tsx index 03e211c5..7ed75946 100644 --- a/apps/client/src/pages/Broadcast/BroadcastPage.tsx +++ b/apps/client/src/pages/Broadcast/BroadcastPage.tsx @@ -1,11 +1,11 @@ import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'; -import ChatContainer from '@/shared/components/ChatContainer'; -import ErrorCharacter from '@/shared/components/ErrorCharacter'; -import { useProducer } from '@/shared/hooks/useProducer'; -import { useRoom } from '@/shared/hooks/useRoom'; -import { useSocket } from '@/shared/hooks/useSocket'; -import { useTransport } from '@/shared/hooks/useTransport'; -import { Button } from '@/shared/components/ui/button'; +import ChatContainer from '@/shared/ui/ChatContainer'; +import ErrorCharacter from '@/shared/ui/ErrorCharacter'; +import { useProducer } from '@/shared/lib/mediasoup/useProducer'; +import { useRoom } from '@/shared/lib/mediasoup/useRoom'; +import { useSocket } from '@/shared/lib/socket/useSocket'; +import { useTransport } from '@/shared/lib/mediasoup/useTransport'; +import { Button } from '@/shared/ui/shadcn/button'; import { MicrophoneOffIcon, MicrophoneOnIcon, @@ -13,15 +13,15 @@ import { VideoOnIcon, ScreenShareIcon, ScreenShareIconOff, -} from '@/shared/components/Icons'; -import BroadcastTitle from './BroadcastTitle'; -import useScreenShare from '@/shared/hooks/useScreenShare'; -import BroadcastPlayer from './BroadcastPlayer'; +} from '@/shared/ui/Icons'; +import BroadcastTitle from './ui/BroadcastTitle'; +import useScreenShare from '@/shared/lib/useScreenShare'; +import BroadcastPlayer from './ui/BroadcastPlayer'; import { Tracks } from '@/shared/types/mediasoupTypes'; -import RecordButton from './RecordButton'; -import axiosInstance from '@/shared/services/axios'; -import { useMedia } from '@/shared/hooks/useMedia'; -import { useTheme } from '@/shared/hooks/useTheme'; +import RecordButton from './ui/RecordButton'; +import axiosInstance from '@/shared/api/axios'; +import { useMedia } from '@/shared/lib/useMedia'; +import { useTheme } from '@/shared/lib/useTheme'; const mediaServerUrl = import.meta.env.VITE_MEDIASERVER_URL; diff --git a/apps/client/src/pages/Broadcast/BroadcastPlayer.tsx b/apps/client/src/pages/Broadcast/ui/BroadcastPlayer.tsx similarity index 98% rename from apps/client/src/pages/Broadcast/BroadcastPlayer.tsx rename to apps/client/src/pages/Broadcast/ui/BroadcastPlayer.tsx index 6e982d64..1733e19f 100644 --- a/apps/client/src/pages/Broadcast/BroadcastPlayer.tsx +++ b/apps/client/src/pages/Broadcast/ui/BroadcastPlayer.tsx @@ -1,5 +1,5 @@ import { useEffect, useRef } from 'react'; -import { RESOLUTION_OPTIONS } from '@/shared/constants/videoOptions'; +import { RESOLUTION_OPTIONS } from '@/shared/config/videoOptions'; import { Tracks } from '@/shared/types/mediasoupTypes'; type BroadcastPlayerProps = { diff --git a/apps/client/src/pages/Broadcast/BroadcastTitle.tsx b/apps/client/src/pages/Broadcast/ui/BroadcastTitle.tsx similarity index 95% rename from apps/client/src/pages/Broadcast/BroadcastTitle.tsx rename to apps/client/src/pages/Broadcast/ui/BroadcastTitle.tsx index 7ecbeca9..33fb8f91 100644 --- a/apps/client/src/pages/Broadcast/BroadcastTitle.tsx +++ b/apps/client/src/pages/Broadcast/ui/BroadcastTitle.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import { useForm, SubmitHandler } from 'react-hook-form'; -import { Button } from '@/shared/components/ui/button'; -import axiosInstance from '@/shared/services/axios'; +import { Button } from '@/shared/ui/shadcn/button'; +import axiosInstance from '@/shared/api/axios'; type Inputs = { title: string; diff --git a/apps/client/src/pages/Broadcast/RecordButton.tsx b/apps/client/src/pages/Broadcast/ui/RecordButton.tsx similarity index 96% rename from apps/client/src/pages/Broadcast/RecordButton.tsx rename to apps/client/src/pages/Broadcast/ui/RecordButton.tsx index 056e1a10..8b74d74a 100644 --- a/apps/client/src/pages/Broadcast/RecordButton.tsx +++ b/apps/client/src/pages/Broadcast/ui/RecordButton.tsx @@ -2,8 +2,8 @@ import { useEffect, useState } from 'react'; import { createPortal } from 'react-dom'; import { useForm } from 'react-hook-form'; import { Socket } from 'socket.io-client'; -import { Button } from '@/shared/components/ui/button'; -import Modal from '@/shared/components/Modal'; +import { Button } from '@/shared/ui/shadcn/button'; +import Modal from '@/shared/ui/Modal'; type FormInput = { title: string; diff --git a/apps/client/src/pages/Home/HomePage.tsx b/apps/client/src/pages/Home/HomePage.tsx index 3e8198f2..ad9f285a 100644 --- a/apps/client/src/pages/Home/HomePage.tsx +++ b/apps/client/src/pages/Home/HomePage.tsx @@ -1,5 +1,5 @@ -import LiveList from '@pages/Home/LiveList'; -import Banner from './Banner'; +import LiveList from '@/pages/Home/ui/LiveList'; +import Banner from './ui/Banner'; export function HomePage() { return ( diff --git a/apps/client/src/pages/Home/Banner.tsx b/apps/client/src/pages/Home/ui/Banner.tsx similarity index 91% rename from apps/client/src/pages/Home/Banner.tsx rename to apps/client/src/pages/Home/ui/Banner.tsx index 63b6cefc..f7b99bbf 100644 --- a/apps/client/src/pages/Home/Banner.tsx +++ b/apps/client/src/pages/Home/ui/Banner.tsx @@ -1,4 +1,4 @@ -import MoveCharacter from '@/shared/components/Icons/MoveCharacter'; +import MoveCharacter from '@/shared/ui/Icons/MoveCharacter'; import Bookmark from './Bookmark'; function Banner() { diff --git a/apps/client/src/pages/Home/Bookmark.tsx b/apps/client/src/pages/Home/ui/Bookmark.tsx similarity index 94% rename from apps/client/src/pages/Home/Bookmark.tsx rename to apps/client/src/pages/Home/ui/Bookmark.tsx index 07b997ac..caca6b65 100644 --- a/apps/client/src/pages/Home/Bookmark.tsx +++ b/apps/client/src/pages/Home/ui/Bookmark.tsx @@ -1,12 +1,12 @@ import { createPortal } from 'react-dom'; import { useForm } from 'react-hook-form'; import { useContext, useEffect, useState } from 'react'; -import Modal from '@/shared/components/Modal'; -import { Button } from '@/shared/components/ui/button'; -import { useToast } from '@/shared/hooks/useToast'; -import { AuthContext } from '@/shared/contexts/AuthContext'; -import axiosInstance from '@/shared/services/axios'; -import { CloseIcon } from '@/shared/components/Icons'; +import Modal from '@/shared/ui/Modal'; +import { Button } from '@/shared/ui/shadcn/button'; +import { useToast } from '@/shared/lib/toast/useToast'; +import { AuthContext } from '@/app/providers/auth/AuthContext'; +import axiosInstance from '@/shared/api/axios'; +import { CloseIcon } from '@/shared/ui/Icons'; type BookmarkData = { bookmarkId: number; diff --git a/apps/client/src/pages/Home/FieldFilter.tsx b/apps/client/src/pages/Home/ui/FieldFilter.tsx similarity index 94% rename from apps/client/src/pages/Home/FieldFilter.tsx rename to apps/client/src/pages/Home/ui/FieldFilter.tsx index 43be438a..8587d786 100644 --- a/apps/client/src/pages/Home/FieldFilter.tsx +++ b/apps/client/src/pages/Home/ui/FieldFilter.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { Button } from '@/shared/components/ui/button'; +import { Button } from '@/shared/ui/shadcn/button'; import { Field } from '@/shared/types/liveTypes'; const fields: Field[] = ['WEB', 'AND', 'IOS']; diff --git a/apps/client/src/pages/Home/LiveCard.tsx b/apps/client/src/pages/Home/ui/LiveCard.tsx similarity index 100% rename from apps/client/src/pages/Home/LiveCard.tsx rename to apps/client/src/pages/Home/ui/LiveCard.tsx diff --git a/apps/client/src/pages/Home/LiveList.tsx b/apps/client/src/pages/Home/ui/LiveList.tsx similarity index 96% rename from apps/client/src/pages/Home/LiveList.tsx rename to apps/client/src/pages/Home/ui/LiveList.tsx index d900df74..22544f8c 100644 --- a/apps/client/src/pages/Home/LiveList.tsx +++ b/apps/client/src/pages/Home/ui/LiveList.tsx @@ -1,11 +1,11 @@ import { useCallback, useEffect, useState } from 'react'; -import axiosInstance from '@/shared/services/axios'; +import axiosInstance from '@/shared/api/axios'; import FieldFilter from './FieldFilter'; import LiveCard from './LiveCard'; import { LivePreviewInfo } from '@/shared/types/homeTypes'; import Search from './Search'; import { Field } from '@/shared/types/liveTypes'; -import { useIntersect } from '@/shared/hooks/useIntersect'; +import { useIntersect } from '@/shared/lib/useIntersect'; const LIMIT = 12; diff --git a/apps/client/src/pages/Home/Search.tsx b/apps/client/src/pages/Home/ui/Search.tsx similarity index 89% rename from apps/client/src/pages/Home/Search.tsx rename to apps/client/src/pages/Home/ui/Search.tsx index 7791ce1c..88d9313d 100644 --- a/apps/client/src/pages/Home/Search.tsx +++ b/apps/client/src/pages/Home/ui/Search.tsx @@ -1,6 +1,6 @@ import { useForm } from 'react-hook-form'; -import IconButton from '@/shared/components/IconButton'; -import { SearchIcon } from '@/shared/components/Icons'; +import IconButton from '@/shared/ui/IconButton'; +import { SearchIcon } from '@/shared/ui/Icons'; type SearchProps = { onSearch: (keyword: string) => void; diff --git a/apps/client/src/pages/Live/LivePage.tsx b/apps/client/src/pages/Live/LivePage.tsx index e7a6feb3..c71d09d8 100644 --- a/apps/client/src/pages/Live/LivePage.tsx +++ b/apps/client/src/pages/Live/LivePage.tsx @@ -1,12 +1,12 @@ import { useEffect } from 'react'; import { useParams } from 'react-router-dom'; -import ChatContainer from '@/shared/components/ChatContainer'; -import ErrorCharacter from '@/shared/components/ErrorCharacter'; -import { useConsumer } from '@/shared/hooks/useConsumer'; -import { useSocket } from '@/shared/hooks/useSocket'; -import { useTransport } from '@/shared/hooks/useTransport'; -import LivePlayer from './LivePlayer'; -import LiveCamperInfo from './LiveCamperInfo'; +import ChatContainer from '@/shared/ui/ChatContainer'; +import ErrorCharacter from '@/shared/ui/ErrorCharacter'; +import { useConsumer } from '@/shared/lib/mediasoup/useConsumer'; +import { useSocket } from '@/shared/lib/socket/useSocket'; +import { useTransport } from '@/shared/lib/mediasoup/useTransport'; +import LivePlayer from './ui/LivePlayer'; +import LiveCamperInfo from './ui/LiveCamperInfo'; const socketUrl = import.meta.env.VITE_MEDIASERVER_URL; diff --git a/apps/client/src/pages/Live/LiveCamperInfo.tsx b/apps/client/src/pages/Live/ui/LiveCamperInfo.tsx similarity index 87% rename from apps/client/src/pages/Live/LiveCamperInfo.tsx rename to apps/client/src/pages/Live/ui/LiveCamperInfo.tsx index 0ac6d751..7eaf98f9 100644 --- a/apps/client/src/pages/Live/LiveCamperInfo.tsx +++ b/apps/client/src/pages/Live/ui/LiveCamperInfo.tsx @@ -1,11 +1,11 @@ -import { Avatar, AvatarFallback, AvatarImage } from '@/shared/components/ui/avatar'; -import { Badge } from '@/shared/components/ui/badge'; -import IconButton from '@/shared/components/IconButton'; -import { useAPI } from '@/shared/hooks/useAPI'; -import LoadingCharacter from '@/shared/components/LoadingCharacter'; -import ErrorCharacter from '@/shared/components/ErrorCharacter'; +import { Avatar, AvatarFallback, AvatarImage } from '@/shared/ui/shadcn/avatar'; +import { Badge } from '@/shared/ui/shadcn/badge'; +import IconButton from '@/shared/ui/IconButton'; +import { useAPI } from '@/shared/lib/useAPI'; +import LoadingCharacter from '@/shared/ui/LoadingCharacter'; +import ErrorCharacter from '@/shared/ui/ErrorCharacter'; import { LiveInfo } from '@/shared/types/liveTypes'; -import { MailIcon, GithubIcon, BlogIcon, LinkedInIcon } from '@/shared/components/Icons'; +import { MailIcon, GithubIcon, BlogIcon, LinkedInIcon } from '@/shared/ui/Icons'; function LiveCamperInfo({ liveId }: { liveId: string }) { const { data, isLoading, error } = useAPI({ url: `v1/broadcasts/${liveId}/info` }); diff --git a/apps/client/src/pages/Live/LivePlayer.tsx b/apps/client/src/pages/Live/ui/LivePlayer.tsx similarity index 96% rename from apps/client/src/pages/Live/LivePlayer.tsx rename to apps/client/src/pages/Live/ui/LivePlayer.tsx index 1c3cb3ee..5be15637 100644 --- a/apps/client/src/pages/Live/LivePlayer.tsx +++ b/apps/client/src/pages/Live/ui/LivePlayer.tsx @@ -1,8 +1,8 @@ import { useEffect, useRef, useState } from 'react'; import { Socket } from 'socket.io-client'; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/shared/components/ui/select'; -import { PlayIcon, PauseIcon, VolumeOffIcon, VolumeOnIcon, ExpandIcon } from '@/shared/components/Icons'; -import ErrorCharacter from '@/shared/components/ErrorCharacter'; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/shared/ui/shadcn/select'; +import { PlayIcon, PauseIcon, VolumeOffIcon, VolumeOnIcon, ExpandIcon } from '@/shared/ui/Icons'; +import ErrorCharacter from '@/shared/ui/ErrorCharacter'; type Errors = { socketError: Error | null; diff --git a/apps/client/src/pages/Profile/ProfilePage.tsx b/apps/client/src/pages/Profile/ProfilePage.tsx index 3f4810a1..6f29763c 100644 --- a/apps/client/src/pages/Profile/ProfilePage.tsx +++ b/apps/client/src/pages/Profile/ProfilePage.tsx @@ -1,11 +1,11 @@ import { useEffect, useState } from 'react'; -import Attendance from './Attendance'; -import UserInfo from './UserInfo'; -import EditUserInfo from './EditUserInfo'; -import axiosInstance from '@/shared/services/axios'; +import Attendance from './ui/Attendance'; +import UserInfo from './ui/UserInfo'; +import EditUserInfo from './ui/EditUserInfo'; +import axiosInstance from '@/shared/api/axios'; import { Field } from '@/shared/types/liveTypes'; -import ErrorCharacter from '@/shared/components/ErrorCharacter'; -import LoadingCharacter from '@/shared/components/LoadingCharacter'; +import ErrorCharacter from '@/shared/ui/ErrorCharacter'; +import LoadingCharacter from '@/shared/ui/LoadingCharacter'; export type Contacts = { email: string; diff --git a/apps/client/src/pages/Profile/Attendance.tsx b/apps/client/src/pages/Profile/ui/Attendance.tsx similarity index 93% rename from apps/client/src/pages/Profile/Attendance.tsx rename to apps/client/src/pages/Profile/ui/Attendance.tsx index 770693f7..f5908e78 100644 --- a/apps/client/src/pages/Profile/Attendance.tsx +++ b/apps/client/src/pages/Profile/ui/Attendance.tsx @@ -1,9 +1,9 @@ import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import ErrorCharacter from '@/shared/components/ErrorCharacter'; -import { PlayIcon } from '@/shared/components/Icons'; -import LoadingCharacter from '@/shared/components/LoadingCharacter'; -import axiosInstance from '@/shared/services/axios'; +import ErrorCharacter from '@/shared/ui/ErrorCharacter'; +import { PlayIcon } from '@/shared/ui/Icons'; +import LoadingCharacter from '@/shared/ui/LoadingCharacter'; +import axiosInstance from '@/shared/api/axios'; type AttendanceData = { attendanceId: number; diff --git a/apps/client/src/pages/Profile/EditUserInfo.tsx b/apps/client/src/pages/Profile/ui/EditUserInfo.tsx similarity index 96% rename from apps/client/src/pages/Profile/EditUserInfo.tsx rename to apps/client/src/pages/Profile/ui/EditUserInfo.tsx index 63b1e009..32f97b95 100644 --- a/apps/client/src/pages/Profile/EditUserInfo.tsx +++ b/apps/client/src/pages/Profile/ui/EditUserInfo.tsx @@ -1,11 +1,11 @@ import { useForm } from 'react-hook-form'; import { useState } from 'react'; -import { Avatar, AvatarFallback, AvatarImage } from '@/shared/components/ui/avatar'; -import { UserData } from './ProfilePage'; +import { Avatar, AvatarFallback, AvatarImage } from '@/shared/ui/shadcn/avatar'; +import { UserData } from '../ProfilePage'; import { Field } from '@/shared/types/liveTypes'; -import { Button } from '@/shared/components/ui/button'; -import axiosInstance from '@/shared/services/axios'; -import { useToast } from '@/shared/hooks/useToast'; +import { Button } from '@/shared/ui/shadcn/button'; +import axiosInstance from '@/shared/api/axios'; +import { useToast } from '@/shared/lib/toast/useToast'; type EditUserInfoProps = { userData: UserData | undefined; diff --git a/apps/client/src/pages/Profile/UserInfo.tsx b/apps/client/src/pages/Profile/ui/UserInfo.tsx similarity index 92% rename from apps/client/src/pages/Profile/UserInfo.tsx rename to apps/client/src/pages/Profile/ui/UserInfo.tsx index 9d7fb649..88b9cdef 100644 --- a/apps/client/src/pages/Profile/UserInfo.tsx +++ b/apps/client/src/pages/Profile/ui/UserInfo.tsx @@ -1,9 +1,9 @@ import { useEffect, useState } from 'react'; -import ErrorCharacter from '@/shared/components/ErrorCharacter'; -import { BlogIcon, EditIcon, GithubIcon, LinkedInIcon, MailIcon } from '@/shared/components/Icons'; -import LoadingCharacter from '@/shared/components/LoadingCharacter'; -import { Avatar, AvatarFallback, AvatarImage } from '@/shared/components/ui/avatar'; -import { UserData } from './ProfilePage'; +import ErrorCharacter from '@/shared/ui/ErrorCharacter'; +import { BlogIcon, EditIcon, GithubIcon, LinkedInIcon, MailIcon } from '@/shared/ui/Icons'; +import LoadingCharacter from '@/shared/ui/LoadingCharacter'; +import { Avatar, AvatarFallback, AvatarImage } from '@/shared/ui/shadcn/avatar'; +import { UserData } from '../ProfilePage'; type UserInfoProps = { userData: UserData | undefined; diff --git a/apps/client/src/pages/Record/RecordPage.tsx b/apps/client/src/pages/Record/RecordPage.tsx new file mode 100644 index 00000000..d025e4c4 --- /dev/null +++ b/apps/client/src/pages/Record/RecordPage.tsx @@ -0,0 +1,27 @@ +import { useState } from 'react'; +import RecordInfo from './ui/RecordInfo'; +import RecordList from './ui/RecordList'; +import RecordPlayer from './ui/RecordPlayer'; + +export type RecordData = { + recordId: number; + title: string; + video: string; + date: string; +}; + +export function RecordPage() { + const [nowPlaying, setIsNowPlaying] = useState({ recordId: 0, title: '', video: '', date: '' }); + + return ( +
+
+ + +
+
+ +
+
+ ); +} diff --git a/apps/client/src/pages/Record/index.tsx b/apps/client/src/pages/Record/index.tsx index a8c52a6b..b1875c25 100644 --- a/apps/client/src/pages/Record/index.tsx +++ b/apps/client/src/pages/Record/index.tsx @@ -1,29 +1 @@ -import { useState } from 'react'; -import RecordInfo from './RecordInfo'; -import RecordList from './RecordList'; -import RecordPlayer from './RecordPlayer'; - -export type RecordData = { - recordId: number; - title: string; - video: string; - date: string; -}; - -function Record() { - const [nowPlaying, setIsNowPlaying] = useState({ recordId: 0, title: '', video: '', date: '' }); - - return ( -
-
- - -
-
- -
-
- ); -} - -export default Record; +export { RecordPage } from './RecordPage'; diff --git a/apps/client/src/pages/Record/RecordInfo.tsx b/apps/client/src/pages/Record/ui/RecordInfo.tsx similarity index 100% rename from apps/client/src/pages/Record/RecordInfo.tsx rename to apps/client/src/pages/Record/ui/RecordInfo.tsx diff --git a/apps/client/src/pages/Record/RecordList.tsx b/apps/client/src/pages/Record/ui/RecordList.tsx similarity index 90% rename from apps/client/src/pages/Record/RecordList.tsx rename to apps/client/src/pages/Record/ui/RecordList.tsx index 30b297cd..a0c7782a 100644 --- a/apps/client/src/pages/Record/RecordList.tsx +++ b/apps/client/src/pages/Record/ui/RecordList.tsx @@ -1,9 +1,9 @@ import { useEffect, useState } from 'react'; import { useParams } from 'react-router-dom'; -import { PlayIcon } from '@/shared/components/Icons'; -import { RecordData } from '.'; -import axiosInstance from '@/shared/services/axios'; -import ErrorCharacter from '@/shared/components/ErrorCharacter'; +import { PlayIcon } from '@/shared/ui/Icons'; +import { RecordData } from '../RecordPage'; +import axiosInstance from '@/shared/api/axios'; +import ErrorCharacter from '@/shared/ui/ErrorCharacter'; type RecordListProps = { onClickList: (data: RecordData) => void; diff --git a/apps/client/src/pages/Record/RecordPlayer.tsx b/apps/client/src/pages/Record/ui/RecordPlayer.tsx similarity index 93% rename from apps/client/src/pages/Record/RecordPlayer.tsx rename to apps/client/src/pages/Record/ui/RecordPlayer.tsx index d8127473..fa84867d 100644 --- a/apps/client/src/pages/Record/RecordPlayer.tsx +++ b/apps/client/src/pages/Record/ui/RecordPlayer.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; import ReactPlayer from 'react-player'; -import LoadingCharacter from '@/shared/components/LoadingCharacter'; +import LoadingCharacter from '@/shared/ui/LoadingCharacter'; type RecordPlayerProps = { video: string; diff --git a/apps/client/src/shared/services/axios.ts b/apps/client/src/shared/api/axios.ts similarity index 100% rename from apps/client/src/shared/services/axios.ts rename to apps/client/src/shared/api/axios.ts diff --git a/apps/client/src/shared/components/Footer/index.tsx b/apps/client/src/shared/components/Footer/index.tsx deleted file mode 100644 index bfccfe88..00000000 --- a/apps/client/src/shared/components/Footer/index.tsx +++ /dev/null @@ -1,12 +0,0 @@ -function Footer() { - return ( - - ); -} -export default Footer; diff --git a/apps/client/src/shared/constants/videoOptions.ts b/apps/client/src/shared/config/videoOptions.ts similarity index 100% rename from apps/client/src/shared/constants/videoOptions.ts rename to apps/client/src/shared/config/videoOptions.ts diff --git a/apps/client/src/shared/contexts/AuthContext.tsx b/apps/client/src/shared/contexts/AuthContext.tsx deleted file mode 100644 index fcb240c4..00000000 --- a/apps/client/src/shared/contexts/AuthContext.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React, { createContext, useMemo, useState } from 'react'; - -type AuthContextInterface = { - isLoggedIn: boolean; - setIsLoggedIn: React.Dispatch>; -}; - -const initialState = { - isLoggedIn: !!localStorage.getItem('accessToken'), - setIsLoggedIn: () => {}, -}; - -export const AuthContext = createContext(initialState); - -export function AuthProvider({ children }: { children: React.ReactNode }) { - const [isLoggedIn, setIsLoggedIn] = useState(() => !!localStorage.getItem('accessToken')); - const value = useMemo(() => ({ isLoggedIn, setIsLoggedIn }), [isLoggedIn, setIsLoggedIn]); - return {children}; -} diff --git a/apps/client/src/shared/contexts/ThemeContext.tsx b/apps/client/src/shared/contexts/ThemeContext.tsx deleted file mode 100644 index 73b1b9ef..00000000 --- a/apps/client/src/shared/contexts/ThemeContext.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { createContext, useMemo, useState } from 'react'; - -type Theme = 'light' | 'dark' | null; - -type ThemeContextInterface = { - theme: Theme; - setTheme: React.Dispatch>; -}; - -const currentTheme = localStorage.getItem('theme') ?? null; - -export const ThemeContext = createContext({ - theme: currentTheme as Theme, - setTheme: () => null, -}); - -export function ThemeProvider({ children }: { children: React.ReactNode }) { - const [theme, setTheme] = useState(() => (localStorage.getItem('theme') as Theme) ?? null); - const value = useMemo(() => ({ theme, setTheme }), [theme, setTheme]); - return {children}; -} diff --git a/apps/client/src/shared/hooks/useConsumer.ts b/apps/client/src/shared/lib/mediasoup/useConsumer.ts similarity index 98% rename from apps/client/src/shared/hooks/useConsumer.ts rename to apps/client/src/shared/lib/mediasoup/useConsumer.ts index c0da4c1a..7936761f 100644 --- a/apps/client/src/shared/hooks/useConsumer.ts +++ b/apps/client/src/shared/lib/mediasoup/useConsumer.ts @@ -1,7 +1,7 @@ import { useEffect, useRef, useState } from 'react'; import { Transport, Device, MediaKind } from 'mediasoup-client/lib/types'; import { Socket } from 'socket.io-client'; -import { checkDependencies } from '@/shared/utils/utils'; +import { checkDependencies } from '@/shared/lib/utils/utils'; import { ConnectTransportResponse, TransportInfo } from '@/shared/types/mediasoupTypes'; type UseConsumerProps = { diff --git a/apps/client/src/shared/hooks/useProducer.ts b/apps/client/src/shared/lib/mediasoup/useProducer.ts similarity index 97% rename from apps/client/src/shared/hooks/useProducer.ts rename to apps/client/src/shared/lib/mediasoup/useProducer.ts index 9dc1e3e2..c5b5ef64 100644 --- a/apps/client/src/shared/hooks/useProducer.ts +++ b/apps/client/src/shared/lib/mediasoup/useProducer.ts @@ -2,8 +2,8 @@ import { useEffect, useRef, useState } from 'react'; import { Transport, Device, Producer } from 'mediasoup-client/lib/types'; import { Socket } from 'socket.io-client'; import { ConnectTransportResponse, TransportInfo } from '@/shared/types/mediasoupTypes'; -import { checkDependencies } from '@/shared/utils/utils'; -import { ENCODING_OPTIONS } from '@/shared/constants/videoOptions'; +import { checkDependencies } from '@/shared/lib/utils/utils'; +import { ENCODING_OPTIONS } from '@/shared/config/videoOptions'; type UseProducerProps = { socket: Socket | null; diff --git a/apps/client/src/shared/hooks/useRoom.ts b/apps/client/src/shared/lib/mediasoup/useRoom.ts similarity index 100% rename from apps/client/src/shared/hooks/useRoom.ts rename to apps/client/src/shared/lib/mediasoup/useRoom.ts diff --git a/apps/client/src/shared/hooks/useTransport.ts b/apps/client/src/shared/lib/mediasoup/useTransport.ts similarity index 98% rename from apps/client/src/shared/hooks/useTransport.ts rename to apps/client/src/shared/lib/mediasoup/useTransport.ts index 39ed4d54..93de43a8 100644 --- a/apps/client/src/shared/hooks/useTransport.ts +++ b/apps/client/src/shared/lib/mediasoup/useTransport.ts @@ -3,7 +3,7 @@ import { useEffect, useState, useRef } from 'react'; import { RtpCapabilities } from 'mediasoup-client/lib/RtpParameters'; import { Device } from 'mediasoup-client/lib/types'; import { Socket } from 'socket.io-client'; -import { checkDependencies } from '@/shared/utils/utils'; +import { checkDependencies } from '@/shared/lib/utils/utils'; import { TransportInfo } from '@/shared/types/mediasoupTypes'; type UseTransportProps = { diff --git a/apps/client/src/shared/hooks/useSocket.ts b/apps/client/src/shared/lib/socket/useSocket.ts similarity index 100% rename from apps/client/src/shared/hooks/useSocket.ts rename to apps/client/src/shared/lib/socket/useSocket.ts diff --git a/apps/client/src/shared/hooks/useToast.ts b/apps/client/src/shared/lib/toast/useToast.ts similarity index 97% rename from apps/client/src/shared/hooks/useToast.ts rename to apps/client/src/shared/lib/toast/useToast.ts index 969b307e..4b55fe82 100644 --- a/apps/client/src/shared/hooks/useToast.ts +++ b/apps/client/src/shared/lib/toast/useToast.ts @@ -4,7 +4,7 @@ // Inspired by react-hot-toast library import * as React from 'react'; -import type { ToastActionElement, ToastProps } from '@/shared/components/ui/toast'; +import type { ToastActionElement, ToastProps } from '@/shared/ui/shadcn/toast'; const TOAST_LIMIT = 1; const TOAST_REMOVE_DELAY = 1000000; diff --git a/apps/client/src/shared/hooks/useAPI.ts b/apps/client/src/shared/lib/useAPI.ts similarity index 93% rename from apps/client/src/shared/hooks/useAPI.ts rename to apps/client/src/shared/lib/useAPI.ts index b0bf7ce2..1cddb0f3 100644 --- a/apps/client/src/shared/hooks/useAPI.ts +++ b/apps/client/src/shared/lib/useAPI.ts @@ -1,6 +1,6 @@ import { AxiosRequestConfig } from 'axios'; import { useEffect, useState } from 'react'; -import axiosInstance from '@/shared/services/axios'; +import axiosInstance from '@/shared/api/axios'; type APIQueryState = { data: T | null; diff --git a/apps/client/src/shared/hooks/useAuth.ts b/apps/client/src/shared/lib/useAuth.ts similarity index 92% rename from apps/client/src/shared/hooks/useAuth.ts rename to apps/client/src/shared/lib/useAuth.ts index 2fa91ff8..fd8c616d 100644 --- a/apps/client/src/shared/hooks/useAuth.ts +++ b/apps/client/src/shared/lib/useAuth.ts @@ -1,6 +1,6 @@ import { useContext, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; -import { AuthContext } from '@/shared/contexts/AuthContext'; +import { AuthContext } from '@/app/providers/auth/AuthContext'; export const useAuth = () => { const navigate = useNavigate(); diff --git a/apps/client/src/shared/hooks/useIntersect.ts b/apps/client/src/shared/lib/useIntersect.ts similarity index 100% rename from apps/client/src/shared/hooks/useIntersect.ts rename to apps/client/src/shared/lib/useIntersect.ts diff --git a/apps/client/src/shared/hooks/useMedia.ts b/apps/client/src/shared/lib/useMedia.ts similarity index 100% rename from apps/client/src/shared/hooks/useMedia.ts rename to apps/client/src/shared/lib/useMedia.ts diff --git a/apps/client/src/shared/hooks/useScreenShare.ts b/apps/client/src/shared/lib/useScreenShare.ts similarity index 100% rename from apps/client/src/shared/hooks/useScreenShare.ts rename to apps/client/src/shared/lib/useScreenShare.ts diff --git a/apps/client/src/shared/hooks/useTheme.ts b/apps/client/src/shared/lib/useTheme.ts similarity index 90% rename from apps/client/src/shared/hooks/useTheme.ts rename to apps/client/src/shared/lib/useTheme.ts index 9a321e19..8a884d21 100644 --- a/apps/client/src/shared/hooks/useTheme.ts +++ b/apps/client/src/shared/lib/useTheme.ts @@ -1,5 +1,5 @@ import { useContext, useLayoutEffect } from 'react'; -import { ThemeContext } from '@/shared/contexts/ThemeContext'; +import { ThemeContext } from '@/app/providers/theme/ThemeContext'; export const useTheme = () => { const { theme, setTheme } = useContext(ThemeContext); diff --git a/apps/client/src/shared/utils/utils.ts b/apps/client/src/shared/lib/utils/utils.ts similarity index 100% rename from apps/client/src/shared/utils/utils.ts rename to apps/client/src/shared/lib/utils/utils.ts diff --git a/apps/client/src/shared/components/ChatContainer/ChatEndModal.tsx b/apps/client/src/shared/ui/ChatContainer/ChatEndModal.tsx similarity index 94% rename from apps/client/src/shared/components/ChatContainer/ChatEndModal.tsx rename to apps/client/src/shared/ui/ChatContainer/ChatEndModal.tsx index beb1663d..8b51b64a 100644 --- a/apps/client/src/shared/components/ChatContainer/ChatEndModal.tsx +++ b/apps/client/src/shared/ui/ChatContainer/ChatEndModal.tsx @@ -1,5 +1,5 @@ import { useNavigate } from 'react-router-dom'; -import Modal from '@/shared/components/Modal'; +import Modal from '@/shared/ui/Modal'; type ChatEndModalProps = { setShowModal: (b: boolean) => void; diff --git a/apps/client/src/shared/components/ChatContainer/index.tsx b/apps/client/src/shared/ui/ChatContainer/index.tsx similarity index 94% rename from apps/client/src/shared/components/ChatContainer/index.tsx rename to apps/client/src/shared/ui/ChatContainer/index.tsx index 996aa1f9..a52c4a5d 100644 --- a/apps/client/src/shared/components/ChatContainer/index.tsx +++ b/apps/client/src/shared/ui/ChatContainer/index.tsx @@ -1,11 +1,11 @@ import { useState, useEffect, useRef, useContext } from 'react'; import { createPortal } from 'react-dom'; -import { Card, CardHeader, CardTitle, CardContent, CardFooter } from '@/shared/components/ui/card'; -import { Input } from '@/shared/components/ui/input'; -import { useSocket } from '@/shared/hooks/useSocket'; -import ErrorCharacter from '@/shared/components/ErrorCharacter'; -import { AuthContext } from '@/shared/contexts/AuthContext'; -import { SmileIcon } from '@/shared/components/Icons'; +import { Card, CardHeader, CardTitle, CardContent, CardFooter } from '@/shared/ui/shadcn/card'; +import { Input } from '@/shared/ui/shadcn/input'; +import { useSocket } from '@/shared/lib/socket/useSocket'; +import ErrorCharacter from '@/shared/ui/ErrorCharacter'; +import { AuthContext } from '@/app/providers/auth/AuthContext'; +import { SmileIcon } from '@/shared/ui/Icons'; import ChatEndModal from './ChatEndModal'; type Chat = { diff --git a/apps/client/src/shared/components/ErrorCharacter/index.tsx b/apps/client/src/shared/ui/ErrorCharacter/index.tsx similarity index 100% rename from apps/client/src/shared/components/ErrorCharacter/index.tsx rename to apps/client/src/shared/ui/ErrorCharacter/index.tsx diff --git a/apps/client/src/shared/components/FloatingButton/index.tsx b/apps/client/src/shared/ui/FloatingButton/index.tsx similarity index 70% rename from apps/client/src/shared/components/FloatingButton/index.tsx rename to apps/client/src/shared/ui/FloatingButton/index.tsx index b974753f..dbaf1201 100644 --- a/apps/client/src/shared/components/FloatingButton/index.tsx +++ b/apps/client/src/shared/ui/FloatingButton/index.tsx @@ -1,6 +1,6 @@ -import { Button } from '@/shared/components/ui/button'; -import { ThemeIcon } from '@/shared/components/Icons'; -import { useTheme } from '@/shared/hooks/useTheme'; +import { Button } from '@/shared/ui/shadcn/button'; +import { ThemeIcon } from '@/shared/ui/Icons'; +import { useTheme } from '@/shared/lib/useTheme'; function FloatingButton() { const { convertTheme } = useTheme(); diff --git a/apps/client/src/shared/components/Header/LogInButton.tsx b/apps/client/src/shared/ui/Header/LogInButton.tsx similarity index 88% rename from apps/client/src/shared/components/Header/LogInButton.tsx rename to apps/client/src/shared/ui/Header/LogInButton.tsx index 5e2fd758..302fcb85 100644 --- a/apps/client/src/shared/components/Header/LogInButton.tsx +++ b/apps/client/src/shared/ui/Header/LogInButton.tsx @@ -1,11 +1,11 @@ import { useState } from 'react'; import { createPortal } from 'react-dom'; -import WelcomeCharacter from '@/shared/components/WelcomeCharacter'; -import { Button } from '@/shared/components/ui/button'; -import Modal from '@/shared/components/Modal'; -import { GithubIcon, GoogleIcon } from '@/shared/components/Icons'; -import { useAuth } from '@/shared/hooks/useAuth'; -import axiosInstance from '@/shared/services/axios'; +import WelcomeCharacter from '@/shared/ui/WelcomeCharacter'; +import { Button } from '@/shared/ui/shadcn/button'; +import Modal from '@/shared/ui/Modal'; +import { GithubIcon, GoogleIcon } from '@/shared/ui/Icons'; +import { useAuth } from '@/shared/lib/useAuth'; +import axiosInstance from '@/shared/api/axios'; function LogInButton() { const [showModal, setShowModal] = useState(false); diff --git a/apps/client/src/shared/components/Header/index.tsx b/apps/client/src/shared/ui/Header/index.tsx similarity index 88% rename from apps/client/src/shared/components/Header/index.tsx rename to apps/client/src/shared/ui/Header/index.tsx index 04cdd0c7..66fd0e1a 100644 --- a/apps/client/src/shared/components/Header/index.tsx +++ b/apps/client/src/shared/ui/Header/index.tsx @@ -1,13 +1,13 @@ import { useContext, useEffect, useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import { Character, Logo } from '@/shared/components/Icons'; -import { Avatar, AvatarFallback, AvatarImage } from '@/shared/components/ui/avatar'; -import { cn } from '@/shared/utils/utils'; -import { AuthContext } from '@/shared/contexts/AuthContext'; -import axiosInstance from '@/shared/services/axios'; +import { Character, Logo } from '@/shared/ui/Icons'; +import { Avatar, AvatarFallback, AvatarImage } from '@/shared/ui/shadcn/avatar'; +import { cn } from '@/shared/lib/utils/utils'; +import { AuthContext } from '@/app/providers/auth/AuthContext'; +import axiosInstance from '@/shared/api/axios'; import LogInButton from './LogInButton'; -import { Button } from '../ui/button'; -import { useAuth } from '@/shared/hooks/useAuth'; +import { Button } from '@/shared/ui/shadcn/button'; +import { useAuth } from '@/shared/lib/useAuth'; function Header() { const [isCheckedIn, setIsCheckedIn] = useState(false); diff --git a/apps/client/src/shared/components/IconButton/index.tsx b/apps/client/src/shared/ui/IconButton/index.tsx similarity index 100% rename from apps/client/src/shared/components/IconButton/index.tsx rename to apps/client/src/shared/ui/IconButton/index.tsx diff --git a/apps/client/src/shared/components/Icons/BlogIcon.tsx b/apps/client/src/shared/ui/Icons/BlogIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/BlogIcon.tsx rename to apps/client/src/shared/ui/Icons/BlogIcon.tsx diff --git a/apps/client/src/shared/components/Icons/Character.tsx b/apps/client/src/shared/ui/Icons/Character.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/Character.tsx rename to apps/client/src/shared/ui/Icons/Character.tsx diff --git a/apps/client/src/shared/components/Icons/CloseIcon.tsx b/apps/client/src/shared/ui/Icons/CloseIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/CloseIcon.tsx rename to apps/client/src/shared/ui/Icons/CloseIcon.tsx diff --git a/apps/client/src/shared/components/Icons/EditIcon.tsx b/apps/client/src/shared/ui/Icons/EditIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/EditIcon.tsx rename to apps/client/src/shared/ui/Icons/EditIcon.tsx diff --git a/apps/client/src/shared/components/Icons/ExpandIcon.tsx b/apps/client/src/shared/ui/Icons/ExpandIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/ExpandIcon.tsx rename to apps/client/src/shared/ui/Icons/ExpandIcon.tsx diff --git a/apps/client/src/shared/components/Icons/GithubIcon.tsx b/apps/client/src/shared/ui/Icons/GithubIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/GithubIcon.tsx rename to apps/client/src/shared/ui/Icons/GithubIcon.tsx diff --git a/apps/client/src/shared/components/Icons/GoogleIcon.tsx b/apps/client/src/shared/ui/Icons/GoogleIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/GoogleIcon.tsx rename to apps/client/src/shared/ui/Icons/GoogleIcon.tsx diff --git a/apps/client/src/shared/components/Icons/LinkedInIcon.tsx b/apps/client/src/shared/ui/Icons/LinkedInIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/LinkedInIcon.tsx rename to apps/client/src/shared/ui/Icons/LinkedInIcon.tsx diff --git a/apps/client/src/shared/components/Icons/Logo.tsx b/apps/client/src/shared/ui/Icons/Logo.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/Logo.tsx rename to apps/client/src/shared/ui/Icons/Logo.tsx diff --git a/apps/client/src/shared/components/Icons/MailIcon.tsx b/apps/client/src/shared/ui/Icons/MailIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/MailIcon.tsx rename to apps/client/src/shared/ui/Icons/MailIcon.tsx diff --git a/apps/client/src/shared/components/Icons/MicrophoneOffIcon.tsx b/apps/client/src/shared/ui/Icons/MicrophoneOffIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/MicrophoneOffIcon.tsx rename to apps/client/src/shared/ui/Icons/MicrophoneOffIcon.tsx diff --git a/apps/client/src/shared/components/Icons/MicrophoneOnIcon.tsx b/apps/client/src/shared/ui/Icons/MicrophoneOnIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/MicrophoneOnIcon.tsx rename to apps/client/src/shared/ui/Icons/MicrophoneOnIcon.tsx diff --git a/apps/client/src/shared/components/Icons/MoveCharacter.tsx b/apps/client/src/shared/ui/Icons/MoveCharacter.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/MoveCharacter.tsx rename to apps/client/src/shared/ui/Icons/MoveCharacter.tsx diff --git a/apps/client/src/shared/components/Icons/PauseIcon.tsx b/apps/client/src/shared/ui/Icons/PauseIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/PauseIcon.tsx rename to apps/client/src/shared/ui/Icons/PauseIcon.tsx diff --git a/apps/client/src/shared/components/Icons/PlayIcon.tsx b/apps/client/src/shared/ui/Icons/PlayIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/PlayIcon.tsx rename to apps/client/src/shared/ui/Icons/PlayIcon.tsx diff --git a/apps/client/src/shared/components/Icons/ScreenShareIcon.tsx b/apps/client/src/shared/ui/Icons/ScreenShareIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/ScreenShareIcon.tsx rename to apps/client/src/shared/ui/Icons/ScreenShareIcon.tsx diff --git a/apps/client/src/shared/components/Icons/ScreenShareOffIcon.tsx b/apps/client/src/shared/ui/Icons/ScreenShareOffIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/ScreenShareOffIcon.tsx rename to apps/client/src/shared/ui/Icons/ScreenShareOffIcon.tsx diff --git a/apps/client/src/shared/components/Icons/SearchIcon.tsx b/apps/client/src/shared/ui/Icons/SearchIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/SearchIcon.tsx rename to apps/client/src/shared/ui/Icons/SearchIcon.tsx diff --git a/apps/client/src/shared/components/Icons/SmileIcon.tsx b/apps/client/src/shared/ui/Icons/SmileIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/SmileIcon.tsx rename to apps/client/src/shared/ui/Icons/SmileIcon.tsx diff --git a/apps/client/src/shared/components/Icons/ThemeIcon.tsx b/apps/client/src/shared/ui/Icons/ThemeIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/ThemeIcon.tsx rename to apps/client/src/shared/ui/Icons/ThemeIcon.tsx diff --git a/apps/client/src/shared/components/Icons/VideoOffIcon.tsx b/apps/client/src/shared/ui/Icons/VideoOffIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/VideoOffIcon.tsx rename to apps/client/src/shared/ui/Icons/VideoOffIcon.tsx diff --git a/apps/client/src/shared/components/Icons/VideoOnIcon.tsx b/apps/client/src/shared/ui/Icons/VideoOnIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/VideoOnIcon.tsx rename to apps/client/src/shared/ui/Icons/VideoOnIcon.tsx diff --git a/apps/client/src/shared/components/Icons/VolumeOffIcon.tsx b/apps/client/src/shared/ui/Icons/VolumeOffIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/VolumeOffIcon.tsx rename to apps/client/src/shared/ui/Icons/VolumeOffIcon.tsx diff --git a/apps/client/src/shared/components/Icons/VolumeOnIcon.tsx b/apps/client/src/shared/ui/Icons/VolumeOnIcon.tsx similarity index 100% rename from apps/client/src/shared/components/Icons/VolumeOnIcon.tsx rename to apps/client/src/shared/ui/Icons/VolumeOnIcon.tsx diff --git a/apps/client/src/shared/components/Icons/index.ts b/apps/client/src/shared/ui/Icons/index.ts similarity index 100% rename from apps/client/src/shared/components/Icons/index.ts rename to apps/client/src/shared/ui/Icons/index.ts diff --git a/apps/client/src/shared/components/LoadingCharacter/index.tsx b/apps/client/src/shared/ui/LoadingCharacter/index.tsx similarity index 100% rename from apps/client/src/shared/components/LoadingCharacter/index.tsx rename to apps/client/src/shared/ui/LoadingCharacter/index.tsx diff --git a/apps/client/src/shared/components/Modal/index.tsx b/apps/client/src/shared/ui/Modal/index.tsx similarity index 96% rename from apps/client/src/shared/components/Modal/index.tsx rename to apps/client/src/shared/ui/Modal/index.tsx index ef1cda19..8f2bdbda 100644 --- a/apps/client/src/shared/components/Modal/index.tsx +++ b/apps/client/src/shared/ui/Modal/index.tsx @@ -1,5 +1,5 @@ import { useEffect, useRef } from 'react'; -import { CloseIcon } from '@/shared/components/Icons'; +import { CloseIcon } from '@/shared/ui/Icons'; type ModalProps = { children: React.ReactNode; diff --git a/apps/client/src/shared/components/WelcomeCharacter/index.tsx b/apps/client/src/shared/ui/WelcomeCharacter/index.tsx similarity index 100% rename from apps/client/src/shared/components/WelcomeCharacter/index.tsx rename to apps/client/src/shared/ui/WelcomeCharacter/index.tsx diff --git a/apps/client/src/shared/components/ui/avatar.tsx b/apps/client/src/shared/ui/shadcn/avatar.tsx similarity index 96% rename from apps/client/src/shared/components/ui/avatar.tsx rename to apps/client/src/shared/ui/shadcn/avatar.tsx index 516d8235..14955ccb 100644 --- a/apps/client/src/shared/components/ui/avatar.tsx +++ b/apps/client/src/shared/ui/shadcn/avatar.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import * as AvatarPrimitive from '@radix-ui/react-avatar'; -import { cn } from '@/shared/utils/utils'; +import { cn } from '@/shared/lib/utils/utils'; const Avatar = React.forwardRef< React.ElementRef, diff --git a/apps/client/src/shared/components/ui/badge.tsx b/apps/client/src/shared/ui/shadcn/badge.tsx similarity index 95% rename from apps/client/src/shared/components/ui/badge.tsx rename to apps/client/src/shared/ui/shadcn/badge.tsx index 843166d1..8e0703a2 100644 --- a/apps/client/src/shared/components/ui/badge.tsx +++ b/apps/client/src/shared/ui/shadcn/badge.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { cva, type VariantProps } from 'class-variance-authority'; -import { cn } from '@/shared/utils/utils'; +import { cn } from '@/shared/lib/utils/utils'; const badgeVariants = cva( 'inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', diff --git a/apps/client/src/shared/components/ui/button.tsx b/apps/client/src/shared/ui/shadcn/button.tsx similarity index 97% rename from apps/client/src/shared/components/ui/button.tsx rename to apps/client/src/shared/ui/shadcn/button.tsx index 51d50f08..8ad2126d 100644 --- a/apps/client/src/shared/components/ui/button.tsx +++ b/apps/client/src/shared/ui/shadcn/button.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { Slot } from '@radix-ui/react-slot'; import { cva, type VariantProps } from 'class-variance-authority'; -import { cn } from '@/shared/utils/utils'; +import { cn } from '@/shared/lib/utils/utils'; const buttonVariants = cva( 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-xl text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', diff --git a/apps/client/src/shared/components/ui/card.tsx b/apps/client/src/shared/ui/shadcn/card.tsx similarity index 97% rename from apps/client/src/shared/components/ui/card.tsx rename to apps/client/src/shared/ui/shadcn/card.tsx index 276d2fcb..2803891b 100644 --- a/apps/client/src/shared/components/ui/card.tsx +++ b/apps/client/src/shared/ui/shadcn/card.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -import { cn } from '@/shared/utils/utils'; +import { cn } from '@/shared/lib/utils/utils'; const Card = React.forwardRef>(({ className, ...props }, ref) => (
diff --git a/apps/client/src/shared/components/ui/input.tsx b/apps/client/src/shared/ui/shadcn/input.tsx similarity index 93% rename from apps/client/src/shared/components/ui/input.tsx rename to apps/client/src/shared/ui/shadcn/input.tsx index 4b2ed315..ef622202 100644 --- a/apps/client/src/shared/components/ui/input.tsx +++ b/apps/client/src/shared/ui/shadcn/input.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -import { cn } from '@/shared/utils/utils'; +import { cn } from '@/shared/lib/utils/utils'; const Input = React.forwardRef>( ({ className, type, ...props }, ref) => ( diff --git a/apps/client/src/shared/components/ui/scroll-area.tsx b/apps/client/src/shared/ui/shadcn/scroll-area.tsx similarity index 97% rename from apps/client/src/shared/components/ui/scroll-area.tsx rename to apps/client/src/shared/ui/shadcn/scroll-area.tsx index ee9db212..2beac1ca 100644 --- a/apps/client/src/shared/components/ui/scroll-area.tsx +++ b/apps/client/src/shared/ui/shadcn/scroll-area.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'; -import { cn } from '@/shared/utils/utils'; +import { cn } from '@/shared/lib/utils/utils'; const ScrollArea = React.forwardRef< React.ElementRef, diff --git a/apps/client/src/shared/components/ui/select.tsx b/apps/client/src/shared/ui/shadcn/select.tsx similarity index 99% rename from apps/client/src/shared/components/ui/select.tsx rename to apps/client/src/shared/ui/shadcn/select.tsx index c8093e4d..47e42a00 100644 --- a/apps/client/src/shared/components/ui/select.tsx +++ b/apps/client/src/shared/ui/shadcn/select.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import * as SelectPrimitive from '@radix-ui/react-select'; import { Check, ChevronDown, ChevronUp } from 'lucide-react'; -import { cn } from '@/shared/utils/utils'; +import { cn } from '@/shared/lib/utils/utils'; const Select = SelectPrimitive.Root; diff --git a/apps/client/src/shared/components/ui/toast.tsx b/apps/client/src/shared/ui/shadcn/toast.tsx similarity index 99% rename from apps/client/src/shared/components/ui/toast.tsx rename to apps/client/src/shared/ui/shadcn/toast.tsx index e8a7079b..4315f917 100644 --- a/apps/client/src/shared/components/ui/toast.tsx +++ b/apps/client/src/shared/ui/shadcn/toast.tsx @@ -3,7 +3,7 @@ import * as ToastPrimitives from '@radix-ui/react-toast'; import { cva, type VariantProps } from 'class-variance-authority'; import { X } from 'lucide-react'; -import { cn } from '@/shared/utils/utils'; +import { cn } from '@/shared/lib/utils/utils'; const ToastProvider = ToastPrimitives.Provider; diff --git a/apps/client/src/shared/components/ui/toaster.tsx b/apps/client/src/shared/ui/shadcn/toaster.tsx similarity index 87% rename from apps/client/src/shared/components/ui/toaster.tsx rename to apps/client/src/shared/ui/shadcn/toaster.tsx index 82544ccd..1ac66a51 100644 --- a/apps/client/src/shared/components/ui/toaster.tsx +++ b/apps/client/src/shared/ui/shadcn/toaster.tsx @@ -1,4 +1,4 @@ -import { useToast } from '@/shared/hooks/useToast'; +import { useToast } from '@/shared/lib/toast/useToast'; import { Toast, ToastClose, @@ -6,7 +6,7 @@ import { ToastProvider, ToastTitle, ToastViewport, -} from '@/shared/components/ui/toast'; +} from '@/shared/ui/shadcn/toast'; export function Toaster() { const { toasts } = useToast(); diff --git a/apps/client/tsconfig.json b/apps/client/tsconfig.json index 19770d9d..96dd57f9 100644 --- a/apps/client/tsconfig.json +++ b/apps/client/tsconfig.json @@ -20,11 +20,11 @@ "@/*": ["./src/*"], "@assets/*": ["./src/assets/*"], "@components/*": ["./src/components/*"], - "@contexts/*": ["src/shared/contexts/*"], + "@contexts/*": ["src/app/providers/theme/*"], "@hooks/*": ["src/shared/hooks/*"], - "@services/*": ["src/shared/services/*"], + "@services/*": ["src/shared/api/*"], "@pages/*": ["./src/pages/*"], - "@utils/*": ["src/shared/utils/*"], + "@utils/*": ["src/shared/lib/utils/*"], "@constants/*": ["src/shared/constants/*"] }, "outDir": "./dist" From e84e4a7afdac1f564e8d7715aa457e805816d704 Mon Sep 17 00:00:00 2001 From: zero0205 Date: Wed, 15 Jan 2025 14:48:49 +0900 Subject: [PATCH 07/11] =?UTF-8?q?:recycle:=20[Refactor]:=20FSD=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EC=A0=81=EC=9A=A9=20-=204.=20shared=20=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EC=96=B4=20unpack=20=EB=A7=88=EB=AC=B4=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/Broadcast/BroadcastPage.tsx | 10 +++++----- .../client/src/pages/Broadcast/config/index.ts | 1 + .../Broadcast}/config/videoOptions.ts | 0 .../lib => pages/Broadcast/hooks}/useMedia.ts | 0 .../Broadcast/hooks}/useProducer.ts | 2 +- .../Broadcast/hooks}/useRoom.ts | 0 .../Broadcast/hooks}/useScreenShare.ts | 0 .../src/pages/Broadcast/types/trackTypes.ts | 5 +++++ .../src/pages/Broadcast/ui/BroadcastPlayer.tsx | 4 ++-- .../{shared => pages/Home}/types/homeTypes.ts | 2 +- apps/client/src/pages/Home/ui/FieldFilter.tsx | 2 +- apps/client/src/pages/Home/ui/LiveList.tsx | 6 +++--- apps/client/src/pages/Live/LivePage.tsx | 2 +- .../Live/hooks}/useConsumer.ts | 0 .../lib => pages/Live/hooks}/useIntersect.ts | 0 .../{shared => pages/Live}/types/liveTypes.ts | 4 ++-- .../src/pages/Live/ui/LiveCamperInfo.tsx | 2 +- apps/client/src/pages/Profile/ProfilePage.tsx | 2 +- .../src/pages/Profile/ui/EditUserInfo.tsx | 2 +- apps/client/src/shared/lib/utils/utils.ts | 18 ------------------ apps/client/src/shared/types/mediasoupTypes.ts | 6 ------ apps/client/src/shared/types/sharedTypes.ts | 1 + .../src/shared/ui/Header/LogInButton.tsx | 2 +- .../index.tsx => Header/WelcomeCharacter.tsx} | 3 +-- apps/client/tsconfig.json | 6 +++--- 25 files changed, 31 insertions(+), 49 deletions(-) create mode 100644 apps/client/src/pages/Broadcast/config/index.ts rename apps/client/src/{shared => pages/Broadcast}/config/videoOptions.ts (100%) rename apps/client/src/{shared/lib => pages/Broadcast/hooks}/useMedia.ts (100%) rename apps/client/src/{shared/lib/mediasoup => pages/Broadcast/hooks}/useProducer.ts (98%) rename apps/client/src/{shared/lib/mediasoup => pages/Broadcast/hooks}/useRoom.ts (100%) rename apps/client/src/{shared/lib => pages/Broadcast/hooks}/useScreenShare.ts (100%) create mode 100644 apps/client/src/pages/Broadcast/types/trackTypes.ts rename apps/client/src/{shared => pages/Home}/types/homeTypes.ts (83%) rename apps/client/src/{shared/lib/mediasoup => pages/Live/hooks}/useConsumer.ts (100%) rename apps/client/src/{shared/lib => pages/Live/hooks}/useIntersect.ts (100%) rename apps/client/src/{shared => pages/Live}/types/liveTypes.ts (82%) create mode 100644 apps/client/src/shared/types/sharedTypes.ts rename apps/client/src/shared/ui/{WelcomeCharacter/index.tsx => Header/WelcomeCharacter.tsx} (97%) diff --git a/apps/client/src/pages/Broadcast/BroadcastPage.tsx b/apps/client/src/pages/Broadcast/BroadcastPage.tsx index 7ed75946..6c2860c7 100644 --- a/apps/client/src/pages/Broadcast/BroadcastPage.tsx +++ b/apps/client/src/pages/Broadcast/BroadcastPage.tsx @@ -1,8 +1,8 @@ import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'; import ChatContainer from '@/shared/ui/ChatContainer'; import ErrorCharacter from '@/shared/ui/ErrorCharacter'; -import { useProducer } from '@/shared/lib/mediasoup/useProducer'; -import { useRoom } from '@/shared/lib/mediasoup/useRoom'; +import { useProducer } from '@/pages/Broadcast/hooks/useProducer'; +import { useRoom } from '@/pages/Broadcast/hooks/useRoom'; import { useSocket } from '@/shared/lib/socket/useSocket'; import { useTransport } from '@/shared/lib/mediasoup/useTransport'; import { Button } from '@/shared/ui/shadcn/button'; @@ -15,12 +15,12 @@ import { ScreenShareIconOff, } from '@/shared/ui/Icons'; import BroadcastTitle from './ui/BroadcastTitle'; -import useScreenShare from '@/shared/lib/useScreenShare'; +import useScreenShare from '@/pages/Broadcast/hooks/useScreenShare'; import BroadcastPlayer from './ui/BroadcastPlayer'; -import { Tracks } from '@/shared/types/mediasoupTypes'; +import { Tracks } from './types/trackTypes'; import RecordButton from './ui/RecordButton'; import axiosInstance from '@/shared/api/axios'; -import { useMedia } from '@/shared/lib/useMedia'; +import { useMedia } from '@/pages/Broadcast/hooks/useMedia'; import { useTheme } from '@/shared/lib/useTheme'; const mediaServerUrl = import.meta.env.VITE_MEDIASERVER_URL; diff --git a/apps/client/src/pages/Broadcast/config/index.ts b/apps/client/src/pages/Broadcast/config/index.ts new file mode 100644 index 00000000..1ffaa539 --- /dev/null +++ b/apps/client/src/pages/Broadcast/config/index.ts @@ -0,0 +1 @@ +export { ENCODING_OPTIONS, RESOLUTION_OPTIONS } from './videoOptions'; diff --git a/apps/client/src/shared/config/videoOptions.ts b/apps/client/src/pages/Broadcast/config/videoOptions.ts similarity index 100% rename from apps/client/src/shared/config/videoOptions.ts rename to apps/client/src/pages/Broadcast/config/videoOptions.ts diff --git a/apps/client/src/shared/lib/useMedia.ts b/apps/client/src/pages/Broadcast/hooks/useMedia.ts similarity index 100% rename from apps/client/src/shared/lib/useMedia.ts rename to apps/client/src/pages/Broadcast/hooks/useMedia.ts diff --git a/apps/client/src/shared/lib/mediasoup/useProducer.ts b/apps/client/src/pages/Broadcast/hooks/useProducer.ts similarity index 98% rename from apps/client/src/shared/lib/mediasoup/useProducer.ts rename to apps/client/src/pages/Broadcast/hooks/useProducer.ts index c5b5ef64..12a3b622 100644 --- a/apps/client/src/shared/lib/mediasoup/useProducer.ts +++ b/apps/client/src/pages/Broadcast/hooks/useProducer.ts @@ -3,7 +3,7 @@ import { Transport, Device, Producer } from 'mediasoup-client/lib/types'; import { Socket } from 'socket.io-client'; import { ConnectTransportResponse, TransportInfo } from '@/shared/types/mediasoupTypes'; import { checkDependencies } from '@/shared/lib/utils/utils'; -import { ENCODING_OPTIONS } from '@/shared/config/videoOptions'; +import { ENCODING_OPTIONS } from '../config'; type UseProducerProps = { socket: Socket | null; diff --git a/apps/client/src/shared/lib/mediasoup/useRoom.ts b/apps/client/src/pages/Broadcast/hooks/useRoom.ts similarity index 100% rename from apps/client/src/shared/lib/mediasoup/useRoom.ts rename to apps/client/src/pages/Broadcast/hooks/useRoom.ts diff --git a/apps/client/src/shared/lib/useScreenShare.ts b/apps/client/src/pages/Broadcast/hooks/useScreenShare.ts similarity index 100% rename from apps/client/src/shared/lib/useScreenShare.ts rename to apps/client/src/pages/Broadcast/hooks/useScreenShare.ts diff --git a/apps/client/src/pages/Broadcast/types/trackTypes.ts b/apps/client/src/pages/Broadcast/types/trackTypes.ts new file mode 100644 index 00000000..7c9f057b --- /dev/null +++ b/apps/client/src/pages/Broadcast/types/trackTypes.ts @@ -0,0 +1,5 @@ +export type Tracks = { + video: MediaStreamTrack | undefined; + mediaAudio: MediaStreamTrack | undefined; + screenAudio: MediaStreamTrack | undefined; +}; diff --git a/apps/client/src/pages/Broadcast/ui/BroadcastPlayer.tsx b/apps/client/src/pages/Broadcast/ui/BroadcastPlayer.tsx index 1733e19f..6afb6e60 100644 --- a/apps/client/src/pages/Broadcast/ui/BroadcastPlayer.tsx +++ b/apps/client/src/pages/Broadcast/ui/BroadcastPlayer.tsx @@ -1,6 +1,6 @@ import { useEffect, useRef } from 'react'; -import { RESOLUTION_OPTIONS } from '@/shared/config/videoOptions'; -import { Tracks } from '@/shared/types/mediasoupTypes'; +import { RESOLUTION_OPTIONS } from '../config'; +import { Tracks } from '../types/trackTypes'; type BroadcastPlayerProps = { mediaStream: MediaStream | null; diff --git a/apps/client/src/shared/types/homeTypes.ts b/apps/client/src/pages/Home/types/homeTypes.ts similarity index 83% rename from apps/client/src/shared/types/homeTypes.ts rename to apps/client/src/pages/Home/types/homeTypes.ts index 4c8875da..20b50474 100644 --- a/apps/client/src/shared/types/homeTypes.ts +++ b/apps/client/src/pages/Home/types/homeTypes.ts @@ -1,4 +1,4 @@ -import { Field } from './liveTypes'; +import { Field } from '@/shared/types/sharedTypes'; export type LivePreviewInfo = { broadcastId: string; diff --git a/apps/client/src/pages/Home/ui/FieldFilter.tsx b/apps/client/src/pages/Home/ui/FieldFilter.tsx index 8587d786..77497eb7 100644 --- a/apps/client/src/pages/Home/ui/FieldFilter.tsx +++ b/apps/client/src/pages/Home/ui/FieldFilter.tsx @@ -1,6 +1,6 @@ import { useState } from 'react'; import { Button } from '@/shared/ui/shadcn/button'; -import { Field } from '@/shared/types/liveTypes'; +import { Field } from '@/shared/types/sharedTypes'; const fields: Field[] = ['WEB', 'AND', 'IOS']; diff --git a/apps/client/src/pages/Home/ui/LiveList.tsx b/apps/client/src/pages/Home/ui/LiveList.tsx index 22544f8c..1eb8b836 100644 --- a/apps/client/src/pages/Home/ui/LiveList.tsx +++ b/apps/client/src/pages/Home/ui/LiveList.tsx @@ -2,10 +2,10 @@ import { useCallback, useEffect, useState } from 'react'; import axiosInstance from '@/shared/api/axios'; import FieldFilter from './FieldFilter'; import LiveCard from './LiveCard'; -import { LivePreviewInfo } from '@/shared/types/homeTypes'; +import { LivePreviewInfo } from '@/pages/Home/types/homeTypes'; import Search from './Search'; -import { Field } from '@/shared/types/liveTypes'; -import { useIntersect } from '@/shared/lib/useIntersect'; +import { Field } from '@/shared/types/sharedTypes'; +import { useIntersect } from '@/pages/Live/hooks/useIntersect'; const LIMIT = 12; diff --git a/apps/client/src/pages/Live/LivePage.tsx b/apps/client/src/pages/Live/LivePage.tsx index c71d09d8..759b4bf6 100644 --- a/apps/client/src/pages/Live/LivePage.tsx +++ b/apps/client/src/pages/Live/LivePage.tsx @@ -2,7 +2,7 @@ import { useEffect } from 'react'; import { useParams } from 'react-router-dom'; import ChatContainer from '@/shared/ui/ChatContainer'; import ErrorCharacter from '@/shared/ui/ErrorCharacter'; -import { useConsumer } from '@/shared/lib/mediasoup/useConsumer'; +import { useConsumer } from '@/pages/Live/hooks/useConsumer'; import { useSocket } from '@/shared/lib/socket/useSocket'; import { useTransport } from '@/shared/lib/mediasoup/useTransport'; import LivePlayer from './ui/LivePlayer'; diff --git a/apps/client/src/shared/lib/mediasoup/useConsumer.ts b/apps/client/src/pages/Live/hooks/useConsumer.ts similarity index 100% rename from apps/client/src/shared/lib/mediasoup/useConsumer.ts rename to apps/client/src/pages/Live/hooks/useConsumer.ts diff --git a/apps/client/src/shared/lib/useIntersect.ts b/apps/client/src/pages/Live/hooks/useIntersect.ts similarity index 100% rename from apps/client/src/shared/lib/useIntersect.ts rename to apps/client/src/pages/Live/hooks/useIntersect.ts diff --git a/apps/client/src/shared/types/liveTypes.ts b/apps/client/src/pages/Live/types/liveTypes.ts similarity index 82% rename from apps/client/src/shared/types/liveTypes.ts rename to apps/client/src/pages/Live/types/liveTypes.ts index 3f448368..60991915 100644 --- a/apps/client/src/shared/types/liveTypes.ts +++ b/apps/client/src/pages/Live/types/liveTypes.ts @@ -1,3 +1,5 @@ +import { Field } from '@/shared/types/sharedTypes'; + export type ContactInfo = { github: string; linkedin: string; @@ -5,8 +7,6 @@ export type ContactInfo = { blog: string; }; -export type Field = 'WEB' | 'AND' | 'IOS' | ''; - export type LiveInfo = { title: string; camperId: string; diff --git a/apps/client/src/pages/Live/ui/LiveCamperInfo.tsx b/apps/client/src/pages/Live/ui/LiveCamperInfo.tsx index 7eaf98f9..f8389f5c 100644 --- a/apps/client/src/pages/Live/ui/LiveCamperInfo.tsx +++ b/apps/client/src/pages/Live/ui/LiveCamperInfo.tsx @@ -4,7 +4,7 @@ import IconButton from '@/shared/ui/IconButton'; import { useAPI } from '@/shared/lib/useAPI'; import LoadingCharacter from '@/shared/ui/LoadingCharacter'; import ErrorCharacter from '@/shared/ui/ErrorCharacter'; -import { LiveInfo } from '@/shared/types/liveTypes'; +import { LiveInfo } from '@/pages/Live/types/liveTypes'; import { MailIcon, GithubIcon, BlogIcon, LinkedInIcon } from '@/shared/ui/Icons'; function LiveCamperInfo({ liveId }: { liveId: string }) { diff --git a/apps/client/src/pages/Profile/ProfilePage.tsx b/apps/client/src/pages/Profile/ProfilePage.tsx index 6f29763c..9e36ca12 100644 --- a/apps/client/src/pages/Profile/ProfilePage.tsx +++ b/apps/client/src/pages/Profile/ProfilePage.tsx @@ -3,7 +3,7 @@ import Attendance from './ui/Attendance'; import UserInfo from './ui/UserInfo'; import EditUserInfo from './ui/EditUserInfo'; import axiosInstance from '@/shared/api/axios'; -import { Field } from '@/shared/types/liveTypes'; +import { Field } from '@/shared/types/sharedTypes'; import ErrorCharacter from '@/shared/ui/ErrorCharacter'; import LoadingCharacter from '@/shared/ui/LoadingCharacter'; diff --git a/apps/client/src/pages/Profile/ui/EditUserInfo.tsx b/apps/client/src/pages/Profile/ui/EditUserInfo.tsx index 32f97b95..a301ea28 100644 --- a/apps/client/src/pages/Profile/ui/EditUserInfo.tsx +++ b/apps/client/src/pages/Profile/ui/EditUserInfo.tsx @@ -2,7 +2,7 @@ import { useForm } from 'react-hook-form'; import { useState } from 'react'; import { Avatar, AvatarFallback, AvatarImage } from '@/shared/ui/shadcn/avatar'; import { UserData } from '../ProfilePage'; -import { Field } from '@/shared/types/liveTypes'; +import { Field } from '@/shared/types/sharedTypes'; import { Button } from '@/shared/ui/shadcn/button'; import axiosInstance from '@/shared/api/axios'; import { useToast } from '@/shared/lib/toast/useToast'; diff --git a/apps/client/src/shared/lib/utils/utils.ts b/apps/client/src/shared/lib/utils/utils.ts index b8c7a53a..ae429998 100644 --- a/apps/client/src/shared/lib/utils/utils.ts +++ b/apps/client/src/shared/lib/utils/utils.ts @@ -11,21 +11,3 @@ export const checkDependencies = (functionName: string, dependencies: { [key: st if (missing.length === 0) return null; return new Error(`${functionName} Error: ${missing.join(',')}이(가) 없습니다.`); }; - -export const getPayloadFromJWT = () => { - const token = localStorage.getItem('accessToken'); - if (!token) return undefined; - const base64Payload = token.split('.')[1]; - const base64 = base64Payload.replace(/-/g, '+').replace(/_/g, '/'); - - const decodedJWT = JSON.parse( - decodeURIComponent( - window - .atob(base64) - .split('') - .map(c => `%${ (`00${ c.charCodeAt(0).toString(16)}`).slice(-2)}`) - .join(''), - ), - ); - return decodedJWT; -}; diff --git a/apps/client/src/shared/types/mediasoupTypes.ts b/apps/client/src/shared/types/mediasoupTypes.ts index ca946b96..a3c63c0c 100644 --- a/apps/client/src/shared/types/mediasoupTypes.ts +++ b/apps/client/src/shared/types/mediasoupTypes.ts @@ -12,9 +12,3 @@ export type ConnectTransportResponse = { connected: boolean; isProducer: boolean; }; - -export type Tracks = { - video: MediaStreamTrack | undefined; - mediaAudio: MediaStreamTrack | undefined; - screenAudio: MediaStreamTrack | undefined; -}; diff --git a/apps/client/src/shared/types/sharedTypes.ts b/apps/client/src/shared/types/sharedTypes.ts new file mode 100644 index 00000000..bc748519 --- /dev/null +++ b/apps/client/src/shared/types/sharedTypes.ts @@ -0,0 +1 @@ +export type Field = 'WEB' | 'AND' | 'IOS' | ''; diff --git a/apps/client/src/shared/ui/Header/LogInButton.tsx b/apps/client/src/shared/ui/Header/LogInButton.tsx index 302fcb85..6786540d 100644 --- a/apps/client/src/shared/ui/Header/LogInButton.tsx +++ b/apps/client/src/shared/ui/Header/LogInButton.tsx @@ -1,6 +1,6 @@ import { useState } from 'react'; import { createPortal } from 'react-dom'; -import WelcomeCharacter from '@/shared/ui/WelcomeCharacter'; +import { WelcomeCharacter } from './WelcomeCharacter'; import { Button } from '@/shared/ui/shadcn/button'; import Modal from '@/shared/ui/Modal'; import { GithubIcon, GoogleIcon } from '@/shared/ui/Icons'; diff --git a/apps/client/src/shared/ui/WelcomeCharacter/index.tsx b/apps/client/src/shared/ui/Header/WelcomeCharacter.tsx similarity index 97% rename from apps/client/src/shared/ui/WelcomeCharacter/index.tsx rename to apps/client/src/shared/ui/Header/WelcomeCharacter.tsx index aa5de154..1864950f 100644 --- a/apps/client/src/shared/ui/WelcomeCharacter/index.tsx +++ b/apps/client/src/shared/ui/Header/WelcomeCharacter.tsx @@ -3,7 +3,7 @@ type Props = { className?: string; }; -function WelcomeCharacter({ size, className }: Props) { +export function WelcomeCharacter({ size, className }: Props) { return ( {/* Shadow */} @@ -110,4 +110,3 @@ function WelcomeCharacter({ size, className }: Props) { ); } -export default WelcomeCharacter; diff --git a/apps/client/tsconfig.json b/apps/client/tsconfig.json index 96dd57f9..a78c09ee 100644 --- a/apps/client/tsconfig.json +++ b/apps/client/tsconfig.json @@ -18,12 +18,12 @@ "baseUrl": ".", "paths": { "@/*": ["./src/*"], - "@assets/*": ["./src/assets/*"], - "@components/*": ["./src/components/*"], + "@assets/*": ["src/assets/*"], + "@components/*": ["src/components/*"], "@contexts/*": ["src/app/providers/theme/*"], "@hooks/*": ["src/shared/hooks/*"], "@services/*": ["src/shared/api/*"], - "@pages/*": ["./src/pages/*"], + "@pages/*": ["src/pages/*"], "@utils/*": ["src/shared/lib/utils/*"], "@constants/*": ["src/shared/constants/*"] }, From db88229b92a19291a267a9129d77018deb7e0dbf Mon Sep 17 00:00:00 2001 From: zero0205 Date: Wed, 15 Jan 2025 20:59:18 +0900 Subject: [PATCH 08/11] =?UTF-8?q?:recycle:=20[Refactor]:=20FSD=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EC=A0=81=EC=9A=A9=20-=205.=20Technical=20Purpose?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EC=BD=94=EB=93=9C=20=EA=B5=AC?= =?UTF-8?q?=EC=84=B1=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client/src/app/layouts/Layout.tsx | 3 +- .../src/app/layouts/{index.tsx => index.ts} | 0 .../app/providers/{auth => }/AuthProvider.tsx | 2 +- .../providers/{index.tsx => Providers.tsx} | 4 +- .../providers/{theme => }/ThemeProvider.tsx | 5 +- apps/client/src/app/providers/auth/types.ts | 4 - apps/client/src/app/providers/index.ts | 1 + apps/client/src/app/providers/theme/types.ts | 6 - apps/client/src/app/routes/ProtectedRoute.tsx | 2 +- apps/client/src/app/routes/config/index.ts | 1 + .../config/{routerOptions.ts => options.ts} | 0 .../src/app/routes/{index.tsx => index.ts} | 0 apps/client/src/app/routes/router.tsx | 4 +- apps/client/src/pages/Auth/AuthPage.tsx | 4 +- .../src/pages/Auth/{index.tsx => index.ts} | 0 .../src/pages/Broadcast/BroadcastPage.tsx | 21 +--- .../src/pages/Broadcast/config/index.ts | 1 - .../client/src/pages/Broadcast/model/index.ts | 4 + .../mediasoup/encodingOptions.ts} | 6 - .../pages/Broadcast/model/mediasoup/index.ts | 2 + .../{hooks => model/mediasoup}/useProducer.ts | 11 +- .../{hooks => model/mediasoup}/useRoom.ts | 0 .../Broadcast/{types => model}/trackTypes.ts | 0 .../Broadcast/{hooks => model}/useMedia.ts | 0 .../{hooks => model}/useScreenShare.ts | 4 +- .../{ => BroadcastPlayer}/BroadcastPlayer.tsx | 8 +- .../Broadcast/ui/BroadcastPlayer/index.ts | 1 + .../ui/BroadcastPlayer/resolutionOptions.ts | 5 + .../src/pages/Broadcast/ui/BroadcastTitle.tsx | 4 +- .../src/pages/Broadcast/ui/RecordButton.tsx | 6 +- apps/client/src/pages/Broadcast/ui/index.ts | 3 + apps/client/src/pages/Home/HomePage.tsx | 3 +- .../src/pages/Home/{index.tsx => index.ts} | 0 .../pages/Home/{types => model}/homeTypes.ts | 0 apps/client/src/pages/Home/model/index.ts | 2 + .../hooks => Home/model}/useIntersect.ts | 0 .../src/pages/Home/ui/{ => Banner}/Banner.tsx | 8 +- .../pages/Home/ui/{ => Banner}/Bookmark.tsx | 18 +-- apps/client/src/pages/Home/ui/Banner/index.ts | 1 + apps/client/src/pages/Home/ui/Banner/types.ts | 5 + apps/client/src/pages/Home/ui/FieldFilter.tsx | 4 +- apps/client/src/pages/Home/ui/LiveCard.tsx | 4 +- apps/client/src/pages/Home/ui/LiveList.tsx | 14 +-- apps/client/src/pages/Home/ui/Search.tsx | 7 +- apps/client/src/pages/Home/ui/index.ts | 5 + apps/client/src/pages/Live/LivePage.tsx | 11 +- .../src/pages/Live/{index.tsx => index.ts} | 0 apps/client/src/pages/Live/model/index.ts | 1 + .../Live/{hooks => model}/useConsumer.ts | 13 +- .../{ => LiveCamperInfo}/LiveCamperInfo.tsx | 19 +-- .../src/pages/Live/ui/LiveCamperInfo/index.ts | 1 + .../LiveCamperInfo/types.ts} | 0 .../Live/ui/{ => LivePlayer}/LivePlayer.tsx | 23 +--- .../src/pages/Live/ui/LivePlayer/index.ts | 1 + .../src/pages/Live/ui/LivePlayer/types.ts | 16 +++ apps/client/src/pages/Live/ui/index.ts | 2 + apps/client/src/pages/Profile/ProfilePage.tsx | 24 +--- .../src/pages/Profile/{index.tsx => index.ts} | 0 .../src/pages/Profile/ui/Attendance.tsx | 7 +- .../src/pages/Profile/ui/EditUserInfo.tsx | 12 +- apps/client/src/pages/Profile/ui/UserInfo.tsx | 10 +- apps/client/src/pages/Profile/ui/index.ts | 4 + apps/client/src/pages/Profile/ui/types.ts | 17 +++ apps/client/src/pages/Record/RecordPage.tsx | 4 +- .../src/pages/Record/{index.tsx => index.ts} | 0 .../client/src/pages/Record/ui/RecordInfo.tsx | 9 +- .../client/src/pages/Record/ui/RecordList.tsx | 9 +- .../src/pages/Record/ui/RecordPlayer.tsx | 11 +- apps/client/src/pages/Record/ui/index.ts | 3 + .../auth => shared/contexts}/AuthContext.tsx | 6 +- .../contexts}/ThemeContext.tsx | 8 +- apps/client/src/shared/contexts/index.ts | 2 + apps/client/src/shared/lib/index.ts | 7 ++ apps/client/src/shared/lib/useAuth.ts | 2 +- .../src/shared/lib/{socket => }/useSocket.ts | 0 apps/client/src/shared/lib/useTheme.ts | 2 +- .../src/shared/lib/{toast => }/useToast.ts | 0 .../lib/{mediasoup => }/useTransport.ts | 2 +- .../src/shared/lib/{utils => }/utils.ts | 0 apps/client/src/shared/types/index.ts | 0 .../index.tsx => FloatingButton.tsx} | 4 +- apps/client/src/shared/ui/Header/Header.tsx | 98 ++++++++++++++++ .../src/shared/ui/Header/LogInButton.tsx | 5 +- .../src/shared/ui/Header/LogoButton.tsx | 21 ++++ apps/client/src/shared/ui/Header/index.tsx | 111 +----------------- .../{IconButton/index.tsx => IconButton.tsx} | 4 +- .../shared/ui/Icons/ScreenShareOffIcon.tsx | 4 +- apps/client/src/shared/ui/Icons/index.ts | 3 +- .../shared/ui/{Modal/index.tsx => Modal.tsx} | 4 +- .../DefaultCharacter.tsx} | 9 +- .../ErrorCharacter.tsx} | 9 +- .../LoadingCharacter.tsx} | 4 +- .../ui/{Icons => character}/MoveCharacter.tsx | 4 +- apps/client/src/shared/ui/character/index.ts | 4 + apps/client/src/shared/ui/character/types.ts | 4 + .../index.tsx => chat/ChatContainer.tsx} | 18 +-- .../{ChatContainer => chat}/ChatEndModal.tsx | 2 +- apps/client/src/shared/ui/chat/index.ts | 1 + apps/client/src/shared/ui/chat/types.ts | 6 + apps/client/src/shared/ui/index.ts | 30 +++++ apps/client/src/shared/ui/shadcn/avatar.tsx | 2 +- apps/client/src/shared/ui/shadcn/badge.tsx | 2 +- apps/client/src/shared/ui/shadcn/button.tsx | 2 +- apps/client/src/shared/ui/shadcn/card.tsx | 2 +- apps/client/src/shared/ui/shadcn/index.ts | 0 apps/client/src/shared/ui/shadcn/input.tsx | 2 +- .../src/shared/ui/shadcn/scroll-area.tsx | 2 +- apps/client/src/shared/ui/shadcn/select.tsx | 2 +- apps/client/src/shared/ui/shadcn/toast.tsx | 2 +- apps/client/src/shared/ui/shadcn/toaster.tsx | 2 +- 110 files changed, 393 insertions(+), 379 deletions(-) rename apps/client/src/app/layouts/{index.tsx => index.ts} (100%) rename apps/client/src/app/providers/{auth => }/AuthProvider.tsx (88%) rename apps/client/src/app/providers/{index.tsx => Providers.tsx} (57%) rename apps/client/src/app/providers/{theme => }/ThemeProvider.tsx (80%) delete mode 100644 apps/client/src/app/providers/auth/types.ts create mode 100644 apps/client/src/app/providers/index.ts delete mode 100644 apps/client/src/app/providers/theme/types.ts create mode 100644 apps/client/src/app/routes/config/index.ts rename apps/client/src/app/routes/config/{routerOptions.ts => options.ts} (100%) rename apps/client/src/app/routes/{index.tsx => index.ts} (100%) rename apps/client/src/pages/Auth/{index.tsx => index.ts} (100%) delete mode 100644 apps/client/src/pages/Broadcast/config/index.ts create mode 100644 apps/client/src/pages/Broadcast/model/index.ts rename apps/client/src/pages/Broadcast/{config/videoOptions.ts => model/mediasoup/encodingOptions.ts} (61%) create mode 100644 apps/client/src/pages/Broadcast/model/mediasoup/index.ts rename apps/client/src/pages/Broadcast/{hooks => model/mediasoup}/useProducer.ts (94%) rename apps/client/src/pages/Broadcast/{hooks => model/mediasoup}/useRoom.ts (100%) rename apps/client/src/pages/Broadcast/{types => model}/trackTypes.ts (100%) rename apps/client/src/pages/Broadcast/{hooks => model}/useMedia.ts (100%) rename apps/client/src/pages/Broadcast/{hooks => model}/useScreenShare.ts (95%) rename apps/client/src/pages/Broadcast/ui/{ => BroadcastPlayer}/BroadcastPlayer.tsx (96%) create mode 100644 apps/client/src/pages/Broadcast/ui/BroadcastPlayer/index.ts create mode 100644 apps/client/src/pages/Broadcast/ui/BroadcastPlayer/resolutionOptions.ts create mode 100644 apps/client/src/pages/Broadcast/ui/index.ts rename apps/client/src/pages/Home/{index.tsx => index.ts} (100%) rename apps/client/src/pages/Home/{types => model}/homeTypes.ts (100%) create mode 100644 apps/client/src/pages/Home/model/index.ts rename apps/client/src/pages/{Live/hooks => Home/model}/useIntersect.ts (100%) rename apps/client/src/pages/Home/ui/{ => Banner}/Banner.tsx (82%) rename apps/client/src/pages/Home/ui/{ => Banner}/Bookmark.tsx (94%) create mode 100644 apps/client/src/pages/Home/ui/Banner/index.ts create mode 100644 apps/client/src/pages/Home/ui/Banner/types.ts create mode 100644 apps/client/src/pages/Home/ui/index.ts rename apps/client/src/pages/Live/{index.tsx => index.ts} (100%) create mode 100644 apps/client/src/pages/Live/model/index.ts rename apps/client/src/pages/Live/{hooks => model}/useConsumer.ts (94%) rename apps/client/src/pages/Live/ui/{ => LiveCamperInfo}/LiveCamperInfo.tsx (87%) create mode 100644 apps/client/src/pages/Live/ui/LiveCamperInfo/index.ts rename apps/client/src/pages/Live/{types/liveTypes.ts => ui/LiveCamperInfo/types.ts} (100%) rename apps/client/src/pages/Live/ui/{ => LivePlayer}/LivePlayer.tsx (86%) create mode 100644 apps/client/src/pages/Live/ui/LivePlayer/index.ts create mode 100644 apps/client/src/pages/Live/ui/LivePlayer/types.ts create mode 100644 apps/client/src/pages/Live/ui/index.ts rename apps/client/src/pages/Profile/{index.tsx => index.ts} (100%) create mode 100644 apps/client/src/pages/Profile/ui/index.ts create mode 100644 apps/client/src/pages/Profile/ui/types.ts rename apps/client/src/pages/Record/{index.tsx => index.ts} (100%) create mode 100644 apps/client/src/pages/Record/ui/index.ts rename apps/client/src/{app/providers/auth => shared/contexts}/AuthContext.tsx (64%) rename apps/client/src/{app/providers/theme => shared/contexts}/ThemeContext.tsx (61%) create mode 100644 apps/client/src/shared/contexts/index.ts create mode 100644 apps/client/src/shared/lib/index.ts rename apps/client/src/shared/lib/{socket => }/useSocket.ts (100%) rename apps/client/src/shared/lib/{toast => }/useToast.ts (100%) rename apps/client/src/shared/lib/{mediasoup => }/useTransport.ts (98%) rename apps/client/src/shared/lib/{utils => }/utils.ts (100%) create mode 100644 apps/client/src/shared/types/index.ts rename apps/client/src/shared/ui/{FloatingButton/index.tsx => FloatingButton.tsx} (88%) create mode 100644 apps/client/src/shared/ui/Header/Header.tsx create mode 100644 apps/client/src/shared/ui/Header/LogoButton.tsx rename apps/client/src/shared/ui/{IconButton/index.tsx => IconButton.tsx} (82%) rename apps/client/src/shared/ui/{Modal/index.tsx => Modal.tsx} (93%) rename apps/client/src/shared/ui/{Icons/Character.tsx => character/DefaultCharacter.tsx} (93%) rename apps/client/src/shared/ui/{ErrorCharacter/index.tsx => character/ErrorCharacter.tsx} (94%) rename apps/client/src/shared/ui/{LoadingCharacter/index.tsx => character/LoadingCharacter.tsx} (96%) rename apps/client/src/shared/ui/{Icons => character}/MoveCharacter.tsx (99%) create mode 100644 apps/client/src/shared/ui/character/index.ts create mode 100644 apps/client/src/shared/ui/character/types.ts rename apps/client/src/shared/ui/{ChatContainer/index.tsx => chat/ChatContainer.tsx} (92%) rename apps/client/src/shared/ui/{ChatContainer => chat}/ChatEndModal.tsx (94%) create mode 100644 apps/client/src/shared/ui/chat/index.ts create mode 100644 apps/client/src/shared/ui/chat/types.ts create mode 100644 apps/client/src/shared/ui/index.ts create mode 100644 apps/client/src/shared/ui/shadcn/index.ts diff --git a/apps/client/src/app/layouts/Layout.tsx b/apps/client/src/app/layouts/Layout.tsx index bd82bdb5..a2cc65f8 100644 --- a/apps/client/src/app/layouts/Layout.tsx +++ b/apps/client/src/app/layouts/Layout.tsx @@ -1,7 +1,6 @@ import { Outlet } from 'react-router-dom'; -import Header from '@/shared/ui/Header'; import { Toaster } from '@/shared/ui/shadcn/toaster'; -import FloatingButton from '@/shared/ui/FloatingButton'; +import { Header, FloatingButton } from '@/shared/ui'; import { Providers } from '../providers'; export function Layout() { diff --git a/apps/client/src/app/layouts/index.tsx b/apps/client/src/app/layouts/index.ts similarity index 100% rename from apps/client/src/app/layouts/index.tsx rename to apps/client/src/app/layouts/index.ts diff --git a/apps/client/src/app/providers/auth/AuthProvider.tsx b/apps/client/src/app/providers/AuthProvider.tsx similarity index 88% rename from apps/client/src/app/providers/auth/AuthProvider.tsx rename to apps/client/src/app/providers/AuthProvider.tsx index a912a189..c1cdb67a 100644 --- a/apps/client/src/app/providers/auth/AuthProvider.tsx +++ b/apps/client/src/app/providers/AuthProvider.tsx @@ -1,5 +1,5 @@ import { useMemo, useState } from 'react'; -import { AuthContext } from './AuthContext'; +import { AuthContext } from '@/shared/contexts'; export function AuthProvider({ children }: { children: React.ReactNode }) { const [isLoggedIn, setIsLoggedIn] = useState(() => !!localStorage.getItem('accessToken')); diff --git a/apps/client/src/app/providers/index.tsx b/apps/client/src/app/providers/Providers.tsx similarity index 57% rename from apps/client/src/app/providers/index.tsx rename to apps/client/src/app/providers/Providers.tsx index eea4db24..9edec631 100644 --- a/apps/client/src/app/providers/index.tsx +++ b/apps/client/src/app/providers/Providers.tsx @@ -1,5 +1,5 @@ -import { ThemeProvider } from '@/app/providers/theme/ThemeProvider'; -import { AuthProvider } from '@/app/providers/auth/AuthProvider'; +import { ThemeProvider } from '@/app/providers/ThemeProvider'; +import { AuthProvider } from '@/app/providers/AuthProvider'; export function Providers({ children }: { children: React.ReactNode }) { return ( diff --git a/apps/client/src/app/providers/theme/ThemeProvider.tsx b/apps/client/src/app/providers/ThemeProvider.tsx similarity index 80% rename from apps/client/src/app/providers/theme/ThemeProvider.tsx rename to apps/client/src/app/providers/ThemeProvider.tsx index 3221d946..9ad225c1 100644 --- a/apps/client/src/app/providers/theme/ThemeProvider.tsx +++ b/apps/client/src/app/providers/ThemeProvider.tsx @@ -1,6 +1,7 @@ import { useMemo, useState } from 'react'; -import { Theme } from './types'; -import { ThemeContext } from './ThemeContext'; +import { ThemeContext } from '@/shared/contexts'; + +type Theme = 'light' | 'dark' | null; export function ThemeProvider({ children }: { children: React.ReactNode }) { const [theme, setTheme] = useState(() => (localStorage.getItem('theme') as Theme) ?? null); diff --git a/apps/client/src/app/providers/auth/types.ts b/apps/client/src/app/providers/auth/types.ts deleted file mode 100644 index 41ffba88..00000000 --- a/apps/client/src/app/providers/auth/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type AuthContextValue = { - isLoggedIn: boolean; - setIsLoggedIn: React.Dispatch>; -}; diff --git a/apps/client/src/app/providers/index.ts b/apps/client/src/app/providers/index.ts new file mode 100644 index 00000000..4c75a95d --- /dev/null +++ b/apps/client/src/app/providers/index.ts @@ -0,0 +1 @@ +export { Providers } from './Providers'; diff --git a/apps/client/src/app/providers/theme/types.ts b/apps/client/src/app/providers/theme/types.ts deleted file mode 100644 index 083c5825..00000000 --- a/apps/client/src/app/providers/theme/types.ts +++ /dev/null @@ -1,6 +0,0 @@ -export type Theme = 'light' | 'dark' | null; - -export type ThemeContextValue = { - theme: Theme; - setTheme: React.Dispatch>; -}; diff --git a/apps/client/src/app/routes/ProtectedRoute.tsx b/apps/client/src/app/routes/ProtectedRoute.tsx index c85fcf41..e4e0acb9 100644 --- a/apps/client/src/app/routes/ProtectedRoute.tsx +++ b/apps/client/src/app/routes/ProtectedRoute.tsx @@ -1,6 +1,6 @@ import { useContext } from 'react'; import { Navigate, Outlet } from 'react-router-dom'; -import { AuthContext } from '@/app/providers/auth/AuthContext'; +import { AuthContext } from '@/shared/contexts/AuthContext'; function ProtectedRoute() { const { isLoggedIn } = useContext(AuthContext); diff --git a/apps/client/src/app/routes/config/index.ts b/apps/client/src/app/routes/config/index.ts new file mode 100644 index 00000000..e8b2d712 --- /dev/null +++ b/apps/client/src/app/routes/config/index.ts @@ -0,0 +1 @@ +export { routerOptions } from './options'; diff --git a/apps/client/src/app/routes/config/routerOptions.ts b/apps/client/src/app/routes/config/options.ts similarity index 100% rename from apps/client/src/app/routes/config/routerOptions.ts rename to apps/client/src/app/routes/config/options.ts diff --git a/apps/client/src/app/routes/index.tsx b/apps/client/src/app/routes/index.ts similarity index 100% rename from apps/client/src/app/routes/index.tsx rename to apps/client/src/app/routes/index.ts diff --git a/apps/client/src/app/routes/router.tsx b/apps/client/src/app/routes/router.tsx index 8783d2a0..1da40b29 100644 --- a/apps/client/src/app/routes/router.tsx +++ b/apps/client/src/app/routes/router.tsx @@ -1,13 +1,13 @@ import { createBrowserRouter } from 'react-router-dom'; import { HomePage } from '@pages/Home'; -import { ProfilePage } from '@pages/Profile'; import { LivePage } from '@pages/Live'; import { BroadcastPage } from '@pages/Broadcast'; import { AuthPage } from '@pages/Auth'; import { RecordPage } from '@pages/Record'; +import { ProfilePage } from '@/pages/Profile'; import { Layout } from '@/app/layouts'; import ProtectedRoute from './ProtectedRoute'; -import { routerOptions } from './config/routerOptions'; +import { routerOptions } from './config'; export const router = createBrowserRouter( [ diff --git a/apps/client/src/pages/Auth/AuthPage.tsx b/apps/client/src/pages/Auth/AuthPage.tsx index 606d3077..48c1762a 100644 --- a/apps/client/src/pages/Auth/AuthPage.tsx +++ b/apps/client/src/pages/Auth/AuthPage.tsx @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react'; import { useNavigate, useSearchParams } from 'react-router-dom'; -import ErrorCharacter from '@/shared/ui/ErrorCharacter'; -import { useAuth } from '@/shared/lib/useAuth'; +import { ErrorCharacter } from '@/shared/ui'; +import { useAuth } from '@/shared/lib'; export function AuthPage() { const [searchParams] = useSearchParams(); diff --git a/apps/client/src/pages/Auth/index.tsx b/apps/client/src/pages/Auth/index.ts similarity index 100% rename from apps/client/src/pages/Auth/index.tsx rename to apps/client/src/pages/Auth/index.ts diff --git a/apps/client/src/pages/Broadcast/BroadcastPage.tsx b/apps/client/src/pages/Broadcast/BroadcastPage.tsx index 6c2860c7..698130cc 100644 --- a/apps/client/src/pages/Broadcast/BroadcastPage.tsx +++ b/apps/client/src/pages/Broadcast/BroadcastPage.tsx @@ -1,10 +1,7 @@ import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'; -import ChatContainer from '@/shared/ui/ChatContainer'; -import ErrorCharacter from '@/shared/ui/ErrorCharacter'; -import { useProducer } from '@/pages/Broadcast/hooks/useProducer'; -import { useRoom } from '@/pages/Broadcast/hooks/useRoom'; -import { useSocket } from '@/shared/lib/socket/useSocket'; -import { useTransport } from '@/shared/lib/mediasoup/useTransport'; +import { ChatContainer, ErrorCharacter } from '@/shared/ui'; +import { useRoom, useProducer, useMedia, useScreenShare, Tracks } from './model'; +import { useSocket, useTransport, useTheme } from '@/shared/lib'; import { Button } from '@/shared/ui/shadcn/button'; import { MicrophoneOffIcon, @@ -12,16 +9,10 @@ import { VideoOffIcon, VideoOnIcon, ScreenShareIcon, - ScreenShareIconOff, + ScreenShareOffIcon, } from '@/shared/ui/Icons'; -import BroadcastTitle from './ui/BroadcastTitle'; -import useScreenShare from '@/pages/Broadcast/hooks/useScreenShare'; -import BroadcastPlayer from './ui/BroadcastPlayer'; -import { Tracks } from './types/trackTypes'; -import RecordButton from './ui/RecordButton'; +import { BroadcastPlayer, BroadcastTitle, RecordButton } from './ui'; import axiosInstance from '@/shared/api/axios'; -import { useMedia } from '@/pages/Broadcast/hooks/useMedia'; -import { useTheme } from '@/shared/lib/useTheme'; const mediaServerUrl = import.meta.env.VITE_MEDIASERVER_URL; @@ -209,7 +200,7 @@ export function BroadcastPage() { {isAudioEnabled ? : }
diff --git a/apps/client/src/pages/Broadcast/config/index.ts b/apps/client/src/pages/Broadcast/config/index.ts deleted file mode 100644 index 1ffaa539..00000000 --- a/apps/client/src/pages/Broadcast/config/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { ENCODING_OPTIONS, RESOLUTION_OPTIONS } from './videoOptions'; diff --git a/apps/client/src/pages/Broadcast/model/index.ts b/apps/client/src/pages/Broadcast/model/index.ts new file mode 100644 index 00000000..1c7e393c --- /dev/null +++ b/apps/client/src/pages/Broadcast/model/index.ts @@ -0,0 +1,4 @@ +export { useMedia } from './useMedia'; +export { useRoom, useProducer } from './mediasoup'; +export { useScreenShare } from './useScreenShare'; +export type { Tracks } from './trackTypes'; diff --git a/apps/client/src/pages/Broadcast/config/videoOptions.ts b/apps/client/src/pages/Broadcast/model/mediasoup/encodingOptions.ts similarity index 61% rename from apps/client/src/pages/Broadcast/config/videoOptions.ts rename to apps/client/src/pages/Broadcast/model/mediasoup/encodingOptions.ts index 1e261c0e..f9f37565 100644 --- a/apps/client/src/pages/Broadcast/config/videoOptions.ts +++ b/apps/client/src/pages/Broadcast/model/mediasoup/encodingOptions.ts @@ -3,9 +3,3 @@ export const ENCODING_OPTIONS = [ { maxBitrate: 2500000, scaleResolutionDownBy: 1.5, maxFramerate: 30 }, { maxBitrate: 4000000, scaleResolutionDownBy: 1, maxFramerate: 30 }, ]; - -export const RESOLUTION_OPTIONS = { - high: { width: 1920, height: 1080 }, - medium: { width: 1280, height: 720 }, - low: { width: 854, height: 480 }, -}; diff --git a/apps/client/src/pages/Broadcast/model/mediasoup/index.ts b/apps/client/src/pages/Broadcast/model/mediasoup/index.ts new file mode 100644 index 00000000..c74ebb69 --- /dev/null +++ b/apps/client/src/pages/Broadcast/model/mediasoup/index.ts @@ -0,0 +1,2 @@ +export { useRoom } from './useRoom'; +export { useProducer } from './useProducer'; diff --git a/apps/client/src/pages/Broadcast/hooks/useProducer.ts b/apps/client/src/pages/Broadcast/model/mediasoup/useProducer.ts similarity index 94% rename from apps/client/src/pages/Broadcast/hooks/useProducer.ts rename to apps/client/src/pages/Broadcast/model/mediasoup/useProducer.ts index 12a3b622..37a4e45d 100644 --- a/apps/client/src/pages/Broadcast/hooks/useProducer.ts +++ b/apps/client/src/pages/Broadcast/model/mediasoup/useProducer.ts @@ -1,9 +1,9 @@ import { useEffect, useRef, useState } from 'react'; import { Transport, Device, Producer } from 'mediasoup-client/lib/types'; import { Socket } from 'socket.io-client'; -import { ConnectTransportResponse, TransportInfo } from '@/shared/types/mediasoupTypes'; -import { checkDependencies } from '@/shared/lib/utils/utils'; -import { ENCODING_OPTIONS } from '../config'; +import { TransportInfo } from '@/shared/types/mediasoupTypes'; +import { checkDependencies } from '@/shared/lib'; +import { ENCODING_OPTIONS } from './encodingOptions'; type UseProducerProps = { socket: Socket | null; @@ -23,6 +23,11 @@ type UseProducerReturn = { producers: Map; }; +type ConnectTransportResponse = { + connected: boolean; + isProducer: boolean; +}; + export const useProducer = ({ socket, mediaStream, diff --git a/apps/client/src/pages/Broadcast/hooks/useRoom.ts b/apps/client/src/pages/Broadcast/model/mediasoup/useRoom.ts similarity index 100% rename from apps/client/src/pages/Broadcast/hooks/useRoom.ts rename to apps/client/src/pages/Broadcast/model/mediasoup/useRoom.ts diff --git a/apps/client/src/pages/Broadcast/types/trackTypes.ts b/apps/client/src/pages/Broadcast/model/trackTypes.ts similarity index 100% rename from apps/client/src/pages/Broadcast/types/trackTypes.ts rename to apps/client/src/pages/Broadcast/model/trackTypes.ts diff --git a/apps/client/src/pages/Broadcast/hooks/useMedia.ts b/apps/client/src/pages/Broadcast/model/useMedia.ts similarity index 100% rename from apps/client/src/pages/Broadcast/hooks/useMedia.ts rename to apps/client/src/pages/Broadcast/model/useMedia.ts diff --git a/apps/client/src/pages/Broadcast/hooks/useScreenShare.ts b/apps/client/src/pages/Broadcast/model/useScreenShare.ts similarity index 95% rename from apps/client/src/pages/Broadcast/hooks/useScreenShare.ts rename to apps/client/src/pages/Broadcast/model/useScreenShare.ts index a53fdfcc..b7fc5261 100644 --- a/apps/client/src/pages/Broadcast/hooks/useScreenShare.ts +++ b/apps/client/src/pages/Broadcast/model/useScreenShare.ts @@ -1,6 +1,6 @@ import { useRef, useState } from 'react'; -const useScreenShare = () => { +export const useScreenShare = () => { const screenStreamRef = useRef(null); const [screenShareError, setScreenShareError] = useState(null); const [isScreenSharing, setIsScreenSharing] = useState(false); @@ -50,5 +50,3 @@ const useScreenShare = () => { toggleScreenShare, }; }; - -export default useScreenShare; diff --git a/apps/client/src/pages/Broadcast/ui/BroadcastPlayer.tsx b/apps/client/src/pages/Broadcast/ui/BroadcastPlayer/BroadcastPlayer.tsx similarity index 96% rename from apps/client/src/pages/Broadcast/ui/BroadcastPlayer.tsx rename to apps/client/src/pages/Broadcast/ui/BroadcastPlayer/BroadcastPlayer.tsx index 6afb6e60..be9ea81c 100644 --- a/apps/client/src/pages/Broadcast/ui/BroadcastPlayer.tsx +++ b/apps/client/src/pages/Broadcast/ui/BroadcastPlayer/BroadcastPlayer.tsx @@ -1,6 +1,6 @@ import { useEffect, useRef } from 'react'; -import { RESOLUTION_OPTIONS } from '../config'; -import { Tracks } from '../types/trackTypes'; +import { RESOLUTION_OPTIONS } from './resolutionOptions'; +import { Tracks } from '../../model/trackTypes'; type BroadcastPlayerProps = { mediaStream: MediaStream | null; @@ -12,7 +12,7 @@ type BroadcastPlayerProps = { tracksRef: React.MutableRefObject; }; -function BroadcastPlayer({ +export function BroadcastPlayer({ mediaStream, screenStream, isVideoEnabled, @@ -144,5 +144,3 @@ function BroadcastPlayer({ ); } - -export default BroadcastPlayer; diff --git a/apps/client/src/pages/Broadcast/ui/BroadcastPlayer/index.ts b/apps/client/src/pages/Broadcast/ui/BroadcastPlayer/index.ts new file mode 100644 index 00000000..8385789a --- /dev/null +++ b/apps/client/src/pages/Broadcast/ui/BroadcastPlayer/index.ts @@ -0,0 +1 @@ +export { BroadcastPlayer } from './BroadcastPlayer'; diff --git a/apps/client/src/pages/Broadcast/ui/BroadcastPlayer/resolutionOptions.ts b/apps/client/src/pages/Broadcast/ui/BroadcastPlayer/resolutionOptions.ts new file mode 100644 index 00000000..37397126 --- /dev/null +++ b/apps/client/src/pages/Broadcast/ui/BroadcastPlayer/resolutionOptions.ts @@ -0,0 +1,5 @@ +export const RESOLUTION_OPTIONS = { + high: { width: 1920, height: 1080 }, + medium: { width: 1280, height: 720 }, + low: { width: 854, height: 480 }, +}; diff --git a/apps/client/src/pages/Broadcast/ui/BroadcastTitle.tsx b/apps/client/src/pages/Broadcast/ui/BroadcastTitle.tsx index 33fb8f91..17649a60 100644 --- a/apps/client/src/pages/Broadcast/ui/BroadcastTitle.tsx +++ b/apps/client/src/pages/Broadcast/ui/BroadcastTitle.tsx @@ -12,7 +12,7 @@ type BroadcastTitleProps = { onTitleChange: (newTitle: string) => void; }; -function BroadcastTitle({ currentTitle, onTitleChange }: BroadcastTitleProps) { +export function BroadcastTitle({ currentTitle, onTitleChange }: BroadcastTitleProps) { const { register, handleSubmit, @@ -71,5 +71,3 @@ function BroadcastTitle({ currentTitle, onTitleChange }: BroadcastTitleProps) { ); } - -export default BroadcastTitle; diff --git a/apps/client/src/pages/Broadcast/ui/RecordButton.tsx b/apps/client/src/pages/Broadcast/ui/RecordButton.tsx index 8b74d74a..7cdf034d 100644 --- a/apps/client/src/pages/Broadcast/ui/RecordButton.tsx +++ b/apps/client/src/pages/Broadcast/ui/RecordButton.tsx @@ -3,7 +3,7 @@ import { createPortal } from 'react-dom'; import { useForm } from 'react-hook-form'; import { Socket } from 'socket.io-client'; import { Button } from '@/shared/ui/shadcn/button'; -import Modal from '@/shared/ui/Modal'; +import { Modal } from '@/shared/ui'; type FormInput = { title: string; @@ -14,7 +14,7 @@ type RecordButtonProps = { roomId: string; }; -function RecordButton({ socket, roomId }: RecordButtonProps) { +export function RecordButton({ socket, roomId }: RecordButtonProps) { const [isRecording, setIsRecording] = useState(false); const [isEditing, setIsEditing] = useState(false); @@ -98,5 +98,3 @@ function RecordButton({ socket, roomId }: RecordButtonProps) { ); } - -export default RecordButton; diff --git a/apps/client/src/pages/Broadcast/ui/index.ts b/apps/client/src/pages/Broadcast/ui/index.ts new file mode 100644 index 00000000..5463a5fd --- /dev/null +++ b/apps/client/src/pages/Broadcast/ui/index.ts @@ -0,0 +1,3 @@ +export { BroadcastPlayer } from './BroadcastPlayer'; +export { BroadcastTitle } from './BroadcastTitle'; +export { RecordButton } from './RecordButton'; diff --git a/apps/client/src/pages/Home/HomePage.tsx b/apps/client/src/pages/Home/HomePage.tsx index ad9f285a..adbf5399 100644 --- a/apps/client/src/pages/Home/HomePage.tsx +++ b/apps/client/src/pages/Home/HomePage.tsx @@ -1,5 +1,4 @@ -import LiveList from '@/pages/Home/ui/LiveList'; -import Banner from './ui/Banner'; +import { Banner, LiveList } from './ui'; export function HomePage() { return ( diff --git a/apps/client/src/pages/Home/index.tsx b/apps/client/src/pages/Home/index.ts similarity index 100% rename from apps/client/src/pages/Home/index.tsx rename to apps/client/src/pages/Home/index.ts diff --git a/apps/client/src/pages/Home/types/homeTypes.ts b/apps/client/src/pages/Home/model/homeTypes.ts similarity index 100% rename from apps/client/src/pages/Home/types/homeTypes.ts rename to apps/client/src/pages/Home/model/homeTypes.ts diff --git a/apps/client/src/pages/Home/model/index.ts b/apps/client/src/pages/Home/model/index.ts new file mode 100644 index 00000000..e62cd6ef --- /dev/null +++ b/apps/client/src/pages/Home/model/index.ts @@ -0,0 +1,2 @@ +export { useIntersect } from './useIntersect'; +export type { LivePreviewInfo, LivePreviewListInfo } from './homeTypes'; diff --git a/apps/client/src/pages/Live/hooks/useIntersect.ts b/apps/client/src/pages/Home/model/useIntersect.ts similarity index 100% rename from apps/client/src/pages/Live/hooks/useIntersect.ts rename to apps/client/src/pages/Home/model/useIntersect.ts diff --git a/apps/client/src/pages/Home/ui/Banner.tsx b/apps/client/src/pages/Home/ui/Banner/Banner.tsx similarity index 82% rename from apps/client/src/pages/Home/ui/Banner.tsx rename to apps/client/src/pages/Home/ui/Banner/Banner.tsx index f7b99bbf..34b53304 100644 --- a/apps/client/src/pages/Home/ui/Banner.tsx +++ b/apps/client/src/pages/Home/ui/Banner/Banner.tsx @@ -1,7 +1,7 @@ -import MoveCharacter from '@/shared/ui/Icons/MoveCharacter'; -import Bookmark from './Bookmark'; +import { MoveCharacter } from '@/shared/ui'; +import { Bookmark } from './Bookmark'; -function Banner() { +export function Banner() { return (
@@ -19,5 +19,3 @@ function Banner() {
); } - -export default Banner; diff --git a/apps/client/src/pages/Home/ui/Bookmark.tsx b/apps/client/src/pages/Home/ui/Banner/Bookmark.tsx similarity index 94% rename from apps/client/src/pages/Home/ui/Bookmark.tsx rename to apps/client/src/pages/Home/ui/Banner/Bookmark.tsx index caca6b65..a0f0ceb2 100644 --- a/apps/client/src/pages/Home/ui/Bookmark.tsx +++ b/apps/client/src/pages/Home/ui/Banner/Bookmark.tsx @@ -1,20 +1,14 @@ import { createPortal } from 'react-dom'; import { useForm } from 'react-hook-form'; import { useContext, useEffect, useState } from 'react'; -import Modal from '@/shared/ui/Modal'; +import { Modal, CloseIcon } from '@/shared/ui'; import { Button } from '@/shared/ui/shadcn/button'; -import { useToast } from '@/shared/lib/toast/useToast'; -import { AuthContext } from '@/app/providers/auth/AuthContext'; +import { useToast } from '@/shared/lib'; +import { AuthContext } from '@/shared/contexts'; import axiosInstance from '@/shared/api/axios'; -import { CloseIcon } from '@/shared/ui/Icons'; +import { BookmarkData } from './types'; -type BookmarkData = { - bookmarkId: number; - name: string; - url: string; -}; - -function Bookmark() { +export function Bookmark() { const { isLoggedIn } = useContext(AuthContext); const [bookmarkList, setBookmarkList] = useState([]); const [showModal, setShowModal] = useState(false); @@ -156,5 +150,3 @@ function Bookmark() { ); } - -export default Bookmark; diff --git a/apps/client/src/pages/Home/ui/Banner/index.ts b/apps/client/src/pages/Home/ui/Banner/index.ts new file mode 100644 index 00000000..f4930c07 --- /dev/null +++ b/apps/client/src/pages/Home/ui/Banner/index.ts @@ -0,0 +1 @@ +export { Banner } from './Banner'; diff --git a/apps/client/src/pages/Home/ui/Banner/types.ts b/apps/client/src/pages/Home/ui/Banner/types.ts new file mode 100644 index 00000000..2c38cd40 --- /dev/null +++ b/apps/client/src/pages/Home/ui/Banner/types.ts @@ -0,0 +1,5 @@ +export type BookmarkData = { + bookmarkId: number; + name: string; + url: string; +}; diff --git a/apps/client/src/pages/Home/ui/FieldFilter.tsx b/apps/client/src/pages/Home/ui/FieldFilter.tsx index 77497eb7..8805f377 100644 --- a/apps/client/src/pages/Home/ui/FieldFilter.tsx +++ b/apps/client/src/pages/Home/ui/FieldFilter.tsx @@ -8,7 +8,7 @@ type FieldFilterProps = { onClickFilterButton: (field: Field) => void; }; -function FieldFilter({ onClickFilterButton }: FieldFilterProps) { +export function FieldFilter({ onClickFilterButton }: FieldFilterProps) { const [selected, setSelected] = useState(''); const handleClick = (field: Field) => { @@ -35,5 +35,3 @@ function FieldFilter({ onClickFilterButton }: FieldFilterProps) {
); } - -export default FieldFilter; diff --git a/apps/client/src/pages/Home/ui/LiveCard.tsx b/apps/client/src/pages/Home/ui/LiveCard.tsx index ba32d2d0..dd9188e6 100644 --- a/apps/client/src/pages/Home/ui/LiveCard.tsx +++ b/apps/client/src/pages/Home/ui/LiveCard.tsx @@ -8,7 +8,7 @@ type LiveCardProps = { thumbnailUrl: string; }; -function LiveCard({ liveId, title, userId, profileUrl, thumbnailUrl }: LiveCardProps) { +export function LiveCard({ liveId, title, userId, profileUrl, thumbnailUrl }: LiveCardProps) { const navigate = useNavigate(); const handleClick = () => { @@ -46,5 +46,3 @@ function LiveCard({ liveId, title, userId, profileUrl, thumbnailUrl }: LiveCardP ); } - -export default LiveCard; diff --git a/apps/client/src/pages/Home/ui/LiveList.tsx b/apps/client/src/pages/Home/ui/LiveList.tsx index 1eb8b836..97d4680b 100644 --- a/apps/client/src/pages/Home/ui/LiveList.tsx +++ b/apps/client/src/pages/Home/ui/LiveList.tsx @@ -1,15 +1,15 @@ import { useCallback, useEffect, useState } from 'react'; import axiosInstance from '@/shared/api/axios'; -import FieldFilter from './FieldFilter'; -import LiveCard from './LiveCard'; -import { LivePreviewInfo } from '@/pages/Home/types/homeTypes'; -import Search from './Search'; +import { FieldFilter } from './FieldFilter'; +import { LiveCard } from './LiveCard'; +import { LivePreviewInfo } from '@/pages/Home/model/homeTypes'; +import { Search } from './Search'; import { Field } from '@/shared/types/sharedTypes'; -import { useIntersect } from '@/pages/Live/hooks/useIntersect'; +import { useIntersect } from '@/pages/Home/model'; const LIMIT = 12; -function LiveList() { +export function LiveList() { const [liveList, setLiveList] = useState([]); const [hasNext, setHasNext] = useState(true); const [cursor, setCursor] = useState(null); @@ -93,5 +93,3 @@ function LiveList() { ); } - -export default LiveList; diff --git a/apps/client/src/pages/Home/ui/Search.tsx b/apps/client/src/pages/Home/ui/Search.tsx index 88d9313d..5bbee8d9 100644 --- a/apps/client/src/pages/Home/ui/Search.tsx +++ b/apps/client/src/pages/Home/ui/Search.tsx @@ -1,6 +1,5 @@ import { useForm } from 'react-hook-form'; -import IconButton from '@/shared/ui/IconButton'; -import { SearchIcon } from '@/shared/ui/Icons'; +import { IconButton, SearchIcon } from '@/shared/ui'; type SearchProps = { onSearch: (keyword: string) => void; @@ -10,7 +9,7 @@ type FormInput = { keyword: string; }; -function Search({ onSearch }: SearchProps) { +export function Search({ onSearch }: SearchProps) { const { register, handleSubmit } = useForm(); const hanldeSearchSubmit = ({ keyword }: FormInput) => { @@ -35,5 +34,3 @@ function Search({ onSearch }: SearchProps) { ); } - -export default Search; diff --git a/apps/client/src/pages/Home/ui/index.ts b/apps/client/src/pages/Home/ui/index.ts new file mode 100644 index 00000000..b4a3cab3 --- /dev/null +++ b/apps/client/src/pages/Home/ui/index.ts @@ -0,0 +1,5 @@ +export { Banner } from './Banner'; +export { FieldFilter } from './FieldFilter'; +export { LiveCard } from './LiveCard'; +export { LiveList } from './LiveList'; +export { Search } from './Search'; diff --git a/apps/client/src/pages/Live/LivePage.tsx b/apps/client/src/pages/Live/LivePage.tsx index 759b4bf6..a0e1f920 100644 --- a/apps/client/src/pages/Live/LivePage.tsx +++ b/apps/client/src/pages/Live/LivePage.tsx @@ -1,12 +1,9 @@ import { useEffect } from 'react'; import { useParams } from 'react-router-dom'; -import ChatContainer from '@/shared/ui/ChatContainer'; -import ErrorCharacter from '@/shared/ui/ErrorCharacter'; -import { useConsumer } from '@/pages/Live/hooks/useConsumer'; -import { useSocket } from '@/shared/lib/socket/useSocket'; -import { useTransport } from '@/shared/lib/mediasoup/useTransport'; -import LivePlayer from './ui/LivePlayer'; -import LiveCamperInfo from './ui/LiveCamperInfo'; +import { ChatContainer, ErrorCharacter } from '@/shared/ui'; +import { useConsumer } from './model'; +import { useSocket, useTransport } from '@/shared/lib'; +import { LivePlayer, LiveCamperInfo } from './ui'; const socketUrl = import.meta.env.VITE_MEDIASERVER_URL; diff --git a/apps/client/src/pages/Live/index.tsx b/apps/client/src/pages/Live/index.ts similarity index 100% rename from apps/client/src/pages/Live/index.tsx rename to apps/client/src/pages/Live/index.ts diff --git a/apps/client/src/pages/Live/model/index.ts b/apps/client/src/pages/Live/model/index.ts new file mode 100644 index 00000000..851f3ff4 --- /dev/null +++ b/apps/client/src/pages/Live/model/index.ts @@ -0,0 +1 @@ +export { useConsumer } from './useConsumer'; diff --git a/apps/client/src/pages/Live/hooks/useConsumer.ts b/apps/client/src/pages/Live/model/useConsumer.ts similarity index 94% rename from apps/client/src/pages/Live/hooks/useConsumer.ts rename to apps/client/src/pages/Live/model/useConsumer.ts index 7936761f..798fcf65 100644 --- a/apps/client/src/pages/Live/hooks/useConsumer.ts +++ b/apps/client/src/pages/Live/model/useConsumer.ts @@ -1,8 +1,8 @@ import { useEffect, useRef, useState } from 'react'; import { Transport, Device, MediaKind } from 'mediasoup-client/lib/types'; import { Socket } from 'socket.io-client'; -import { checkDependencies } from '@/shared/lib/utils/utils'; -import { ConnectTransportResponse, TransportInfo } from '@/shared/types/mediasoupTypes'; +import { checkDependencies } from '@/shared/lib'; +import { TransportInfo } from '@/shared/types/mediasoupTypes'; type UseConsumerProps = { socket: Socket | null; @@ -12,17 +12,22 @@ type UseConsumerProps = { isConnected: boolean; }; -export type CreateConsumer = { +type CreateConsumer = { consumerId: string; producerId: string; kind: MediaKind; rtpParameters: any; }; -export type CreateConsumerResponse = { +type CreateConsumerResponse = { consumers: CreateConsumer[]; }; +type ConnectTransportResponse = { + connected: boolean; + isProducer: boolean; +}; + export const useConsumer = ({ socket, device, roomId, transportInfo, isConnected }: UseConsumerProps) => { const transportRef = useRef(null); const [isLoading, setIsLoading] = useState(true); diff --git a/apps/client/src/pages/Live/ui/LiveCamperInfo.tsx b/apps/client/src/pages/Live/ui/LiveCamperInfo/LiveCamperInfo.tsx similarity index 87% rename from apps/client/src/pages/Live/ui/LiveCamperInfo.tsx rename to apps/client/src/pages/Live/ui/LiveCamperInfo/LiveCamperInfo.tsx index f8389f5c..d24d419a 100644 --- a/apps/client/src/pages/Live/ui/LiveCamperInfo.tsx +++ b/apps/client/src/pages/Live/ui/LiveCamperInfo/LiveCamperInfo.tsx @@ -1,13 +1,18 @@ import { Avatar, AvatarFallback, AvatarImage } from '@/shared/ui/shadcn/avatar'; import { Badge } from '@/shared/ui/shadcn/badge'; -import IconButton from '@/shared/ui/IconButton'; import { useAPI } from '@/shared/lib/useAPI'; -import LoadingCharacter from '@/shared/ui/LoadingCharacter'; -import ErrorCharacter from '@/shared/ui/ErrorCharacter'; -import { LiveInfo } from '@/pages/Live/types/liveTypes'; -import { MailIcon, GithubIcon, BlogIcon, LinkedInIcon } from '@/shared/ui/Icons'; +import { + LoadingCharacter, + ErrorCharacter, + IconButton, + MailIcon, + GithubIcon, + BlogIcon, + LinkedInIcon, +} from '@/shared/ui'; +import { LiveInfo } from './types'; -function LiveCamperInfo({ liveId }: { liveId: string }) { +export function LiveCamperInfo({ liveId }: { liveId: string }) { const { data, isLoading, error } = useAPI({ url: `v1/broadcasts/${liveId}/info` }); if (error || !data) { @@ -81,5 +86,3 @@ function LiveCamperInfo({ liveId }: { liveId: string }) { ); } - -export default LiveCamperInfo; diff --git a/apps/client/src/pages/Live/ui/LiveCamperInfo/index.ts b/apps/client/src/pages/Live/ui/LiveCamperInfo/index.ts new file mode 100644 index 00000000..20af8fdb --- /dev/null +++ b/apps/client/src/pages/Live/ui/LiveCamperInfo/index.ts @@ -0,0 +1 @@ +export { LiveCamperInfo } from './LiveCamperInfo'; diff --git a/apps/client/src/pages/Live/types/liveTypes.ts b/apps/client/src/pages/Live/ui/LiveCamperInfo/types.ts similarity index 100% rename from apps/client/src/pages/Live/types/liveTypes.ts rename to apps/client/src/pages/Live/ui/LiveCamperInfo/types.ts diff --git a/apps/client/src/pages/Live/ui/LivePlayer.tsx b/apps/client/src/pages/Live/ui/LivePlayer/LivePlayer.tsx similarity index 86% rename from apps/client/src/pages/Live/ui/LivePlayer.tsx rename to apps/client/src/pages/Live/ui/LivePlayer/LivePlayer.tsx index 5be15637..e1f5cdba 100644 --- a/apps/client/src/pages/Live/ui/LivePlayer.tsx +++ b/apps/client/src/pages/Live/ui/LivePlayer/LivePlayer.tsx @@ -1,25 +1,10 @@ import { useEffect, useRef, useState } from 'react'; -import { Socket } from 'socket.io-client'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/shared/ui/shadcn/select'; import { PlayIcon, PauseIcon, VolumeOffIcon, VolumeOnIcon, ExpandIcon } from '@/shared/ui/Icons'; -import ErrorCharacter from '@/shared/ui/ErrorCharacter'; +import { ErrorCharacter } from '@/shared/ui'; +import { LivePlayerProps, VideoQuality } from './types'; -type Errors = { - socketError: Error | null; - transportError: Error | null; - consumerError: Error | null; -}; - -type LivePlayerProps = { - mediaStream: MediaStream | null; - socket: Socket | null; - transportId: string | undefined; - errors: Errors; -}; - -type VideoQuality = 'auto' | '480p' | '720p' | '1080p'; - -function LivePlayer({ mediaStream, socket, transportId, errors }: LivePlayerProps) { +export function LivePlayer({ mediaStream, socket, transportId, errors }: LivePlayerProps) { const [isVideoEnabled, setIsVideoEnabled] = useState(true); const [isAudioEnabled, setIsAudioEnabled] = useState(false); const [videoQuality, setVideoQuality] = useState('720p'); @@ -116,5 +101,3 @@ function LivePlayer({ mediaStream, socket, transportId, errors }: LivePlayerProp ); } - -export default LivePlayer; diff --git a/apps/client/src/pages/Live/ui/LivePlayer/index.ts b/apps/client/src/pages/Live/ui/LivePlayer/index.ts new file mode 100644 index 00000000..be87dbad --- /dev/null +++ b/apps/client/src/pages/Live/ui/LivePlayer/index.ts @@ -0,0 +1 @@ +export { LivePlayer } from './LivePlayer'; diff --git a/apps/client/src/pages/Live/ui/LivePlayer/types.ts b/apps/client/src/pages/Live/ui/LivePlayer/types.ts new file mode 100644 index 00000000..6e0df374 --- /dev/null +++ b/apps/client/src/pages/Live/ui/LivePlayer/types.ts @@ -0,0 +1,16 @@ +import { Socket } from 'socket.io-client'; + +export type Errors = { + socketError: Error | null; + transportError: Error | null; + consumerError: Error | null; +}; + +export type LivePlayerProps = { + mediaStream: MediaStream | null; + socket: Socket | null; + transportId: string | undefined; + errors: Errors; +}; + +export type VideoQuality = 'auto' | '480p' | '720p' | '1080p'; diff --git a/apps/client/src/pages/Live/ui/index.ts b/apps/client/src/pages/Live/ui/index.ts new file mode 100644 index 00000000..199d1712 --- /dev/null +++ b/apps/client/src/pages/Live/ui/index.ts @@ -0,0 +1,2 @@ +export { LiveCamperInfo } from './LiveCamperInfo'; +export { LivePlayer } from './LivePlayer'; diff --git a/apps/client/src/pages/Profile/ProfilePage.tsx b/apps/client/src/pages/Profile/ProfilePage.tsx index 9e36ca12..69e7df4c 100644 --- a/apps/client/src/pages/Profile/ProfilePage.tsx +++ b/apps/client/src/pages/Profile/ProfilePage.tsx @@ -1,27 +1,7 @@ import { useEffect, useState } from 'react'; -import Attendance from './ui/Attendance'; -import UserInfo from './ui/UserInfo'; -import EditUserInfo from './ui/EditUserInfo'; +import { Attendance, UserInfo, EditUserInfo, UserData } from './ui'; import axiosInstance from '@/shared/api/axios'; -import { Field } from '@/shared/types/sharedTypes'; -import ErrorCharacter from '@/shared/ui/ErrorCharacter'; -import LoadingCharacter from '@/shared/ui/LoadingCharacter'; - -export type Contacts = { - email: string; - github: string; - blog: string; - linkedIn: string; -}; - -export type UserData = { - id: number; - camperId: string; - name: string; - field: Field; - contacts: Contacts; - profileImage: string; -}; +import { ErrorCharacter, LoadingCharacter } from '@/shared/ui'; export function ProfilePage() { const [userData, setUserData] = useState(null); diff --git a/apps/client/src/pages/Profile/index.tsx b/apps/client/src/pages/Profile/index.ts similarity index 100% rename from apps/client/src/pages/Profile/index.tsx rename to apps/client/src/pages/Profile/index.ts diff --git a/apps/client/src/pages/Profile/ui/Attendance.tsx b/apps/client/src/pages/Profile/ui/Attendance.tsx index f5908e78..8ebdbbcb 100644 --- a/apps/client/src/pages/Profile/ui/Attendance.tsx +++ b/apps/client/src/pages/Profile/ui/Attendance.tsx @@ -1,8 +1,7 @@ import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import ErrorCharacter from '@/shared/ui/ErrorCharacter'; +import { ErrorCharacter, LoadingCharacter } from '@/shared/ui'; import { PlayIcon } from '@/shared/ui/Icons'; -import LoadingCharacter from '@/shared/ui/LoadingCharacter'; import axiosInstance from '@/shared/api/axios'; type AttendanceData = { @@ -13,7 +12,7 @@ type AttendanceData = { isAttendance: boolean; }; -function Attendance() { +export function Attendance() { const [attendanceList, setAttendanceList] = useState([]); const [isLoading, setIsLoading] = useState(true); const [showLoading, setShowLoading] = useState(false); @@ -99,5 +98,3 @@ function Attendance() { ); } - -export default Attendance; diff --git a/apps/client/src/pages/Profile/ui/EditUserInfo.tsx b/apps/client/src/pages/Profile/ui/EditUserInfo.tsx index a301ea28..5c438039 100644 --- a/apps/client/src/pages/Profile/ui/EditUserInfo.tsx +++ b/apps/client/src/pages/Profile/ui/EditUserInfo.tsx @@ -1,18 +1,18 @@ import { useForm } from 'react-hook-form'; import { useState } from 'react'; import { Avatar, AvatarFallback, AvatarImage } from '@/shared/ui/shadcn/avatar'; -import { UserData } from '../ProfilePage'; +import { UserData } from './types'; import { Field } from '@/shared/types/sharedTypes'; import { Button } from '@/shared/ui/shadcn/button'; import axiosInstance from '@/shared/api/axios'; -import { useToast } from '@/shared/lib/toast/useToast'; +import { useToast } from '@/shared/lib'; type EditUserInfoProps = { userData: UserData | undefined; toggleEditing: () => void; }; -export interface FormInput { +export type FormInput = { camperId: string | undefined; name: string | undefined; field: Field | undefined; @@ -20,9 +20,9 @@ export interface FormInput { github: string | undefined; blog: string | undefined; linkedIn: string | undefined; -} +}; -function EditUserInfo({ userData, toggleEditing }: EditUserInfoProps) { +export function EditUserInfo({ userData, toggleEditing }: EditUserInfoProps) { const [selectedField, setSelectedField] = useState(userData?.field); const { register, @@ -195,5 +195,3 @@ function EditUserInfo({ userData, toggleEditing }: EditUserInfoProps) { ); } - -export default EditUserInfo; diff --git a/apps/client/src/pages/Profile/ui/UserInfo.tsx b/apps/client/src/pages/Profile/ui/UserInfo.tsx index 88b9cdef..6136ebca 100644 --- a/apps/client/src/pages/Profile/ui/UserInfo.tsx +++ b/apps/client/src/pages/Profile/ui/UserInfo.tsx @@ -1,9 +1,7 @@ import { useEffect, useState } from 'react'; -import ErrorCharacter from '@/shared/ui/ErrorCharacter'; -import { BlogIcon, EditIcon, GithubIcon, LinkedInIcon, MailIcon } from '@/shared/ui/Icons'; -import LoadingCharacter from '@/shared/ui/LoadingCharacter'; +import { ErrorCharacter, LoadingCharacter, BlogIcon, EditIcon, GithubIcon, LinkedInIcon, MailIcon } from '@/shared/ui'; import { Avatar, AvatarFallback, AvatarImage } from '@/shared/ui/shadcn/avatar'; -import { UserData } from '../ProfilePage'; +import { UserData } from './types'; type UserInfoProps = { userData: UserData | undefined; @@ -12,7 +10,7 @@ type UserInfoProps = { toggleEditing: () => void; }; -function UserInfo({ userData, isLoading, error, toggleEditing }: UserInfoProps) { +export function UserInfo({ userData, isLoading, error, toggleEditing }: UserInfoProps) { const [showLoading, setShowLoading] = useState(false); useEffect(() => { @@ -86,5 +84,3 @@ function UserInfo({ userData, isLoading, error, toggleEditing }: UserInfoProps) ); } - -export default UserInfo; diff --git a/apps/client/src/pages/Profile/ui/index.ts b/apps/client/src/pages/Profile/ui/index.ts new file mode 100644 index 00000000..d6e828a6 --- /dev/null +++ b/apps/client/src/pages/Profile/ui/index.ts @@ -0,0 +1,4 @@ +export { Attendance } from './Attendance'; +export { EditUserInfo } from './EditUserInfo'; +export { UserInfo } from './UserInfo'; +export type { UserData } from './types'; diff --git a/apps/client/src/pages/Profile/ui/types.ts b/apps/client/src/pages/Profile/ui/types.ts new file mode 100644 index 00000000..5b54fd70 --- /dev/null +++ b/apps/client/src/pages/Profile/ui/types.ts @@ -0,0 +1,17 @@ +import { Field } from '@/shared/types/sharedTypes'; + +type Contacts = { + email: string; + github: string; + blog: string; + linkedIn: string; +}; + +export type UserData = { + id: number; + camperId: string; + name: string; + field: Field; + contacts: Contacts; + profileImage: string; +}; diff --git a/apps/client/src/pages/Record/RecordPage.tsx b/apps/client/src/pages/Record/RecordPage.tsx index d025e4c4..e4e9e4da 100644 --- a/apps/client/src/pages/Record/RecordPage.tsx +++ b/apps/client/src/pages/Record/RecordPage.tsx @@ -1,7 +1,5 @@ import { useState } from 'react'; -import RecordInfo from './ui/RecordInfo'; -import RecordList from './ui/RecordList'; -import RecordPlayer from './ui/RecordPlayer'; +import { RecordInfo, RecordList, RecordPlayer } from './ui'; export type RecordData = { recordId: number; diff --git a/apps/client/src/pages/Record/index.tsx b/apps/client/src/pages/Record/index.ts similarity index 100% rename from apps/client/src/pages/Record/index.tsx rename to apps/client/src/pages/Record/index.ts diff --git a/apps/client/src/pages/Record/ui/RecordInfo.tsx b/apps/client/src/pages/Record/ui/RecordInfo.tsx index ea12f3dd..3605c750 100644 --- a/apps/client/src/pages/Record/ui/RecordInfo.tsx +++ b/apps/client/src/pages/Record/ui/RecordInfo.tsx @@ -1,14 +1,7 @@ -type RecordInfoProps = { - title: string; -}; - -function RecordInfo(props: RecordInfoProps) { - const { title } = props; +export function RecordInfo({ title }: { title: string }) { return (

{title}

); } - -export default RecordInfo; diff --git a/apps/client/src/pages/Record/ui/RecordList.tsx b/apps/client/src/pages/Record/ui/RecordList.tsx index a0c7782a..04c70373 100644 --- a/apps/client/src/pages/Record/ui/RecordList.tsx +++ b/apps/client/src/pages/Record/ui/RecordList.tsx @@ -1,21 +1,18 @@ import { useEffect, useState } from 'react'; import { useParams } from 'react-router-dom'; -import { PlayIcon } from '@/shared/ui/Icons'; +import { PlayIcon, ErrorCharacter } from '@/shared/ui'; import { RecordData } from '../RecordPage'; import axiosInstance from '@/shared/api/axios'; -import ErrorCharacter from '@/shared/ui/ErrorCharacter'; type RecordListProps = { onClickList: (data: RecordData) => void; }; -function RecordList(props: RecordListProps) { +export function RecordList({ onClickList }: RecordListProps) { const [recordList, setRecordList] = useState([]); const { attendanceId } = useParams<{ attendanceId: string }>(); const [error, setError] = useState(''); - const { onClickList } = props; - useEffect(() => { axiosInstance.get(`/v1/records/${attendanceId}`).then(response => { if (response.data.success) setRecordList(response.data.data.records); @@ -56,5 +53,3 @@ function RecordList(props: RecordListProps) { ); } - -export default RecordList; diff --git a/apps/client/src/pages/Record/ui/RecordPlayer.tsx b/apps/client/src/pages/Record/ui/RecordPlayer.tsx index fa84867d..d36dfd00 100644 --- a/apps/client/src/pages/Record/ui/RecordPlayer.tsx +++ b/apps/client/src/pages/Record/ui/RecordPlayer.tsx @@ -1,14 +1,9 @@ import { useEffect, useState } from 'react'; import ReactPlayer from 'react-player'; -import LoadingCharacter from '@/shared/ui/LoadingCharacter'; +import { LoadingCharacter } from '@/shared/ui'; -type RecordPlayerProps = { - video: string; -}; - -function RecordPlayer(props: RecordPlayerProps) { +export function RecordPlayer({ video }: { video: string }) { const [isSelectedVideo, setIsSelectedVideo] = useState(false); - const { video } = props; useEffect(() => { if (video) { @@ -40,5 +35,3 @@ function RecordPlayer(props: RecordPlayerProps) { ); } - -export default RecordPlayer; diff --git a/apps/client/src/pages/Record/ui/index.ts b/apps/client/src/pages/Record/ui/index.ts new file mode 100644 index 00000000..b7b6255a --- /dev/null +++ b/apps/client/src/pages/Record/ui/index.ts @@ -0,0 +1,3 @@ +export { RecordInfo } from './RecordInfo'; +export { RecordList } from './RecordList'; +export { RecordPlayer } from './RecordPlayer'; diff --git a/apps/client/src/app/providers/auth/AuthContext.tsx b/apps/client/src/shared/contexts/AuthContext.tsx similarity index 64% rename from apps/client/src/app/providers/auth/AuthContext.tsx rename to apps/client/src/shared/contexts/AuthContext.tsx index 92e9406c..e0c77a8b 100644 --- a/apps/client/src/app/providers/auth/AuthContext.tsx +++ b/apps/client/src/shared/contexts/AuthContext.tsx @@ -1,9 +1,13 @@ import { createContext } from 'react'; -import { AuthContextValue } from './types'; const initialState = { isLoggedIn: !!localStorage.getItem('accessToken'), setIsLoggedIn: () => {}, }; +export type AuthContextValue = { + isLoggedIn: boolean; + setIsLoggedIn: React.Dispatch>; +}; + export const AuthContext = createContext(initialState); diff --git a/apps/client/src/app/providers/theme/ThemeContext.tsx b/apps/client/src/shared/contexts/ThemeContext.tsx similarity index 61% rename from apps/client/src/app/providers/theme/ThemeContext.tsx rename to apps/client/src/shared/contexts/ThemeContext.tsx index fd4ff99d..6cc4f639 100644 --- a/apps/client/src/app/providers/theme/ThemeContext.tsx +++ b/apps/client/src/shared/contexts/ThemeContext.tsx @@ -1,8 +1,14 @@ import { createContext } from 'react'; -import { Theme, ThemeContextValue } from './types'; const currentTheme = localStorage.getItem('theme') ?? null; +type Theme = 'light' | 'dark' | null; + +type ThemeContextValue = { + theme: Theme; + setTheme: React.Dispatch>; +}; + export const ThemeContext = createContext({ theme: currentTheme as Theme, setTheme: () => null, diff --git a/apps/client/src/shared/contexts/index.ts b/apps/client/src/shared/contexts/index.ts new file mode 100644 index 00000000..80ca23e3 --- /dev/null +++ b/apps/client/src/shared/contexts/index.ts @@ -0,0 +1,2 @@ +export { AuthContext } from './AuthContext'; +export { ThemeContext } from './ThemeContext'; diff --git a/apps/client/src/shared/lib/index.ts b/apps/client/src/shared/lib/index.ts new file mode 100644 index 00000000..e6b963ab --- /dev/null +++ b/apps/client/src/shared/lib/index.ts @@ -0,0 +1,7 @@ +export { useAPI } from './useAPI'; +export { useAuth } from './useAuth'; +export { useSocket } from './useSocket'; +export { useTheme } from './useTheme'; +export { useToast } from './useToast'; +export { useTransport } from './useTransport'; +export { cn, checkDependencies } from './utils'; diff --git a/apps/client/src/shared/lib/useAuth.ts b/apps/client/src/shared/lib/useAuth.ts index fd8c616d..2fa91ff8 100644 --- a/apps/client/src/shared/lib/useAuth.ts +++ b/apps/client/src/shared/lib/useAuth.ts @@ -1,6 +1,6 @@ import { useContext, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; -import { AuthContext } from '@/app/providers/auth/AuthContext'; +import { AuthContext } from '@/shared/contexts/AuthContext'; export const useAuth = () => { const navigate = useNavigate(); diff --git a/apps/client/src/shared/lib/socket/useSocket.ts b/apps/client/src/shared/lib/useSocket.ts similarity index 100% rename from apps/client/src/shared/lib/socket/useSocket.ts rename to apps/client/src/shared/lib/useSocket.ts diff --git a/apps/client/src/shared/lib/useTheme.ts b/apps/client/src/shared/lib/useTheme.ts index 8a884d21..9a321e19 100644 --- a/apps/client/src/shared/lib/useTheme.ts +++ b/apps/client/src/shared/lib/useTheme.ts @@ -1,5 +1,5 @@ import { useContext, useLayoutEffect } from 'react'; -import { ThemeContext } from '@/app/providers/theme/ThemeContext'; +import { ThemeContext } from '@/shared/contexts/ThemeContext'; export const useTheme = () => { const { theme, setTheme } = useContext(ThemeContext); diff --git a/apps/client/src/shared/lib/toast/useToast.ts b/apps/client/src/shared/lib/useToast.ts similarity index 100% rename from apps/client/src/shared/lib/toast/useToast.ts rename to apps/client/src/shared/lib/useToast.ts diff --git a/apps/client/src/shared/lib/mediasoup/useTransport.ts b/apps/client/src/shared/lib/useTransport.ts similarity index 98% rename from apps/client/src/shared/lib/mediasoup/useTransport.ts rename to apps/client/src/shared/lib/useTransport.ts index 93de43a8..b6aaa01e 100644 --- a/apps/client/src/shared/lib/mediasoup/useTransport.ts +++ b/apps/client/src/shared/lib/useTransport.ts @@ -3,7 +3,7 @@ import { useEffect, useState, useRef } from 'react'; import { RtpCapabilities } from 'mediasoup-client/lib/RtpParameters'; import { Device } from 'mediasoup-client/lib/types'; import { Socket } from 'socket.io-client'; -import { checkDependencies } from '@/shared/lib/utils/utils'; +import { checkDependencies } from '@/shared/lib/utils'; import { TransportInfo } from '@/shared/types/mediasoupTypes'; type UseTransportProps = { diff --git a/apps/client/src/shared/lib/utils/utils.ts b/apps/client/src/shared/lib/utils.ts similarity index 100% rename from apps/client/src/shared/lib/utils/utils.ts rename to apps/client/src/shared/lib/utils.ts diff --git a/apps/client/src/shared/types/index.ts b/apps/client/src/shared/types/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/apps/client/src/shared/ui/FloatingButton/index.tsx b/apps/client/src/shared/ui/FloatingButton.tsx similarity index 88% rename from apps/client/src/shared/ui/FloatingButton/index.tsx rename to apps/client/src/shared/ui/FloatingButton.tsx index dbaf1201..c60b7217 100644 --- a/apps/client/src/shared/ui/FloatingButton/index.tsx +++ b/apps/client/src/shared/ui/FloatingButton.tsx @@ -2,7 +2,7 @@ import { Button } from '@/shared/ui/shadcn/button'; import { ThemeIcon } from '@/shared/ui/Icons'; import { useTheme } from '@/shared/lib/useTheme'; -function FloatingButton() { +export function FloatingButton() { const { convertTheme } = useTheme(); return ( @@ -16,5 +16,3 @@ function FloatingButton() { ); } - -export default FloatingButton; diff --git a/apps/client/src/shared/ui/Header/Header.tsx b/apps/client/src/shared/ui/Header/Header.tsx new file mode 100644 index 00000000..bee794e4 --- /dev/null +++ b/apps/client/src/shared/ui/Header/Header.tsx @@ -0,0 +1,98 @@ +import { useContext, useEffect, useRef, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { Avatar, AvatarFallback, AvatarImage } from '@/shared/ui/shadcn/avatar'; +import { cn } from '@/shared/lib/utils'; +import { AuthContext } from '@/shared/contexts/AuthContext'; +import axiosInstance from '@/shared/api/axios'; +import LogInButton from './LogInButton'; +import { Button } from '@/shared/ui/shadcn/button'; +import { useAuth } from '@/shared/lib/useAuth'; +import { LogoButton } from './LogoButton'; + +export function Header() { + const [isCheckedIn, setIsCheckedIn] = useState(false); + const [profileImgUrl, setProfileImgUrl] = useState(''); + const broadcastRef = useRef(null); + const { isLoggedIn } = useContext(AuthContext); + const { logout } = useAuth(); + const navigate = useNavigate(); + + const handleCheckInClick = () => { + if (broadcastRef.current && !broadcastRef.current.closed) { + broadcastRef.current.focus(); + return; + } + const newTapFeature = [ + `width=580`, + `height=1024`, + `bottom=0`, + `right=0`, + `resizable=yes`, + `scrollbars=no`, + 'status=no', + 'location=no', + 'toolbar=no', + 'menubar=no', + ].join(','); + const broadcastUrl = `${window.location.origin}/broadcast`; + const newWindow = window.open(broadcastUrl, '_blank', newTapFeature); + + if (newWindow) { + setIsCheckedIn(true); + broadcastRef.current = newWindow; + + newWindow.addEventListener('load', () => { + newWindow.addEventListener('unload', () => { + setIsCheckedIn(false); + broadcastRef.current = null; + }); + }); + } + }; + + const handleLogOutClick = () => { + logout(); + navigate('/'); + }; + + useEffect(() => { + if (!isLoggedIn) return; + axiosInstance.get('/v1/members/profile-image').then(response => { + if (!response.data.success) return; + setProfileImgUrl(response.data.data.profileImage); + }); + }, [isLoggedIn]); + + return ( +
+ +
+ {isLoggedIn ? ( +
+ + + { + navigate('/profile'); + }} + className="cursor-pointer h-10 w-10" + aria-label="마이페이지로 이동" + > + + MY + +
+ ) : ( + + )} +
+
+ ); +} diff --git a/apps/client/src/shared/ui/Header/LogInButton.tsx b/apps/client/src/shared/ui/Header/LogInButton.tsx index 6786540d..d988143f 100644 --- a/apps/client/src/shared/ui/Header/LogInButton.tsx +++ b/apps/client/src/shared/ui/Header/LogInButton.tsx @@ -2,9 +2,8 @@ import { useState } from 'react'; import { createPortal } from 'react-dom'; import { WelcomeCharacter } from './WelcomeCharacter'; import { Button } from '@/shared/ui/shadcn/button'; -import Modal from '@/shared/ui/Modal'; -import { GithubIcon, GoogleIcon } from '@/shared/ui/Icons'; -import { useAuth } from '@/shared/lib/useAuth'; +import { Modal, GithubIcon, GoogleIcon } from '@/shared/ui'; +import { useAuth } from '@/shared/lib'; import axiosInstance from '@/shared/api/axios'; function LogInButton() { diff --git a/apps/client/src/shared/ui/Header/LogoButton.tsx b/apps/client/src/shared/ui/Header/LogoButton.tsx new file mode 100644 index 00000000..e448009f --- /dev/null +++ b/apps/client/src/shared/ui/Header/LogoButton.tsx @@ -0,0 +1,21 @@ +import { useNavigate } from 'react-router-dom'; +import { Logo } from '@/shared/ui/Icons'; +import { DefaultCharacter } from '../character'; + +export function LogoButton() { + const navigate = useNavigate(); + const handleLogoClick = () => { + if (window.location.pathname === '/') { + window.location.reload(); + } else { + navigate('/'); + } + }; + + return ( + + ); +} diff --git a/apps/client/src/shared/ui/Header/index.tsx b/apps/client/src/shared/ui/Header/index.tsx index 66fd0e1a..29429dc9 100644 --- a/apps/client/src/shared/ui/Header/index.tsx +++ b/apps/client/src/shared/ui/Header/index.tsx @@ -1,110 +1 @@ -import { useContext, useEffect, useRef, useState } from 'react'; -import { useNavigate } from 'react-router-dom'; -import { Character, Logo } from '@/shared/ui/Icons'; -import { Avatar, AvatarFallback, AvatarImage } from '@/shared/ui/shadcn/avatar'; -import { cn } from '@/shared/lib/utils/utils'; -import { AuthContext } from '@/app/providers/auth/AuthContext'; -import axiosInstance from '@/shared/api/axios'; -import LogInButton from './LogInButton'; -import { Button } from '@/shared/ui/shadcn/button'; -import { useAuth } from '@/shared/lib/useAuth'; - -function Header() { - const [isCheckedIn, setIsCheckedIn] = useState(false); - const [profileImgUrl, setProfileImgUrl] = useState(''); - const broadcastRef = useRef(null); - const { isLoggedIn } = useContext(AuthContext); - const { logout } = useAuth(); - const navigate = useNavigate(); - - const handleLogoClick = () => { - if (window.location.pathname === '/') { - window.location.reload(); - } else { - navigate('/'); - } - }; - const handleCheckInClick = () => { - if (broadcastRef.current && !broadcastRef.current.closed) { - broadcastRef.current.focus(); - return; - } - const newTapFeature = [ - `width=580`, - `height=1024`, - `bottom=0`, - `right=0`, - `resizable=yes`, - `scrollbars=no`, - 'status=no', - 'location=no', - 'toolbar=no', - 'menubar=no', - ].join(','); - const broadcastUrl = `${window.location.origin}/broadcast`; - const newWindow = window.open(broadcastUrl, '_blank', newTapFeature); - - if (newWindow) { - setIsCheckedIn(true); - broadcastRef.current = newWindow; - - newWindow.addEventListener('load', () => { - newWindow.addEventListener('unload', () => { - setIsCheckedIn(false); - broadcastRef.current = null; - }); - }); - } - }; - - const handleLogOutClick = () => { - logout(); - navigate('/'); - }; - - useEffect(() => { - if (!isLoggedIn) return; - axiosInstance.get('/v1/members/profile-image').then(response => { - if (!response.data.success) return; - setProfileImgUrl(response.data.data.profileImage); - }); - }, [isLoggedIn]); - - return ( -
- -
- {isLoggedIn ? ( -
- - - { - navigate('/profile'); - }} - className="cursor-pointer h-10 w-10" - aria-label="마이페이지로 이동" - > - - MY - -
- ) : ( - - )} -
-
- ); -} - -export default Header; +export { Header } from './Header'; diff --git a/apps/client/src/shared/ui/IconButton/index.tsx b/apps/client/src/shared/ui/IconButton.tsx similarity index 82% rename from apps/client/src/shared/ui/IconButton/index.tsx rename to apps/client/src/shared/ui/IconButton.tsx index f37a498b..9c43165d 100644 --- a/apps/client/src/shared/ui/IconButton/index.tsx +++ b/apps/client/src/shared/ui/IconButton.tsx @@ -7,7 +7,7 @@ type IconButtonProps = { className?: string; }; -function IconButton({ children, title, ariaLabel, onClick, disabled, className }: IconButtonProps) { +export function IconButton({ children, title, ariaLabel, onClick, disabled, className }: IconButtonProps) { return (