From eef0d92a56ae568efabd5e889c8f47fa860c5ce2 Mon Sep 17 00:00:00 2001 From: SeungminCha Date: Sun, 16 Mar 2025 16:34:45 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20navigation=20util=EC=9D=84=20?= =?UTF-8?q?=EB=A7=8C=EB=93=A4=EC=96=B4=EC=9A=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Community/CommunityOutlet/index.tsx | 6 +- src/lib/router/header-route.ts | 2 +- src/lib/router/routeConfig.tsx | 96 ++++++++++++++++ src/lib/router/router.tsx | 104 ++++++++---------- src/util/hooks/useNavigateRouter.ts | 26 +++++ 5 files changed, 173 insertions(+), 61 deletions(-) create mode 100644 src/lib/router/routeConfig.tsx create mode 100644 src/util/hooks/useNavigateRouter.ts diff --git a/src/features/Community/CommunityOutlet/index.tsx b/src/features/Community/CommunityOutlet/index.tsx index b648b1a5..7ffc77ec 100644 --- a/src/features/Community/CommunityOutlet/index.tsx +++ b/src/features/Community/CommunityOutlet/index.tsx @@ -4,8 +4,10 @@ import SearchBox from '@/components/timetable/SearchBox' import CommunityPostDetail from '@/features/Community/CommunityPostDetail' import { Button } from '@/ui/Button' import { Typography } from '@/ui/Typography' +import { useNavigateRouter } from '@/util/hooks/useNavigateRouter' const CommunityOutlet = () => { + const navigateTo = useNavigateRouter() return (
@@ -17,7 +19,9 @@ const CommunityOutlet = () => { Check out our recent posts
- +
{}} /> diff --git a/src/lib/router/header-route.ts b/src/lib/router/header-route.ts index 3b3fece4..f7a96a6f 100644 --- a/src/lib/router/header-route.ts +++ b/src/lib/router/header-route.ts @@ -1,6 +1,6 @@ export const headerRouteConfig = [ { route: 'home', navName: 'Home' }, { route: 'timetable', navName: 'Timetable', innerTab: ['timetable', 'timetable/friend'] }, - { route: 'community', navName: 'Community' }, + { route: 'community/all?board=All&boardId=0', navName: 'Community' }, { route: 'matching', navName: '1:1 Matching' }, ] diff --git a/src/lib/router/routeConfig.tsx b/src/lib/router/routeConfig.tsx new file mode 100644 index 00000000..79665c6d --- /dev/null +++ b/src/lib/router/routeConfig.tsx @@ -0,0 +1,96 @@ +import { + BoardPage, + ClubDetailPage, + ClubPage, + CourseInfoPage, + CourseReviewPage, + FriendPage, + FriendTimetablePage, + HotBoardPage, + MainCommunityPage, + MyPage, + MyTimetablePage, + PostViewPage, + ReviewDetailPage, + ReviewPage, + SchedulePage, + TimetablePage, + WritePostPage, + WriteReviewPage, +} from '@/lib/router/lazy-route' +import CommunityAllPage from '@/pages/Community/All' +import HomePage from '@/pages/Home' +import LandingPage from '@/pages/LandingPage' +import Login from '@/pages/LoginPage' +import PasswordResetPage from '@/pages/PasswordResetPage' +import RegisterPage from '@/pages/RegisterPage' + +export const routeConfig = { + // 메인 페이지 + LandingPage: { path: '/', element: , params: [] }, + HomePage: { path: 'home', element: , params: [] }, + + // 인증 관련 + Login: { path: 'login', element: , params: [] }, + RegisterPage: { path: 'register', element: , params: [] }, + PasswordResetPage: { path: 'password-reset', element: , params: [] }, + + // 마이페이지 + MyPage: { path: 'mypage', element: , params: [] }, + + // 시간표 + TimetablePage: { path: '/timetable', element: , params: [] }, + MyTimetablePage: { path: '/timetable', element: , params: [] }, + FriendPage: { path: '/timetable/friend', element: , params: [] }, + FriendTimetablePage: { + path: 'timetable/friend/:userHandler', + params: ['userHandler'], + element: , + }, + + // 강의 리뷰 + CourseReviewPage: { path: '/course-review', element: , params: [] }, + CourseInfoPage: { path: '/course-review/info', element: , params: [] }, + ReviewPage: { path: '/course-review/detail', element: , params: [] }, + ReviewDetailPage: { path: '/course-review/review', element: , params: [] }, + WriteReviewPage: { path: '/course-review/write', element: , params: [] }, + + // 커뮤니티 + MainCommunityPage: { path: '/community', element: , params: [] }, + CommunityAllPage: { path: '/community/all', element: , params: [] }, + WritePostPage: { + path: '/community/action/:type/post/:boardName', + params: ['type', 'boardName'], + element: , + }, + BoardPage: { + path: '/community/board/:boardName', + params: ['boardName'], + element: , + }, + HotBoardPage: { path: '/community/board/hotboard', element: , params: [] }, + PostViewPage: { + path: '/community/:boardName/post/:postId', + params: ['boardName', 'postId'], + element: , + }, + + // 일정 + SchedulePage: { path: '/calendar', element: , params: [] }, + + // 동아리 + ClubPage: { path: '/club', element: , params: [] }, + ClubDetailPage: { + path: '/club/detail/:clubId', + params: ['clubId'], + element: , + }, +} as const + +export type RouteKey = keyof typeof routeConfig + +export type RouteParams = (typeof routeConfig)[T]['params'][number] + +// 파라미터 배열을 객체 타입으로 변환하는 타입 +export type RouteParamsObject = + RouteParams extends never ? undefined : { [K in RouteParams]: string } diff --git a/src/lib/router/router.tsx b/src/lib/router/router.tsx index 74a66d8b..f3fb08db 100644 --- a/src/lib/router/router.tsx +++ b/src/lib/router/router.tsx @@ -1,33 +1,9 @@ import { RouteObject } from 'react-router-dom' import MainLayout from '@/components/MainLayout' -import { - BoardPage, - ClubDetailPage, - ClubPage, - CourseInfoPage, - CourseReviewPage, - FriendPage, - FriendTimetablePage, - HotBoardPage, - MainCommunityPage, - MyPage, - MyTimetablePage, - PostViewPage, - ReviewDetailPage, - ReviewPage, - SchedulePage, - TimetablePage, - WritePostPage, - WriteReviewPage, -} from '@/lib/router/lazy-route' import ProtectedRoutes from '@/lib/router/ProtectedRoutes' -import CommunityAllPage from '@/pages/Community/All' -import HomePage from '@/pages/Home' +import { routeConfig } from '@/lib/router/routeConfig' import LandingPage from '@/pages/LandingPage' -import Login from '@/pages/LoginPage' -import PasswordResetPage from '@/pages/PasswordResetPage' -import RegisterPage from '@/pages/RegisterPage' const routes: RouteObject[] = [ { @@ -42,70 +18,80 @@ const routes: RouteObject[] = [ path: '', element: , children: [ - { path: 'mypage', element: }, + { ...routeConfig.MyPage }, { - path: 'timetable', - element: , + ...routeConfig.TimetablePage, children: [ - { path: '', element: }, { - path: 'friend', - element: , + ...routeConfig.MyTimetablePage, + path: routeConfig.MyTimetablePage.path.replace('/timetable', ''), + }, + { + ...routeConfig.FriendPage, + path: routeConfig.FriendPage.path.replace('/timetable/', ''), + }, + { + ...routeConfig.FriendTimetablePage, + path: routeConfig.FriendTimetablePage.path.replace('/timetable/', ''), }, - { path: 'friend/:userHandler', element: }, ], }, { - path: 'course-review', - element: , + ...routeConfig.CourseReviewPage, children: [ - { path: 'info', element: }, - { path: 'detail', element: }, - { path: 'review', element: }, - { path: 'write', element: }, + { + ...routeConfig.CourseInfoPage, + path: routeConfig.CourseInfoPage.path.replace('/course-review/', ''), + }, + { + ...routeConfig.ReviewPage, + path: routeConfig.ReviewPage.path.replace('/course-review/', ''), + }, + { + ...routeConfig.ReviewDetailPage, + path: routeConfig.ReviewDetailPage.path.replace('/course-review/', ''), + }, + { + ...routeConfig.WriteReviewPage, + path: routeConfig.WriteReviewPage.path.replace('/course-review/', ''), + }, ], }, { - path: 'community', - element: , + ...routeConfig.MainCommunityPage, }, { - path: 'community/all', - element: , + ...routeConfig.CommunityAllPage, }, { - path: 'community/action/:type/post/:boardName', - element: , + ...routeConfig.WritePostPage, }, { - path: 'community/board/:boardName', - element: , + ...routeConfig.BoardPage, }, { - path: 'community/board/hotboard', - element: , + ...routeConfig.HotBoardPage, }, { - path: 'community/:boardName/post/:postId', - element: , + ...routeConfig.PostViewPage, }, ], }, - { path: 'home', element: }, - { path: 'calendar', element: }, - { path: 'login', element: }, - { path: 'register', element: }, - { path: 'password-reset', element: }, + { ...routeConfig.HomePage }, + { ...routeConfig.SchedulePage }, + { ...routeConfig.Login }, + { ...routeConfig.RegisterPage }, + { ...routeConfig.PasswordResetPage }, { path: 'club', children: [ { - path: '', - element: , + ...routeConfig.ClubPage, + path: routeConfig.ClubPage.path.replace('/club', ''), }, { - path: 'detail/:clubId', - element: , + ...routeConfig.ClubDetailPage, + path: routeConfig.ClubDetailPage.path.replace('/club/', ''), }, ], }, diff --git a/src/util/hooks/useNavigateRouter.ts b/src/util/hooks/useNavigateRouter.ts new file mode 100644 index 00000000..beb2e070 --- /dev/null +++ b/src/util/hooks/useNavigateRouter.ts @@ -0,0 +1,26 @@ +import { useCallback } from 'react' +import { generatePath, NavigateOptions, useNavigate } from 'react-router-dom' + +import { routeConfig, RouteKey, RouteParamsObject } from '@/lib/router/routeConfig' + +export const useNavigateRouter = () => { + const navigate = useNavigate() + + // 컴포넌트 이름과 파라미터로 네비게이션하는 함수 + const navigateTo = useCallback( + (routeName: T, params?: RouteParamsObject, options?: NavigateOptions) => { + const route = routeConfig[routeName] + // React Router의 generatePath 사용 + try { + const path = generatePath(route.path, params as { [K in (typeof route.params)[number]]: string }) + navigate(path, options) + } catch (error) { + console.error(`Failed to generate path for "${routeName}":`, error) + console.error('Provided params:', params) + } + }, + [navigate], + ) + + return navigateTo +} From 41fe151e96f3858a2f757ed9d153b015d28a70a7 Mon Sep 17 00:00:00 2001 From: SeungminCha Date: Sun, 16 Mar 2025 16:55:08 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20navigation=20=EC=9C=A0=ED=8B=B8=20p?= =?UTF-8?q?oc=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/HomeClubs/components/HotClubs/index.tsx | 12 ++++++++---- .../HomeClubs/components/RecommendedClubs/index.tsx | 12 +++++++----- src/util/hooks/useNavigateRouter.ts | 2 -- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/features/HomeClubs/components/HotClubs/index.tsx b/src/features/HomeClubs/components/HotClubs/index.tsx index d1645204..33602927 100644 --- a/src/features/HomeClubs/components/HotClubs/index.tsx +++ b/src/features/HomeClubs/components/HotClubs/index.tsx @@ -1,14 +1,14 @@ import { motion } from 'framer-motion' -import { useNavigate } from 'react-router-dom' import * as s from '../Clubs/style.css' import { useReadHotClubs } from '@/features/HomeClubs/hooks/useReadHotClubs' import { Typography } from '@/ui/Typography' +import { useNavigateRouter } from '@/util/hooks/useNavigateRouter' + const HotClubs = () => { const { data: hotClubs } = useReadHotClubs() - const navigate = useNavigate() - const handleClick = (id: number) => navigate(`/club/detail/${id}`) + const navigateTo = useNavigateRouter() return ( { transition={{ duration: 0.2, ease: 'easeInOut' }} > {hotClubs.map(item => ( -