Skip to content

Commit

Permalink
feat: Implement socket connection in Setting component for real-time …
Browse files Browse the repository at this point in the history
…updates (#106)

* feat: Implement updateSettings socket emission for updating game settings

* feat: Implement settingsUpdated handler to update room settings in game state

* feat: Connect Setting component to socket for real-time updates

* feat: Update options for drawTime setting in ROOM_SETTINGS

* fix: Change type from 'host' to 'participant' in Setting component

* design: Update max-width for better layout
  • Loading branch information
choiseona authored Nov 21, 2024
1 parent 906ad5f commit cde878b
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 20 deletions.
46 changes: 28 additions & 18 deletions client/src/components/setting/Setting.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { HTMLAttributes, useState } from 'react';
import { HTMLAttributes, useEffect, useState } from 'react';
import { RoomSettings } from '@troublepainter/core';
import Dropdown from '@/components/ui/Dropdown';
import { gameSocketHandlers } from '@/handlers/socket/gameSocket.handler';
import { useGameSocketStore } from '@/stores/socket/gameSocket.store';
import { cn } from '@/utils/cn';

type SettingKey = keyof RoomSettings;
Expand All @@ -12,34 +14,42 @@ interface RoomSettingItem {
}

interface SettingProps extends HTMLAttributes<HTMLDivElement> {
roomSettings?: RoomSettings;
type: 'host' | 'participant';
}

export const ROOM_SETTINGS: RoomSettingItem[] = [
{ label: '라운드 수', key: 'totalRounds', options: [4, 6, 8] },
{ label: '플레이어 수', key: 'maxPlayers', options: [4, 5, 6] },
{ label: '제한 시간', key: 'drawTime', options: [15, 30] },
{ label: '픽셀 수', key: 'maxPixels', options: [300, 500] },
{ label: '라운드 수', key: 'totalRounds', options: [3, 5] },
{ label: '최대 플레이어 수', key: 'maxPlayers', options: [4, 5] },
{ label: '제한 시간', key: 'drawTime', options: [15, 20, 25, 30] },
//{ label: '픽셀 수', key: 'maxPixels', options: [300, 500] },
];

const Setting = ({ className, roomSettings, type, ...props }: SettingProps) => {
const [selectedValues, setSelectedValues] = useState<RoomSettings>({
totalRounds: roomSettings?.totalRounds || 4,
maxPlayers: roomSettings?.maxPlayers || 4,
drawTime: roomSettings?.drawTime || 30,
maxPixels: roomSettings?.drawTime || 300,
const Setting = ({ className, type, ...props }: SettingProps) => {
const { roomSettings } = useGameSocketStore();

const [selectedValues, setSelectedValues] = useState<Partial<RoomSettings>>({
totalRounds: undefined,
maxPlayers: undefined,
drawTime: undefined,
});

useEffect(() => {
if (!roomSettings) return;
setSelectedValues(roomSettings);
}, [roomSettings]);

useEffect(() => {
if (type === 'participant') return;
void gameSocketHandlers.updateSettings({ settings: selectedValues });
}, [selectedValues, type]);

const handleChange = (key: SettingKey) => (value: string) => {
setSelectedValues((prev) => ({
...prev,
[key]: Number(value),
}));
};

const convertToString = (options: number[]) => options.map((option) => String(option));

return (
<section
className={cn('flex w-full flex-col border-0 border-violet-950 sm:rounded-xl sm:border-2', className)}
Expand All @@ -54,14 +64,14 @@ const Setting = ({ className, roomSettings, type, ...props }: SettingProps) => {
<div className="flex min-h-[16.125rem] items-center justify-center bg-violet-200 sm:min-h-[18.56rem] sm:rounded-b-xl sm:px-6">
<div className="flex min-h-[13.8rem] w-full flex-col items-center justify-center gap-4 border-0 border-violet-950 bg-violet-50 p-4 text-xl sm:h-auto sm:rounded-[0.625rem] sm:border-2 lg:gap-6 lg:text-2xl">
{ROOM_SETTINGS.map(({ label, key, options }) => (
<div key={label} className="flex w-full max-w-80 items-center justify-between sm:max-w-[70%]">
<div key={label} className="flex w-full max-w-80 items-center justify-between lg:max-w-[80%]">
<span>{label}</span>
{type === 'participant' ? (
<span>{selectedValues[key]}</span>
<span>{roomSettings?.[key] || ''}</span>
) : (
<Dropdown
options={convertToString(options)}
selectedValue={selectedValues[key].toString()}
options={options.map((option) => option.toString())}
selectedValue={selectedValues?.[key]?.toString() || ''}
handleChange={handleChange(key)}
className="h-7 w-[30%] min-w-[4.25rem] text-xl sm:min-w-28 lg:h-auto lg:text-2xl"
/>
Expand Down
12 changes: 11 additions & 1 deletion client/src/handlers/socket/gameSocket.handler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { JoinRoomRequest, JoinRoomResponse, ReconnectRequest } from '@troublepainter/core';
import type { JoinRoomRequest, JoinRoomResponse, ReconnectRequest, UpdateSettingsRequest } from '@troublepainter/core';
import { useSocketStore } from '@/stores/socket/socket.store';

// socket 요청만 처리하는 핸들러
Expand All @@ -21,6 +21,16 @@ export const gameSocketHandlers = {
});
},

updateSettings: async (request: UpdateSettingsRequest): Promise<void> => {
const socket = useSocketStore.getState().sockets.game;
if (!socket) throw new Error('Socket not connected');

return new Promise((resolve) => {
socket.emit('updateSettings', request);
resolve();
});
},

// updatePlayerStatus: async (request) => {
// const socket = useSocketStore.getState().sockets.game;
// if (!socket) throw new Error('Socket not connected');
Expand Down
7 changes: 6 additions & 1 deletion client/src/hooks/socket/useGameSocket.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect } from 'react';
import { useParams } from 'react-router-dom';
import type { JoinRoomResponse, PlayerLeftResponse } from '@troublepainter/core';
import type { JoinRoomResponse, PlayerLeftResponse, UpdateSettingsResponse } from '@troublepainter/core';
import { gameSocketHandlers } from '@/handlers/socket/gameSocket.handler';
import { useGameSocketStore } from '@/stores/socket/gameSocket.store';
import { SocketNamespace } from '@/stores/socket/socket.config';
Expand Down Expand Up @@ -123,6 +123,11 @@ export const useGameSocket = () => {
gameActions.removePlayer(leftPlayerId);
gameActions.updatePlayers(players);
},

settingsUpdated: (response: UpdateSettingsResponse) => {
const { settings } = response;
gameActions.updateRoomSettings(settings);
},
};

// 이벤트 리스너 등록
Expand Down

0 comments on commit cde878b

Please sign in to comment.