Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions apps/backend/src/play/entities/quiz-summary.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Rank } from './rank.entity';

export interface QuizSummary {
readonly ranks: Rank[];
readonly endSocketTime?: number;
}
6 changes: 6 additions & 0 deletions apps/backend/src/play/entities/rank.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface Rank {
readonly id: string;
readonly nickname: string;
readonly score: number;
readonly ranking: number;
}
15 changes: 7 additions & 8 deletions apps/backend/src/play/play.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@ import { SendEventMessage } from './entities/send-event.entity';
import { ClientInfo } from './entities/client-info.entity';
import { WebSocketWithSession } from '../core/SessionWsAdapter';
import { RuntimeException } from '@nestjs/core/errors/exceptions';
import { CLOSE_CODE } from '../common/constants';
import { SubmitResponseDto } from './dto/submit-response.dto';
import { clearTimeout } from 'node:timers';
import { ChatMessage } from 'src/chat/entities/chat-message.entity';
import { ChatService } from '../chat/chat.service'; // 경로 수정
import { ChatService } from '../chat/chat.service';
import { CLOSE_CODE } from '../common/constants'; // 경로 수정

/**
* 퀴즈 게임에 대한 WebSocket 연결을 관리하는 Gateway입니다.
Expand Down Expand Up @@ -248,7 +247,7 @@ export class PlayGateway implements OnGatewayInit {

const clientsIds = summaries.map(({ id }) => id);

this.clearQuizZone(clientsIds, quizZoneId, endSocketTime);
this.clearQuizZone(clientsIds, quizZoneId, endSocketTime - Date.now());
}

/**
Expand All @@ -258,16 +257,16 @@ export class PlayGateway implements OnGatewayInit {
* - 일반 플레이어가 나가면 퀴즈 존에서 나가고 다른 플레이어에게 나갔다고 알립니다.
* @param clientIds - 퀴즈존에 참여하고 있는 클라이언트 id 리스트
* @param quizZoneId - 퀴즈가 끝난 퀴즈존 id
* @param endSocketTime - 소켓 연결 종료 시간 종료 시간
* @param time - 소켓 연결 종료 시간 종료 시간
*/
private clearQuizZone(clientIds: string[], quizZoneId: string, endSocketTime: number) {
private clearQuizZone(clientIds: string[], quizZoneId: string, time: number) {
setTimeout(() => {
clientIds.forEach((id) => {
this.clearClient(id, 'finish');
});
this.playService.clearQuizZone(quizZoneId);
this.chatService.delete(quizZoneId);
}, endSocketTime - Date.now());
}, time);
}

