Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning
|
| Cohort / File(s) | Summary |
|---|---|
라우팅 frontend/src/App.tsx |
/clubDetail/@:clubName 경로 추가, 기존 경로 유지. |
쿼리 키 상수 frontend/src/constants/queryKeys.ts |
detail 함수 파라미터명 clubId → clubParam으로 이름 변경(동작 변경 없음). |
쿼리 훅 frontend/src/hooks/Queries/useClub.ts |
useGetClubDetail에 전달되는 파라미터명 clubId → clubParam으로 변경, 내부 사용처 업데이트. |
페이지 네비게이션 변경 frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx |
에러 및 성공 후 리다이렉트 대상이 /clubDetail/@{clubDetail.name} 우선으로 변경(없으면 기본 경로 사용). |
클럽 상세 로직 및 카드 네비게이션 frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx, frontend/src/pages/MainPage/components/ClubCard/ClubCard.tsx |
ClubDetailPage가 clubName을 우선 읽어 `useGetClubDetail((clubName ?? clubId) |
Sequence Diagram
sequenceDiagram
participant User
participant ClubCard
participant Router
participant ClubDetailPage
participant useClub as useGetClubDetail Hook
participant API
User->>ClubCard: 클릭 (클럽 선택)
ClubCard->>Router: navigate("/clubDetail/@{clubName}")
Router->>ClubDetailPage: 라우트 파라미터 전달 (clubName 또는 clubId)
ClubDetailPage->>ClubDetailPage: identifier = clubName ?? clubId
ClubDetailPage->>useClub: 호출( clubParam = identifier )
useClub->>API: getClubDetail(clubParam) 요청
API-->>useClub: 클럽 데이터 응답
useClub-->>ClubDetailPage: 데이터 반환
ClubDetailPage-->>User: 상세 페이지 렌더링
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related PRs
- [release] FE v1.1.20 #1116: 클럽 상세 라우팅 및 네비게이션 변경과 직접적으로 겹침(라우트/네비게이션 수정).
- [fix] 상세페이지에서 clubName이 undefined되는 문제를 해결한다 #886: ClubDetailPage 내 clubName 처리 로직 변경과 연관 있음.
- [feature] 지원서 제출 후 메시지 개선 및 리다이렉트 처리 추가 #592: ApplicationFormPage의 제출 후 리다이렉트 흐름 변경과 연관 있음.
Suggested reviewers
- seongwon030
- suhyun113
- oesnuj
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | PR 제목은 한글로 작성된 기능 설명('[feature] 동아리 한글 표시 이름 추가 -FE')으로, 전체 변경사항의 핵심을 정확히 요약하고 있습니다. |
| Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. |
✏️ Tip: You can configure your own custom pre-merge checks in the settings.
✨ Finishing Touches
- 📝 Generate docstrings (stacked PR)
- 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Post copyable unit tests in a comment
- Commit unit tests in branch
feature/add-korean-routing
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
frontend/src/hooks/Queries/useClub.ts (1)
73-76:⚠️ Potential issue | 🟠 Major이름 기반 라우트 사용 시 뮤테이션 캐시 무효화 불일치
useUpdateClubDescription과useUpdateClubDetail의onSuccess에서variables.id(MongoDB ObjectId)로 캐시를 무효화합니다. 그런데/clubDetail/@:clubName라우트로 접근 시 쿼리 키가['clubDetail', '동아리이름']으로 저장됩니다. 두 키가 일치하지 않아 어드민에서 클럽 정보를 업데이트해도 이름 기반 라우트 방문자의 캐시는 무효화되지 않습니다.부분 키 매칭으로
clubId·clubName양쪽 모두를 무효화하는 것이 안전합니다.🐛 제안 수정
// useUpdateClubDescription onSuccess: (_, variables) => { - queryClient.invalidateQueries({ - queryKey: queryKeys.club.detail(variables.id), - }); + queryClient.invalidateQueries({ + queryKey: ['clubDetail'], + }); }, // useUpdateClubDetail onSuccess: (_, variables) => { if (variables.id) { - queryClient.invalidateQueries({ - queryKey: queryKeys.club.detail(variables.id), - }); + queryClient.invalidateQueries({ + queryKey: ['clubDetail'], + }); } },Also applies to: 91-94
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/hooks/Queries/useClub.ts` around lines 73 - 76, The mutation onSuccess handlers in useUpdateClubDescription and useUpdateClubDetail currently invalidate only queryKeys.club.detail(variables.id) (MongoDB ObjectId), which misses name-based routes; update both invalidations so you call queryClient.invalidateQueries for queryKeys.club.detail(variables.id) and for queryKeys.club.detail(variables.clubName) (or the name key used by the route) so both clubId- and clubName-based cache entries are invalidated; locate the onSuccess in useClub.ts where queryClient.invalidateQueries is called and add the second invalidate for the name-based key.frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx (1)
83-85:⚠️ Potential issue | 🟠 Major
ClubDetailTopBar에 빈 문자열이 전달되어 알림 기능이 작동하지 않음이름 기반 라우트(
/clubDetail/@:clubName)로 진입할 때clubId는undefined이고,clubId || ''은 빈 문자열을ClubDetailTopBar에 전달합니다.ClubDetailTopBar는 이clubId를requestNotificationSubscribe,requestNotificationUnsubscribe호출에 사용하므로, 빈 문자열이 전달되면 알림 등록/해제 기능이 정상 작동하지 않습니다.이 시점에는
clubDetail이 이미 로드된 상태(75-77줄의 guard 확인)이므로,clubDetail.id를 사용하면 어떤 라우트로 진입하든 올바른 ID를 보장할 수 있습니다.제안 수정
{showTopBar && ( <ClubDetailTopBar - clubId={clubId || ''} + clubId={clubDetail.id || clubId || ''} clubName={clubDetail.name}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx` around lines 83 - 85, The ClubDetailTopBar is receiving clubId || '' which passes an empty string when clubId is undefined (name-based route), breaking notification subscribe/unsubscribe; change the prop to use the loaded club's numeric ID instead by passing clubDetail.id to ClubDetailTopBar (replace clubId || '' with clubDetail.id) so requestNotificationSubscribe/requestNotificationUnsubscribe receive a valid ID; ensure clubDetail is still guarded (as in the existing guard before render) so this value is safe to use.
🧹 Nitpick comments (3)
frontend/src/hooks/Queries/useClub.ts (1)
27-27: 불필요한as string타입 단언 제거
clubParam이 이미string으로 선언되어 있으므로as string캐스트는 중복입니다.♻️ 제안 수정
- queryFn: () => getClubDetail(clubParam as string), + queryFn: () => getClubDetail(clubParam),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/hooks/Queries/useClub.ts` at line 27, Remove the redundant type assertion on clubParam in the query function: in useClub's queryFn where you call getClubDetail(clubParam as string), pass clubParam directly (getClubDetail(clubParam)) because clubParam is already typed as string; update the queryFn to use getClubDetail(clubParam) and remove the unnecessary "as string" cast.frontend/src/pages/MainPage/components/ClubCard/ClubCard.tsx (1)
26-26: 클럽 이름을 URL에 삽입할 때encodeURIComponent적용 권장
club.name에 공백이나?,#,&등이 포함될 경우 URL이 깨지거나 쿼리스트링·해시로 잘못 파싱될 수 있습니다.ApplicationFormPage.tsx의 동일한 패턴(63, 114번 줄)에도 동일하게 적용해야 합니다.♻️ 제안 수정
- navigate(`/clubDetail/@${club.name}`); + navigate(`/clubDetail/@${encodeURIComponent(club.name)}`);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/pages/MainPage/components/ClubCard/ClubCard.tsx` at line 26, Wrap the club name with URL-encoding when building the route to avoid broken URLs for names containing spaces or reserved chars: in ClubCard (the navigate call that currently does navigate(`/clubDetail/@${club.name}`)) replace the interpolation to use encodeURIComponent(club.name); also apply the same change in ApplicationFormPage where club names are interpolated into routes (the two occurrences noted) so all navigations consistently use encodeURIComponent for club.name.frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx (1)
39-42:useParams제네릭 타입에 옵셔널(?) 표기 누락React Router v7의
useParams는 해당 라우트에 없는 파라미터를 런타임에undefined로 반환하지만, 현재 제네릭에는 두 파라미터 모두 필수(string)로 선언되어 있습니다. 타입 선언과 런타임 값이 불일치하면 이후 코드에서 타입 가드 없이 사용할 때 예기치 않은 동작이 발생할 수 있습니다.♻️ 제안 수정
- const { clubId, clubName } = useParams<{ - clubId: string; - clubName: string; - }>(); + const { clubId, clubName } = useParams<{ + clubId?: string; + clubName?: string; + }>();🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx` around lines 39 - 42, The useParams generic currently declares clubId and clubName as required strings but React Router can return undefined at runtime; update the generic in the ClubDetailPage component so clubId and clubName are optional (e.g., clubId?: string; clubName?: string) and then add necessary null/undefined guards where clubId or clubName are used (search for uses of clubId and clubName in ClubDetailPage.tsx and wrap them with conditional checks or early returns). This ensures the types align with runtime behavior and prevents unsafe assumptions when calling functions or rendering based on those params.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@frontend/src/pages/ApplicationFormPage/ApplicationFormPage.tsx`:
- Around line 61-64: When handling errors in ApplicationFormPage.tsx, avoid
navigating to `/clubDetail/@undefined` when clubError is true by falling back to
the clubId from useParams instead of clubDetail?.name; update the error branch
that currently uses navigate(`/clubDetail/@${clubDetail?.name}`) to use the club
name or fallback to the clubId (e.g., navigate(`/clubDetail/@${clubDetail?.name
|| clubId}`)), ensuring you reference the same useParams variable name used in
this file and keep the alert on applicationError?.message as before.
---
Outside diff comments:
In `@frontend/src/hooks/Queries/useClub.ts`:
- Around line 73-76: The mutation onSuccess handlers in useUpdateClubDescription
and useUpdateClubDetail currently invalidate only
queryKeys.club.detail(variables.id) (MongoDB ObjectId), which misses name-based
routes; update both invalidations so you call queryClient.invalidateQueries for
queryKeys.club.detail(variables.id) and for
queryKeys.club.detail(variables.clubName) (or the name key used by the route) so
both clubId- and clubName-based cache entries are invalidated; locate the
onSuccess in useClub.ts where queryClient.invalidateQueries is called and add
the second invalidate for the name-based key.
In `@frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx`:
- Around line 83-85: The ClubDetailTopBar is receiving clubId || '' which passes
an empty string when clubId is undefined (name-based route), breaking
notification subscribe/unsubscribe; change the prop to use the loaded club's
numeric ID instead by passing clubDetail.id to ClubDetailTopBar (replace clubId
|| '' with clubDetail.id) so
requestNotificationSubscribe/requestNotificationUnsubscribe receive a valid ID;
ensure clubDetail is still guarded (as in the existing guard before render) so
this value is safe to use.
---
Nitpick comments:
In `@frontend/src/hooks/Queries/useClub.ts`:
- Line 27: Remove the redundant type assertion on clubParam in the query
function: in useClub's queryFn where you call getClubDetail(clubParam as
string), pass clubParam directly (getClubDetail(clubParam)) because clubParam is
already typed as string; update the queryFn to use getClubDetail(clubParam) and
remove the unnecessary "as string" cast.
In `@frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx`:
- Around line 39-42: The useParams generic currently declares clubId and
clubName as required strings but React Router can return undefined at runtime;
update the generic in the ClubDetailPage component so clubId and clubName are
optional (e.g., clubId?: string; clubName?: string) and then add necessary
null/undefined guards where clubId or clubName are used (search for uses of
clubId and clubName in ClubDetailPage.tsx and wrap them with conditional checks
or early returns). This ensures the types align with runtime behavior and
prevents unsafe assumptions when calling functions or rendering based on those
params.
In `@frontend/src/pages/MainPage/components/ClubCard/ClubCard.tsx`:
- Line 26: Wrap the club name with URL-encoding when building the route to avoid
broken URLs for names containing spaces or reserved chars: in ClubCard (the
navigate call that currently does navigate(`/clubDetail/@${club.name}`)) replace
the interpolation to use encodeURIComponent(club.name); also apply the same
change in ApplicationFormPage where club names are interpolated into routes (the
two occurrences noted) so all navigations consistently use encodeURIComponent
for club.name.
| club: { | ||
| all: ['clubs'] as const, | ||
| detail: (clubId: string) => ['clubDetail', clubId] as const, | ||
| detail: (clubParam: string) => ['clubDetail', clubParam] as const, |
There was a problem hiding this comment.
구조변경에 맞게 clubParam 네이밍 변경좋습니다
There was a problem hiding this comment.
근데 clubParam 변수명뭔가 애매쓰 추천받습니다
#️⃣연관된 이슈
📝작업 내용
/clubDetail/@{clubName}로 라우팅을 추가했습니다.navigate Url 링크를
@동아리이름으로 이동되게 변경하였습니다.중점적으로 리뷰받고 싶은 부분(선택)
논의하고 싶은 부분(선택)
🫡 참고사항
Summary by CodeRabbit
새로운 기능
개선 사항