-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #104 from hufs-sports-live/feat/rummikub
[FEAT] 루미큐브 페이지 별도 추가
- Loading branch information
Showing
13 changed files
with
466 additions
and
169 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
'use client'; | ||
|
||
import { useRef, useState } from 'react'; | ||
|
||
import AsyncBoundary from '@/components/common/AsyncBoundary'; | ||
import Loader from '@/components/common/Loader'; | ||
import CommentForm from '@/components/match/CommentForm'; | ||
import CommentList from '@/components/match/CommentList'; | ||
import Lineup from '@/components/match/LineupList'; | ||
import Panel from '@/components/match/Panel'; | ||
import RecordList from '@/components/match/RecordList'; | ||
import Video from '@/components/match/Video'; | ||
import Cheer from '@/components/rummikub/Cheer'; | ||
import RummiKubMatchBanner from '@/components/rummikub/MatchBanner'; | ||
import useSocket from '@/hooks/useSocket'; | ||
import MatchByIdFetcher from '@/queries/useMatchById/Fetcher'; | ||
import MatchCheerByIdFetcher from '@/queries/useMatchCheerById/Fetcher'; | ||
import MatchCommentFetcher from '@/queries/useMatchCommentById/Fetcher'; | ||
import MatchLineupFetcher from '@/queries/useMatchLineupById/Fetcher'; | ||
import MatchTimelineFetcher from '@/queries/useMatchTimelineById/Fetcher'; | ||
import MatchVideoFetcher from '@/queries/useMatchVideoById/Fetcher'; | ||
import useSaveCommentMutation from '@/queries/useSaveCommentMutation/query'; | ||
import { MatchCommentType } from '@/types/match'; | ||
|
||
export default function Rummikute({ params }: { params: { id: string } }) { | ||
const [comments, setComments] = useState<MatchCommentType[]>([]); | ||
|
||
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 ( | ||
<section> | ||
<AsyncBoundary | ||
errorFallback={props => ( | ||
<RummiKubMatchBanner.ErrorFallback {...props} /> | ||
)} | ||
loadingFallback={<RummiKubMatchBanner.Skeleton />} | ||
> | ||
<MatchByIdFetcher matchId={params.id}> | ||
{data => <RummiKubMatchBanner {...data} />} | ||
</MatchByIdFetcher> | ||
</AsyncBoundary> | ||
|
||
<AsyncBoundary | ||
errorFallback={props => <Cheer.ErrorFallback {...props} />} | ||
loadingFallback={<Loader />} | ||
> | ||
<MatchCheerByIdFetcher matchId={params.id}> | ||
{data => <Cheer cheers={data} />} | ||
</MatchCheerByIdFetcher> | ||
</AsyncBoundary> | ||
<Panel options={options} defaultValue="라인업"> | ||
{({ selected }) => ( | ||
<> | ||
{selected === '라인업' && ( | ||
<AsyncBoundary | ||
errorFallback={props => <Lineup.ErrorFallback {...props} />} | ||
loadingFallback={<Loader />} | ||
> | ||
<MatchLineupFetcher matchId={params.id}> | ||
{([firstTeam, secondTeam]) => ( | ||
<div className="grid grid-cols-2 py-5 [&>*:first-child>ul]:before:absolute [&>*:first-child>ul]:before:right-0 [&>*:first-child>ul]:before:h-full [&>*:first-child>ul]:before:border-l-2 [&>*:first-child>ul]:before:bg-gray-2"> | ||
<Lineup {...firstTeam} /> | ||
<Lineup {...secondTeam} /> | ||
</div> | ||
)} | ||
</MatchLineupFetcher> | ||
</AsyncBoundary> | ||
)} | ||
{selected === '타임라인' && ( | ||
<AsyncBoundary | ||
errorFallback={props => <RecordList.ErrorFallback {...props} />} | ||
loadingFallback={<Loader />} | ||
> | ||
<MatchTimelineFetcher matchId={params.id}> | ||
{([firstHalf, secondHalf]) => ( | ||
<div className="overflow-y-auto p-5"> | ||
<RecordList {...firstHalf} /> | ||
<RecordList {...secondHalf} /> | ||
</div> | ||
)} | ||
</MatchTimelineFetcher> | ||
</AsyncBoundary> | ||
)} | ||
{selected === '응원댓글' && ( | ||
<AsyncBoundary | ||
errorFallback={props => ( | ||
<CommentList.ErrorFallback {...props} /> | ||
)} | ||
loadingFallback={<Loader />} | ||
> | ||
<MatchCommentFetcher matchId={params.id}> | ||
{({ commentList, matchTeams, ...data }) => ( | ||
<div className="max-h-[450px] overflow-y-auto p-5"> | ||
<ul className="pb-8"> | ||
<CommentList | ||
commentList={commentList.pages.flat()} | ||
scrollToBottom={scrollToBottom} | ||
{...data} | ||
/> | ||
<CommentList.SocketList commentList={comments} /> | ||
<li ref={scrollRef}></li> | ||
</ul> | ||
<CommentForm | ||
matchTeams={matchTeams} | ||
matchId={params.id} | ||
mutate={mutate} | ||
scrollToBottom={scrollToBottom} | ||
/> | ||
</div> | ||
)} | ||
</MatchCommentFetcher> | ||
</AsyncBoundary> | ||
)} | ||
{selected === '경기영상' && ( | ||
<AsyncBoundary | ||
errorFallback={props => <Video.ErrorFallback {...props} />} | ||
loadingFallback={<Loader />} | ||
> | ||
<MatchVideoFetcher matchId={params.id}> | ||
{data => ( | ||
<div className="overflow-y-auto p-5"> | ||
<Video {...data} /> | ||
</div> | ||
)} | ||
</MatchVideoFetcher> | ||
</AsyncBoundary> | ||
)} | ||
</> | ||
)} | ||
</Panel> | ||
</section> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { ComponentProps } from 'react'; | ||
|
||
export const Profile = ({ | ||
viewBox = '0 0 20 20', | ||
...props | ||
}: ComponentProps<'svg'>) => { | ||
return ( | ||
<svg | ||
aria-hidden="true" | ||
xmlns="http://www.w3.org/2000/svg" | ||
fill="currentColor" | ||
viewBox={viewBox} | ||
{...props} | ||
> | ||
<path d="M10 0a10 10 0 1 0 10 10A10.011 10.011 0 0 0 10 0Zm0 5a3 3 0 1 1 0 6 3 3 0 0 1 0-6Zm0 13a8.949 8.949 0 0 1-4.951-1.488A3.987 3.987 0 0 1 9 13h2a3.987 3.987 0 0 1 3.951 3.512A8.949 8.949 0 0 1 10 18Z" /> | ||
</svg> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.