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
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"@hookform/resolvers": "^3.9.1",
"@tanstack/react-query": "4",
"axios": "^1.7.9",
"jwt-decode": "^4.0.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.54.2",
Expand All @@ -26,6 +27,7 @@
"@types/node": "^22.10.2",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/socket.io-client": "^3.0.0",
"@vitejs/plugin-react": "^4.3.4",
"eslint": "^9.15.0",
"eslint-plugin-react-hooks": "^5.0.0",
Expand Down
1 change: 1 addition & 0 deletions src/api/axios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const instance = axios.create({

export const authInstance = axios.create({
baseURL: import.meta.env.VITE_BASE_URL,
withCredentials: true,
});

authInstance.interceptors.request.use(
Expand Down
19 changes: 18 additions & 1 deletion src/api/gameRoomApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,20 @@ export const getGameRoomsList = async () => {
}
};

export const getGameRoomInfo = async (roomId: number) => {
try {
const response = await authInstance.get(`/gameRoom/${roomId}`);

return response.data;
} catch (error) {
const axiosError = error as AxiosError<unknown>;

if (axiosError.response) {
return axiosError.response.data;
}
}
};

export const createGameRoom = async ({
roomName,
}: {
Expand All @@ -43,6 +57,9 @@ export const createGameRoom = async ({
const response = await authInstance.post<ICreateGameRoomResponse>(
"gameRoom/create",
{ roomName },
{
headers: { Authorization: localStorage.getItem("accessToken") },
},
);

return response.data;
Expand All @@ -64,7 +81,7 @@ export const createGameRoom = async ({
export const joinGameRoom = async (gameRoomId: number) => {
try {
const response = await authInstance.post(`/gameRoom/join/${gameRoomId}`);
console.log(response, "joinresponse확인");

if (response.status === 200) {
return response.data;
}
Expand Down
10 changes: 4 additions & 6 deletions src/api/userAuthApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,14 @@ export const loginUser = async (logInfo: {

export const refreshToken = async () => {
try {
const response = await authInstance.post("/auth/refresh", {
withCredentials: true,
});
const response = await authInstance.post("/auth/refresh");
console.log(response);
const accessToken = response?.headers.authorization;
const { accessToken } = response.data;

localStorage.setItem("accessToken", accessToken);
return response.data.accessToken;
} catch (err) {
console.log(err);
} catch (error) {
console.log(error);
}
};

Expand Down
8 changes: 6 additions & 2 deletions src/components/ui/card/cardList/GameRoomCard.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { useJoinRoomMutation } from "../../../../hooks/useMutation";
import { useJoinGameRoomMutation } from "../../../../hooks/useMutation";
import { useRoomIdStore } from "../../../../store/useRoomIdStore";
import Badge from "../../badge/Badge";
import Button from "../../button/Button";
import * as S from "./GameRoomCardStyle";

export default function GameRoomCard({ room }: { room: IRoomProps }) {
const { setRoomId } = useRoomIdStore();
const disabled = room.currentCount === 2 ? true : false;
const mutation = useJoinRoomMutation();
const mutation = useJoinGameRoomMutation();
const onClickJoin = (roomId: number) => {
setRoomId(roomId);
mutation.mutate(roomId);
};

return (
<S.cardContainer>
<Badge playerNumber={room.currentCount} />
Expand Down
16 changes: 12 additions & 4 deletions src/components/ui/card/profileCard/ProfileCard.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import { ReactNode } from "react";
import { CardIndex, PlayerCard } from "./ProfileCardStyle";
import PlayerCard from "./playerCard/playerCard";
import * as S from "./ProfileCardStyle";

export default function ProfileCard({ children }: { children: ReactNode }) {
interface IProfileCard {
nickname: string | undefined;
children: ReactNode;
}

export default function ProfileCard({ nickname, children }: IProfileCard) {
return (
<div>
<CardIndex>나 or 상대플레이어</CardIndex>
<PlayerCard>{children}</PlayerCard>
<S.CardIndex>{children}</S.CardIndex>
<S.PlayerCardContainer>
<PlayerCard nickname={nickname} />
</S.PlayerCardContainer>
</div>
);
}
2 changes: 1 addition & 1 deletion src/components/ui/card/profileCard/ProfileCardStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const CardIndex = styled.div`
line-height: 46px;
`;

export const PlayerCard = styled.div`
export const PlayerCardContainer = styled.div`
display: flex;
flex-direction: column;
gap: 22px;
Expand Down
14 changes: 9 additions & 5 deletions src/components/ui/card/profileCard/playerCard/playerCard.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { Fragment } from "react/jsx-runtime";
import Button from "../../../button/Button";
import Profile from "../../../profile/Profile";
import ProfileCard from "../ProfileCard";

export default function PlayerCard() {
export default function PlayerCard({
nickname,
}: {
nickname: string | undefined;
}) {
return (
<ProfileCard>
<Profile nickname="플레이어" rank="78위" />
<Fragment>
<Profile nickname={nickname} />
<Button type="button" bgcolor="blue" textcolor="black" size="sm">
Ready
</Button>
</ProfileCard>
</Fragment>
);
}
8 changes: 2 additions & 6 deletions src/components/ui/profile/Profile.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import * as S from "./profileStyle";

export default function Profile({ nickname, rank, avatar }: IprofileProps) {
export default function Profile({ nickname }: IprofileProps) {
return (
<S.container>
<S.avatar>{avatar}</S.avatar>
<S.avatar></S.avatar>
<S.nameBox>
<S.nickname>{nickname}</S.nickname>
<S.rankBox>
<S.trophyImg src="/trophy.png" alt="trophy"></S.trophyImg>
<S.rank>{rank}</S.rank>
</S.rankBox>
</S.nameBox>
</S.container>
);
Expand Down
4 changes: 2 additions & 2 deletions src/components/ui/profile/profile.props.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
interface IprofileProps {
nickname: string;
rank: string | number;
nickname: string | undefined;
rank?: string | number;
avatar?: string;
}
2 changes: 1 addition & 1 deletion src/hooks/useMutation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const useCreateRoomMutation = () => {
});
};

export const useJoinRoomMutation = () => {
export const useJoinGameRoomMutation = () => {
const navigate = useNavigate();
return useMutation({
mutationFn: joinGameRoom,
Expand Down
9 changes: 8 additions & 1 deletion src/hooks/useQuery.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { useQuery } from "@tanstack/react-query";
import { getGameRoomsList } from "../api/gameRoomApi";
import { getGameRoomInfo, getGameRoomsList } from "../api/gameRoomApi";

export const useGetGameRoomList = () => {
return useQuery({
queryKey: ["gameRoomsList"],
queryFn: getGameRoomsList,
});
};

export const useGetGameRoomInfo = (roomId: number) => {
return useQuery({
queryKey: ["gameRoomInfo", roomId],
queryFn: () => getGameRoomInfo(roomId),
});
};
94 changes: 91 additions & 3 deletions src/pages/game/GameRoom.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,100 @@
import { io } from "socket.io-client";
import ChattingBox from "../../components/ui/card/chatting/Chatting";
// import ProfileCard from "../../components/ui/card/profileCard/ProfileCard";
import { useSocketStore } from "../../store/useSocketStore";
import ProfileCard from "../../components/ui/card/profileCard/ProfileCard";
import * as S from "./gameRoomStyle";
import { useEffect, useState } from "react";
import { jwtDecode } from "jwt-decode";
import { useGetGameRoomInfo } from "../../hooks/useQuery";
import { useParams } from "react-router-dom";

interface IUser {
id: number;
roomId: number;
userId: number;
joinedAt: string;
userNickname: string;
}

interface IJoinRoomResponse {
sender: string;
userNickname: string;
message: string;
}

interface IJwtDecode {
exp: number;
iat: number;
userEmail: string;
userId: number;
}

export default function GameRoom() {
const { socket, setSocket } = useSocketStore();
const params = useParams();
const roomId = Number(params.id);
const [userMyId, setUserMyId] = useState<number | undefined>(undefined);
const [myInfo, setMyInfo] = useState<IUser | undefined>(undefined);
const [otherInfo, setOtherInfo] = useState<IUser[] | undefined>(undefined);
const accessToken = localStorage.getItem("accessToken");
const { data, refetch } = useGetGameRoomInfo(roomId);

useEffect(() => {
if (!accessToken) {
console.error("Access token is missing.");
//오류 표시하거나 로그인창으로 리다이렉션 하기
return;
}

const decoded = jwtDecode<IJwtDecode>(accessToken);
setUserMyId(decoded.userId);

if (socket) {
socket.on("connect", () => {
console.log(`Socket connected: ${socket.id}`);
});
}

const newSocket = io(`wss://api.davincicodegame.store/game`, {
extraHeaders: { Authorization: accessToken },
auth: { token: accessToken },
});
setSocket(newSocket);

newSocket.emit("joinRoom", { roomId }, (response: IJoinRoomResponse) => {
console.log(`Join room response: ${JSON.stringify(response)}`);
});
}, []);

useEffect(() => {
const myProfile = data?.users.find(
(user: IUser) => user.userId == userMyId,
);

setMyInfo(myProfile);

const otherProfile = data?.users.filter(
(user: IUser) => user.userId !== userMyId,
);

setOtherInfo(otherProfile);
}, [data]);

useEffect(() => {
if (!socket) return;
socket.on("join", async (data) => {
console.log(`${JSON.stringify(data)}`);
const refetchInfo = await refetch();
console.log(refetchInfo, "리페치정보");
});
}, [socket]);

return (
<S.container>
<S.leftContainer>
{/* <ProfileCard /> */}
<ProfileCard nickname={otherInfo ? otherInfo[0]?.userNickname : ""}>
상대 플레이어
</ProfileCard>
<ChattingBox />
</S.leftContainer>
<S.centerContainer>
Expand All @@ -16,7 +104,7 @@ export default function GameRoom() {
</S.centerContainer>
<S.rightContainer>
<S.myDeckBox />
{/* <ProfileCard /> */}
<ProfileCard nickname={myInfo?.userNickname}>나</ProfileCard>
</S.rightContainer>
</S.container>
);
Expand Down
10 changes: 4 additions & 6 deletions src/pages/game/gameRoomStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,16 @@ export const container = styled.div`
`;

export const leftContainer = styled.div`
padding-top: 44px;
margin-left: 63px;
width: 390px;
height: 100%;
height: 1000px;
display: flex;
flex-direction: column;
justify-content: space-between;
background-color: yellow;
gap: 90px;
`;

export const centerContainer = styled.div`
height: 100%;
height: 1000px;
width: 100%;
background-color: green;
position: relative;
Expand All @@ -30,7 +28,7 @@ export const rightContainer = styled.div`
margin-right: 77px;
padding-bottom: 44px;
width: 390px;
height: 100%;
height: 1000px;
display: flex;
gap: 40px;
flex-direction: column;
Expand Down
16 changes: 0 additions & 16 deletions src/pages/game/waitingPage/WaitingPage.tsx

This file was deleted.

14 changes: 0 additions & 14 deletions src/pages/game/waitingPage/waitingPageStyle.ts

This file was deleted.

Loading