Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/#144 라운드별 매치 횟수를 설정 및 대진표 기본 디자인 #145

Merged
merged 7 commits into from
Sep 16, 2023
Merged
10 changes: 5 additions & 5 deletions __mocks__/constants/matchRoundMock.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { BracketContents } from '@type/bracket';

interface mockRoundData {
[key: string]: BracketContents;
[key: number]: BracketContents;
}

export const matchRoundMock: mockRoundData = {
'1': {
1: {
myGameId: 'NO_DATA',
matchInfoDtoList: [
{
Expand Down Expand Up @@ -439,7 +439,7 @@ export const matchRoundMock: mockRoundData = {
},
],
},
'2': {
2: {
myGameId: 'NO_DATA',
matchInfoDtoList: [
{
Expand Down Expand Up @@ -658,7 +658,7 @@ export const matchRoundMock: mockRoundData = {
},
],
},
'3': {
3: {
myGameId: 'NO_DATA',
matchInfoDtoList: [
{
Expand Down Expand Up @@ -773,7 +773,7 @@ export const matchRoundMock: mockRoundData = {
},
],
},
'4': {
4: {
myGameId: 'NO_DATA',
matchInfoDtoList: [
{
Expand Down
20 changes: 16 additions & 4 deletions __mocks__/handlers/bracketHandlers.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
import { SERVER_URL } from '@config/index';
import { matchRoundMock } from '@mocks/constants/matchRoundMock';
import { MatchCountList } from '@type/channelConfig';
import { rest } from 'msw';

const channelRoundList: MatchCountList[] = [
{
roundCountList: [2, 3, 4, 5],
},
];
const bracketHandlers = [
rest.get(SERVER_URL + '/api/match/:channelLink', (req, res, ctx) => {
const { channelLink } = req.params;

return res(ctx.json({ roundList: [1, 2, 3, 4], liveRound: 1 }));
}),

rest.get(SERVER_URL + '/api/match/:channelLink/:matchRound', (req, res, ctx) => {
rest.get(SERVER_URL + '/api/match/:channelLink/:matchRound(\\d+)', (req, res, ctx) => {
const { channelLink, matchRound } = req.params;

if (typeof matchRound === 'string') {
return res(ctx.json(matchRoundMock[matchRound]));
}
return res(ctx.json(matchRoundMock[Number(matchRound)]));
}),

rest.get(SERVER_URL + '/api/match/:channelLink/count', (req, res, ctx) => {
return res(ctx.json(channelRoundList[0]));
}),

rest.post(SERVER_URL + '/api/match/:channelLink/count', (req, res, ctx) => {
return res(ctx.json({ message: '채널 재설정 완료' }));
}),
];

Expand Down
3 changes: 3 additions & 0 deletions src/@types/channelConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface MatchCountList {
roundCountList: number[];
}
4 changes: 3 additions & 1 deletion src/@types/icon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ export type IconKind =
| 'clock'
| 'refresh'
| 'sendEmail'
| 'modify';
| 'modify'
| 'setting'
| 'cancel';
57 changes: 38 additions & 19 deletions src/components/Bracket/BracketContents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,29 +39,33 @@ const BracketContents = (props: Props) => {
return (
<MatchContainer>
<MatchHeader>
<MatchHeaderRound>R{match.matchRoundCount}</MatchHeaderRound>
<MatchHeaderRound>M{match.matchRoundCount}</MatchHeaderRound>
<MatchHeaderName>{match.matchName}</MatchHeaderName>
<MatchHeaderMore>자세히</MatchHeaderMore>
</MatchHeader>
<MatchContent>
{match.matchPlayerInfoList.map((user) => {
return (
<UserContainer myself={user.gameId === data.myGameId}>
<UserImgContainer>
{user.profileSrc ? (
<UserImg src={user.profileSrc} alt='profile' width={30} height={30} />
) : (
<UserNameImg>
<UserNameImgText>{user.gameId.substring(0, 2)}</UserNameImgText>
</UserNameImg>
)}
</UserImgContainer>

<UserName>{user.gameId}</UserName>
<UserScore>{user.score}</UserScore>
</UserContainer>
);
})}
{match.matchPlayerInfoList.length === 0 ? (
<MatchNoGame>아직 대진표가 생성되지 않았어요 :(</MatchNoGame>
) : (
match.matchPlayerInfoList.map((user) => {
return (
<UserContainer myself={user.gameId === data.myGameId}>
<UserImgContainer>
{user.profileSrc ? (
<UserImg src={user.profileSrc} alt='profile' width={30} height={30} />
) : (
<UserNameImg>
<UserNameImgText>{user.gameId.substring(0, 2)}</UserNameImgText>
</UserNameImg>
)}
</UserImgContainer>

<UserName>{user.gameId}</UserName>
<UserScore>{user.score}</UserScore>
</UserContainer>
);
})
)}
</MatchContent>
</MatchContainer>
);
Expand All @@ -78,6 +82,8 @@ const Container = styled.div``;
const Header = styled.div``;

const Content = styled.div`
position: relative;

display: grid;

max-width: 100rem;
Expand Down Expand Up @@ -170,6 +176,19 @@ const MatchContent = styled.div`
flex-direction: column;
`;

const MatchNoGame = styled.div`
height: 35rem;
width: 21rem;
display: flex;
align-items: center;
justify-content: center;
background-color: #b4b4b3;
opacity: 0.6;

font-size: 1.8 rem;
color: black;
`;

const UserContainer = styled.div<{ myself: boolean }>`
width: 20rem;
display: grid;
Expand Down
4 changes: 4 additions & 0 deletions src/components/Icon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {
MdRefresh,
MdSend,
MdModeEdit,
MdSettings,
MdCancel,
} from 'react-icons/md';
import { MouseEventHandler } from 'react';

Expand All @@ -29,6 +31,8 @@ const ICON: { [key in IconKind]: IconType } = {
refresh: MdRefresh,
sendEmail: MdSend,
modify: MdModeEdit,
setting: MdSettings,
cancel: MdCancel,
};

interface IconProps {
Expand Down
156 changes: 55 additions & 101 deletions src/components/Modal/ModifyChannel/ModifyChannel.tsx
Original file line number Diff line number Diff line change
@@ -1,136 +1,90 @@
import authAPI from '@apis/authAPI';
import { css } from '@emotion/react';
import Icon from '@components/Icon';
import BasicInfoChannel from '@components/ModifyChannel/BasicInfoChannel';
import BracketInfoChannel from '@components/ModifyChannel/BracketInfoChannel';
import styled from '@emotion/styled';
import { useRef } from 'react';

import { useState } from 'react';
interface ModifyChannelProps {
channelLink: string;
leagueTitle: string;
maxPlayer: number;
onClose: (leagueTitle?: string, maxPlayer?: number) => void;
}

type MenuList = 'basicInfo' | 'bracketInfo';

const ModifyChannel = ({ channelLink, leagueTitle, maxPlayer, onClose }: ModifyChannelProps) => {
const leagueTitleRef = useRef<HTMLInputElement>(null);
const maxPlayerRef = useRef<HTMLInputElement>(null);
const [selectedMenu, setSelectedMenu] = useState<MenuList>('basicInfo');

const onClickSubmit = async () => {
console.log(leagueTitleRef.current?.value, maxPlayerRef.current?.value);
if (!leagueTitleRef.current || !maxPlayerRef.current) return;
const updatedLeagueTitle = leagueTitleRef.current.value;
const updatedMaxPlayer = parseInt(maxPlayerRef.current.value, 10);
if (isNaN(updatedMaxPlayer)) {
alert('최대인원수를 숫자로 입력해주세요');
return;
}
if (!confirm('리그를 수정하시겠습니까?')) return;
const res = await authAPI({
method: 'post',
url: `/api/channel/${channelLink}`,
data: {
title: updatedLeagueTitle,
maxPlayer: updatedMaxPlayer,
},
});
if (res.status !== 200) return;
alert('정보가 수정되었습니다');
onClose(updatedLeagueTitle, updatedMaxPlayer);
const handleSelectedMenu = (menu: MenuList) => {
setSelectedMenu(menu);
};

return (
<Container>
<Wrapper
css={css`
padding-bottom: 3rem;
`}
>
<h1>리그 수정하기</h1>
</Wrapper>
<Wrapper>
<FlexWrapper>리그 제목</FlexWrapper>
<FlexWrapper>
<Input
type='text'
placeholder='리그 제목을 입력해주세요'
ref={leagueTitleRef}
defaultValue={leagueTitle}
<Sidebar>
<SidebarContent onClick={() => handleSelectedMenu('basicInfo')}>
대회 기본 정보 수정
</SidebarContent>
<SidebarContent onClick={() => handleSelectedMenu('bracketInfo')}>
대진표 수정
</SidebarContent>
</Sidebar>
<MainContent>
{selectedMenu === 'basicInfo' && (
<BasicInfoChannel
channelLink={channelLink}
leagueTitle={leagueTitle}
maxPlayer={maxPlayer}
/>
</FlexWrapper>
</Wrapper>
<Wrapper>
<FlexWrapper>최대 참여자 인원</FlexWrapper>
<FlexWrapper>
<Input
type='text'
placeholder='최대 인원을 설정해주세요'
ref={maxPlayerRef}
defaultValue={maxPlayer}
/>
</FlexWrapper>
</Wrapper>
<ButtonWrapper>
<SubmitButton onClick={() => onClose()}>취소</SubmitButton>
<SubmitButton onClick={onClickSubmit}>수정하기</SubmitButton>
</ButtonWrapper>
)}
{selectedMenu === 'bracketInfo' && <BracketInfoChannel />}
</MainContent>
<CloseButtonContainer>
<Icon kind='cancel' size={40} onClick={() => onClose()} />
</CloseButtonContainer>
</Container>
);
};

export default ModifyChannel;

const Container = styled.div`
color: black;
padding: 5%;
`;
width: 100vw;
height: 100vh;
background-color: white;

const Wrapper = styled.div`
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 1rem;
font-size: 1.7rem;
font-weight: bold;
min-height: 7rem;
`;

const FlexWrapper = styled.div`
flex: 1;
justify-content: flex-start;
const Sidebar = styled.div`
width: 30rem;
background-color: #141c24;
`;

const ButtonWrapper = styled.div`
const SidebarContent = styled.div`
width: 80%;
height: 5rem;
margin: 0 auto;
color: white;

font-size: 2rem;
font-weight: 900;

display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 1rem;
font-size: 1.7rem;
font-weight: bold;
min-height: 7rem;

cursor: pointer;
`;

const Input = styled.input`
width: 80%;
height: 4rem;
border: none;
border-radius: 0.6rem;
padding: 0.6rem;
const MainContent = styled.div`
width: calc(100vw - 30rem);

background-color: #202b37;
`;

const SubmitButton = styled.button`
width: 10rem;
height: 6rem;
background-color: #344051;
border: none;
border-radius: 0.5rem;
color: white;
margin: 0 6rem 0 6rem;
&:hover {
cursor: pointer;
}
&:disabled {
background-color: #d3d3d3;
cursor: not-allowed;
}
const CloseButtonContainer = styled.div`
position: absolute;
top: 1rem;
right: 1rem;
cursor: pointer;
`;
Loading