Skip to content

Commit

Permalink
Merge pull request #65 from NARARIA03/main
Browse files Browse the repository at this point in the history
Fix: 효과음 버그 수정, 텍스트 수정(해파리 충돌, 리더보드, 튜토리얼), 리더보드, 회원가입, 랜딩 페이지 수정, 어드민 페이지 정렬 수정
  • Loading branch information
NARARIA03 authored Dec 7, 2024
2 parents a6f677d + e40f16c commit 1dcf62b
Show file tree
Hide file tree
Showing 17 changed files with 84 additions and 57 deletions.
5 changes: 1 addition & 4 deletions backend/controllers/adminController.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
// controllers/adminController.js
const { redisClient, subscriber } = require("../config/db");
const mongoose = require("mongoose");
const { redisClient } = require("../config/db");
require("dotenv").config(); // 환경 변수를 로드
const bcrypt = require("bcryptjs");
const User = require("../models/user");
const Report = require("../models/report");
const Ban = require("../models/ban");
const jwt = require("jsonwebtoken");

// 제제당한 유저 조회 로직
exports.getBannedUsers = async (req, res) => {
Expand Down
1 change: 0 additions & 1 deletion backend/models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ const userSchema = new mongoose.Schema({
isAdmin: { type: Boolean, default: false }, // 기본값 false
topRate: { type: Number, default: 0 },
coin: { type: Number, default: 0 },
trash: { type: Number, default: 10000 }, // 임시 추가 - 환전 api용
countPlay: { type: Number, default: 0 },
status: {
type: String,
Expand Down
5 changes: 3 additions & 2 deletions backend/sockets/eventHandler/gameEvent.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@ exports.generateRandomTrash = async (io) => {

if (isNaN(trashSpeed) || isNaN(trashLimit)) {
await redisClient.set("trashGenerationSpeed", "10");
await redisClient.publish("trashGenerationSpeed", speed.toString());
await redisClient.publish("trashGenerationSpeed", "10");

await redisClient.set("trashGenerationLimit", "20");
await redisClient.publish("trashGenerationLimit", quantity.toString());
await redisClient.publish("trashGenerationLimit", "20");
}

// 클로저 활용! 해당 함수를 한 번 실행시키면 기존 이벤트를 지우고 새 이벤트를 등록한다.
Expand Down
4 changes: 2 additions & 2 deletions backend/sockets/eventHandler/leaderboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ const { makeLeaderBoard } = require("../../utils/makeLeaderBoard");
* @description 특정 유저의 trashAmount가 변경되면, 모든 클라이언트의 리더보드 데이터를 새로고침
*/
exports.leaderboard = (io) => {
subscriber.subscribe("leaderboard", (userTrashData) => {
const topUsers = makeLeaderBoard(JSON.parse(userTrashData));
subscriber.subscribe("leaderboard", async (userTrashData) => {
const topUsers = await makeLeaderBoard(JSON.parse(userTrashData));

io.emit("getLeaderBoard", topUsers);
});
Expand Down
17 changes: 12 additions & 5 deletions backend/utils/makeLeaderBoard.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
const User = require("../models/user");

// 데이터 정렬 및 상위 5명 추출
exports.makeLeaderBoard = (userTrashData) => {
const topUsers = Object.entries(userTrashData)
.map(([userId, trashAmount]) => ({
userId,
trashAmount: parseFloat(trashAmount) || 0, // 기본값 0
exports.makeLeaderBoard = async (userTrashData) => {
// 현재 플레이 중인 유저들의 닉네임 추출 목적
const userIds = Object.keys(userTrashData);
const users = await User.find({ id: { $in: userIds } });

const topUsers = users
.map((user) => ({
userId: user.id,
nickName: user.nickName,
trashAmount: parseFloat(userTrashData[user.id] || 0),
}))
.sort((a, b) => b.trashAmount - a.trashAmount) // 쓰레기량 내림차순 정렬
.slice(0, 5); // 상위 5명
Expand Down
2 changes: 1 addition & 1 deletion backend/utils/redisHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ exports.getLeaderBoard = async () => {
// Redis에서 모든 유저와 쓰레기량 데이터 가져오기
const userTrashData = await redisClient.hGetAll("user_trash");

const topUsers = makeLeaderBoard(userTrashData);
const topUsers = await makeLeaderBoard(userTrashData);
return topUsers;
};

Expand Down
Binary file added frontend/public/images/landing.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions frontend/src/components/admin/ViewUsers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default function ViewUsers() {
<th className="px-6 py-3 text-left text-sm font-semibold border-b">
Nickname
</th>
<th className="px-6 py-3 text-left text-sm font-semibold border-b">
<th className="px-6 py-3 text-center text-sm font-semibold border-b">
Report Count
</th>
<th className="px-6 py-3 text-center text-sm font-semibold border-b">
Expand All @@ -39,7 +39,7 @@ export default function ViewUsers() {
<tr key={index} className="hover:bg-sky-100">
<td className="px-6 py-4 border-b">{userData.userId}</td>
<td className="px-6 py-4 border-b">{userData.nickName}</td>
<td className="px-6 py-4 border-b">
<td className="px-6 py-4 border-b text-center">
{userData.reportCount}
</td>
<td className="px-6 py-4 border-b flex justify-center items-center">
Expand Down
13 changes: 9 additions & 4 deletions frontend/src/components/game/modal/TutorialModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default function TutorialModal(): JSX.Element | null {

const handleBgClick = (e: React.MouseEvent<HTMLDivElement>) => {
if (e.target === e.currentTarget) {
toggleModal("tutorial");
closeModal();
}
};

Expand All @@ -29,23 +29,28 @@ export default function TutorialModal(): JSX.Element | null {
}
};

const closeModal = () => {
toggleModal("tutorial");
setPageIdx(0);
};

if (!isOpen.tutorial) return null;

return (
<div
className="absolute inset-0 flex items-center justify-center bg-black bg-opacity-50 text-gray-800 z-40"
onClick={handleBgClick}
>
<div className="bg-slate-200 p-2 m-2 mx-8 sm:max-w-2xl sm:w-full sm:h-fit sm:p-8 sm:m-4 flex flex-col justify-center items-center shadow-lg rounded-lg">
<div className="min-h-64 h-64 bg-slate-200 p-2 m-2 mx-8 sm:max-w-2xl sm:w-full sm:h-fit sm:p-8 sm:m-4 flex gap-3 flex-col justify-center items-center shadow-lg rounded-lg">
<div className="relative w-full text-center font-bold text-xs sm:text-2xl py-3 mx-auto">
<AiFillCloseSquare
className="absolute top-1.5 p-1 w-7 h-7 sm:w-11 sm:h-11 cursor-pointer hover:text-red-500"
onClick={() => toggleModal("tutorial")}
onClick={closeModal}
/>
{tutorialDataList[pageIdx].title}
</div>

<p className="text-[8px] sm:text-base self-start">
<p className="text-[8px] sm:text-base self-start whitespace-pre-wrap px-12">
{tutorialDataList[pageIdx].description}
</p>
<div className="w-full flex justify-between items-center mt-1">
Expand Down
16 changes: 8 additions & 8 deletions frontend/src/components/game/ui/LeaderBoard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface Props {

export default function LeaderBoard({ isJoinGameRoom, socket }: Props) {
const [topUsers, setTopUsers] = useState<TopUser[]>([]);
const myUserId = useGameDataStore((s) => s.userId);
const myNickName = useGameDataStore((s) => s.nickName);
const myTrash = useGameDataStore((s) => s.myCurrency.trash);

useEffect(() => {
Expand All @@ -25,23 +25,23 @@ export default function LeaderBoard({ isJoinGameRoom, socket }: Props) {
if (!isJoinGameRoom) return null;

return (
<div className="absolute rounded bg-black bg-opacity-30 text-white text-xs p-2 top-4 right-4 w-40 shadow-md">
<div className="mb-2 font-medium text-center border-b border-white pb-1">
리더보드
<div className="absolute rounded bg-black bg-opacity-30 text-white p-2 top-4 right-4 w-40 shadow-md">
<div className="mb-2 pb-2 font-medium text-center border-b border-white">
순위
</div>
<ul className="space-y-1">
{topUsers.map(({ userId, trashAmount }, idx) => (
{topUsers.map(({ nickName, trashAmount }, idx) => (
<li
key={idx}
className="flex justify-between text-sm py-1 px-2 bg-gray-800 rounded"
>
<span>{userId}</span>
<span>{nickName}</span>
<span>{trashAmount}</span>
</li>
))}
{!topUsers.some(({ userId }) => userId === myUserId) && (
{!topUsers.some(({ nickName }) => nickName === myNickName) && (
<li className="flex justify-between text-sm py-1 px-2 bg-gray-800 rounded">
<span>{myUserId}</span>
<span>{myNickName}</span>
<span>{myTrash}</span>
</li>
)}
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/landing/LoginModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export default function LoginModal() {
type="text"
autoComplete="username"
placeholder="ID"
className="w-full p-3 mb-4 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
className="w-full p-3 mb-4 border-2 rounded-lg outline-none focus:border-blue-500"
value={inputs.id}
onChange={(e) =>
setInputs((prev) => ({ ...prev, id: e.target.value }))
Expand All @@ -82,7 +82,7 @@ export default function LoginModal() {
type="password"
autoComplete="current-password"
placeholder="Password"
className="w-full p-3 mb-4 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
className="w-full p-3 mb-4 border-2 rounded-lg outline-none focus:border-blue-500"
value={inputs.pw}
onChange={(e) =>
setInputs((prev) => ({ ...prev, pw: e.target.value }))
Expand Down
18 changes: 9 additions & 9 deletions frontend/src/components/landing/RegisterModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,25 +68,25 @@ export default function RegisterModal() {
onClick={handleBgClick}
>
<Loading isLoading={isLoading} />
<div className="bg-sky-50 text-gray-800 p-8 rounded-lg shadow-lg w-full max-w-sm">
<div className="bg-sky-50 text-gray-800 p-8 rounded-lg shadow-lg w-full max-w-sm min-w-sm">
<AiFillCloseSquare
size={30}
className=" hover:text-red-500"
onClick={() => navigate("/")}
/>
<div className="text-xl font-semibold text-center mb-6">회원가입</div>
<form onSubmit={(e) => e.preventDefault()}>
<div className="flex relative">
<div className="flex">
<input
name="nickName"
type="text"
placeholder="Your nickname"
className="w-full h-full p-3 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
className="w-full flex-[3] p-3 border-2 rounded-lg border-r-0 rounded-r-none outline-none focus:border-blue-500"
value={inputs.nickName}
onChange={(e) => handleInputChange(e.target.name, e.target.value)}
/>
<button
className="absolute right-0 p-[10.5px] border-slate-700 bg-slate-700 text-slate-200 transition-colors rounded-r-lg hover:bg-slate-600"
className="flex-1 min-w-20 border-slate-700 bg-slate-700 text-sm text-slate-200 transition-colors rounded-r-lg hover:bg-slate-600"
onClick={() => handleInputCheck("nickName")}
>
닉네임 확인
Expand All @@ -101,18 +101,18 @@ export default function RegisterModal() {
{infoMsgs.nickName || "\u00A0"}
</p>
</div>
<div className="flex relative">
<div className="flex">
<input
name="id"
type="text"
autoComplete="username"
placeholder="ID"
className="w-full h-full p-3 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
className="w-full flex-[3] p-3 border-2 rounded-lg border-r-0 rounded-r-none outline-none focus:border-blue-500"
value={inputs.id}
onChange={(e) => handleInputChange(e.target.name, e.target.value)}
/>
<button
className="absolute right-0 p-[10.5px] border-slate-700 bg-slate-700 text-slate-200 transition-colors rounded-r-lg hover:bg-slate-600"
className="flex-1 min-w-20 border-slate-700 bg-slate-700 text-sm text-slate-200 transition-colors rounded-r-lg hover:bg-slate-600"
onClick={() => handleInputCheck("id")}
>
ID 확인
Expand All @@ -132,7 +132,7 @@ export default function RegisterModal() {
type="password"
autoComplete="new-password"
placeholder="Password"
className="w-full p-3 mb-4 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
className="w-full p-3 mb-4 border-2 rounded-lg outline-none focus:border-blue-500"
value={inputs.pw}
onChange={(e) => handleInputChange(e.target.name, e.target.value)}
/>
Expand All @@ -141,7 +141,7 @@ export default function RegisterModal() {
type="password"
autoComplete="new-password"
placeholder="Check again password"
className="w-full p-3 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
className="w-full p-3 mb-4 border-2 rounded-lg outline-none focus:border-blue-500"
value={inputs.checkPw}
onChange={(e) => handleInputChange(e.target.name, e.target.value)}
/>
Expand Down
20 changes: 10 additions & 10 deletions frontend/src/constants/tutorial.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
export const tutorialDataList = [
{
title: "게임 소개 1",
title: "바다 이야기에 오신 것을 환영합니다",
description:
"게임 소개 1 Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga iure nisi illo dicta. Quasi explicabo, ullam aut quidem voluptate consectetur soluta possimus commodi non fuga quos, reiciendis magni maxime id.",
"이곳은 환경 보존의 마지막 보루인 마린시아로, 이곳을 지킬 용사로 당신을 초대하였습니다. 부디 환경 수호를 위해 함께해 주세요. ",
},
{
title: "게임 소개 2",
title: "플레이 방법",
description:
"게임 소개 2 Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga iure nisi illo dicta. Quasi explicabo, ullam aut quidem voluptate consectetur soluta possimus commodi non fuga quos, reiciendis magni maxime id.",
"방향키를 활용해 해변으로 출동하여 모험을 시작합니다. 마린시아의 정기를 받으며 쓰레기를 수집하는 당신의 사명감과, 용사들과의 경쟁을 통해 사기를 끌어올릴 수 있습니다.",
},
{
title: "게임 소개 3",
title: "플레이 방법",
description:
"게임 소개 3 Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga iure nisi illo dicta. Quasi explicabo, ullam aut quidem voluptate consectetur soluta possimus commodi non fuga quos, reiciendis magni maxime id.",
"수집한 쓰레기는 해변으로 복귀하여 상점(우측 하단)에서 재화로 환전해 장비를 구매할 수 있습니다. 상점으로 가 스페이스바를 클릭해 상점에 입장하세요. 더욱 강화된 장비를 통해 마린시아을 지켜주세요.",
},
{
title: "게임 소개 4",
title: "플레이어 신고",
description:
"게임 소개 4 Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga iure nisi illo dicta. Quasi explicabo, ullam aut quidem voluptate consectetur soluta possimus commodi non fuga quos, reiciendis magni maxime id.",
"마린시아 수호의 임무를 저해하는 용사들은 우리와 함께 할 수 없습니다. 플레이어를 클릭한 후 신고를 통해 신속히 처단하세요.",
},
{
title: "게임 소개 5",
title: "건투를 빕니다!",
description:
"게임 소개 5 Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga iure nisi illo dicta. Quasi explicabo, ullam aut quidem voluptate consectetur soluta possimus commodi non fuga quos, reiciendis magni maxime id.",
"이제 모든 준비는 끝났습니다. 마린시아 수호에 참여할 용사님의 행운을 빌게요!",
},
];
6 changes: 3 additions & 3 deletions frontend/src/hooks/game/useSocketRecv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,16 @@ export const useSocketRecv = (socket: Socket | null) => {
});
socket.on("collisionTrash", (collisionTrashRes: Trash[]) => {
setTrashInfo(collisionTrashRes);
playGetSound(); // 획득 효과음 실행
});
socket.on("collisionItem", (collisionItemRes: GameItem[]) => {
setItemInfo(collisionItemRes);
playGetSound(); // 획득 효과음 실행
});
socket.on("collisionObstacle", (collisionObstacleRes: Obstacle[]) => {
setObstacleInfo(collisionObstacleRes);
});
socket.on("getTrashAmount", (trashAmountRes: number) => {
setMyTrashAmount(trashAmountRes);
playGetSound(); // 획득 효과음 실행
});
socket.on("getItem", async (itemId: string) => {
console.log(`itemId: ${itemId}`);
Expand All @@ -65,6 +64,7 @@ export const useSocketRecv = (socket: Socket | null) => {
if (token) {
// 습득한 아이템을 백엔드 mongodb에 업데이트하도록 요청을 날리고
await getItemApi(token, itemId);
playGetSound(); // 획득 효과음 실행
// 끝나면 인벤토리 내 아이템 정보를 다시 받아와서 zustand state를 업데이트하는 함수 실행
await fetchMyItems(token);
}
Expand All @@ -81,7 +81,7 @@ export const useSocketRecv = (socket: Socket | null) => {
socket.on("collisionJellyfish", (duration: number) => {
toggleConfusionDirection(duration); // 방향 전환 효과를 duration동안 적용
playHitSound(); // 충돌 효과음 실행
showToast(`해파리와 부딧쳐 ${duration / 1000}초 동안 어지러워집니다!!`);
showToast(`해파리와 부딪쳐 ${duration / 1000}초 동안 어지러워집니다!!`);
});
} else if (!socket) {
setAnotherPlayersInfo([]);
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/index.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
@import url("https://cdn.jsdelivr.net/gh/orioncactus/[email protected]/dist/web/static/pretendard.min.css");

@tailwind base;
@tailwind components;
@tailwind utilities;

html {
font-family: "Pretendard", sans-serif;
}
19 changes: 15 additions & 4 deletions frontend/src/pages/LandingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,31 @@ export default function LandingPage() {
}, [navigate, showToast]);

return (
<div className="w-screen h-screen relative flex justify-center items-center bg-sky-100 text-gray-800">
<div
className="w-screen h-screen relative text-gray-800"
style={{
backgroundImage:
"linear-gradient(rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.3)), url('/images/landing.png')",
backgroundSize: "cover",
backgroundPosition: "center",
backgroundRepeat: "no-repeat",
}}
>
<div className="absolute top-20 left-20">
<p className="text-3xl font-bold">바다 이야기</p>
<p className="text-slate-200 text-5xl font-black drop-shadow-2xl">
바다 이야기
</p>
</div>
<div className="absolute flex flex-col text-center right-20 bottom-20">
<Link
to="login"
className="bg-blue-500 hover:bg-blue-600 min-w-28 px-3 py-2 m-2 border rounded-xl text-slate-200"
className="bg-blue-500 hover:bg-blue-600 min-w-28 px-3 py-2 m-2 rounded-xl text-slate-200 font-bold"
>
로그인
</Link>
<Link
to="register"
className="bg-blue-500 hover:bg-blue-600 min-w-28 px-3 py-2 m-2 border rounded-xl text-slate-200"
className="bg-blue-500 hover:bg-blue-600 min-w-28 px-3 py-2 m-2 rounded-xl text-slate-200 font-bold"
>
회원가입
</Link>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/types/GameType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ export type ObjectPos = {

export type TopUser = {
userId: string;
nickName: string;
trashAmount: number;
};

0 comments on commit 1dcf62b

Please sign in to comment.