diff --git a/src/api/index.ts b/src/api/index.ts index 9c272f0..f4bb269 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -1,5 +1,7 @@ import axios from 'axios'; +import LocalStorage from '@/utils/LocalStorage'; + const instance = axios.create({ baseURL: process.env.NEXT_PUBLIC_API_BASE_URL, headers: { @@ -16,7 +18,7 @@ export const adminInstance = axios.create({ }); adminInstance.interceptors.request.use(config => { - config.headers.Authorization = `Bearer ${localStorage.getItem('token')}`; + config.headers.Authorization = `Bearer ${LocalStorage.getItem('token')}`; return config; }); diff --git a/src/app/admin/league/page.tsx b/src/app/admin/league/page.tsx index cf37d21..01ca8cf 100644 --- a/src/app/admin/league/page.tsx +++ b/src/app/admin/league/page.tsx @@ -1,11 +1,18 @@ 'use client'; +import dynamic from 'next/dynamic'; import Link from 'next/link'; import { Suspense } from 'react'; -import LeagueList from '@/components/admin/league/LeagueList'; import Button from '@/components/common/Button'; -import LeagueListFetcher from '@/queries/admin/useLeagueList/Fetcher'; + +const LeagueListFetcher = dynamic( + () => import('@/queries/admin/useLeagueList/Fetcher'), + { ssr: false }, +); +const LeagueList = dynamic( + () => import('@/components/admin/league/LeagueList'), +); export default function LeaguePage() { return ( diff --git a/src/app/admin/register/[leagueId]/page.tsx b/src/app/admin/register/[leagueId]/page.tsx index be8ad23..daa3a9a 100644 --- a/src/app/admin/register/[leagueId]/page.tsx +++ b/src/app/admin/register/[leagueId]/page.tsx @@ -2,15 +2,11 @@ import { Suspense } from 'react'; -import RegisterLeague from '@/components/admin/register/League'; +import EditLeague from '@/components/admin/register/League/edit'; import LeagueRegisterFetcher from '@/queries/admin/useLeagueRegister/Fetcher'; import useSportsListByLeagueId from '@/queries/useSportsListByLeagueId/query'; -export default function EditLeague({ - params, -}: { - params: { leagueId: string }; -}) { +export default function Edit({ params }: { params: { leagueId: string } }) { const { leagueId } = params; const { sportsList: leagueSportsData } = useSportsListByLeagueId(leagueId); return ( @@ -18,7 +14,7 @@ export default function EditLeague({ 리그 정보 로딩중...}> {data => ( - diff --git a/src/app/admin/register/page.tsx b/src/app/admin/register/page.tsx index a01eabb..c8b9a2c 100644 --- a/src/app/admin/register/page.tsx +++ b/src/app/admin/register/page.tsx @@ -3,7 +3,7 @@ import { Suspense } from 'react'; import RegisterWrapper from '@/components/admin/register/context/RegisterWrapper'; -import RegisterLeague from '@/components/admin/register/League'; +import RegisterLeague from '@/components/admin/register/League/'; import RegisterTeam from '@/components/admin/register/Team'; import { useFunnel } from '@/hooks/useFunnel'; import LeagueRegisterFetcher from '@/queries/admin/useLeagueRegister/Fetcher'; diff --git a/src/components/admin/register/League/edit/index.tsx b/src/components/admin/register/League/edit/index.tsx new file mode 100644 index 0000000..e1dffcf --- /dev/null +++ b/src/components/admin/register/League/edit/index.tsx @@ -0,0 +1,213 @@ +'use client'; + +import { useRouter } from 'next/navigation'; +import { ChangeEvent, FormEvent, useEffect, useState } from 'react'; + +import Button from '@/components/common/Button'; +import CheckboxItem from '@/components/common/Checkbox/Item'; +import Input from '@/components/common/Input/Input'; +import useValidate from '@/hooks/useValidate'; +import { + usePostLeagueMutation, + usePutLeagueMutation, +} from '@/queries/admin/useLeagueRegister/query'; +import { + LeagueDataType, + LeagueRegisterDataType, + SportsDataType, +} from '@/types/admin/league'; +import { SportsType } from '@/types/league'; +import { updateSet } from '@/utils/set'; +import { parseTimeString } from '@/utils/time'; + +export default function EditLeague({ + data, + leagueId, + onNext, +}: { + data: LeagueRegisterDataType & { leagueSportsData: SportsType[] }; + leagueId?: number; + onNext?: () => void; +}) { + const [newLeagueData, setNewLeagueData] = useState( + {} as LeagueDataType, + ); + const [newSportsData, setNewSportsData] = useState>(new Set()); + + const { leagueData, leagueSportsData, sportsListData } = data; + const currentLeague = leagueData.find(e => e.leagueId === Number(leagueId)); + + const router = useRouter(); + + const { mutate: postLeague } = usePostLeagueMutation(); + const { mutate: putLeague } = usePutLeagueMutation(); + + useEffect(() => { + if (currentLeague) { + const parseDate = (dateString: string) => dateString.split('T')[0]; + + setNewLeagueData({ + name: currentLeague.name, + startAt: parseDate(currentLeague.startAt), + endAt: parseDate(currentLeague.endAt), + }); + } + if (leagueSportsData) { + const reducedSportsData = leagueSportsData.reduce( + (acc, cur) => [...acc, cur.sportId], + [] as SportsDataType, + ); + + setNewSportsData(new Set(reducedSportsData)); + } + }, []); + + const { month, date } = parseTimeString(new Date().toString()); + + const isDateError = + new Date(newLeagueData.endAt) < new Date(newLeagueData.startAt); + const { isError: isStartAtEmpty } = useValidate( + newLeagueData.startAt, + dateValue => !dateValue, + ); + const { isError: isEndAtEmpty } = useValidate( + newLeagueData.endAt, + dateValue => !dateValue, + ); + const { isError: isNameEmpty } = useValidate( + newLeagueData.name, + nameValue => String(nameValue).length < 1, + ); + const { isError: isSportsEmpty } = useValidate( + Array.from(newSportsData).length, + length => length === 0, + ); + const isAnyInvalid = + isNameEmpty || + isDateError || + isSportsEmpty || + isStartAtEmpty || + isEndAtEmpty; + + const updateCheckbox = (id: number) => { + setNewSportsData(prevSet => updateSet(prevSet, id)); + }; + + const handleInput = ( + e: ChangeEvent, + ) => { + const { name, value } = e.target; + + setNewLeagueData(prev => ({ ...prev, [name]: value })); + }; + + const onSubmit = (e: FormEvent) => { + e.preventDefault(); + + const payload = { + leagueData: newLeagueData, + sportData: Array.from(newSportsData), + }; + + if (leagueId) { + putLeague({ + leagueId, + ...payload, + }); + } else { + postLeague(payload); + } + + if (onNext) { + onNext(); + } else { + router.push('/admin/league/'); + } + }; + + return ( +
+
+ {currentLeague ? '리그 수정' : '새 리그 등록'} +
+
+ + + + +
+
+ ); +} diff --git a/src/components/admin/register/League/index.tsx b/src/components/admin/register/League/index.tsx index 653ef63..db9182e 100644 --- a/src/components/admin/register/League/index.tsx +++ b/src/components/admin/register/League/index.tsx @@ -11,11 +11,7 @@ import { usePostLeagueMutation, usePutLeagueMutation, } from '@/queries/admin/useLeagueRegister/query'; -import { - LeagueDataType, - LeagueRegisterDataType, - SportsDataType, -} from '@/types/admin/league'; +import { LeagueDataType, LeagueRegisterDataType } from '@/types/admin/league'; import { updateSet } from '@/utils/set'; import { parseTimeString } from '@/utils/time'; @@ -33,7 +29,7 @@ export default function RegisterLeague({ ); const [newSportsData, setNewSportsData] = useState>(new Set()); - const { leagueData, leagueSportsData, sportsListData } = data; + const { leagueData, sportsListData } = data; const currentLeague = leagueData.find(e => e.leagueId === Number(leagueId)); const router = useRouter(); @@ -51,14 +47,6 @@ export default function RegisterLeague({ endAt: parseDate(currentLeague.endAt), }); } - if (leagueSportsData) { - const reducedSportsData = leagueSportsData.reduce( - (acc, cur) => [...acc, cur.sportId], - [] as SportsDataType, - ); - - setNewSportsData(new Set(reducedSportsData)); - } }, []); const { month, date } = parseTimeString(new Date().toString()); diff --git a/src/components/common/Sidebar/index.tsx b/src/components/common/Sidebar/index.tsx index ed0db88..6dc9347 100644 --- a/src/components/common/Sidebar/index.tsx +++ b/src/components/common/Sidebar/index.tsx @@ -3,8 +3,8 @@ import Link from 'next/link'; import { useEffect, useState } from 'react'; -import { getAllLeaguesWithAuth } from '@/api/admin/league'; -import { LeagueType } from '@/types/admin/league'; +import { getAllLeagues } from '@/api/league'; +import { LeagueType } from '@/types/league'; type SidebarProps = { isSidebarOpen: boolean; @@ -15,12 +15,12 @@ export default function Sidebar({ onClickSidebar, }: SidebarProps) { const [menuContent, setMenuContent] = useState([ - { name: '전체', leagueId: 0, startAt: '', endAt: '' }, + { name: '전체', leagueId: 0 }, ]); useEffect(() => { const getLeagueData = async () => { - const res = await getAllLeaguesWithAuth(); + const res = await getAllLeagues(); setMenuContent(prev => [...prev, ...res]); }; diff --git a/src/types/admin/league.ts b/src/types/admin/league.ts index 74312ef..89e7bc2 100644 --- a/src/types/admin/league.ts +++ b/src/types/admin/league.ts @@ -33,6 +33,5 @@ export type DeleteLeaguePayload = LeagueIdType; export type LeagueRegisterDataType = { leagueData: LeagueType[]; - leagueSportsData?: SportsCategoriesType[]; sportsListData: SportsCategoriesType[]; }; diff --git a/src/utils/LocalStorage.ts b/src/utils/LocalStorage.ts new file mode 100644 index 0000000..926b37b --- /dev/null +++ b/src/utils/LocalStorage.ts @@ -0,0 +1,25 @@ +class LocalStorage { + constructor() {} + + static setItem(key: string, value: string) { + if (typeof window !== 'undefined') { + localStorage.setItem(key, value); + } + } + + static getItem(key: string) { + if (typeof window !== 'undefined') { + return localStorage.getItem(key); + } + + return null; + } + + static removeItem(key: string) { + if (typeof window !== 'undefined') { + localStorage.removeItem(key); + } + } +} + +export default LocalStorage;