diff --git a/src/app/match/[id]/modify/page.tsx b/src/app/match/[id]/modify/page.tsx deleted file mode 100644 index e95f9bb..0000000 --- a/src/app/match/[id]/modify/page.tsx +++ /dev/null @@ -1,92 +0,0 @@ -'use client'; - -import { useParams, useRouter } from 'next/navigation'; -import { ChangeEvent, FormEvent, useState } from 'react'; - -import { postGameScore } from '@/api/admin'; -import Input from '@/components/common/Input/Input'; -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 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('/')); - }; - - return ( -
- - -

득점한 팀

- - - -
- ); -} diff --git a/src/app/match/[id]/page.tsx b/src/app/match/[id]/page.tsx index 5ef4ff4..60e9dfd 100644 --- a/src/app/match/[id]/page.tsx +++ b/src/app/match/[id]/page.tsx @@ -115,7 +115,7 @@ export default function Match({ params }: { params: { id: string } }) { {({ commentList, matchTeams, ...data }) => (
-
    +
      ([]); + + const handleSocketMessage = (comment: MatchCommentType) => { + if (comment) { + setComments(prev => [...prev, comment]); + } + }; + + const { connect } = useSocket({ + url: 'wss://api.hufstreaming.site/ws', + destination: `/topic/games/${params.id}`, + callback: handleSocketMessage, + }); + + connect(); + + const { mutate } = useSaveCommentMutation(); + const options = [ + { label: '라인업' }, + { label: '응원댓글' }, + { label: '경기영상' }, + { label: '타임라인' }, + ]; + + const scrollRef = useRef(null); + const scrollToBottom = () => { + if (!scrollRef.current) return; + + (scrollRef.current as HTMLDivElement).scrollIntoView(); + }; + + return ( +
      + ( + + )} + loadingFallback={} + > + + {data => } + + + + } + loadingFallback={} + > + + {data => } + + + + {({ selected }) => ( + <> + {selected === '라인업' && ( + } + loadingFallback={} + > + + {([firstTeam, secondTeam]) => ( +
      + + +
      + )} +
      +
      + )} + {selected === '타임라인' && ( + } + loadingFallback={} + > + + {([firstHalf, secondHalf]) => ( +
      + + +
      + )} +
      +
      + )} + {selected === '응원댓글' && ( + ( + + )} + loadingFallback={} + > + + {({ commentList, matchTeams, ...data }) => ( +
      +
        + + +
      • +
      + +
      + )} +
      +
      + )} + {selected === '경기영상' && ( + } + loadingFallback={} + > + + {data => ( +
      +
      + )} +
      +
      + )} + + )} +
      +
      + ); +} diff --git a/src/components/common/Icon/iconMap.ts b/src/components/common/Icon/iconMap.ts index 400b6fc..801e72c 100644 --- a/src/components/common/Icon/iconMap.ts +++ b/src/components/common/Icon/iconMap.ts @@ -11,6 +11,7 @@ import { Image } from './svg/Image'; import { PaperPlane } from './svg/PaperPlane'; import { Pencil } from './svg/Pencil'; import { PlusCircled } from './svg/PlusCircled'; +import { Profile } from './svg/Profile'; import { Symbol } from './svg/Symbol'; import { ThumbsUp } from './svg/Thumbsup'; import { Trash } from './svg/Trash'; @@ -34,4 +35,5 @@ export const iconMap = { thumbsUp: ThumbsUp, trash: Trash, write: Write, + profile: Profile, }; diff --git a/src/components/common/Icon/svg/Profile.tsx b/src/components/common/Icon/svg/Profile.tsx new file mode 100644 index 0000000..6e782ca --- /dev/null +++ b/src/components/common/Icon/svg/Profile.tsx @@ -0,0 +1,18 @@ +import { ComponentProps } from 'react'; + +export const Profile = ({ + viewBox = '0 0 20 20', + ...props +}: ComponentProps<'svg'>) => { + return ( + + ); +}; diff --git a/src/components/common/MatchCard/pieces/Team.tsx b/src/components/common/MatchCard/pieces/Team.tsx index bf745fa..6c01fa8 100644 --- a/src/components/common/MatchCard/pieces/Team.tsx +++ b/src/components/common/MatchCard/pieces/Team.tsx @@ -3,6 +3,8 @@ import Image from 'next/image'; import { useMatchCardContext } from '@/hooks/useMatchCardContext'; import { $ } from '@/utils/core'; +import { Icon } from '../../Icon'; + type TeamProps = { teamIndex: number; className?: string; @@ -14,15 +16,10 @@ export default function Team({ teamIndex, className }: TeamProps) { if (gameTeams.length === 0) { return (
      - +
      ); } diff --git a/src/components/match/CommentForm/index.tsx b/src/components/match/CommentForm/index.tsx index 0e3100e..818206d 100644 --- a/src/components/match/CommentForm/index.tsx +++ b/src/components/match/CommentForm/index.tsx @@ -18,7 +18,6 @@ export default function CommentForm({ }: CommentFormProps) { const [inputValue, setInputValue] = useState(''); const [selectedTeamId, setSelectedTeamId] = useState(1); - const [isOpen, toggleOpen] = useState(false); const handleCommentSubmit = ( e: FormEvent, @@ -37,7 +36,7 @@ export default function CommentForm({ return ( <>
      handleCommentSubmit(e, { gameTeamId: Number(matchId), @@ -45,22 +44,20 @@ export default function CommentForm({ }) } > - {isOpen && ( -
      - {matchTeams.map(team => ( - - ))} -
      - )} +
      + {matchTeams.map(team => ( + + ))} +
      setInputValue(e.target.value)} placeholder="응원하는 팀에 댓글을 남겨보세요!" - onFocus={() => toggleOpen(true)} />
    diff --git a/src/components/rummikub/Cheer/index.tsx b/src/components/rummikub/Cheer/index.tsx new file mode 100644 index 0000000..7f3c925 --- /dev/null +++ b/src/components/rummikub/Cheer/index.tsx @@ -0,0 +1,55 @@ +import { FallbackProps } from '@/components/common/ErrorBoundary'; +import CheerTeam from '@/components/match/CheerTeam'; +import { MatchCheerType } from '@/types/match'; + +type CheerProps = { + cheers: MatchCheerType[]; +}; + +export default function Cheer({ cheers }: CheerProps) { + const [firstTeam, secondTeam, thirdTeam, fourthTeam] = cheers; + + return ( +
    +
    + + 🤜 + {firstTeam.cheerCount} + + + 🤜 + {thirdTeam.cheerCount} + +
    +
    + VS +
    +
    + + {secondTeam.cheerCount} + 🤛 + + + {fourthTeam.cheerCount} + 🤛 + +
    +
    + ); +} + +Cheer.ErrorFallback = function ErrorFallback({ + resetErrorBoundary, +}: FallbackProps) { + return ( +
    +
    + 응원하기를 불러올 수 없어요. + 잠시 후 다시 시도해주세요! +
    + +
    + ); +}; diff --git a/src/components/rummikub/MatchBanner/index.tsx b/src/components/rummikub/MatchBanner/index.tsx new file mode 100644 index 0000000..6875146 --- /dev/null +++ b/src/components/rummikub/MatchBanner/index.tsx @@ -0,0 +1,89 @@ +import { FallbackProps } from '@/components/common/ErrorBoundary'; +import { MatchCard } from '@/components/common/MatchCard'; +import { MatchType } from '@/types/match'; + +export default function RummiKubMatchBanner(match: MatchType) { + return ( + + +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    +
    +
    + ); +} + +RummiKubMatchBanner.ErrorFallback = function ErrorFallback({ + resetErrorBoundary, +}: FallbackProps) { + return ( +
    +
    + 게임 정보를 불러올 수 없어요. + 잠시 후 다시 시도해주세요! +
    + +
    + ); +}; + +RummiKubMatchBanner.Skeleton = function Skeleton() { + return ( + +
    + +
    +
    + ); +}; diff --git a/src/components/rummikub/MatchItem/index.tsx b/src/components/rummikub/MatchItem/index.tsx new file mode 100644 index 0000000..b880ea9 --- /dev/null +++ b/src/components/rummikub/MatchItem/index.tsx @@ -0,0 +1,51 @@ +import { MatchCard } from '@/components/common/MatchCard'; +import { MatchType } from '@/types/match'; + +export default function RummiKubMatchItem(match: MatchType) { + return ( + + +
    + + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    +
    +
    + ); +}