Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions src/pages/game/components/game-card.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,22 @@
import Button from '@components/button/button/button';
import type { ChipColor } from '@components/card/match-card/types/card';
import Chip from '@components/chip/chip';
import { ROUTES } from '@routes/routes-config';
import { useNavigate } from 'react-router-dom';

export interface GameCardItem {
id: number;
awayTeam: string;
homeTeam: string;
gameTime: string;
stadium: string;
matchCount?: number;
}

interface GameCardProps {
game: GameCardItem;
dateStr: string;
onGameClick: (game: GameCardItem) => void;
}

const GameCard = ({ game, dateStr }: GameCardProps) => {
const navigate = useNavigate();

const handleGoToGame = () => {
navigate(ROUTES.GAME(dateStr, String(game.id)));
};

const GameCard = ({ game, onGameClick }: GameCardProps) => {
return (
<div key={game.id} className="flex-col gap-[2rem] rounded-[12px] bg-gray-950 p-[1.6rem]">
<div className="flex-col gap-[1.6rem]">
Expand All @@ -50,7 +43,7 @@ const GameCard = ({ game, dateStr }: GameCardProps) => {
<Button
label="메이트 만나기"
className="cap_14_sb h-[3.8rem] rounded-[8px] p-[0.8rem]"
onClick={handleGoToGame}
onClick={() => onGameClick(game)}
/>
</div>
);
Expand Down
72 changes: 67 additions & 5 deletions src/pages/game/game.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { matchMutations } from '@apis/match/match-mutations';
import { matchQueries } from '@apis/match/match-queries';
import MatchingCtaBottomSheet from '@components/bottom-sheet/matching-cta/matching-cta-bottom-sheet';
import Card from '@components/card/match-card/card';
import Icon from '@components/icon/icon';
import { TAB_TYPES } from '@components/tab/tab/constants/tab-type';
import type { TabType } from '@components/tab/tab/tab-content';
import { HAS_DONE_TOAST_MESSAGE } from '@constants/error-toast';
import { gaEvent } from '@libs/analytics';
import { ROUTES } from '@routes/routes-config';
import { useQuery } from '@tanstack/react-query';
import { useEffect } from 'react';
import { useMutation, useQuery } from '@tanstack/react-query';
import { useEffect, useState } from 'react';
import { useNavigate, useOutletContext, useParams } from 'react-router-dom';
import { showErrorToast } from '@/shared/utils/show-error-toast';

Expand All @@ -18,18 +23,65 @@ const Game = () => {
const parsedGameId = Number(gameId);
const navigate = useNavigate();

const [isMatchingCtaBottomSheetOpen, setIsMatchingCtaBottomSheetOpen] = useState(false);

const { data: gameMatchData } = useQuery({
...matchQueries.GAME_MATCH_LIST(parsedGameId),
enabled: Number.isFinite(parsedGameId),
});

const hasCreatedMatch = gameMatchData?.result.some((match) => match.matchRate === null);
const createMatchMutation = useMutation(matchMutations.CREATE_MATCH());

const hasCreatedMatch = gameMatchData?.result?.some((match) => match.matchRate === null);

const gameSchedule = gameMatchData
? [
{
id: parsedGameId,
awayTeam: gameMatchData.awayTeam,
homeTeam: gameMatchData.homeTeam,
gameTime: '',
stadium: gameMatchData.stadium,
},
]
: [];

const handleCreateMatchClick = () => {
if (hasCreatedMatch) {
showErrorToast(HAS_DONE_TOAST_MESSAGE, { offset: '2.4rem', icon: false });
return;
}

setIsMatchingCtaBottomSheetOpen(true);
};
Comment thread
bongtta marked this conversation as resolved.

const handleMatchingCtaSubmit = (type: TabType) => {
if (!Number.isFinite(parsedGameId)) return;

const matchType = type === TAB_TYPES.SINGLE ? 'DIRECT' : 'GROUP';
const queryType = type === TAB_TYPES.SINGLE ? 'single' : 'group';
const gaMatchType = type === TAB_TYPES.SINGLE ? 'one_to_one' : 'group';

gaEvent('match_create_click', {
match_type: gaMatchType,
role: 'creator',
});

createMatchMutation.mutate(
{
gameId: parsedGameId,
matchType,
},
{
onSuccess: (response) => {
const createdMatchId = response.matchId.toString();

setIsMatchingCtaBottomSheetOpen(false);

navigate(`${ROUTES.RESULT(createdMatchId)}?type=success&mode=${queryType}`);
},
},
);
};

const handleCardClick = (matchId: number, isGroup: boolean) => {
Expand All @@ -55,7 +107,7 @@ const Game = () => {

return (
<div className="relative h-full flex-col gap-[1.2rem] px-[1.6rem] pt-[2rem]">
{gameMatchData?.result.map((match) => (
{gameMatchData?.result?.map((match) => (
// TODO: 매칭 현황 상태가 [그룹원 모집중]인 카드만 노출
<button
key={match.matchId}
Expand All @@ -81,7 +133,7 @@ const Game = () => {
/>
</button>
))}
{/* TODO: 매칭 생성 바텀시트 연결 */}

<button
type="button"
aria-label="매칭 생성"
Expand All @@ -90,6 +142,16 @@ const Game = () => {
>
<Icon name="plus" color="white" />
</button>

<MatchingCtaBottomSheet
isOpen={isMatchingCtaBottomSheetOpen}
onClose={() => setIsMatchingCtaBottomSheetOpen(false)}
date={gameMatchData?.date ?? ''}
gameSchedule={gameSchedule}
initialType={TAB_TYPES.SINGLE}
onSubmit={handleMatchingCtaSubmit}
showDescription={false}
/>
</div>
);
};
Expand Down
6 changes: 4 additions & 2 deletions src/pages/home/components/game-list-section.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { gameQueries } from '@apis/game/game-queries';
import EmptyView from '@components/ui/empty-view';
import type { GameCardItem } from '@pages/game/components/game-card';
import GameCard from '@pages/game/components/game-card';
import { useQuery } from '@tanstack/react-query';
import { format } from 'date-fns';

interface GameListSectionProps {
selectedDate: Date;
onGameClick: (game: GameCardItem) => void;
}

const GameListSection = ({ selectedDate }: GameListSectionProps) => {
const GameListSection = ({ selectedDate, onGameClick }: GameListSectionProps) => {
const formattedDate = format(selectedDate, 'yyyy-MM-dd');

const { data: gameSchedule, isLoading: gameLoading } = useQuery({
Expand All @@ -32,7 +34,7 @@ const GameListSection = ({ selectedDate }: GameListSectionProps) => {
<section className="px-[1.6rem]">
<div className="flex-col gap-[1.2rem]">
{(gameSchedule ?? []).map((game) => (
<GameCard key={game.id} game={game} dateStr={formattedDate} />
<GameCard key={game.id} game={game} onGameClick={() => onGameClick(game)} />
))}
</div>
</section>
Expand Down
8 changes: 5 additions & 3 deletions src/pages/home/components/top-section.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { userQueries } from '@apis/user/user-queries';
import { useQuery } from '@tanstack/react-query';

const TopSection = () => {
// TODO: 유저 수 api 연결
const MOCK_USERS = 124;
const { data } = useQuery(userQueries.USER_COUNT());

return (
<section className="mx-[1.6rem] rounded-[12px] bg-gray-900 px-[1.6rem] py-[1rem]">
<p className="cap_14_m text-gray-white">
현재 <span className="text-sub-800">{MOCK_USERS}명</span>이 메이트를 찾고 있어요!🔥
현재 <span className="text-sub-800">{data?.userCnt}명</span>이 메이트를 찾고 있어요!🔥
</p>
</section>
);
Expand Down
Loading
Loading