From 3b75baa72058d35dbfb452295ab3a3137676a008 Mon Sep 17 00:00:00 2001 From: seongminn Date: Wed, 22 Nov 2023 14:38:00 +0900 Subject: [PATCH 01/21] =?UTF-8?q?chore:=20detail=20->=20match=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/match/[id]/modify/page.tsx | 127 +++++++++++++++++++++++++++++ src/app/match/[id]/page.tsx | 85 +++++++++++++++++++ src/app/match/[id]/status/page.tsx | 42 ++++++++++ 3 files changed, 254 insertions(+) create mode 100644 src/app/match/[id]/modify/page.tsx create mode 100644 src/app/match/[id]/page.tsx create mode 100644 src/app/match/[id]/status/page.tsx diff --git a/src/app/match/[id]/modify/page.tsx b/src/app/match/[id]/modify/page.tsx new file mode 100644 index 0000000..5e9ef4f --- /dev/null +++ b/src/app/match/[id]/modify/page.tsx @@ -0,0 +1,127 @@ +'use client'; + +import { useParams, useRouter } from 'next/navigation'; +import { ChangeEvent, FormEvent, useEffect, useState } from 'react'; + +import { postGameScore } from '@/api/admin'; +import { getGameDetail } from '@/api/game'; +import { GameBanner } from '@/components/common/Game'; +import Input from '@/components/common/Input/Input'; +import Select from '@/components/common/Select/Select'; +import { GameDetailType, GameType } from '@/types/game'; +import { getUtcHours } from '@/utils/utc-times'; + +export default function ModifyGame() { + const router = useRouter(); + const params = useParams(); + const id = Number(params.id); + const [scoreData, setScoreData] = useState({ + playerName: '', + team: 0, + hour: new Date().getHours(), + minute: new Date().getMinutes(), + }); + const [gameInfo, setGameInfo] = useState(); + + const handleChange = ( + e: ChangeEvent, + ) => { + const { name, value } = e.target; + + setScoreData(prev => ({ ...prev, [name]: value })); + }; + + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + + const date = getUtcHours({ + hour: scoreData.hour, + minute: scoreData.minute, + }); + + postGameScore(id, { + playerName: scoreData.playerName, + team: scoreData.team, + scoredAt: date, + }).then(() => router.push('/')); + }; + + useEffect(() => { + const getGameInfo = async () => { + const id = Number(params.id); + const gameDetail = await getGameDetail(id); + + if (typeof gameDetail === 'number') return; + + setGameInfo(gameDetail); + }; + + getGameInfo(); + }, [params.id]); + + return ( +
+ + + + + +

득점한 팀

+ + + + +
+ ); +} diff --git a/src/app/match/[id]/page.tsx b/src/app/match/[id]/page.tsx new file mode 100644 index 0000000..fd8cd9b --- /dev/null +++ b/src/app/match/[id]/page.tsx @@ -0,0 +1,85 @@ +'use client'; + +// import Link from 'next/link'; + +import { Suspense } from 'react'; + +import { GameBanner } from '@/components/common/Game'; +// import CommentList from '@/components/detail/CommentList'; +// import GameInfo from '@/components/detail/GameInfo'; +// import GameTimeline from '@/components/detail/GameTimeline'; +import { GameDetailFetcher } from '@/queries/useGameDetail'; + +export default function DetailPage({ params }: { params: { id: string } }) { + return ( + 로딩 중...}> + + {data => ( + + +
+ + + + + +
+
+ )} +
+
+ ); + + // const { gameDetail } = useGameDetail(params.id); + // useEffect(() => { + // const getGameData = async () => { + // const res = await getGameDetail(Number(gameId)); + + // if (typeof res === 'number') return notFound(); + + // setGameData(res); + // }; + // getGameData(); + // const token = localStorage.getItem('token'); + // if (!token) return; + // setIsLoggedIn(true); + // }, [gameId]); + + // return ( + // 로딩 중...}> + // + // + // + // + // + // + // + // + //
+ // {isLoggedIn && ( + // + // 수정 + // + // )} + // {gameData && } + // {isLoggedIn && ( + // + // 전/후반 변경하러 가기 + // + // )} + // {gameData && ( + // + // )} + // {gameData && } + //
+ // ) +} diff --git a/src/app/match/[id]/status/page.tsx b/src/app/match/[id]/status/page.tsx new file mode 100644 index 0000000..2b63cf9 --- /dev/null +++ b/src/app/match/[id]/status/page.tsx @@ -0,0 +1,42 @@ +'use client'; + +import { useParams, useRouter } from 'next/navigation'; +import { useState } from 'react'; + +import { postGameStatus } from '@/api/auth'; +import Select from '@/components/common/Select/Select'; +import { GameStatusType } from '@/types/game'; + +export default function Status() { + const router = useRouter(); + const params = useParams(); + const [gameState, setGameState] = useState('BEFORE'); + + const updateGameStatus = async () => { + postGameStatus(Number(params.id), gameState).then(() => + router.push(`/detail/${params.id}`), + ); + }; + + return ( +
+ + +
+ ); +} From 4c685a53006e897e6ceba61857a9b765181e8e2e Mon Sep 17 00:00:00 2001 From: seongminn Date: Wed, 22 Nov 2023 14:51:38 +0900 Subject: [PATCH 02/21] =?UTF-8?q?chore:=20=EC=9D=B4=EB=A6=84=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=EC=9C=BC=EB=A1=9C=20=EC=9D=B8=ED=95=B4=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0=EB=90=9C=20=ED=8C=8C=EC=9D=BC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/detail/[id]/modify/page.tsx | 127 ---------------------------- src/app/detail/[id]/page.tsx | 55 ------------ src/app/detail/[id]/status/page.tsx | 42 --------- 3 files changed, 224 deletions(-) delete mode 100644 src/app/detail/[id]/modify/page.tsx delete mode 100644 src/app/detail/[id]/page.tsx delete mode 100644 src/app/detail/[id]/status/page.tsx diff --git a/src/app/detail/[id]/modify/page.tsx b/src/app/detail/[id]/modify/page.tsx deleted file mode 100644 index 4fde17f..0000000 --- a/src/app/detail/[id]/modify/page.tsx +++ /dev/null @@ -1,127 +0,0 @@ -'use client'; - -import { useParams, useRouter } from 'next/navigation'; -import { ChangeEvent, FormEvent, useEffect, useState } from 'react'; - -import { postGameScore } from '@/api/admin'; -import { getGameDetail } from '@/api/game'; -import { Game } from '@/components/common/Game'; -import Input from '@/components/common/Input/Input'; -import Select from '@/components/common/Select/Select'; -import { GameDetailType, GameType } from '@/types/game'; -import { getUtcHours } from '@/utils/utc-times'; - -export default function ModifyGame() { - const router = useRouter(); - const params = useParams(); - const id = Number(params.id); - const [scoreData, setScoreData] = useState({ - playerName: '', - team: 0, - hour: new Date().getHours(), - minute: new Date().getMinutes(), - }); - const [gameInfo, setGameInfo] = useState(); - - const handleChange = ( - e: ChangeEvent, - ) => { - const { name, value } = e.target; - - setScoreData(prev => ({ ...prev, [name]: value })); - }; - - const handleSubmit = (e: FormEvent) => { - e.preventDefault(); - - const date = getUtcHours({ - hour: scoreData.hour, - minute: scoreData.minute, - }); - - postGameScore(id, { - playerName: scoreData.playerName, - team: scoreData.team, - scoredAt: date, - }).then(() => router.push('/')); - }; - - useEffect(() => { - const getGameInfo = async () => { - const id = Number(params.id); - const gameDetail = await getGameDetail(id); - - if (typeof gameDetail === 'number') return; - - setGameInfo(gameDetail); - }; - - getGameInfo(); - }, [params.id]); - - return ( -
- - - - - -

득점한 팀

- - - - -
- ); -} diff --git a/src/app/detail/[id]/page.tsx b/src/app/detail/[id]/page.tsx deleted file mode 100644 index 7c1335d..0000000 --- a/src/app/detail/[id]/page.tsx +++ /dev/null @@ -1,55 +0,0 @@ -'use client'; - -import Link from 'next/link'; -import { notFound } from 'next/navigation'; -import { useEffect, useState } from 'react'; - -import { getGameDetail } from '@/api/game'; -import CommentList from '@/components/detail/CommentList'; -import GameInfo from '@/components/detail/GameInfo'; -import GameTimeline from '@/components/detail/GameTimeline'; -import { GameDetailType } from '@/types/game'; - -export default function DetailPage({ params }: { params: { id: string } }) { - const [gameData, setGameData] = useState(); - const [isLoggedIn, setIsLoggedIn] = useState(false); - - const gameId = params.id; - - useEffect(() => { - const getGameData = async () => { - const res = await getGameDetail(Number(gameId)); - - if (typeof res === 'number') return notFound(); - - setGameData(res); - }; - getGameData(); - const token = localStorage.getItem('token'); - if (!token) return; - setIsLoggedIn(true); - }, [gameId]); - - return ( -
- {isLoggedIn && ( - - 수정 - - )} - {gameData && } - {isLoggedIn && ( - - 전/후반 변경하러 가기 - - )} - {gameData && ( - - )} - {gameData && } -
- ); -} diff --git a/src/app/detail/[id]/status/page.tsx b/src/app/detail/[id]/status/page.tsx deleted file mode 100644 index 2b63cf9..0000000 --- a/src/app/detail/[id]/status/page.tsx +++ /dev/null @@ -1,42 +0,0 @@ -'use client'; - -import { useParams, useRouter } from 'next/navigation'; -import { useState } from 'react'; - -import { postGameStatus } from '@/api/auth'; -import Select from '@/components/common/Select/Select'; -import { GameStatusType } from '@/types/game'; - -export default function Status() { - const router = useRouter(); - const params = useParams(); - const [gameState, setGameState] = useState('BEFORE'); - - const updateGameStatus = async () => { - postGameStatus(Number(params.id), gameState).then(() => - router.push(`/detail/${params.id}`), - ); - }; - - return ( -
- - -
- ); -} From 4809b060d34766164377ddd04c1048e28c8d25c8 Mon Sep 17 00:00:00 2001 From: seongminn Date: Wed, 22 Nov 2023 14:53:00 +0900 Subject: [PATCH 03/21] =?UTF-8?q?feat:=20=EA=B2=BD=EA=B8=B0=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=EC=A0=95=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/queries/useMatchById/api.ts | 8 ++++++++ src/queries/useMatchById/query.ts | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/queries/useMatchById/api.ts create mode 100644 src/queries/useMatchById/query.ts diff --git a/src/queries/useMatchById/api.ts b/src/queries/useMatchById/api.ts new file mode 100644 index 0000000..b5a37ed --- /dev/null +++ b/src/queries/useMatchById/api.ts @@ -0,0 +1,8 @@ +import instance from '@/api/instance'; +import { GameDetailType } from '@/types/game'; + +export const getMatchById = async (gameId: string) => { + const { data } = await instance.get(`/games/${gameId}`); + + return data; +}; diff --git a/src/queries/useMatchById/query.ts b/src/queries/useMatchById/query.ts new file mode 100644 index 0000000..1ac72e5 --- /dev/null +++ b/src/queries/useMatchById/query.ts @@ -0,0 +1,20 @@ +import { useSuspenseQuery } from '@tanstack/react-query'; + +import { getMatchById } from './api'; + +export const QUERY_KEY = { + MATCH_DETAIL: 'MATCH_DETAL', +}; + +export default function useGameDetail(matchId: string) { + const { data, isLoading, error } = useSuspenseQuery({ + queryKey: [QUERY_KEY.MATCH_DETAIL, matchId], + queryFn: () => getMatchById(matchId), + }); + + return { + matchDetail: data, + isLoading, + error, + }; +} From 9bd2d496c602127fb822c51111e17d98e7da64af Mon Sep 17 00:00:00 2001 From: seongminn Date: Wed, 22 Nov 2023 14:54:34 +0900 Subject: [PATCH 04/21] =?UTF-8?q?feat:=20=EA=B2=BD=EA=B8=B0=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=ED=98=B8=EC=B6=9C=20?= =?UTF-8?q?=EB=B0=8F=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/match/[id]/page.tsx | 6 +++--- src/queries/useMatchById/Fetcher.tsx | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 src/queries/useMatchById/Fetcher.tsx diff --git a/src/app/match/[id]/page.tsx b/src/app/match/[id]/page.tsx index fd8cd9b..4900bcf 100644 --- a/src/app/match/[id]/page.tsx +++ b/src/app/match/[id]/page.tsx @@ -8,12 +8,12 @@ import { GameBanner } from '@/components/common/Game'; // import CommentList from '@/components/detail/CommentList'; // import GameInfo from '@/components/detail/GameInfo'; // import GameTimeline from '@/components/detail/GameTimeline'; -import { GameDetailFetcher } from '@/queries/useGameDetail'; +import MatchByIdFetcher from '@/queries/useMatchById/Fetcher'; export default function DetailPage({ params }: { params: { id: string } }) { return ( 로딩 중...}> - + {data => ( @@ -32,7 +32,7 @@ export default function DetailPage({ params }: { params: { id: string } }) { )} - + ); diff --git a/src/queries/useMatchById/Fetcher.tsx b/src/queries/useMatchById/Fetcher.tsx new file mode 100644 index 0000000..188ba91 --- /dev/null +++ b/src/queries/useMatchById/Fetcher.tsx @@ -0,0 +1,21 @@ +import { ReactNode } from 'react'; + +import { GameDetailType } from '@/types/game'; + +import useMatchById from './query'; + +type MatchByIdFetcherProps = { + matchId: string; + children: (data: GameDetailType) => ReactNode; +}; + +export default function MatchByIdFetcher({ + matchId, + children, +}: MatchByIdFetcherProps) { + const { matchDetail, error } = useMatchById(matchId); + + if (error) throw error; + + return children(matchDetail); +} From b610a9ba877b7c09fdf24615e00c21a272b42ac3 Mon Sep 17 00:00:00 2001 From: seongminn Date: Wed, 22 Nov 2023 14:55:48 +0900 Subject: [PATCH 05/21] =?UTF-8?q?chore:=20image=20domain=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- next.config.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/next.config.js b/next.config.js index 8e85f77..1ba0668 100644 --- a/next.config.js +++ b/next.config.js @@ -3,8 +3,7 @@ const nextConfig = { images: { domains: [ 'hufstreaming.s3.ap-northeast-2.amazonaws.com', - 'lh3.googleusercontent.com', - 'velog.velcdn.com', + 'hufscheer-server.s3.ap-northeast-2.amazonaws.com', ], }, }; From 2d836b7e124d8259d9b3cfaf17f238c063608805 Mon Sep 17 00:00:00 2001 From: seongminn Date: Wed, 22 Nov 2023 16:22:12 +0900 Subject: [PATCH 06/21] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B9=98=20=EB=B0=B1?= =?UTF-8?q?=EA=B7=B8=EB=9D=BC=EC=9A=B4=EB=93=9C=20=EB=A1=9C=EA=B3=A0=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/Game/pieces/GameWrapper.tsx | 10 +++++++++- src/components/common/Game/pieces/Status.tsx | 4 +++- src/components/common/Icon/IconMap.ts | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/components/common/Game/pieces/GameWrapper.tsx b/src/components/common/Game/pieces/GameWrapper.tsx index dcd2408..449b558 100644 --- a/src/components/common/Game/pieces/GameWrapper.tsx +++ b/src/components/common/Game/pieces/GameWrapper.tsx @@ -1,5 +1,6 @@ import { createContext, ReactNode } from 'react'; +import { Icon } from '@/components/common/Icon'; import { GameDetailType } from '@/types/game'; import { $ } from '@/utils/core'; @@ -19,10 +20,17 @@ export default function GameWrapper({
+ {children}
diff --git a/src/components/common/Game/pieces/Status.tsx b/src/components/common/Game/pieces/Status.tsx index a3c1739..ee7933f 100644 --- a/src/components/common/Game/pieces/Status.tsx +++ b/src/components/common/Game/pieces/Status.tsx @@ -8,5 +8,7 @@ type StatusProps = { export default function Status({ className }: StatusProps) { const { gameQuarter } = useGameContext(); - return
{gameQuarter}
; + return ( +
{gameQuarter}
+ ); } diff --git a/src/components/common/Icon/IconMap.ts b/src/components/common/Icon/IconMap.ts index 37d5def..2559cda 100644 --- a/src/components/common/Icon/IconMap.ts +++ b/src/components/common/Icon/IconMap.ts @@ -2,4 +2,5 @@ export const iconMap = { hamburgerMenu: 'M3.75 17.25a.75.75 0 0 1 .75-.75h15a.75.75 0 0 1 0 1.5h-15a.75.75 0 0 1-.75-.75ZM3.75 11.25a.75.75 0 0 1 .75-.75h15a.75.75 0 0 1 0 1.5h-15a.75.75 0 0 1-.75-.75ZM3.75 5.25a.75.75 0 0 1 .75-.75h15a.75.75 0 0 1 0 1.5h-15a.75.75 0 0 1-.75-.75Z', cross: 'm7.757 16.243 8.486-8.486M16.243 16.243 7.757 7.757', + logo: 'M85.5606 195.998C77.732 198.97 68.9512 195.108 65.9441 187.377L57.1409 164.737C55.6563 165.736 54.0584 166.581 52.3706 167.248L95.2766 277.598C98.2837 285.337 94.377 294.018 86.5559 296.99L86.5635 296.998C78.7349 299.97 69.9541 296.108 66.947 288.377L2.01711 121.395C-0.989967 113.655 2.91677 104.975 10.7378 102.003C18.5664 99.0299 27.3472 102.892 30.354 110.624L34.2395 120.617C35.9024 119.988 37.6497 119.531 39.4597 119.266L1.01418 20.3946C-1.9929 12.6554 1.91384 3.97519 9.73489 1.00254C17.5635 -1.97012 26.3443 1.89218 29.3511 9.62363L94.2737 176.598C97.2808 184.337 93.374 193.018 85.553 195.99L85.5606 195.998Z', }; From 991a8c046db8869630eedf7adc0063829db53773 Mon Sep 17 00:00:00 2001 From: seongminn Date: Wed, 22 Nov 2023 17:52:31 +0900 Subject: [PATCH 07/21] =?UTF-8?q?refactor:=20match=20banner=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/match/[id]/page.tsx | 78 +++------------------------ src/components/match/Banner/index.tsx | 17 ++++++ 2 files changed, 25 insertions(+), 70 deletions(-) create mode 100644 src/components/match/Banner/index.tsx diff --git a/src/app/match/[id]/page.tsx b/src/app/match/[id]/page.tsx index 4900bcf..27cf26e 100644 --- a/src/app/match/[id]/page.tsx +++ b/src/app/match/[id]/page.tsx @@ -4,7 +4,7 @@ import { Suspense } from 'react'; -import { GameBanner } from '@/components/common/Game'; +import MatchBanner from '@/components/match/Banner'; // import CommentList from '@/components/detail/CommentList'; // import GameInfo from '@/components/detail/GameInfo'; // import GameTimeline from '@/components/detail/GameTimeline'; @@ -12,74 +12,12 @@ import MatchByIdFetcher from '@/queries/useMatchById/Fetcher'; export default function DetailPage({ params }: { params: { id: string } }) { return ( - 로딩 중...}> - - {data => ( - - -
- - - - - -
-
- )} -
-
+
+ 배너 로딩 중...}> + + {data => } + + +
); - - // const { gameDetail } = useGameDetail(params.id); - // useEffect(() => { - // const getGameData = async () => { - // const res = await getGameDetail(Number(gameId)); - - // if (typeof res === 'number') return notFound(); - - // setGameData(res); - // }; - // getGameData(); - // const token = localStorage.getItem('token'); - // if (!token) return; - // setIsLoggedIn(true); - // }, [gameId]); - - // return ( - // 로딩 중...}> - // - // - // - // - // - // - // - // - //
- // {isLoggedIn && ( - // - // 수정 - // - // )} - // {gameData && } - // {isLoggedIn && ( - // - // 전/후반 변경하러 가기 - // - // )} - // {gameData && ( - // - // )} - // {gameData && } - //
- // ) } diff --git a/src/components/match/Banner/index.tsx b/src/components/match/Banner/index.tsx new file mode 100644 index 0000000..a7083f5 --- /dev/null +++ b/src/components/match/Banner/index.tsx @@ -0,0 +1,17 @@ +import { GameBanner } from '@/components/common/Game'; +import { GameDetailType } from '@/types/game'; + +export default function MatchBanner(props: GameDetailType) { + return ( + + +
+ + + + + +
+
+ ); +} From 53e1b820bf8221a59ec4583948e0ce37c546d5e6 Mon Sep 17 00:00:00 2001 From: seongminn Date: Wed, 22 Nov 2023 17:58:21 +0900 Subject: [PATCH 08/21] =?UTF-8?q?feat:=20=ED=8C=80=20=EC=9D=91=EC=9B=90?= =?UTF-8?q?=ED=95=98=EA=B8=B0=20=EC=A1=B0=ED=9A=8C=20=EB=B0=8F=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/match/[id]/page.tsx | 7 +++ src/components/detail/CommentItem.tsx | 58 -------------------- src/components/detail/CommentList.tsx | 67 ----------------------- src/components/detail/GameInfo.tsx | 16 ------ src/components/detail/GameTimeline.tsx | 23 -------- src/components/detail/Record.tsx | 19 ------- src/components/match/Cheer/index.tsx | 21 +++++++ src/components/match/CheerTeam/index.tsx | 21 +++++++ src/queries/useMatchCheerById/Fetcher.tsx | 20 +++++++ src/queries/useMatchCheerById/api.ts | 11 ++++ src/queries/useMatchCheerById/query.ts | 16 ++++++ src/queries/useMatchCheerById/type.ts | 4 ++ 12 files changed, 100 insertions(+), 183 deletions(-) delete mode 100644 src/components/detail/CommentItem.tsx delete mode 100644 src/components/detail/CommentList.tsx delete mode 100644 src/components/detail/GameInfo.tsx delete mode 100644 src/components/detail/GameTimeline.tsx delete mode 100644 src/components/detail/Record.tsx create mode 100644 src/components/match/Cheer/index.tsx create mode 100644 src/components/match/CheerTeam/index.tsx create mode 100644 src/queries/useMatchCheerById/Fetcher.tsx create mode 100644 src/queries/useMatchCheerById/api.ts create mode 100644 src/queries/useMatchCheerById/query.ts create mode 100644 src/queries/useMatchCheerById/type.ts diff --git a/src/app/match/[id]/page.tsx b/src/app/match/[id]/page.tsx index 27cf26e..6d3de2f 100644 --- a/src/app/match/[id]/page.tsx +++ b/src/app/match/[id]/page.tsx @@ -5,10 +5,12 @@ import { Suspense } from 'react'; import MatchBanner from '@/components/match/Banner'; +import Cheer from '@/components/match/Cheer'; // import CommentList from '@/components/detail/CommentList'; // import GameInfo from '@/components/detail/GameInfo'; // import GameTimeline from '@/components/detail/GameTimeline'; import MatchByIdFetcher from '@/queries/useMatchById/Fetcher'; +import MatchCheerByIdFetcher from '@/queries/useMatchCheerById/Fetcher'; export default function DetailPage({ params }: { params: { id: string } }) { return ( @@ -18,6 +20,11 @@ export default function DetailPage({ params }: { params: { id: string } }) { {data => } + 응원 로딩 중...}> + + {data => } + + ); } diff --git a/src/components/detail/CommentItem.tsx b/src/components/detail/CommentItem.tsx deleted file mode 100644 index 30a8e4b..0000000 --- a/src/components/detail/CommentItem.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { Cross2Icon } from '@radix-ui/react-icons'; -import { useEffect, useState } from 'react'; - -import { postBlockComment } from '@/api/admin'; -import useDate from '@/hooks/useDate'; -import { GameCommentType } from '@/types/game'; -import { parseTime } from '@/utils/utc-times'; - -export const CommentItem = ({ - content, - createdAt, - isBlocked, - id, -}: GameCommentType) => { - const [isLoggedIn, setIsLoggedIn] = useState(false); - const { month, day, hour, minute } = useDate(createdAt); - - useEffect(() => { - const token = localStorage.getItem('token'); - token && setIsLoggedIn(true); - }, []); - - const handleBlockComment = async () => { - await postBlockComment(id); - }; - return ( -
  • -
    -
    - - {month}월 {day}일 {parseTime(hour < 24 ? hour : hour - 24)}시{' '} - {parseTime(minute)}분 - -
    -
    - {isBlocked ? '관리자에 의해 차단된 댓글입니다.' : content} -
    -
    - {!isBlocked && isLoggedIn && ( - - )} -
  • - ); -}; diff --git a/src/components/detail/CommentList.tsx b/src/components/detail/CommentList.tsx deleted file mode 100644 index 2172d33..0000000 --- a/src/components/detail/CommentList.tsx +++ /dev/null @@ -1,67 +0,0 @@ -'use client'; - -import { useEffect, useState } from 'react'; - -import { getGameComments, postGameComment } from '@/api/game'; -import { GameCommentType } from '@/types/game'; - -import { CommentItem } from './CommentItem'; - -export default function CommentList({ gameId }: { gameId: number }) { - const [comments, setComments] = useState(); - const [inputContent, setInputContent] = useState(''); - const getData = async () => { - const res = await getGameComments(gameId); - typeof res !== 'number' && setComments(res); - }; - useEffect(() => { - getData(); - }, [gameId]); - - const CommentSubmitHandler = async ( - event: React.FormEvent, - ) => { - event.preventDefault(); - if (!inputContent) return; - - await postGameComment({ content: inputContent, gameId }); - getData(); - setInputContent(''); - }; - - return ( -
    -

    응원 댓글

    -
    - setInputContent(e.target.value)} - placeholder="댓글을 작성하세요" - className="w-full rounded-lg border-2 border-slate-400 p-4" - /> -
    - - 욕설 및 스포츠와 무관한 내용을 포함한 댓글은 -
    - 관리자에 의해 차단될 수 있습니다. -
    - -
    -
    -
      - {comments && - comments.map((comment, idx) => ( - - ))} -
    -
    - ); -} diff --git a/src/components/detail/GameInfo.tsx b/src/components/detail/GameInfo.tsx deleted file mode 100644 index 7a2756d..0000000 --- a/src/components/detail/GameInfo.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { Game } from '@/components/common/Game'; -import { GameDetailType } from '@/types/game'; - -export default function GameInfo({ game }: { game: GameDetailType }) { - return ( -
    - - - - - - - -
    - ); -} diff --git a/src/components/detail/GameTimeline.tsx b/src/components/detail/GameTimeline.tsx deleted file mode 100644 index b83e5f1..0000000 --- a/src/components/detail/GameTimeline.tsx +++ /dev/null @@ -1,23 +0,0 @@ -'use client'; - -import { GameDetailType } from '@/types/game'; - -import { Record } from './Record'; - -type GameTimelineProps = { - records: GameDetailType['records']; - status: GameDetailType['gameStatus']; -}; - -export default function GameTimeline({ records, status }: GameTimelineProps) { - return ( -
      -

      타임라인

      - {status !== 'BEFORE' ? ( - records.map(record => ) - ) : ( -
    • 경기 시작 전입니다.
    • - )} -
    - ); -} diff --git a/src/components/detail/Record.tsx b/src/components/detail/Record.tsx deleted file mode 100644 index f911c63..0000000 --- a/src/components/detail/Record.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import useDate from '@/hooks/useDate'; -import { GameRecordType } from '@/types/game'; - -export const Record = ({ id, playerName, score, scoredAt }: GameRecordType) => { - const { hour, minute } = useDate(scoredAt); - return ( -
  • - - {playerName} 선수 {score}골 득점! - - - {hour}시 {minute}분 - -
  • - ); -}; diff --git a/src/components/match/Cheer/index.tsx b/src/components/match/Cheer/index.tsx new file mode 100644 index 0000000..860714e --- /dev/null +++ b/src/components/match/Cheer/index.tsx @@ -0,0 +1,21 @@ +import { MatchCheerType } from '@/queries/useMatchCheerById/type'; + +import CheerTeam from '../CheerTeam'; + +type CheerProps = { + cheers: MatchCheerType[]; +}; + +export default function Cheer({ cheers }: CheerProps) { + const [firstTeam, secondTeam] = cheers; + + return ( +
    + {firstTeam.cheerCount} +
    + VS +
    + {secondTeam.cheerCount} +
    + ); +} diff --git a/src/components/match/CheerTeam/index.tsx b/src/components/match/CheerTeam/index.tsx new file mode 100644 index 0000000..58e1519 --- /dev/null +++ b/src/components/match/CheerTeam/index.tsx @@ -0,0 +1,21 @@ +import { ComponentProps } from 'react'; + +import { $ } from '@/utils/core'; + +export default function CheerTeam({ + children, + className, + ...props +}: ComponentProps<'div'>) { + return ( +
    + {children} +
    + ); +} diff --git a/src/queries/useMatchCheerById/Fetcher.tsx b/src/queries/useMatchCheerById/Fetcher.tsx new file mode 100644 index 0000000..6887a6e --- /dev/null +++ b/src/queries/useMatchCheerById/Fetcher.tsx @@ -0,0 +1,20 @@ +import { ReactNode } from 'react'; + +import { useMatchCheerById } from './query'; +import { MatchCheerType } from './type'; + +type MatchCheerByIdFetcherProps = { + matchId: string; + children: (data: MatchCheerType[]) => ReactNode; +}; + +export default function MatchCheerByIdFetcher({ + matchId, + children, +}: MatchCheerByIdFetcherProps) { + const { cheers, error } = useMatchCheerById(matchId); + + if (error) throw error; + + return children(cheers); +} diff --git a/src/queries/useMatchCheerById/api.ts b/src/queries/useMatchCheerById/api.ts new file mode 100644 index 0000000..27e459a --- /dev/null +++ b/src/queries/useMatchCheerById/api.ts @@ -0,0 +1,11 @@ +import instance from '@/api/instance'; + +import { MatchCheerType } from './type'; + +export const getMatchCheerById = async (matchId: string) => { + const { data } = await instance.get( + `/games/${matchId}/cheer`, + ); + + return data; +}; diff --git a/src/queries/useMatchCheerById/query.ts b/src/queries/useMatchCheerById/query.ts new file mode 100644 index 0000000..19682c0 --- /dev/null +++ b/src/queries/useMatchCheerById/query.ts @@ -0,0 +1,16 @@ +import { useSuspenseQuery } from '@tanstack/react-query'; + +import { getMatchCheerById } from './api'; + +export const useMatchCheerById = (matchId: string) => { + const { data, isLoading, error } = useSuspenseQuery({ + queryKey: ['match-cheer', matchId], + queryFn: () => getMatchCheerById(matchId), + }); + + return { + cheers: data, + isLoading, + error, + }; +}; diff --git a/src/queries/useMatchCheerById/type.ts b/src/queries/useMatchCheerById/type.ts new file mode 100644 index 0000000..30b5f4d --- /dev/null +++ b/src/queries/useMatchCheerById/type.ts @@ -0,0 +1,4 @@ +export type MatchCheerType = { + gameTeamId: number; + cheerCount: number; +}; From af2c9bd999ca306269bdd24fc0e410fa098b634d Mon Sep 17 00:00:00 2001 From: seongminn Date: Thu, 23 Nov 2023 18:15:09 +0900 Subject: [PATCH 09/21] =?UTF-8?q?chore:=20=EC=9D=91=EC=9B=90=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EC=83=89=EC=83=81=20=EC=B6=94=EA=B0=80=20=EB=B0=8F?= =?UTF-8?q?=20=EB=A1=9C=EA=B3=A0=20=EB=8C=80=EC=8B=A0=20=EC=9D=B4=EB=AA=A8?= =?UTF-8?q?=EC=A7=80=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/match/Cheer/index.tsx | 12 +++++++++--- src/components/match/CheerTeam/index.tsx | 6 ++++-- tailwind.config.ts | 4 ++++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/components/match/Cheer/index.tsx b/src/components/match/Cheer/index.tsx index 860714e..91a92d9 100644 --- a/src/components/match/Cheer/index.tsx +++ b/src/components/match/Cheer/index.tsx @@ -10,12 +10,18 @@ export default function Cheer({ cheers }: CheerProps) { const [firstTeam, secondTeam] = cheers; return ( -
    - {firstTeam.cheerCount} +
    + +
    👍
    + {firstTeam.cheerCount} +
    VS
    - {secondTeam.cheerCount} + + {secondTeam.cheerCount} +
    👍
    +
    ); } diff --git a/src/components/match/CheerTeam/index.tsx b/src/components/match/CheerTeam/index.tsx index 58e1519..e23c300 100644 --- a/src/components/match/CheerTeam/index.tsx +++ b/src/components/match/CheerTeam/index.tsx @@ -10,12 +10,14 @@ export default function CheerTeam({ return (
    - {children} +
    + {children} +
    ); } diff --git a/tailwind.config.ts b/tailwind.config.ts index b501370..42d4e7d 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -18,6 +18,10 @@ const config: Config = { 5: '#374553', }, black: '#14191F', + cheer: { + left: '#FF0000', + right: '#003AFF', + }, }, keyframes: { 'dialog-overlay-show': { From e63747cd16f8e69f229c0a411cb1d45ca2b023d4 Mon Sep 17 00:00:00 2001 From: seongminn Date: Fri, 24 Nov 2023 03:02:10 +0900 Subject: [PATCH 10/21] =?UTF-8?q?chore:=20game=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=EC=9D=84=20match=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/queries/useMatchById/Fetcher.tsx | 4 +- src/queries/useMatchById/api.ts | 8 ---- src/queries/useMatchById/query.ts | 5 +-- src/queries/useMatchCheerById/Fetcher.tsx | 3 +- src/queries/useMatchCheerById/api.ts | 11 ----- src/queries/useMatchCheerById/query.ts | 5 +-- src/queries/useMatchCheerById/type.ts | 4 -- src/types/game.ts | 49 --------------------- src/types/match.ts | 53 +++++++++++++++++++++++ 9 files changed, 61 insertions(+), 81 deletions(-) delete mode 100644 src/queries/useMatchById/api.ts delete mode 100644 src/queries/useMatchCheerById/api.ts delete mode 100644 src/queries/useMatchCheerById/type.ts delete mode 100644 src/types/game.ts create mode 100644 src/types/match.ts diff --git a/src/queries/useMatchById/Fetcher.tsx b/src/queries/useMatchById/Fetcher.tsx index 188ba91..c2ad2c3 100644 --- a/src/queries/useMatchById/Fetcher.tsx +++ b/src/queries/useMatchById/Fetcher.tsx @@ -1,12 +1,12 @@ import { ReactNode } from 'react'; -import { GameDetailType } from '@/types/game'; +import { MatchDetailType } from '@/types/match'; import useMatchById from './query'; type MatchByIdFetcherProps = { matchId: string; - children: (data: GameDetailType) => ReactNode; + children: (data: MatchDetailType) => ReactNode; }; export default function MatchByIdFetcher({ diff --git a/src/queries/useMatchById/api.ts b/src/queries/useMatchById/api.ts deleted file mode 100644 index b5a37ed..0000000 --- a/src/queries/useMatchById/api.ts +++ /dev/null @@ -1,8 +0,0 @@ -import instance from '@/api/instance'; -import { GameDetailType } from '@/types/game'; - -export const getMatchById = async (gameId: string) => { - const { data } = await instance.get(`/games/${gameId}`); - - return data; -}; diff --git a/src/queries/useMatchById/query.ts b/src/queries/useMatchById/query.ts index 1ac72e5..ce28657 100644 --- a/src/queries/useMatchById/query.ts +++ b/src/queries/useMatchById/query.ts @@ -1,20 +1,19 @@ import { useSuspenseQuery } from '@tanstack/react-query'; -import { getMatchById } from './api'; +import { getMatchById } from '@/api/match'; export const QUERY_KEY = { MATCH_DETAIL: 'MATCH_DETAL', }; export default function useGameDetail(matchId: string) { - const { data, isLoading, error } = useSuspenseQuery({ + const { data, error } = useSuspenseQuery({ queryKey: [QUERY_KEY.MATCH_DETAIL, matchId], queryFn: () => getMatchById(matchId), }); return { matchDetail: data, - isLoading, error, }; } diff --git a/src/queries/useMatchCheerById/Fetcher.tsx b/src/queries/useMatchCheerById/Fetcher.tsx index 6887a6e..c48bdb5 100644 --- a/src/queries/useMatchCheerById/Fetcher.tsx +++ b/src/queries/useMatchCheerById/Fetcher.tsx @@ -1,7 +1,8 @@ import { ReactNode } from 'react'; +import { MatchCheerType } from '@/types/match'; + import { useMatchCheerById } from './query'; -import { MatchCheerType } from './type'; type MatchCheerByIdFetcherProps = { matchId: string; diff --git a/src/queries/useMatchCheerById/api.ts b/src/queries/useMatchCheerById/api.ts deleted file mode 100644 index 27e459a..0000000 --- a/src/queries/useMatchCheerById/api.ts +++ /dev/null @@ -1,11 +0,0 @@ -import instance from '@/api/instance'; - -import { MatchCheerType } from './type'; - -export const getMatchCheerById = async (matchId: string) => { - const { data } = await instance.get( - `/games/${matchId}/cheer`, - ); - - return data; -}; diff --git a/src/queries/useMatchCheerById/query.ts b/src/queries/useMatchCheerById/query.ts index 19682c0..9fe850c 100644 --- a/src/queries/useMatchCheerById/query.ts +++ b/src/queries/useMatchCheerById/query.ts @@ -1,16 +1,15 @@ import { useSuspenseQuery } from '@tanstack/react-query'; -import { getMatchCheerById } from './api'; +import { getMatchCheerById } from '@/api/match'; export const useMatchCheerById = (matchId: string) => { - const { data, isLoading, error } = useSuspenseQuery({ + const { data, error } = useSuspenseQuery({ queryKey: ['match-cheer', matchId], queryFn: () => getMatchCheerById(matchId), }); return { cheers: data, - isLoading, error, }; }; diff --git a/src/queries/useMatchCheerById/type.ts b/src/queries/useMatchCheerById/type.ts deleted file mode 100644 index 30b5f4d..0000000 --- a/src/queries/useMatchCheerById/type.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type MatchCheerType = { - gameTeamId: number; - cheerCount: number; -}; diff --git a/src/types/game.ts b/src/types/game.ts deleted file mode 100644 index 05a1b3a..0000000 --- a/src/types/game.ts +++ /dev/null @@ -1,49 +0,0 @@ -export type GameType = { - id: number; - name: string; - sportsName: string; - startTime: string; - firstTeamScore: number; - secondTeamScore: number; - gameStatus: GameQuarterType; - statusChangedAt: string; - firstTeam: GameTeamType; - secondTeam: GameTeamType; -}; - -export type GameDetailType = { - gameTeams: GameTeamType[]; - startTime: string; - videoId: number; - gameQuarter: GameQuarterType; - gameName: string; -}; - -export type GameTeamType = { - gameTeamId: number; - gameTeamName: string; - logoImageUrl: string; - score: number; -}; - -export type GameRecordType = { - id: number; - teamId: number; - playerName: string; - score: number; - scoredAt: string; -}; - -export type GameCommentType = { - id: number; - content: string; - createdAt: string; - isBlocked: boolean; -}; - -export type GameQuarterType = - | 'BEFORE' - | 'FIRST_HALF' - | 'BREAK_TIME' - | 'SECOND_HALF' - | 'END'; diff --git a/src/types/match.ts b/src/types/match.ts new file mode 100644 index 0000000..f04b2b0 --- /dev/null +++ b/src/types/match.ts @@ -0,0 +1,53 @@ +export type MatchType = { + id: number; + name: string; + sportsName: string; + startTime: string; + firstTeamScore: number; + secondTeamScore: number; + gameStatus: MatchQuarterType; + statusChangedAt: string; + firstTeam: MatchTeamType; + secondTeam: MatchTeamType; +}; + +export type MatchDetailType = { + gameTeams: MatchTeamType[]; + startTime: string; + videoId: number; + gameQuarter: MatchQuarterType; + gameName: string; +}; + +export type MatchTeamType = { + gameTeamId: number; + gameTeamName: string; + logoImageUrl: string; + score: number; +}; + +export type MatchCheerType = { + gameTeamId: number; + cheerCount: number; +}; + +export type MatchRecordsType = { + scoredAt: number; + playerName: string; + teamName: string; + score: number; +}; + +export type MatchTimelineType = { + gameQuater: MatchQuarterType; + records: MatchRecordsType[]; +}; + +export type MatchCommentType = { + id: number; + content: string; + createdAt: string; + isBlocked: boolean; +}; + +export type MatchQuarterType = string; From 82d65e27d2cf68b40c5c49c9efa47390fbc26264 Mon Sep 17 00:00:00 2001 From: seongminn Date: Fri, 24 Nov 2023 03:06:05 +0900 Subject: [PATCH 11/21] =?UTF-8?q?chore:=20imoji=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/match/Cheer/index.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/match/Cheer/index.tsx b/src/components/match/Cheer/index.tsx index 91a92d9..78ffa3e 100644 --- a/src/components/match/Cheer/index.tsx +++ b/src/components/match/Cheer/index.tsx @@ -1,4 +1,4 @@ -import { MatchCheerType } from '@/queries/useMatchCheerById/type'; +import { MatchCheerType } from '@/types/match'; import CheerTeam from '../CheerTeam'; @@ -12,15 +12,15 @@ export default function Cheer({ cheers }: CheerProps) { return (
    -
    👍
    - {firstTeam.cheerCount} + 🤜 + {firstTeam.cheerCount}
    VS
    - {secondTeam.cheerCount} -
    👍
    + {secondTeam.cheerCount} + 🤛
    ); From 5a527e4649e4d77b46ad4396651b3d1e3b5ae9e4 Mon Sep 17 00:00:00 2001 From: seongminn Date: Fri, 24 Nov 2023 03:17:42 +0900 Subject: [PATCH 12/21] =?UTF-8?q?chore:=20useMatchById=20hook=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/queries/useMatchById/query.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/queries/useMatchById/query.ts b/src/queries/useMatchById/query.ts index ce28657..307b4d1 100644 --- a/src/queries/useMatchById/query.ts +++ b/src/queries/useMatchById/query.ts @@ -6,7 +6,7 @@ export const QUERY_KEY = { MATCH_DETAIL: 'MATCH_DETAL', }; -export default function useGameDetail(matchId: string) { +export default function useMatchById(matchId: string) { const { data, error } = useSuspenseQuery({ queryKey: [QUERY_KEY.MATCH_DETAIL, matchId], queryFn: () => getMatchById(matchId), From 929905724e40c33793acd2662ac62165dc7bc4e5 Mon Sep 17 00:00:00 2001 From: seongminn Date: Fri, 24 Nov 2023 03:20:23 +0900 Subject: [PATCH 13/21] =?UTF-8?q?chore:=20=EA=B2=8C=EC=9E=84=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=EB=AA=85=EC=9D=84=20MatchInfo?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/{Game => MatchInfo}/index.ts | 4 ++-- .../{Game => MatchInfo}/pieces/Label.tsx | 4 ++-- .../{Game => MatchInfo}/pieces/Score.tsx | 4 ++-- .../{Game => MatchInfo}/pieces/Status.tsx | 4 ++-- .../{Game => MatchInfo}/pieces/Team.tsx | 4 ++-- .../pieces/Wrapper.tsx} | 16 ++++++++------ src/components/match/Banner/index.tsx | 22 +++++++++---------- src/hooks/useGameContext.ts | 14 ------------ src/hooks/useMatchInfoContext.ts | 14 ++++++++++++ 9 files changed, 44 insertions(+), 42 deletions(-) rename src/components/common/{Game => MatchInfo}/index.ts (64%) rename src/components/common/{Game => MatchInfo}/pieces/Label.tsx (63%) rename src/components/common/{Game => MatchInfo}/pieces/Score.tsx (74%) rename src/components/common/{Game => MatchInfo}/pieces/Status.tsx (67%) rename src/components/common/{Game => MatchInfo}/pieces/Team.tsx (82%) rename src/components/common/{Game/pieces/GameWrapper.tsx => MatchInfo/pieces/Wrapper.tsx} (67%) delete mode 100644 src/hooks/useGameContext.ts create mode 100644 src/hooks/useMatchInfoContext.ts diff --git a/src/components/common/Game/index.ts b/src/components/common/MatchInfo/index.ts similarity index 64% rename from src/components/common/Game/index.ts rename to src/components/common/MatchInfo/index.ts index 232fc4a..780fd9a 100644 --- a/src/components/common/Game/index.ts +++ b/src/components/common/MatchInfo/index.ts @@ -1,10 +1,10 @@ -import GameWrapper from './pieces/GameWrapper'; import Label from './pieces/Label'; import Score from './pieces/Score'; import Status from './pieces/Status'; import Team from './pieces/Team'; +import MatchWrapper from './pieces/Wrapper'; -export const GameBanner = Object.assign(GameWrapper, { +export const MatchInfo = Object.assign(MatchWrapper, { Label, Score, Status, diff --git a/src/components/common/Game/pieces/Label.tsx b/src/components/common/MatchInfo/pieces/Label.tsx similarity index 63% rename from src/components/common/Game/pieces/Label.tsx rename to src/components/common/MatchInfo/pieces/Label.tsx index 25f1ce7..396f68d 100644 --- a/src/components/common/Game/pieces/Label.tsx +++ b/src/components/common/MatchInfo/pieces/Label.tsx @@ -1,4 +1,4 @@ -import { useGameContext } from '@/hooks/useGameContext'; +import { useMatchInfoContext } from '@/hooks/useMatchInfoContext'; import { $ } from '@/utils/core'; type LabelProps = { @@ -6,7 +6,7 @@ type LabelProps = { }; export default function Label({ className }: LabelProps) { - const { gameName } = useGameContext(); + const { gameName } = useMatchInfoContext(); return
    {gameName}
    ; } diff --git a/src/components/common/Game/pieces/Score.tsx b/src/components/common/MatchInfo/pieces/Score.tsx similarity index 74% rename from src/components/common/Game/pieces/Score.tsx rename to src/components/common/MatchInfo/pieces/Score.tsx index e46a412..68a8dc4 100644 --- a/src/components/common/Game/pieces/Score.tsx +++ b/src/components/common/MatchInfo/pieces/Score.tsx @@ -1,4 +1,4 @@ -import { useGameContext } from '@/hooks/useGameContext'; +import { useMatchInfoContext } from '@/hooks/useMatchInfoContext'; import { $ } from '@/utils/core'; type ScoreProps = { @@ -7,7 +7,7 @@ type ScoreProps = { }; export default function Score({ teamIndex, className }: ScoreProps) { - const { gameTeams } = useGameContext(); + const { gameTeams } = useMatchInfoContext(); const [targetTeam] = gameTeams.filter(team => team.gameTeamId === teamIndex); diff --git a/src/components/common/Game/pieces/Status.tsx b/src/components/common/MatchInfo/pieces/Status.tsx similarity index 67% rename from src/components/common/Game/pieces/Status.tsx rename to src/components/common/MatchInfo/pieces/Status.tsx index ee7933f..673a1d8 100644 --- a/src/components/common/Game/pieces/Status.tsx +++ b/src/components/common/MatchInfo/pieces/Status.tsx @@ -1,4 +1,4 @@ -import { useGameContext } from '@/hooks/useGameContext'; +import { useMatchInfoContext } from '@/hooks/useMatchInfoContext'; import { $ } from '@/utils/core'; type StatusProps = { @@ -6,7 +6,7 @@ type StatusProps = { }; export default function Status({ className }: StatusProps) { - const { gameQuarter } = useGameContext(); + const { gameQuarter } = useMatchInfoContext(); return (
    {gameQuarter}
    diff --git a/src/components/common/Game/pieces/Team.tsx b/src/components/common/MatchInfo/pieces/Team.tsx similarity index 82% rename from src/components/common/Game/pieces/Team.tsx rename to src/components/common/MatchInfo/pieces/Team.tsx index c5ff67f..84e97c8 100644 --- a/src/components/common/Game/pieces/Team.tsx +++ b/src/components/common/MatchInfo/pieces/Team.tsx @@ -1,6 +1,6 @@ import Image from 'next/image'; -import { useGameContext } from '@/hooks/useGameContext'; +import { useMatchInfoContext } from '@/hooks/useMatchInfoContext'; import { $ } from '@/utils/core'; type TeamProps = { @@ -9,7 +9,7 @@ type TeamProps = { }; export default function Team({ teamIndex, className }: TeamProps) { - const { gameTeams } = useGameContext(); + const { gameTeams } = useMatchInfoContext(); const targetTeamInfo = gameTeams[teamIndex - 1]; diff --git a/src/components/common/Game/pieces/GameWrapper.tsx b/src/components/common/MatchInfo/pieces/Wrapper.tsx similarity index 67% rename from src/components/common/Game/pieces/GameWrapper.tsx rename to src/components/common/MatchInfo/pieces/Wrapper.tsx index 449b558..14a2cec 100644 --- a/src/components/common/Game/pieces/GameWrapper.tsx +++ b/src/components/common/MatchInfo/pieces/Wrapper.tsx @@ -1,23 +1,25 @@ import { createContext, ReactNode } from 'react'; import { Icon } from '@/components/common/Icon'; -import { GameDetailType } from '@/types/game'; +import { MatchDetailType } from '@/types/match'; import { $ } from '@/utils/core'; -type GameProps = GameDetailType & { +type MatchProps = MatchDetailType & { children: ReactNode; className?: string; }; -export const GameContext = createContext({} as GameDetailType); +export const MatchContext = createContext( + {} as MatchDetailType, +); -export default function GameWrapper({ +export default function MatchWrapper({ className, children, ...props -}: GameProps) { +}: MatchProps) { return ( - +
    {children}
    -
    + ); } diff --git a/src/components/match/Banner/index.tsx b/src/components/match/Banner/index.tsx index a7083f5..22f1772 100644 --- a/src/components/match/Banner/index.tsx +++ b/src/components/match/Banner/index.tsx @@ -1,17 +1,17 @@ -import { GameBanner } from '@/components/common/Game'; -import { GameDetailType } from '@/types/game'; +import { MatchInfo } from '@/components/common/MatchInfo'; +import { MatchDetailType } from '@/types/match'; -export default function MatchBanner(props: GameDetailType) { +export default function MatchBanner(props: MatchDetailType) { return ( - - + +
    - - - - - + + + + +
    -
    + ); } diff --git a/src/hooks/useGameContext.ts b/src/hooks/useGameContext.ts deleted file mode 100644 index f7ca8fa..0000000 --- a/src/hooks/useGameContext.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { useContext } from 'react'; - -import { GameContext } from '@/components/common/Game/pieces/GameWrapper'; -import { GameDetailType } from '@/types/game'; - -type GameContextType = () => GameDetailType; - -export const useGameContext: GameContextType = () => { - const gameContext = useContext(GameContext); - - if (!gameContext) throw new Error('Context가 비었습니다.'); - - return gameContext; -}; diff --git a/src/hooks/useMatchInfoContext.ts b/src/hooks/useMatchInfoContext.ts new file mode 100644 index 0000000..52de974 --- /dev/null +++ b/src/hooks/useMatchInfoContext.ts @@ -0,0 +1,14 @@ +import { useContext } from 'react'; + +import { MatchContext } from '@/components/common/MatchInfo/pieces/Wrapper'; +import { MatchDetailType } from '@/types/match'; + +type MatchInfoContextType = () => MatchDetailType; + +export const useMatchInfoContext: MatchInfoContextType = () => { + const matchContext = useContext(MatchContext); + + if (!matchContext) throw new Error('Context가 비었습니다.'); + + return matchContext; +}; From a652159e9d35dd085902d2252b9efaa08f008d7e Mon Sep 17 00:00:00 2001 From: seongminn Date: Fri, 24 Nov 2023 03:22:50 +0900 Subject: [PATCH 14/21] =?UTF-8?q?chore:=20detailPage=20->=20matchPage=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/match/[id]/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/match/[id]/page.tsx b/src/app/match/[id]/page.tsx index 6d3de2f..361c4f6 100644 --- a/src/app/match/[id]/page.tsx +++ b/src/app/match/[id]/page.tsx @@ -12,7 +12,7 @@ import Cheer from '@/components/match/Cheer'; import MatchByIdFetcher from '@/queries/useMatchById/Fetcher'; import MatchCheerByIdFetcher from '@/queries/useMatchCheerById/Fetcher'; -export default function DetailPage({ params }: { params: { id: string } }) { +export default function MatchPage({ params }: { params: { id: string } }) { return (
    배너 로딩 중...
    }> From 0b6bc9762565e9e8390bbc4f8e4ebc19b1918ec2 Mon Sep 17 00:00:00 2001 From: seongminn Date: Fri, 24 Nov 2023 03:24:09 +0900 Subject: [PATCH 15/21] =?UTF-8?q?chore:=20type=EB=AA=85=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EB=B0=8F=20instance=EB=A5=BC=20default=EB=A1=9C=20=EB=B0=98?= =?UTF-8?q?=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/admin.ts | 2 +- src/api/auth.ts | 6 +-- src/api/game.ts | 80 ------------------------------- src/api/{instance.ts => index.ts} | 0 src/api/match.ts | 38 +++++++++++++++ src/api/team.ts | 24 ---------- 6 files changed, 42 insertions(+), 108 deletions(-) delete mode 100644 src/api/game.ts rename src/api/{instance.ts => index.ts} (100%) create mode 100644 src/api/match.ts delete mode 100644 src/api/team.ts diff --git a/src/api/admin.ts b/src/api/admin.ts index da61cb0..308802a 100644 --- a/src/api/admin.ts +++ b/src/api/admin.ts @@ -3,7 +3,7 @@ import { AxiosError } from 'axios'; import { GameScorePayload, NewGamePayload } from '@/types/admin'; -import { adminInstance } from './instance'; +import { adminInstance } from '.'; export const createNewGame = (body: NewGamePayload) => { try { diff --git a/src/api/auth.ts b/src/api/auth.ts index 832a496..382592b 100644 --- a/src/api/auth.ts +++ b/src/api/auth.ts @@ -2,9 +2,9 @@ import * as Sentry from '@sentry/nextjs'; import { AxiosError } from 'axios'; import { AuthPayload, AuthType } from '@/types/auth'; -import { GameStatusType } from '@/types/game'; +import { MatchQuarterType } from '@/types/match'; -import { adminInstance } from './instance'; +import { adminInstance } from '.'; export const postLogin = async (body: AuthPayload) => { try { @@ -29,7 +29,7 @@ export const postLogin = async (body: AuthPayload) => { export const postGameStatus = async ( id: number, - gameStatus: GameStatusType, + gameStatus: MatchQuarterType, ) => { adminInstance.post(`/manage/game/statustype/${id}/`, { gameStatus }); }; diff --git a/src/api/game.ts b/src/api/game.ts deleted file mode 100644 index 3d2d39d..0000000 --- a/src/api/game.ts +++ /dev/null @@ -1,80 +0,0 @@ -import * as Sentry from '@sentry/nextjs'; -import { AxiosError } from 'axios'; - -import { GameCommentType, GameDetailType, GameType } from '@/types/game'; - -import instance from './instance'; - -export const getAllGames = async () => { - try { - const response = await instance.get('/games'); - - return response.data; - } catch (error) { - const axiosError = error as AxiosError; - - Sentry.captureException(axiosError); - - if (axiosError.response) { - throw new Error(axiosError.response.statusText); - } else { - throw new Error('경기 목록을 불러오는 데에 실패했습니다!'); - } - } -}; - -export const getGameDetail = async (gameID: number) => { - try { - const response = await instance.get(`/games/${gameID}`); - return response.data; - } catch (error) { - const axiosError = error as AxiosError; - - Sentry.captureException(error); - - if (axiosError.response) { - throw new Error(axiosError.response.statusText); - } else { - throw new Error('경기 상세 정보를 불러오는 데에 실패했습니다!'); - } - } -}; - -export const getGameComments = async (gameID: number) => { - try { - const response = await instance.get( - `/games/${gameID}/comments`, - ); - - return response.data; - } catch (error) { - const axiosError = error as AxiosError; - - Sentry.captureException(axiosError); - - if (axiosError.response) { - throw new Error(axiosError.response.statusText); - } else { - throw new Error('댓글을 불러오는 데에 실패했습니다!'); - } - } -}; - -export const postGameComment = async (body: { - content: string; - gameId: number; -}) => { - try { - await instance.post('/comments/register', body); - } catch (error) { - const axiosError = error as AxiosError; - - Sentry.captureException(axiosError); - - if (axiosError.response) { - throw new Error(axiosError.response.statusText); - } else { - throw new Error('댓글 등록에 실패했습니다!'); - } - } -}; diff --git a/src/api/instance.ts b/src/api/index.ts similarity index 100% rename from src/api/instance.ts rename to src/api/index.ts diff --git a/src/api/match.ts b/src/api/match.ts new file mode 100644 index 0000000..35bd327 --- /dev/null +++ b/src/api/match.ts @@ -0,0 +1,38 @@ +import { + MatchCheerType, + MatchCommentType, + MatchDetailType, + MatchTimelineType, +} from '@/types/match'; + +import instance from '.'; + +export const getMatchById = async (gameId: string) => { + const { data } = await instance.get(`/games/${gameId}`); + + return data; +}; + +export const getMatchCheerById = async (matchId: string) => { + const { data } = await instance.get( + `/games/${matchId}/cheer`, + ); + + return data; +}; + +export const getGameComments = async (gameId: string, cursor = 1) => { + const response = await instance.get( + `/games/${gameId}/comments?cursor=${cursor}`, + ); + + return response.data; +}; + +export const getMatchTimelineById = async (matchId: string) => { + const { data } = await instance.get( + `/games/${matchId}/timeline`, + ); + + return data; +}; diff --git a/src/api/team.ts b/src/api/team.ts deleted file mode 100644 index 680c67e..0000000 --- a/src/api/team.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as Sentry from '@sentry/nextjs'; -import { AxiosError } from 'axios'; - -import { GameTeamType } from '@/types/game'; - -import instance from './instance'; - -export const getTeams = async () => { - try { - const response = await instance.get('/teams'); - - return response.data; - } catch (error) { - const axiosError = error as AxiosError; - - Sentry.captureException(axiosError); - - if (axiosError.response) { - throw new Error(axiosError.response.statusText); - } else { - throw new Error('팀 목록을 불러오는 데에 실패했습니다!'); - } - } -}; From 594ed000b19eed1519b50028a921708254fc4b22 Mon Sep 17 00:00:00 2001 From: seongminn Date: Fri, 24 Nov 2023 03:26:13 +0900 Subject: [PATCH 16/21] =?UTF-8?q?chore:=20api=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EC=97=90=EB=9F=AC=20=EB=B0=9C?= =?UTF-8?q?=EC=83=9D=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/admin/page.tsx | 47 ++---------------------------- src/app/match/[id]/modify/page.tsx | 37 +---------------------- src/app/match/[id]/status/page.tsx | 8 ++--- 3 files changed, 8 insertions(+), 84 deletions(-) diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 710b57f..2a736a1 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -1,21 +1,18 @@ 'use client'; -import { notFound, useRouter } from 'next/navigation'; -import { ChangeEvent, FormEvent, useEffect, useState } from 'react'; +import { useRouter } from 'next/navigation'; +import { ChangeEvent, FormEvent, useState } from 'react'; import { createNewGame } from '@/api/admin'; -import { getTeams } from '@/api/team'; import Input from '@/components/common/Input/Input'; -import Select from '@/components/common/Select/Select'; import useDate from '@/hooks/useDate'; import useValidate from '@/hooks/useValidate'; -import { GameTeamType } from '@/types/game'; export default function Admin() { const router = useRouter(); const { month, day } = useDate(new Date().toString()); - const [teams, setTeams] = useState([]); + const [gameData, setGameData] = useState({ name: '삼건물대회', sportsName: '축구', @@ -61,18 +58,6 @@ export default function Admin() { }).then(() => router.push('/')); }; - useEffect(() => { - const loadTeams = async () => { - const res = await getTeams(); - - if (typeof res === 'number') return notFound(); - - setTeams(res); - }; - - loadTeams(); - }, []); - return (

    팀 선택

    - - {isTeamError && (
    팀을 다시 선택해주세요!
    )} diff --git a/src/app/match/[id]/modify/page.tsx b/src/app/match/[id]/modify/page.tsx index 5e9ef4f..e95f9bb 100644 --- a/src/app/match/[id]/modify/page.tsx +++ b/src/app/match/[id]/modify/page.tsx @@ -1,14 +1,10 @@ 'use client'; import { useParams, useRouter } from 'next/navigation'; -import { ChangeEvent, FormEvent, useEffect, useState } from 'react'; +import { ChangeEvent, FormEvent, useState } from 'react'; import { postGameScore } from '@/api/admin'; -import { getGameDetail } from '@/api/game'; -import { GameBanner } from '@/components/common/Game'; import Input from '@/components/common/Input/Input'; -import Select from '@/components/common/Select/Select'; -import { GameDetailType, GameType } from '@/types/game'; import { getUtcHours } from '@/utils/utc-times'; export default function ModifyGame() { @@ -21,7 +17,6 @@ export default function ModifyGame() { hour: new Date().getHours(), minute: new Date().getMinutes(), }); - const [gameInfo, setGameInfo] = useState(); const handleChange = ( e: ChangeEvent, @@ -46,24 +41,8 @@ export default function ModifyGame() { }).then(() => router.push('/')); }; - useEffect(() => { - const getGameInfo = async () => { - const id = Number(params.id); - const gameDetail = await getGameDetail(id); - - if (typeof gameDetail === 'number') return; - - setGameInfo(gameDetail); - }; - - getGameInfo(); - }, [params.id]); - return ( - - -