Skip to content

Commit

Permalink
[Feat] TournamentPreview #1149
Browse files Browse the repository at this point in the history
  • Loading branch information
Clearsu committed Dec 12, 2023
1 parent d4bb3b1 commit 9833c23
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 111 deletions.
4 changes: 2 additions & 2 deletions components/main/Section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { useRouter } from 'next/router';
import React from 'react';
import { FaChevronRight } from 'react-icons/fa';
import GameResult from 'components/game/GameResult';
import TournamentPreview from 'components/main/TournamentPreview/TournamentPreview';
import RankListMain from 'components/rank/topRank/RankListMain';
import TournamentMegaphone from 'components/tournament/TournamentMegaphone';
import styles from 'styles/main/Section.module.scss';

type SectionProps = {
Expand All @@ -18,7 +18,7 @@ export default function Section({ sectionTitle, path }: SectionProps) {
const pathCheck: pathType = {
game: <GameResult />,
rank: <RankListMain isMain={true} season={0} />,
tournament: <TournamentMegaphone />,
tournament: <TournamentPreview />,
};

return (
Expand Down
81 changes: 81 additions & 0 deletions components/main/TournamentPreview/TournamentPreview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { useRouter } from 'next/router';
import { useState, useEffect, useRef, useCallback } from 'react';
import { Virtuoso, VirtuosoHandle } from 'react-virtuoso';
import { useSetRecoilState } from 'recoil';
import { TournamentInfo } from 'types/tournamentTypes';
import { instance } from 'utils/axios';
import { errorState } from 'utils/recoil/error';
import useInterval from 'hooks/useInterval';
import styles from 'styles/main/TournamentPreview/TournamentPreview.module.scss';
import TournamentPreviewItem from './TournamentPreviewItem';

export default function TournamentPreview() {
const [tournamentList, setTournamentList] = useState<TournamentInfo[]>([]);
const [selectedIndex, setSelectedIndex] = useState<number>(0);
const virtuoso = useRef<VirtuosoHandle>(null);
const router = useRouter();
const setError = useSetRecoilState(errorState);

const fetchTournamentList = useCallback(async () => {
try {
const liveRes = await instance.get(
'/pingpong/tournaments?page=1&status=LIVE'
);
const beforeRes = await instance.get(
'/pingpong/tournaments?page=1&status=BEFORE'
);
const joinedRes = [
...liveRes.data.tournaments,
...beforeRes.data.tournaments,
];
setTournamentList(joinedRes);
} catch (e: any) {
setError('JC04');
}
}, [setError]);

useEffect(() => {
fetchTournamentList();
}, [fetchTournamentList]);

useInterval(() => {
if (tournamentList.length === 0) {
return;
}
const nextIndex = (selectedIndex + 1) % tournamentList.length;
setSelectedIndex(nextIndex);
if (virtuoso.current !== null) {
virtuoso.current.scrollToIndex({
index: nextIndex,
align: 'start',
behavior: 'smooth',
});
}
}, 5000);

return (
<div
className={styles.rollingBanner}
onClick={() => router.push('tournament')}
>
{tournamentList.length > 0 && (
<Virtuoso
className={styles.virtuoso}
totalCount={tournamentList.length}
data={tournamentList}
ref={virtuoso}
itemContent={(index) => (
<TournamentPreviewItem
id={tournamentList[index].tournamentId}
title={tournamentList[index].title}
startTime={tournamentList[index].startTime}
endTime={tournamentList[index].endTime}
status={tournamentList[index].status}
/>
)}
style={{ height: '100%' }}
/>
)}
</div>
);
}
45 changes: 45 additions & 0 deletions components/main/TournamentPreview/TournamentPreviewItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import styles from 'styles/main/TournamentPreview/TournamentPreviewItem.module.scss';

interface TournamentPreviewItemProps {
id: number;
title: string;
startTime: string;
endTime: string;
status: string;
}

export default function TournamentPreviewItem({
title,
startTime,
endTime,
status,
}: TournamentPreviewItemProps) {
function formatTime(timeString: string) {
const date = new Date(timeString);
return date.toLocaleTimeString('ko-KR', {
year: 'numeric',
month: 'numeric',
hour: 'numeric',
minute: 'numeric',
day: 'numeric',
hour12: true,
});
}

const formattedStartTime = formatTime(startTime);
const formattedEndTime = formatTime(endTime);

const statusColor = status === 'LIVE' ? 'live' : 'scheduled';

return (
<div className={styles.itemWrapper}>
<div className={styles.titleStatusWrapper}>
<h4>{title}</h4>
<div className={`${styles.statusWrapper} ${styles[statusColor]}`}>
{status === 'LIVE' ? '경기 중' : '예정'}
</div>
</div>
<time>{formattedStartTime}</time> ~ <time>{formattedEndTime}</time>
</div>
);
}
109 changes: 0 additions & 109 deletions components/tournament/TournamentMegaphone.tsx

This file was deleted.

13 changes: 13 additions & 0 deletions styles/main/TournamentPreview/TournamentPreview.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.rollingBanner {
width: 100%;
height: 5rem;
color: white;
background: #8034f7;
border-radius: 1rem;
}

.virtuoso {
// NOTE : 라이브러리에서 인라인 스타일로 overflow-y: auto를 주고 있어 스크롤바가 생김
// 이를 상쇄하기 위해서 !important를 사용함.
overflow-y: hidden !important;
}
35 changes: 35 additions & 0 deletions styles/main/TournamentPreview/TournamentPreviewItem.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
.itemWrapper {
width: 100%;
height: 5rem;
padding: 1rem;

.titleStatusWrapper {
display: flex;
align-items: center;

h4 {
margin: 0;
}

.statusWrapper {
display: flex;
padding: 0.3rem;
margin-left: 0.5rem;
font-size: 0.7rem;
border-radius: 0.5rem;
align-items: center;

&.live {
background-color: red;
}
&.scheduled {
background-color: green;
}
}
}

time {
font-size: 0.8rem;
color: yellow;
}
}

0 comments on commit 9833c23

Please sign in to comment.