Skip to content

Commit

Permalink
Merge pull request #272 from ijun17/feature-fe-design
Browse files Browse the repository at this point in the history
[FE] feat ๋””์ž์ธ
  • Loading branch information
ijun17 authored Nov 27, 2024
2 parents aaee417 + 44a680f commit 425bac9
Show file tree
Hide file tree
Showing 20 changed files with 347 additions and 281 deletions.
43 changes: 26 additions & 17 deletions FE/src/api/socket/mocks/SocketMock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,27 @@ type SocketEvent = keyof SocketDataMap;
export class SocketMock {
private listenerSet: Record<string, ((...args: unknown[]) => void)[]> = {};
private onAnyListenerList: ((event: string, ...args: unknown[]) => void)[] = [];
initialrized: Promise<void>;
constructor() {
console.log(`Mock WebSocket ์—ฐ๊ฒฐ`);
console.log(`%c Mock WebSocket ์—ฐ๊ฒฐ`, 'color:yellow; font-weight:bold;');
this.initialrized = new Promise((resolve) => {
this.delay(0).then(() => {
resolve();
});
});
this.initialrized.then(() => {
const currentPlayer = {
playerId: this.id,
playerName: 'Me',
playerPosition: [0.5, 0.5] as [number, number]
};
this.emitServer('joinRoom', { players: [currentPlayer] });
this.addPlayers([currentPlayer]);
this.emitServer('getSelfId', { playerId: this.id });
this.emitServer('setPlayerName', { playerId: this.id, playerName: 'Me' });
});

// }
}

/**
Expand All @@ -28,12 +47,10 @@ 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']);
case SocketEvents.JOIN_ROOM:
return this.handleJoin(data as SocketDataMap[typeof SocketEvents.JOIN_ROOM]['request']);
case SocketEvents.UPDATE_POSITION:
return this.handlePosition(
data as SocketDataMap[typeof SocketEvents.UPDATE_POSITION]['request']
Expand Down Expand Up @@ -119,18 +136,6 @@ export class SocketMock {
await this.delay(0.1);
this.chatMessage(this.id, data.message);
}
private async handleJoin(data: SocketDataMap[typeof SocketEvents.JOIN_ROOM]['request']) {
if (this.getPlayer(this.id)) return;
await this.delay(0.1);
const currentPlayer: (typeof this.players)[string] = {
playerId: this.id,
playerName: data.playerName,
playerPosition: [0.5, 0.5]
};
this.emitServer(SocketEvents.JOIN_ROOM, { players: this.getPlayerList() });
this.emitServer(SocketEvents.JOIN_ROOM, { players: [currentPlayer] });
this.addPlayers([currentPlayer]);
}
private async handlePosition(
data: SocketDataMap[typeof SocketEvents.UPDATE_POSITION]['request']
) {
Expand Down Expand Up @@ -172,6 +177,7 @@ export class SocketMock {
}
addPlayers(players: Array<SocketMock['players'][keyof SocketMock['players']]>) {
players.forEach((p) => (this.players[p.playerId] = p));
this.emitServer('joinRoom', { players });
}
setQuiz(quiz: string, quizSecond: number, choiceList: string[]) {
const COUNT_DOWN_TIME = 3000;
Expand Down Expand Up @@ -225,7 +231,8 @@ export class SocketMock {
});
}

createDummyPlayer(count: number) {
async createDummyPlayer(count: number) {
await this.initialrized;
const playerCount = Object.keys(this.players).length;
this.addPlayers(
Array(count)
Expand All @@ -239,6 +246,7 @@ export class SocketMock {
}

async chatRandom(testSec: number, chatPerSecPerPlyaer: number = 1) {
await this.initialrized;
const playerCount = this.getPlayerList().length;
for (let j = 0; j < testSec; j++) {
for (const player of this.getPlayerList()) {
Expand All @@ -250,6 +258,7 @@ export class SocketMock {
}

async moveRandom(testSec: number, movePerSecPerPlyaer: number = 1) {
await this.initialrized;
const playerCount = this.getPlayerList().length;
for (let j = 0; j < testSec; j++) {
for (const player of this.getPlayerList()) {
Expand Down
63 changes: 28 additions & 35 deletions FE/src/api/socket/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,20 @@ class SocketService {
this.handlers = [];
}

async connect() {
async connect(header: { 'create-room'?: string; 'game-id'?: string }) {
if (this.isActive()) return;
this.socket = io(this.url) as SocketInterface;
await new Promise<void>((resolve, reject) => {
this.socket.on('connect', () => resolve());
this.socket.on('error', () => reject());
});
this.initHandler();
return;
}

async connectMock(gameId: keyof typeof mockMap) {
if (this.isActive()) return;
this.socket = new mockMap[gameId]() as SocketInterface;
const gameId = header['game-id'];
if (gameId && gameId in mockMap) {
// mock๊ณผ ์—ฐ๊ฒฐ
this.socket = new mockMap[gameId as keyof typeof mockMap]() as SocketInterface;
} else {
// ์†Œ์ผ“ ์—ฐ๊ฒฐ
this.socket = io(this.url, { query: header }) as SocketInterface;
await new Promise<void>((resolve, reject) => {
this.socket.on('connect', () => resolve());
this.socket.on('error', () => reject());
});
}
this.initHandler();
}

Expand All @@ -70,27 +70,13 @@ class SocketService {
}

disconnect() {
this.socket.disconnect();
if (this.isActive()) this.socket.disconnect();
}

isActive() {
return this.socket && this.socket.connected;
}

getSocketId() {
return this.socket.id;
}

// deprecated
onPermanently<T extends SocketEvent>(
event: T,
callback: (data: SocketDataMap[T]['response']) => void
) {
const handler = () => this.socket.on(event, callback);
this.handlers.push(handler);
if (this.isActive()) handler();
}

on<T extends SocketEvent>(event: T, callback: (data: SocketDataMap[T]['response']) => void) {
if (this.isActive()) this.socket.on(event, callback);
if (!this.handlerMap[event]) this.handlerMap[event] = [];
Expand All @@ -107,15 +93,22 @@ class SocketService {
this.socket.emit(event, data);
}

async createRoom(payload: SocketDataMap['createRoom']['request']) {
await this.connect();
this.socket.emit(SocketEvents.CREATE_ROOM, payload);
async createRoom(option: {
title: string;
gameMode: 'RANKING' | 'SURVIVAL';
maxPlayerCount: number;
isPublic: boolean;
}) {
this.disconnect();
await this.connect({
'create-room': Object.entries(option)
.map(([key, value]) => key + '=' + value)
.join(';')
});
}

async joinRoom(gameId: string, playerName: string) {
if (gameId in mockMap) this.connectMock(gameId as keyof typeof mockMap);
else if (!this.isActive()) await this.connect();
this.socket.emit(SocketEvents.JOIN_ROOM, { gameId, playerName });
async joinRoom(gameId: string) {
await this.connect({ 'game-id': gameId });
}

kickRoom(gameId: string, kickPlayerId: string) {
Expand Down
62 changes: 24 additions & 38 deletions FE/src/api/socket/socketEventTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,6 @@ type UpdatePositionResponse = {
playerPosition: [number, number];
};

// ๊ฒŒ์ž„๋ฐฉ ์ƒ์„ฑ ํƒ€์ž…
type CreateRoomRequest = {
title: string;
gameMode: 'RANKING' | 'SURVIVAL';
maxPlayerCount: number;
isPublic: boolean;
};

type CreateRoomResponse = {
gameId: string; // PIN
};
Expand Down Expand Up @@ -62,12 +54,6 @@ type UpdateRoomQuizsetResponse = {
quizCount: number;
};

// ๊ฒŒ์ž„๋ฐฉ ์ž…์žฅ ํƒ€์ž…
type JoinRoomRequest = {
gameId: string;
playerName: string;
};

type JoinRoomResponse = {
players: Array<{
playerId: string; // socketId
Expand All @@ -76,22 +62,26 @@ type JoinRoomResponse = {
}>;
};

// ๊ฒŒ์ž„ ์‹œ์ž‘ ํƒ€์ž…
type StartGameRequest = {
gameId: string;
type getSelfIdResponse = {
playerId: string;
};

type StartGameResponse = Record<string, never>; // ๋นˆ ๊ฐ์ฒด
type setPlayerNameRequest = {
playerName: string;
};

// ๊ฒŒ์ž„ ์ •์ง€ ํƒ€์ž…
type StopGameRequest = {
gameId: string;
type setPlayerNameResponse = {
playerId: string;
playerName: string;
};

type StopGameResponse = {
status: string;
// ๊ฒŒ์ž„ ์‹œ์ž‘ ํƒ€์ž…
type StartGameRequest = {
gameId: string;
};

type StartGameResponse = Record<string, never>; // ๋นˆ ๊ฐ์ฒด

type EndGameRequest = {
gameId: string;
};
Expand All @@ -113,11 +103,6 @@ type StartQuizTimeEvent = {
startTime: number; //timestamp
};

// ๊ฒŒ์ž„ ์ ์ˆ˜ ์—…๋ฐ์ดํŠธ ํƒ€์ž…
type UpdateScoreEvent = {
scores: Map<string, number>; // Map<playerId, score>
};

// ๊ฒŒ์ž„๋ฐฉ ํ‡ด์žฅ ํƒ€์ž…
type ExitRoomEvent = {
playerId: string;
Expand All @@ -127,6 +112,7 @@ type KickRoomRequest = {
gameId: string;
kickPlayerId: string;
};

type KickRoomResponse = {
playerId: string;
};
Expand All @@ -142,7 +128,7 @@ export type SocketDataMap = {
response: UpdatePositionResponse;
};
createRoom: {
request: CreateRoomRequest;
request: null;
response: CreateRoomResponse;
};
updateRoomOption: {
Expand All @@ -154,17 +140,21 @@ export type SocketDataMap = {
response: UpdateRoomQuizsetResponse;
};
joinRoom: {
request: JoinRoomRequest;
request: null;
response: JoinRoomResponse;
};
getSelfId: {
request: null;
response: getSelfIdResponse;
};
setPlayerName: {
request: setPlayerNameRequest;
response: setPlayerNameResponse;
};
startGame: {
request: StartGameRequest;
response: StartGameResponse;
};
stopGame: {
request: StopGameRequest;
response: StopGameResponse;
};
endQuizTime: {
request: null;
response: EndQuizTimeEvent;
Expand All @@ -173,10 +163,6 @@ export type SocketDataMap = {
request: null;
response: StartQuizTimeEvent;
};
updateScore: {
request: null;
response: UpdateScoreEvent;
};
exitRoom: {
request: null;
response: ExitRoomEvent;
Expand Down
42 changes: 17 additions & 25 deletions FE/src/features/game/components/AnswerModal.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,31 @@
import Lottie from 'lottie-react';
import AnswerBg from '@/assets/lottie/answer_background.json';
// import { useEffect, useState } from 'react';
import { useEffect, useState } from 'react';

type AnswerModalProps = {
isOpen: boolean;
// onClose: () => void;
answer: number;
};

const AnswerModal: React.FC<AnswerModalProps> = ({ isOpen, answer }) => {
// const [countdown, setCountdown] = useState(3);
const [countdown, setCountdown] = useState(3);

// useEffect(() => {
// if (isOpen) {
// setCountdown(3); // ๋ชจ๋‹ฌ์ด ์—ด๋ฆด ๋•Œ ์นด์šดํŠธ๋‹ค์šด์„ ์ดˆ๊ธฐํ™”
// const interval = setInterval(() => {
// setCountdown((prev) => {
// if (prev === 1) {
// clearInterval(interval);
// onClose(); // 0์— ๋„๋‹ฌํ•˜๋ฉด ๋ชจ๋‹ฌ ๋‹ซ๊ธฐ
// }
// return prev - 1;
// });
// }, 1000);
// return () => clearInterval(interval); // ๋ชจ๋‹ฌ์ด ๋‹ซํžˆ๊ฑฐ๋‚˜ ์–ธ๋งˆ์šดํŠธ๋  ๋•Œ ํƒ€์ด๋จธ ์ •๋ฆฌ
// }
// }, [isOpen, onClose]);
useEffect(() => {
if (isOpen) {
setCountdown(3);
const interval = setInterval(() => {
setCountdown((prev: number) => {
if (prev === 1) {
clearInterval(interval);
}
return prev - 1;
});
}, 1000);
return () => clearInterval(interval);
}
}, [isOpen]);

if (!isOpen) return null;
if (!isOpen || countdown <= 0) return null;
return (
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50 pointer-events-none">
<Lottie
Expand All @@ -46,12 +44,6 @@ const AnswerModal: React.FC<AnswerModalProps> = ({ isOpen, answer }) => {
<p className="text-2xl text-black" style={{ marginBottom: '4rem' }}>
{answer}
</p>
{/* <button
onClick={onClose}
className="bg-blue-500 text-white px-6 py-3 rounded-md hover:bg-blue-600 transition"
>
๋‹ซ๊ธฐ ({countdown})
</button> */}
</div>
</div>
);
Expand Down
Loading

0 comments on commit 425bac9

Please sign in to comment.