/**
Expand All @@ -286,7 +285,7 @@ export class PlayGateway implements OnGatewayInit {

if (isHost) {
this.broadcast(playerIds, 'close');
playerIds.forEach((id) => this.clearClient(id, 'Host leave.'));
this.clearQuizZone(playerIds, quizZoneId, 0);
} else {
this.broadcast(playerIds, 'someone_leave', clientId);
this.clearClient(clientId, 'Client leave');
Expand Down
6 changes: 5 additions & 1 deletion apps/backend/src/play/play.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,14 +304,18 @@ export class PlayService {
const now = Date.now();
const endSocketTime = now + socketConnectTime;

return [...players.values()].map(({ id, score, submits }) => ({

const summaries = [...players.values()].map(({ id, score, submits }) => ({
id,
score,
submits,
quizzes,
ranks,
endSocketTime
}));

quizZone.summaries = {ranks, endSocketTime};
return summaries;
}

public clearQuizZone(quizZoneId: string) {
Expand Down
8 changes: 8 additions & 0 deletions apps/backend/src/quiz-zone/dto/find-quiz-zone.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { PLAYER_STATE, QUIZ_ZONE_STAGE } from '../../common/constants';
import { CurrentQuizDto } from '../../play/dto/current-quiz.dto';
import { SubmittedQuiz } from '../entities/submitted-quiz.entity';
import { ChatMessage } from 'src/chat/entities/chat-message.entity';
import { Rank } from '../../play/entities/rank.entity';
import { Quiz } from '../entities/quiz.entity';

/**
* 퀴즈 게임에 참여하는 플레이어 엔티티
Expand Down Expand Up @@ -42,4 +44,10 @@ export interface FindQuizZoneDto {
readonly currentQuiz?: CurrentQuizDto;
readonly maxPlayers?: number;
readonly chatMessages?: ChatMessage[];

readonly ranks?: Rank[];
readonly endSocketTime?: number;
readonly score?: number;
readonly quizzes?: Quiz[];
readonly submits?: SubmittedQuiz[];
}
2 changes: 2 additions & 0 deletions apps/backend/src/quiz-zone/entities/quiz-zone.entity.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Quiz } from './quiz.entity';
import { Player } from './player.entity';
import { QUIZ_ZONE_STAGE } from '../../common/constants';
import { QuizSummary } from '../../play/entities/quiz-summary.entity';
/**
* 퀴즈 게임을 진행하는 공간을 나타내는 퀴즈존 인터페이스
*
Expand Down Expand Up @@ -28,4 +29,5 @@ export interface QuizZone {
currentQuizStartTime: number;
currentQuizDeadlineTime: number;
intervalTime: number;
summaries?: QuizSummary;
}
16 changes: 13 additions & 3 deletions apps/backend/src/quiz-zone/quiz-zone.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { IQuizZoneRepository } from './repository/quiz-zone.repository.interface
import { Quiz } from './entities/quiz.entity';
import { PLAYER_STATE, QUIZ_TYPE, QUIZ_ZONE_STAGE } from '../common/constants';
import { QuizService } from '../quiz/quiz.service';
import { max } from 'class-validator';
import { ChatService } from '../chat/chat.service';

const nickNames: string[] = [
Expand Down Expand Up @@ -571,6 +570,13 @@ describe('QuizZoneService', () => {
currentQuizStartTime: Date.now(),
currentQuizDeadlineTime: Date.now() + playTime,
intervalTime: 5000,
summaries: {
ranks: [
{id: "player1", nickname: "미친투사", score: 0, ranking: 1},
{id: "player2", nickname: "미친투사", score: 0, ranking: 1}
],
endSocketTime: Date.now(),
}
};

mockQuizZoneRepository.get.mockResolvedValue(mockQuizZone);
Expand All @@ -579,7 +585,7 @@ describe('QuizZoneService', () => {
const result = await service.getQuizZoneInfo(clientId, quizZoneId);

// then
expect(result).toEqual({
expect(result).toMatchObject({
currentPlayer: {
id: clientId,
nickname: '닉네임',
Expand All @@ -591,8 +597,12 @@ describe('QuizZoneService', () => {
description: '테스트 퀴즈입니다',
quizCount: quizzes.length,
stage: QUIZ_ZONE_STAGE.RESULT,
maxPlayers: 10,
hostId: 'adminId',
ranks: [
{id: "player1", nickname: "미친투사", score: 0, ranking: 1},
{id: "player2", nickname: "미친투사", score: 0, ranking: 1}
],
endSocketTime: Date.now(),
});
});

Expand Down
10 changes: 7 additions & 3 deletions apps/backend/src/quiz-zone/quiz-zone.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ export class QuizZoneService {
}

private async getResultInfo(clientId: string, quizZoneId: string): Promise<FindQuizZoneDto> {
const { players, stage, title, description, hostId, quizzes, maxPlayers } =
const { players, stage, title, description, hostId, quizzes, summaries } =
await this.findOne(quizZoneId);
const { id, nickname, state, submits, score } = players.get(clientId);
const chatMessages = await this.chatService.get(quizZoneId);
Expand All @@ -181,11 +181,15 @@ export class QuizZoneService {
currentPlayer: { id, nickname, state, score, submits },
title,
description,
maxPlayers: maxPlayers,
quizCount: quizzes.length,
stage: stage,
hostId,
chatMessages: chatMessages,
chatMessages,
ranks: summaries.ranks,
endSocketTime: summaries.endSocketTime,
quizzes,
score,
submits
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,9 @@ const CreateQuizZoneBasic = ({
onChange={(e) => handleChangeQuizZoneBasic(e, 'DESC')}
isBorder={true}
placeholder="퀴즈존 설명을 입력하세요"
error={validationError == '500자 이하로 입력해주세요.' ? validationError : ''}
error={validationError == '300자 이하로 입력해주세요.' ? validationError : ''}
isShowCount={true}
max={500}
max={300}
/>
</ContentBox>
<ContentBox className="gap-2 w-full bg-white shadow-md">
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/components/common/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
)}

{typeof value === 'string' && isShowCount && (
<div className="w-14 text-right pr-1 ml-auto">
<div className="w-20 text-right pr-1 ml-auto">
<Typography
text={value.length.toString() + '/' + max}
color="gray"
Expand Down
12 changes: 3 additions & 9 deletions apps/frontend/src/hook/quizZone/useQuizZone.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,11 @@ const quizZoneReducer: Reducer<QuizZone, QuizZoneAction> = (state, action) => {
...state.currentPlayer,
state: 'SUBMIT',
},
chatMessages: payload.chatMessages,
currentQuizResult: {
...payload,
fastestPlayers: payload.fastestPlayerIds
.map((id) => state.players?.find((p) => p.id === id))
.filter((p) => !!p),
submittedCount: payload.submittedCount,
totalPlayerCount: payload.totalPlayerCount,
},
};
case 'someone_submit':
Expand Down Expand Up @@ -115,9 +113,8 @@ const quizZoneReducer: Reducer<QuizZone, QuizZoneAction> = (state, action) => {
},
currentQuiz: {
...state.currentQuiz,
...nextQuiz,
question: atob(nextQuiz.question),
currentIndex: nextQuiz.currentIndex,
playTime: nextQuiz.playTime,
startTime: nextQuiz.startTime - state.offset,
deadlineTime: nextQuiz.deadlineTime - state.offset,
quizType: 'SHORT',
Expand Down Expand Up @@ -154,11 +151,8 @@ const quizZoneReducer: Reducer<QuizZone, QuizZoneAction> = (state, action) => {
case 'summary':
return {
...state,
...payload,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요 부분 훨씬 깔끔해진 것 같습니다!

stage: 'RESULT',
score: payload.score,
submits: payload.submits,
quizzes: payload.quizzes,
ranks: payload.ranks,
endSocketTime: payload.endSocketTime - state.offset,
};
case 'chat':
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/utils/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const validateQuizZoneSetName = (name: string) => {

//퀴즈존 설명 유효성 검사
export const validateQuizZoneSetDescription = (description: string) => {
if (description.length > 500) return '500자 이하로 입력해주세요.';
if (description.length > 300) return '300자 이하로 입력해주세요.';
};

//퀴즈존 입장 코드 유효성 검사
Expand Down
Loading