Skip to content

Commit

Permalink
Merge pull request #226 from boostcampwm-2024/feature/#221
Browse files Browse the repository at this point in the history
[Feat] ๋ฐฉ์žฅ ํ‘œ์‹œ ๊ธฐ๋Šฅ ๊ตฌํ˜„
  • Loading branch information
Cllaude99 authored Dec 3, 2024
2 parents 0bd8de1 + 7ae2ae6 commit b1f038a
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 26 deletions.
Binary file modified packages/frontend/public/images/videoStream/videoPoster.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default function ReadyButton() {

return (
<Button
buttonText={isReady ? '์ค€๋น„์™„๋ฃŒโœ…' : '์ค€๋น„ํ•˜๊ธฐ๐Ÿค”'}
buttonText={isReady ? '์ค€๋น„์™„๋ฃŒ' : '์ค€๋น„ํ•˜๊ธฐ'}
className={`max-w-xs text-xl transition-all text-white-default ${
isReady ? 'bg-green-default' : 'bg-black opacity-90'
}`}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useEffect } from 'react';
import VideoStream from '@/components/gamePage/stream/VideoStream';
import { useAuthStore } from '@/store/authStore';
import { useLocalStreamStore } from '@/store/localStreamStore';
Expand All @@ -11,29 +10,44 @@ export default function VideoFeed() {
const { userId } = useAuthStore();
const feedHeight = 'h-[180px]';
const readyUsers = useRoomStore((state) => state.readyUsers);
const hostUserId = useRoomStore((state) => state.hostUserId);
const isUserReady = (userId: string) => readyUsers.includes(userId);
const isHost = (userId: string) => userId === hostUserId;

return (
<>
<div
className={`relative rounded-lg`}
style={{
boxShadow: isUserReady(userId || '') ? '0 0 0 4px white' : '',
}}
className={`relative rounded-lg ${
isHost(userId || '')
? 'border-4 border-blue-500'
: isUserReady(userId || '')
? 'border-4 border-white'
: ''
}`}
>
<VideoStream stream={localStream} userName={userId} isLocal={true} height={feedHeight} />
{isUserReady(userId || '') && (
<div className="absolute bottom-2 right-2">
<span className="px-2 py-1 text-orange-500 font-bold bg-white rounded-full">READY</span>
</div>
)}
{isHost(userId || '') && (
<div className="absolute top-2 right-2">
<span className="px-2 py-1 text-blue-500 font-bold bg-white rounded-full">HOST</span>
</div>
)}
</div>

{Array.from(remoteStreams).map(([remoteUserId, stream]) => (
<div
key={remoteUserId}
className={`relative ${
isUserReady(remoteUserId) ? 'border-4 border-white' : ''
} rounded-lg`}
className={`relative rounded-lg ${
isHost(remoteUserId)
? 'border-4 border-blue-500'
: isUserReady(remoteUserId)
? 'border-4 border-white'
: ''
}`}
>
<VideoStream
stream={stream}
Expand All @@ -48,8 +62,14 @@ export default function VideoFeed() {
</span>
</div>
)}
{isHost(remoteUserId) && (
<div className="absolute top-2 right-2">
<span className="px-2 py-1 text-blue-500 font-bold bg-white rounded-full">HOST</span>
</div>
)}
</div>
))}

{[...Array(Math.max(0, 5 - remoteStreams.size))].map((_, idx) => (
<VideoStream
key={`empty-${idx}`}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default function LeaveButton() {
socket.emit('leave_room');
signalingSocket.emit('leave_room');
setChatHistory([]);
setRoomData(null, false, false);
setRoomData(null, false, false, '');
navigate('/lobby');
}

Expand Down
36 changes: 28 additions & 8 deletions packages/frontend/src/hooks/useChatSocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ interface IUserJoined {
export const useChatSocket = (gsid: string, userId: string) => {
const { userId: myUserId } = useAuthStore();
const addChatEntry = useChatStore((state) => state.addChatEntry);
const { addUser, removeUser, setIsHost } = useRoomStore();
const { addUser, removeUser, setHostUserId, setIsHost, removeReadyUser } = useRoomStore();
const socket = useSocketStore((state) => state.socket);

useEffect(() => {
Expand All @@ -38,16 +38,27 @@ export const useChatSocket = (gsid: string, userId: string) => {

socket.on('user_left', (data: IUserLeft) => {
removeUser(data.userId);
if (data.hostUserId === userId) {
setIsHost(true);
} else {
setIsHost(false);
}
setHostUserId(data.hostUserId);

removeReadyUser(data.hostUserId);
console.log('์ค€๋น„์œ ์ € ์—…๋ฐ์ดํŠธ ์™„๋ฃŒ');

addChatEntry({
userId: `[์•Œ๋ฆผ]`,
message: `${data.userId}๋‹˜์ด ํ‡ด์žฅํ•˜์…จ์Šต๋‹ˆ๋‹ค.`,
chatType: ChatType.NOTICE,
});

if (data.hostUserId === myUserId) {
setIsHost(true);
addChatEntry({
userId: `[์•Œ๋ฆผ]`,
message: `๋ฐฉ์žฅ์ด ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์ด ์ƒˆ๋กœ์šด ๋ฐฉ์žฅ์ž…๋‹ˆ๋‹ค.`,
chatType: ChatType.NOTICE,
});
} else {
setIsHost(false);
}
});

socket.on('user_joined', (data: IUserJoined) => {
Expand All @@ -64,12 +75,21 @@ export const useChatSocket = (gsid: string, userId: string) => {
socket.off('user_left');
socket.off('user_joined');
};
}, [gsid, socket, addChatEntry, addUser, removeUser, setIsHost, userId, myUserId]);
}, [
gsid,
socket,
addChatEntry,
addUser,
removeUser,
setHostUserId,
setIsHost,
myUserId,
removeReadyUser,
]);

const sendChatEntry = (message: string) => {
if (!socket || !message.trim()) return;

// ์„œ๋ฒ„๋กœ ๋ฉ”์‹œ์ง€ ์ „์†ก
socket.emit('send_message', { gsid, message });
};

Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/hooks/useCreateRoom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export default function useCreateRoom() {
socket.emit('create_room');

socket.on('create_room_success', (data: { gsid: string; isHost: boolean }) => {
setRoomData(data.gsid, data.isHost, false);
setRoomData(data.gsid, data.isHost, false, userId);
setAllUsers([userId]);
signalingSocket.emit('create_room', { gsid: data.gsid });
navigate(`/game/${data.gsid}`);
Expand Down
7 changes: 4 additions & 3 deletions packages/frontend/src/hooks/useJoinRoom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import { useSignalingSocketStore } from '@/store/signalingSocketStore';
export default function useJoinRoom() {
const navigate = useNavigate();
const userId = useAuthStore((state) => state.userId);
const setRoomData = useRoomStore((state) => state.setRoomData);
const { setAllUsers } = useRoomStore();
const { setRoomData, setAllUsers, setReadyUsers, setHostUserId } = useRoomStore();
const socket = useSocketStore((state) => state.socket);
const signalingSocket = useSignalingSocketStore((state) => state.signalingSocket);

Expand All @@ -17,8 +16,10 @@ export default function useJoinRoom() {

socket.emit('join_room', { gsid });
socket.on('join_room_success', (data) => {
setRoomData(gsid, data.isHost, false);
setRoomData(gsid, data.isHost, false, data.hostUserId);
setAllUsers(data.userIds);
setReadyUsers(data.readyUserIds);
setHostUserId(data.hostUserId);
signalingSocket.emit('join_room', { gsid });
navigate(`/game/${gsid}`);
});
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/pages/lobbyPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default function LobbyPage() {
if (gsid) {
socket?.emit('leave_room');
setChatHistory([]);
setRoomData(null, false, false);
setRoomData(null, false, false, '');
}
}, []);

Check warning on line 27 in packages/frontend/src/pages/lobbyPage/index.tsx

View workflow job for this annotation

GitHub Actions / Frontend CI

React Hook useEffect has missing dependencies: 'gsid', 'setChatHistory', 'setRoomData', and 'socket'. Either include them or remove the dependency array

Expand Down
15 changes: 12 additions & 3 deletions packages/frontend/src/store/roomStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ interface IRoomState {
isPinoco: boolean;
allUsers: Set<string>;
readyUsers: string[];
setRoomData: (gsid: string | null, isHost: boolean, isPinoco: boolean) => void;
hostUserId: string | null;
setRoomData: (
gsid: string | null,
isHost: boolean,
isPinoco: boolean,
hostUserId: string,
) => void;
setIsPinoco: (isPinoco: boolean) => void;
setAllUsers: (allUsers: string[]) => void;
addUser: (userId: string) => void;
Expand All @@ -16,6 +22,7 @@ interface IRoomState {
setReadyUsers: (readyUsers: string[]) => void;
addReadyUser: (userId: string) => void;
removeReadyUser: (userId: string) => void;
setHostUserId: (hostUserId: string) => void;
}
export const useRoomStore = create<IRoomState>()(
persist(
Expand All @@ -25,8 +32,10 @@ export const useRoomStore = create<IRoomState>()(
isPinoco: false,
allUsers: new Set(),
readyUsers: [],
hostUserId: null,

setRoomData: (gsid, isHost, isPinoco) => set({ gsid, isHost, isPinoco }),
setRoomData: (gsid, isHost, isPinoco, hostUserId) =>
set({ gsid, isHost, isPinoco, hostUserId }),
setIsPinoco: (isPinoco) => set({ isPinoco }),
setAllUsers: (allUsers) => set({ allUsers: new Set(allUsers) }),
addUser: (userId) =>
Expand All @@ -38,7 +47,6 @@ export const useRoomStore = create<IRoomState>()(
allUsers: new Set([...state.allUsers].filter((id) => id !== userId)),
})),
setIsHost: (isHost) => set({ isHost }),

setReadyUsers: (readyUsers) => set({ readyUsers }),
addReadyUser: (userId) =>
set((state) => ({
Expand All @@ -48,6 +56,7 @@ export const useRoomStore = create<IRoomState>()(
set((state) => ({
readyUsers: state.readyUsers.filter((id) => id !== userId),
})),
setHostUserId: (hostUserId) => set({ hostUserId }),
}),
{ name: 'room-storage' },
),
Expand Down

0 comments on commit b1f038a

Please sign in to comment.