Skip to content

Commit

Permalink
Merge pull request #4 from 5wonju/feat/#2-waiting-room
Browse files Browse the repository at this point in the history
Feat/#2 대기방 리스트 관련 UI 작업
  • Loading branch information
leewooseong authored Apr 23, 2024
2 parents 672b4f4 + ab57e26 commit 0fb0e13
Show file tree
Hide file tree
Showing 11 changed files with 267 additions and 3 deletions.
4 changes: 3 additions & 1 deletion frontend/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ export default function RootLayout({
return (
<html lang="en">
<body className={inter.className}>
<ReactQueryProviders>{children}</ReactQueryProviders>
<ReactQueryProviders>
<div id="root">{children}</div>
</ReactQueryProviders>
</body>
</html>
)
Expand Down
21 changes: 21 additions & 0 deletions frontend/app/lobby/lib/type.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
interface Room {
roomTitle: string
roomOwnerName: string
roomCurUserNum: number
roomMaxUserNum: number
roomId: number
isGameStart: boolean
isRoomFull: boolean
probCategory: string
isHavePW: boolean
curRound: number
totalRound: number
roomMode: 'basic' | 'yutnori'
}

interface RoomListResponse {
msg: string
data: {
roomList: Room[]
}
}
82 changes: 82 additions & 0 deletions frontend/app/lobby/lib/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// export const roomsDummyData: Room[] = [
// {
// roomId: 1,
// roomTitle: '초고수의 도전',
// roomOwnerName: 'GameMaster',
// roomCurUserNum: 4,
// roomMaxUserNum: 10,
// isGameStart: false,
// isRoomFull: false,
// probCategory: '수학 퀴즈',
// isHavePW: false,
// curRound: 0,
// totalRound: 20,
// roomMode: 'basic',
// },
// {
// roomId: 2,
// roomTitle: '초보자만 오세요',
// roomOwnerName: 'Newbie',
// roomCurUserNum: 10,
// roomMaxUserNum: 10,
// isGameStart: true,
// isRoomFull: true,
// probCategory: '일반상식',
// isHavePW: true,
// curRound: 3,
// totalRound: 15,
// roomMode: 'basic',
// },
// {
// roomId: 3,
// roomTitle: '윷놀이 챌린지',
// roomOwnerName: 'YutMaster',
// roomCurUserNum: 6,
// roomMaxUserNum: 8,
// isGameStart: false,
// isRoomFull: false,
// probCategory: '한국사',
// isHavePW: false,
// curRound: 0,
// totalRound: 30,
// roomMode: 'yutnori',
// },
// {
// roomId: 4,
// roomTitle: '파이썬 프로그래밍',
// roomOwnerName: 'Coder',
// roomCurUserNum: 8,
// roomMaxUserNum: 8,
// isGameStart: true,
// isRoomFull: true,
// probCategory: '코딩',
// isHavePW: true,
// curRound: 5,
// totalRound: 10,
// roomMode: 'basic',
// },
// ]

export const generateRooms = (): Room[] => {
const rooms: Room[] = []
for (let i = 1; i <= 100; i++) {
const roomMaxUserNum = 10
const roomCurUserNum = Math.floor(Math.random() * roomMaxUserNum) + 1

rooms.push({
roomId: i,
roomTitle: `방 제목 ${i}`,
roomOwnerName: `방장${i}`,
roomCurUserNum: roomCurUserNum,
roomMaxUserNum: 10,
isGameStart: Math.random() > 0.5,
isRoomFull: roomCurUserNum === roomMaxUserNum,
probCategory: ['수학 퀴즈', '일반상식', '역사', '코딩'][Math.floor(Math.random() * 4)],
isHavePW: Math.random() > 0.5,
curRound: Math.floor(Math.random() * 10),
totalRound: 20,
roomMode: ['basic', 'yutnori'][Math.floor(Math.random() * 2)] as 'basic' | 'yutnori',
})
}
return rooms
}
6 changes: 4 additions & 2 deletions frontend/app/lobby/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React from 'react'
'use client'

import WaitingRoomList from './ui/WaitingRoomList'

const Lobby = () => {
return <div>Lobby</div>
return <WaitingRoomList />
}

export default Lobby
Empty file removed frontend/app/lobby/ui/.gitkeep
Empty file.
51 changes: 51 additions & 0 deletions frontend/app/lobby/ui/RoomPasswordModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
'use client'
// components/PasswordModal.tsx
import React, { useEffect, useState } from 'react'
import ReactDOM from 'react-dom'

interface PasswordModalProps {
isOpen: boolean
onClose: (event: React.MouseEvent<HTMLButtonElement>) => void
submitPassword: (password: string) => void
}

const RoomPasswordModal: React.FC<PasswordModalProps> = ({ isOpen, onClose, submitPassword }) => {
const [password, setPassword] = useState<string>('')
const handleSubmitPassword = (event: React.MouseEvent<HTMLButtonElement>) => {
event.stopPropagation()
submitPassword(password)
}

if (!isOpen) return null

const modalContent = (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4">
<div className="bg-white p-6 rounded-lg shadow-lg max-w-sm w-full">
<h2 className="text-xl font-semibold mb-4">Enter Room Password</h2>
<input
type="text"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
className="border border-gray-300 p-2 w-full rounded-md mb-4 text-black"
/>
<button
onClick={handleSubmitPassword}
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded mr-2"
>
Submit
</button>
<button
onClick={onClose}
className="bg-gray-300 hover:bg-gray-400 text-black font-bold py-2 px-4 rounded"
>
Close
</button>
</div>
</div>
)

return ReactDOM.createPortal(modalContent, document.getElementById('root') as HTMLElement)
}

export default RoomPasswordModal
63 changes: 63 additions & 0 deletions frontend/app/lobby/ui/WaitingRoom.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
'use client'

import React, { useState } from 'react'
import { Lock } from 'lucide-react'
import RoomPasswordModal from './RoomPasswordModal'

interface RoomProps {
room: Room
}

const WaitingRoom = ({ room }: RoomProps) => {
const [isModalOpen, setModalOpen] = useState(false)

const handleRoomClick = () => {
if (room.isHavePW) {
setModalOpen(true)
} else {
// Todo : 방 입장 로직(유효성 검증 및 소켓 연결 로직 작성 필요)
// enterRoom()
console.log('Entering room without password')
}
}

const submitPassword = (password: string) => {
console.log('Password entered:', password)
// Todo : 방 입장 로직(유효성 검증 및 소켓 연결 로직 작성 필요)
// enterRoom(password)
setModalOpen(false)
}

const handleCloseModal = (event: React.MouseEvent<HTMLButtonElement>) => {
event.stopPropagation()
console.log('try to close modal')
setModalOpen(false)
}

return (
<div
onClick={handleRoomClick}
className={`p-4 rounded-lg shadow-md flex items-center gap-6 ${
room.isRoomFull ? 'border-2 border-red-500' : 'border-2 border-gray-200'
}`}
>
<div className="text-lg font-bold">{room.roomId}</div>
<div className="flex-grow">
<h2 className="text-xl font-semibold">{room.roomTitle}</h2>
<p>{`${room.roomMode} / ${room.probCategory}`}</p>
<p>Problems: {room.totalRound}</p>
</div>
<div className="text-right">
<p>{`${room.roomCurUserNum}/${room.roomMaxUserNum}`}</p>
{room.isHavePW && <Lock size={24} />}
</div>
<RoomPasswordModal
isOpen={isModalOpen}
onClose={handleCloseModal}
submitPassword={submitPassword}
/>
</div>
)
}

export default WaitingRoom
27 changes: 27 additions & 0 deletions frontend/app/lobby/ui/WaitingRoomList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use client'

import React, { useEffect } from 'react'
import WaitingRoom from './WaitingRoom'
import { generateRooms } from '../lib/util'

const WaitingRoomList: React.FC = () => {
const [rooms, setRooms] = React.useState<Room[]>([])
useEffect(() => {
setRooms(generateRooms())
}, [])
useEffect(() => {
console.log('rooms', rooms)
}, [rooms])

// const roomsData = generateRooms()

return (
<div className="grid grid-cols-2 gap-4">
{rooms.map((room) => (
<WaitingRoom key={room.roomId} room={room} />
))}
</div>
)
}

export default WaitingRoomList
9 changes: 9 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@mui/material": "^5.15.15",
"@tanstack/react-query": "^5.29.2",
"@tanstack/react-query-devtools": "^5.29.2",
"lucide-react": "^0.372.0",
"next": "14.2.2",
"react": "^18",
"react-dom": "^18",
Expand Down
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 0fb0e13

Please sign in to comment.