Skip to content

Commit

Permalink
Merge pull request #322 from boostcampwm-2024/dev-fe
Browse files Browse the repository at this point in the history
[FE] Dev fe -> release
  • Loading branch information
ijun17 authored Dec 5, 2024
2 parents f3fe9c2 + bb05a75 commit 3e3a053
Show file tree
Hide file tree
Showing 10 changed files with 250 additions and 17 deletions.
1 change: 0 additions & 1 deletion FE/src/api/socket/mocks/SocketMock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ export class SocketMock {
this.onAnyListenerList.push(listener);
}
emit<T extends SocketEvent>(event: T, data: SocketDataMap[T]['request']) {
console.log(`%c SERVER_SOCKET[${event}]`, 'background:blue; color:white', data);
switch (event) {
case SocketEvents.CHAT_MESSAGE:
return this.handleChat(data as SocketDataMap[typeof SocketEvents.CHAT_MESSAGE]['request']);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const chatMessages = [
'고마워!'
];

export default class SocketMockForReadme extends SocketMock {
export default class SocketMockForReadme200 extends SocketMock {
constructor() {
super();
this.test();
Expand All @@ -37,7 +37,7 @@ export default class SocketMockForReadme extends SocketMock {
await this.initialrized;
const playerCount = Object.keys(this.players).length;
this.addPlayers(
Array(77)
Array(200)
.fill(null)
.map((_, i) => ({
playerId: String(playerCount + i + 1),
Expand All @@ -59,9 +59,21 @@ export default class SocketMockForReadme extends SocketMock {
this.emitServer('startGame', {});

//퀴즈 전송
await this.progressQuiz('1+1=?', 5, ['1', '2', '3'], 1);
await this.progressQuiz(
'우리 팀의 이름은?',
5,
['시크릿주주', '시크릿추추', '시크릿쥬쥬', '시크릿츄츄'],
0
);
await this.delay(3);
await this.progressQuiz(
'이 서비스의 이름은?',
5,
['퀴즈 그라운드', '배틀 그라운드', '큐플레이', '카훗'],
0
);
await this.delay(3);
await this.progressQuiz('2+2=?', 5, ['1', '2', '4'], 2);
await this.progressQuiz('네이버 부스트캠프는 국내 최고의 부트캠트다', 5, ['O', 'X'], 0);

// 퀴즈 종료
await this.delay(5);
Expand All @@ -74,7 +86,7 @@ export default class SocketMockForReadme extends SocketMock {
for (let j = 0; j < 20; j++) {
for (const player of this.getPlayerList()) {
if (player.playerId === this.id) continue;
await this.delay(1 / playerCount / 0.01);
await this.delay(1 / playerCount / 0.05);
this.chatMessage(
player.playerId,
chatMessages[Math.floor(Math.random() * chatMessages.length)]
Expand Down
97 changes: 97 additions & 0 deletions FE/src/api/socket/mocks/socketMocks/SocketMockForReadmeRanking.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { getRandomNickname } from '@/features/game/utils/nickname';
import { SocketMock } from '../SocketMock';

const chatMessages = [
'안녕하세요?',
'이 문제 뭐지?',
'점심 먹었어?',
'뭐 하고 있어?',
'오늘 날씨 좋다!',
'잠깐 시간 돼?',
'여기 봐봐!',
'도움이 필요해.',
'언제 만날까?',
'진짜야?',
'좋은 하루 보내!',
'이거 어때?',
'잘 모르겠어.',
'대박!',
'좀 더 설명해줘.',
'같이 할래?',
'괜찮아?',
'나중에 이야기하자.',
'너무 웃겨!',
'고마워!'
];

export default class SocketMockForReadmeRanking extends SocketMock {
constructor() {
super();
this.test();

this.moveRandom(15, 0.5);
this.testChat();
}

async test() {
await this.initialrized;
const playerCount = Object.keys(this.players).length;
this.addPlayers(
Array(35)
.fill(null)
.map((_, i) => ({
playerId: String(playerCount + i + 1),
playerName: getRandomNickname(),
playerPosition: [this.random(), this.random()],
isHost: false
}))
);

this.emitServer('updateRoomOption', {
title: '즐거운 퀴즈 시간~~',
gameMode: 'RANKING',
maxPlayerCount: 200,
isPublic: true
});

//2초후 게임 시작
await this.delay(2);
this.emitServer('startGame', {});

//퀴즈 전송
await this.progressQuiz(
'우리 팀의 이름은?',
5,
['시크릿주주', '시크릿추추', '시크릿쥬쥬', '시크릿츄츄'],
0
);
await this.delay(3);
await this.progressQuiz(
'이 서비스의 이름은?',
5,
['퀴즈 그라운드', '배틀 그라운드', '큐플레이', '카훗'],
0
);
await this.delay(3);
await this.progressQuiz('네이버 부스트캠프는 국내 최고의 부트캠트다', 5, ['O', 'X'], 0);

// 퀴즈 종료
await this.delay(5);
this.emitServer('endGame', { hostId: this.id });
}

async testChat() {
await this.initialrized;
const playerCount = this.getPlayerList().length;
for (let j = 0; j < 20; j++) {
for (const player of this.getPlayerList()) {
if (player.playerId === this.id) continue;
await this.delay(1 / playerCount / 0.1);
this.chatMessage(
player.playerId,
chatMessages[Math.floor(Math.random() * chatMessages.length)]
);
}
}
}
}
97 changes: 97 additions & 0 deletions FE/src/api/socket/mocks/socketMocks/SocketMockForReadmeSurvival.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { getRandomNickname } from '@/features/game/utils/nickname';
import { SocketMock } from '../SocketMock';

const chatMessages = [
'안녕하세요?',
'이 문제 뭐지?',
'점심 먹었어?',
'뭐 하고 있어?',
'오늘 날씨 좋다!',
'잠깐 시간 돼?',
'여기 봐봐!',
'도움이 필요해.',
'언제 만날까?',
'진짜야?',
'좋은 하루 보내!',
'이거 어때?',
'잘 모르겠어.',
'대박!',
'좀 더 설명해줘.',
'같이 할래?',
'괜찮아?',
'나중에 이야기하자.',
'너무 웃겨!',
'고마워!'
];

export default class SocketMockForReadmeSurvival extends SocketMock {
constructor() {
super();
this.test();

this.moveRandom(15, 0.5);
this.testChat();
}

async test() {
await this.initialrized;
const playerCount = Object.keys(this.players).length;
this.addPlayers(
Array(35)
.fill(null)
.map((_, i) => ({
playerId: String(playerCount + i + 1),
playerName: getRandomNickname(),
playerPosition: [this.random(), this.random()],
isHost: false
}))
);

this.emitServer('updateRoomOption', {
title: '즐거운 퀴즈 시간~~',
gameMode: 'SURVIVAL',
maxPlayerCount: 200,
isPublic: true
});

//2초후 게임 시작
await this.delay(2);
this.emitServer('startGame', {});

//퀴즈 전송
await this.progressQuiz(
'우리 팀의 이름은?',
5,
['시크릿주주', '시크릿추추', '시크릿쥬쥬', '시크릿츄츄'],
0
);
await this.delay(3);
await this.progressQuiz(
'이 서비스의 이름은?',
5,
['퀴즈 그라운드', '배틀 그라운드', '큐플레이', '카훗'],
0
);
await this.delay(3);
await this.progressQuiz('네이버 부스트캠프는 국내 최고의 부트캠트다', 5, ['O', 'X'], 0);

// 퀴즈 종료
await this.delay(5);
this.emitServer('endGame', { hostId: this.id });
}

async testChat() {
await this.initialrized;
const playerCount = this.getPlayerList().length;
for (let j = 0; j < 20; j++) {
for (const player of this.getPlayerList()) {
if (player.playerId === this.id) continue;
await this.delay(1 / playerCount / 0.1);
this.chatMessage(
player.playerId,
chatMessages[Math.floor(Math.random() * chatMessages.length)]
);
}
}
}
}
8 changes: 6 additions & 2 deletions FE/src/api/socket/mocks/socketMocks/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import SocketMockChat from './SocketMockChat';
import SocketMockForReadme from './SocketMockForReadme';
import SocketMockForReadmeSurvival from './SocketMockForReadmeSurvival';
import SocketMockForReadmeRanking from './SocketMockForReadmeRanking';
import SocketMockForReadme200 from './SocketMockForReadme200';
import SocketMockHost from './SocketMockHost';
import SocketMockLoadTest from './SocketMockLoadTest';
import SocketMockLoadTestOnlyMove from './SocketMockLoadTestOnlyMove';
Expand All @@ -17,7 +19,9 @@ const mockMap = {
'test-load-with-quiz': SocketMockLoadTestWithQuiz,
'test-start-end': SocketMockStartEnd,
'test-load-only-move': SocketMockLoadTestOnlyMove,
readme: SocketMockForReadme
'readme-survival': SocketMockForReadmeSurvival,
'readme-ranking': SocketMockForReadmeRanking,
'readme-200': SocketMockForReadme200
} as const;

export default mockMap;
10 changes: 9 additions & 1 deletion FE/src/api/socket/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class SocketService {
private handlerMap: Partial<
Record<SocketEvent, ((data: SocketDataMap[SocketEvent]['response']) => void)[]>
> = {};
private log = true;

constructor(url: string) {
this.socket = null;
Expand Down Expand Up @@ -65,7 +66,13 @@ class SocketService {
handlers.forEach((h) => socket.on(event, h))
);
this.socket.onAny((eventName, ...args) => {
console.log(`SOCKET[${eventName}]`, ...args);
if (this.log) {
if (eventName === 'exception')
console.log(`%cSOCKET[${eventName}]`, 'color:red', Date.now(), ...args);
else if (eventName !== 'updatePosition' && eventName !== 'chatMessage')
console.log(`%cSOCKET[${eventName}]`, 'color:green', Date.now(), ...args);
else console.log(`SOCKET[${eventName}]`, ...args);
}
});
}

Expand All @@ -92,6 +99,7 @@ class SocketService {
emit<T extends SocketEvent>(event: T, data: SocketDataMap[T]['request']) {
if (!this.socket) return;
this.socket.emit(event, data);
if (this.log) console.log(`%cSOCKET[${event}]`, 'background-color:blue', Date.now(), data);
}

async createRoom(option: {
Expand Down
10 changes: 8 additions & 2 deletions FE/src/features/game/components/GameHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useNavigate, useParams } from 'react-router-dom';
import { useRoomStore } from '@/features/game/data/store/useRoomStore';
import React, { useState } from 'react';
import { QuizSettingModal } from './QuizSettingModal';
import { socketService } from '@/api/socket';
import { socketService, useSocketEvent, useSocketException } from '@/api/socket';
import { usePlayerStore } from '@/features/game/data/store/usePlayerStore';
import { useQuizStore } from '@/features/game/data/store/useQuizStore';
import CustomButton from '@/components/CustomButton';
Expand All @@ -17,14 +17,20 @@ export const GameHeader = React.memo(
const gameTitle = useRoomStore((state) => state.title);
const [isQuizModalOpen, setIsQuizModalOpen] = useState(false);
const { quizSetTitle, quizSetCategory } = useQuizStore();
const [gameLoading, setGameLoading] = useState(false);
const pinNum = String(gameId);
const linkURL = window.location.hostname + `/game/${gameId}`;
const gameMode = useRoomStore((state) => state.gameMode);
const navigate = useNavigate();

const handleStartGame = () => {
if (gameLoading) return;
setGameLoading(true);
if (gameId) socketService.emit('startGame', { gameId });
};
const navigate = useNavigate();

useSocketEvent('startGame', () => setGameLoading(false));
useSocketException('startGame', () => setGameLoading(false));

return (
<div className="component-default h-full flex justify-center">
Expand Down
12 changes: 11 additions & 1 deletion FE/src/features/lobby/GameLobbyPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ export const GameLobbyPage = () => {
},
[isLoading, paging]
);
const refreshRooms = useCallback(() => {
if (isLoading) return;
setRooms([]);
setPaging(null);
loadRooms(null);
}, [isLoading, loadRooms]);

useEffect(() => {
loadRooms(null);
}, [loadRooms]);

useEffect(() => {
loadRooms(null);
Expand All @@ -70,7 +80,7 @@ export const GameLobbyPage = () => {
return (
<div className="bg-gradient-to-r from-blue-300 to-indigo-500 min-h-screen flex flex-col items-center justify-center">
<Header />
<LobbyList rooms={rooms} loadRooms={loadRooms} />
<LobbyList rooms={rooms} refreshRooms={refreshRooms} />
{isLoading && <div className="text-center mt-4">Loading...</div>}
</div>
);
Expand Down
6 changes: 3 additions & 3 deletions FE/src/features/lobby/LobbyList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ type Room = {

type LobbyListProps = {
rooms: Room[];
loadRooms: (cursor: string | null, take: number) => Promise<void>;
refreshRooms: () => void;
};
import { useNavigate } from 'react-router-dom';

export const LobbyList: React.FC<LobbyListProps> = ({ rooms, loadRooms }) => {
export const LobbyList: React.FC<LobbyListProps> = ({ rooms, refreshRooms }) => {
const navigate = useNavigate();

const handleJoinRoom = (gameId: string) => {
Expand All @@ -35,7 +35,7 @@ export const LobbyList: React.FC<LobbyListProps> = ({ rooms, loadRooms }) => {
width: '50px',
height: '50px'
}}
onClick={() => loadRooms(null, 10)}
onClick={refreshRooms}
/>
</header>
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-8 w-full">
Expand Down
4 changes: 2 additions & 2 deletions FE/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,11 @@ export default {
borderWidth: '1px',
borderColor: theme('borderColor.default'),
borderRadius: theme('borderRadius.m'),
backgroundColor: '#FFFD'
backgroundColor: '#FFFC'
},
'.component-popup': {
borderRadius: theme('borderRadius.m'),
backgroundColor: '#FFFD',
backgroundColor: '#FFFC',
boxShadow: theme('boxShadow.default')
},
'.center': {
Expand Down

0 comments on commit 3e3a053

Please sign in to comment.