diff --git a/src/api/league.ts b/src/api/league.ts index 5c62d53..6cf7adf 100644 --- a/src/api/league.ts +++ b/src/api/league.ts @@ -1,12 +1,9 @@ import * as Sentry from '@sentry/nextjs'; import { AxiosError } from 'axios'; -import instance from '.'; +import { LeagueType, SportsType } from '@/types/league'; -export type LeagueType = { - name: string; - leagueId: number; -}; +import instance from '.'; export const getAllLeagues = async () => { try { @@ -25,3 +22,11 @@ export const getAllLeagues = async () => { } } }; + +export const getSportsListByLeagueId = async (leagueId: string) => { + const { data } = await instance.get( + `/leagues/${leagueId}/sports`, + ); + + return data; +}; diff --git a/src/api/match.ts b/src/api/match.ts index 4180cdf..30c8f5a 100644 --- a/src/api/match.ts +++ b/src/api/match.ts @@ -15,6 +15,8 @@ export type MatchListParams = { sportsId: number | number[]; status: 'playing' | 'scheduled' | 'finished'; leagueId: number; + cursor: number; + size: number; }; export const getMatchList = async (params: MatchListParams) => { diff --git a/src/app/page.tsx b/src/app/page.tsx index ef50baf..7e22e3a 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -2,21 +2,49 @@ import { Suspense } from 'react'; -import MatchList from '@/components/match/MatchList'; -import MatchListFetcher from '@/queries/useMatchList/Fetcher'; +import SportsList from '@/components/league/SportsList'; +import useQueryParams from '@/hooks/useQueryParams'; +import SportsListFetcher from '@/queries/useSportsListByLeagueId/Fetcher'; export default function Home() { + const { appendToParams, setInParams } = useQueryParams(); + return ( -
-

매치

-
+
+ + + {data => } + + + +
+ + + +
+ + {/*
MatchList 로딩중...
}> - {/* // TODO sportsId, leagueId, status 상태를 동적 주입 */} - + {data => } -
-
+ */} + ); } diff --git a/src/components/common/Sidebar/index.tsx b/src/components/common/Sidebar/index.tsx index 29e738d..725938b 100644 --- a/src/components/common/Sidebar/index.tsx +++ b/src/components/common/Sidebar/index.tsx @@ -3,7 +3,8 @@ import Link from 'next/link'; import { useEffect, useState } from 'react'; -import { getAllLeagues, LeagueType } from '@/api/league'; +import { getAllLeagues } from '@/api/league'; +import { LeagueType } from '@/types/league'; type SidebarProps = { onClickSidebar: () => void; diff --git a/src/components/league/SportsList/index.tsx b/src/components/league/SportsList/index.tsx new file mode 100644 index 0000000..2b10f53 --- /dev/null +++ b/src/components/league/SportsList/index.tsx @@ -0,0 +1,26 @@ +import { SportsType } from '@/types/league'; + +type SportsListProps = { + sportsList: SportsType[]; + onClick: (key: string, value: string) => void; +}; + +export default function SportsList({ sportsList, onClick }: SportsListProps) { + return ( + + ); +} diff --git a/src/hooks/useQueryParams.ts b/src/hooks/useQueryParams.ts new file mode 100644 index 0000000..69b5326 --- /dev/null +++ b/src/hooks/useQueryParams.ts @@ -0,0 +1,30 @@ +import { usePathname, useRouter, useSearchParams } from 'next/navigation'; + +export default function useQueryParams() { + const params = useSearchParams(); + const pathname = usePathname(); + const router = useRouter(); + + const appendToParams = (key: string, value: string) => { + const newParams = new URLSearchParams(params.toString()); + const targetParams = newParams.getAll(key); + + if (targetParams.includes(value)) { + newParams.delete(key, value); + } else { + newParams.append(key, value); + } + router.push(`${pathname}?${newParams.toString()}`); + }; + + const setInParams = (key: string, value: string) => { + const newParams = new URLSearchParams(params.toString()); + + if (newParams.get(key) === value) return; + + newParams.set(key, value); + router.push(`${pathname}?${newParams.toString()}`); + }; + + return { params, appendToParams, setInParams }; +} diff --git a/src/queries/useSportsListByLeagueId/Fetcher.tsx b/src/queries/useSportsListByLeagueId/Fetcher.tsx new file mode 100644 index 0000000..37c063a --- /dev/null +++ b/src/queries/useSportsListByLeagueId/Fetcher.tsx @@ -0,0 +1,36 @@ +import { ReactNode } from 'react'; + +import { SportsType } from '@/types/league'; + +import useSportsListByLeagueId from './query'; + +type SportsListFetcherProps = { + leagueId: string; + children: (data: SportsType[]) => ReactNode; +}; + +const DUMMY = [ + { + sportId: 1, + name: '축구', + }, + { + sportId: 3, + name: '농구', + }, + { + sportId: 2, + name: '롤', + }, +]; + +export default function SportsListFetcher({ + leagueId, + children, +}: SportsListFetcherProps) { + const { error } = useSportsListByLeagueId(leagueId); + + if (error) throw error; + + return children(DUMMY); +} diff --git a/src/queries/useSportsListByLeagueId/query.ts b/src/queries/useSportsListByLeagueId/query.ts new file mode 100644 index 0000000..c3357d8 --- /dev/null +++ b/src/queries/useSportsListByLeagueId/query.ts @@ -0,0 +1,15 @@ +import { useSuspenseQuery } from '@tanstack/react-query'; + +import { getSportsListByLeagueId } from '@/api/league'; + +export default function useSportsListByLeagueId(leagueId: string) { + const { data, error } = useSuspenseQuery({ + queryKey: ['sports-list', leagueId], + queryFn: () => getSportsListByLeagueId(leagueId), + }); + + return { + sportsList: data, + error, + }; +} diff --git a/src/types/league.ts b/src/types/league.ts new file mode 100644 index 0000000..316d6da --- /dev/null +++ b/src/types/league.ts @@ -0,0 +1,9 @@ +export type LeagueType = { + leagueId: number; + name: string; +}; + +export type SportsType = { + name: string; + sportId: number; +};