Skip to content

Comments

[feature] 동아리 한글 표시 이름 추가 -FE#1233

Open
lepitaaar wants to merge 4 commits intodevelop-fefrom
feature/add-korean-routing
Open

[feature] 동아리 한글 표시 이름 추가 -FE#1233
lepitaaar wants to merge 4 commits intodevelop-fefrom
feature/add-korean-routing

Conversation

@lepitaaar
Copy link
Contributor

@lepitaaar lepitaaar commented Feb 23, 2026

#️⃣연관된 이슈

📝작업 내용

/clubDetail/@{clubName}로 라우팅을 추가했습니다.
navigate Url 링크를 @동아리이름 으로 이동되게 변경하였습니다.

스크린샷 2026-02-23 15 43 54

중점적으로 리뷰받고 싶은 부분(선택)

리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요

ex) 메서드 XXX의 이름을 더 잘 짓고 싶은데 혹시 좋은 명칭이 있을까요?

논의하고 싶은 부분(선택)

논의하고 싶은 부분이 있다면 작성해주세요.

🫡 참고사항

Summary by CodeRabbit

  • 새로운 기능

    • 클럽 상세 페이지에서 한글 스타일 핸들(@이름) URL을 지원하는 경로 추가
  • 개선 사항

    • 클럽 접근 및 네비게이션이 가능한 경우 이름 기반(@이름) 경로로 이동하도록 변경
    • 신청 완료 및 오류 시 리다이렉트 대상이 이름 기반 경로를 우선 사용하도록 개선

@lepitaaar lepitaaar self-assigned this Feb 23, 2026
@lepitaaar lepitaaar added ✨ Feature 기능 개발 💻 FE Frontend labels Feb 23, 2026
@vercel
Copy link

vercel bot commented Feb 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
moadong Ready Ready Preview, Comment Feb 23, 2026 7:04am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 23, 2026

Warning

.coderabbit.yaml has a parsing error

The CodeRabbit configuration file in this repository has a parsing error and default settings were used instead. Please fix the error(s) in the configuration file. You can initialize chat with CodeRabbit to get help with the configuration file.

💥 Parsing errors (1)
Validation error: Invalid regex pattern for base branch. Received: "**" at "reviews.auto_review.base_branches[0]"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

No actionable comments were generated in the recent review. 🎉


Walkthrough

클럽 상세 조회 라우트를 기존 clubId 기반에서 clubName 기반 별칭(/clubDetail/@:clubName)을 추가해 한국식 핸들 스타일 URL을 지원하고, 관련 훅/네비게이션 파라미터 이름을 clubParam/clubName 우선 사용으로 변경합니다. (50단어 이내)

Changes

Cohort / File(s) Summary
라우팅
frontend/src/App.tsx
/clubDetail/@:clubName 경로 추가, 기존 경로 유지.
쿼리 키 상수
frontend/src/constants/queryKeys.ts
detail 함수 파라미터명 clubIdclubParam으로 이름 변경(동작 변경 없음).
쿼리 훅
frontend/src/hooks/Queries/useClub.ts
useGetClubDetail에 전달되는 파라미터명 clubIdclubParam으로 변경, 내부 사용처 업데이트.
페이지 네비게이션 변경
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: 상세 페이지 렌더링
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

이름 기반 라우트 사용 시 뮤테이션 캐시 무효화 불일치

useUpdateClubDescriptionuseUpdateClubDetailonSuccess에서 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)로 진입할 때 clubIdundefined이고, clubId || ''은 빈 문자열을 ClubDetailTopBar에 전달합니다. ClubDetailTopBar는 이 clubIdrequestNotificationSubscribe, 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.

Copy link
Member

@seongwon030 seongwon030 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

한글이름이 훨씬 더 좋네요 수고하셨습니다 ~

club: {
all: ['clubs'] as const,
detail: (clubId: string) => ['clubDetail', clubId] as const,
detail: (clubParam: string) => ['clubDetail', clubParam] as const,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

구조변경에 맞게 clubParam 네이밍 변경좋습니다

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

근데 clubParam 변수명뭔가 애매쓰 추천받습니다

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💻 FE Frontend ✨ Feature 기능 개발

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants