Conversation
Walkthrough
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested reviewers
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/app/university/search/PageContent.tsx (1)
64-66: 라우팅 경로 변경:/university/search-results→/universityPR 요약에 따라
/university/search-results디렉토리가 제거되고, 결과 페이지가 상위 경로인/university에서 직접 렌더링됩니다. 현재 남아 있는 모든router.push호출을/university?${queryString}로 수정해야 404를 방지할 수 있습니다.변경이 필요한 파일 목록:
- PageContent.tsx 라우팅 경로 수정
- 파일:
src/app/university/search/PageContent.tsx(64–66행)- SearchBar.tsx (검색 페이지) 라우팅 경로 수정
- 파일:
src/app/university/search/SearchBar.tsx(52–53행)- SearchBar.tsx (상위 페이지) 라우팅 경로 수정
- 파일:
src/app/university/SearchBar.tsx(54–55행)적용할 diff (공통):
- router.push(`/university/search-results?${queryString}`); + router.push(`/university?${queryString}`);src/app/university/SearchResultsContent.tsx (1)
40-55: 2) 텍스트/필터 검색 분기 조건이 잘못되어 필터가 무시될 수 있습니다.'countries'는 항상 truthy(Array)라 '!countries'는 false입니다. 현재 로직은 'lang'이 없으면 거의 항상 텍스트 검색으로 떨어져, '국가만 선택'한 경우 필터 검색이 작동하지 않습니다.
간결하고 안전한 분기로 아래처럼 회귀하는 것을 제안합니다.
- if (!lang || !countries) { - return { - isTextSearch: true, - searchText: text, - filterParams: {} as UniversitySearchFilterParams, - }; - } else { - return { - isTextSearch: false, - searchText: "", - filterParams: { - languageTestType: (lang as LanguageTestType) || undefined, - countryCode: filteredCountries.length > 0 ? filteredCountries : undefined, - }, - }; - } + if (text) { + return { + isTextSearch: true, + searchText: text, + filterParams: {} as UniversitySearchFilterParams, + }; + } + return { + isTextSearch: false, + searchText: "", + filterParams: { + languageTestType: lang ? (lang as LanguageTestType) : undefined, + countryCode: filteredCountries.length > 0 ? filteredCountries : undefined, + }, + };대안으로, '언어 또는 국가 중 하나라도 선택되면 필터 검색'을 원하시면 isFilter = Boolean(lang) || countries.length > 0 로 분기하는 방식도 가능합니다.
♻️ Duplicate comments (1)
src/app/university/SearchBar.tsx (1)
77-77: 6) 기본 export 변경 재확인(상단 코멘트와 동일 맥락).해당 변경은 1)번 네이밍 정합성 코멘트와 동일 이슈이므로 함께 처리 부탁드립니다.
🧹 Nitpick comments (10)
src/app/university/application/ScorePageContent.tsx (1)
49-51: 2) isError = 곧바로 ‘지원하기’ 리다이렉트: 에러 유형별 분기 필요 여부 점검
설명: isError에는 네트워크/서버/권한/데이터 없음(404) 등이 혼재할 수 있어요. 전부를 ‘지원하기’로 보내면 오동작 가능성이 있어요.
제안(필수는 아님, 가벼운 보강):
- hook에서 error 객체를 함께 구조 분해해 상태코드 기반 분기를 고려합니다. (404 → apply, 401 → 로그인, 그 외 → 알럿/재시도)
- 네비게이션은 replace 권장(뒤로 가기 루프 방지).
- retry: false 유지하되 사용자 주도 재시도 버튼은 추후 필요 시 추가.
변경(diff: 최소 보강으로 error만 함께 받기)
- const { data: scoreResponseData = initialData, isError } = useGetApplicationsList({ + const { data: scoreResponseData = initialData, isError, error } = useGetApplicationsList({ retry: false, });
- 추가(범위 밖 예시): 상태코드에 따른 분기 예시
useEffect(() => { if (!isError) return; // @ts-ignore — react-query 패턴 가정 const status = (error as any)?.response?.status; if (status === 404) { alert("지원 이력이 없어 ‘지원하기’ 페이지로 이동합니다."); router.replace("/university/application/apply"); } else if (status === 401) { alert("로그인이 필요합니다."); router.replace("/login"); } else { alert("일시적인 오류가 발생했습니다. 잠시 후 다시 시도해주세요."); // 유지 또는 별도 안내 모달 선택 } }, [isError, error, router]);
- 빠른 QA 체크리스트
- 정상 200 → 목록 노출, 리다이렉트 없음
- 404 → 알럿 1회 + /university/application/apply로 replace
- 500/네트워크 차단 → 알럿 1회, 페이지 잔류(또는 재시도 UX)
- StrictMode에서 알럿 중복/다중 리다이렉트 없는지 확인
src/app/my/_ui/MyProfileContent/index.tsx (2)
68-71: 1) '프로필 변경' 영역 전체를 실제 클릭 가능하게 만들어 주세요.현재 div에만 cursor-pointer가 있어 시각적으로는 클릭 가능해 보이지만, 실제 클릭 타깃은 내부의 Link 텍스트에 한정됩니다. Link로 래핑하거나 Link에 블록 스타일을 적용해 전체 영역을 클릭 가능하게 만드는 편이 명확합니다.
아래와 같이 간결하게 정리 가능합니다.
- <div className="w-full cursor-pointer rounded-lg bg-secondary-500 py-2 text-center font-medium text-white"> - <Link href={"/my/modify"}>프로필 변경</Link> - </div> + <Link + href="/my/modify" + className="block w-full rounded-lg bg-secondary-500 py-2 text-center font-medium text-white" + > + 프로필 변경 + </Link>
73-76: 2) (멘티 분기) 동일하게 CTA 전체를 클릭 가능하도록 통일해 주세요.멘토 분기와 동일한 이유로 UX 혼선을 줄이기 위해 Link 블록화가 적합합니다.
- <div className="w-full cursor-pointer rounded-lg bg-secondary-500 py-2 text-center font-medium text-white"> - <Link href={"/my/modify"}>프로필 변경</Link> - </div> + <Link + href="/my/modify" + className="block w-full rounded-lg bg-secondary-500 py-2 text-center font-medium text-white" + > + 프로필 변경 + </Link>src/app/university/score/submit/gpa/GpaSubmitForm.tsx (1)
48-49: 3) issueDate가 하드코딩되어 있어 데이터 정확도에 영향을 줄 수 있습니다.배포 전 실제 발급일 데이터를 연결하거나, 최소한 오늘 날짜로 대체하도록 확인이 필요합니다.
- issueDate: "2025-01-01", // TODO: 실제 날짜 데이터로 변경 + issueDate: new Date().toISOString().slice(0, 10), // TODO: 실제 데이터 소스로 대체src/app/university/SearchResultsContent.tsx (1)
58-60: 3) 두 종류의 검색 쿼리가 동시에 실행됩니다.isTextSearch 여부와 무관하게 두 훅이 모두 호출되어 불필요한 API 트래픽이 발생할 수 있습니다. enabled 옵션(react-query 기반 가정)을 제공해 하나만 실행하도록 조정하는 것을 권장합니다.
- const textSearchQuery = useGetUniversitySearchByText(searchText ?? ""); - const filterSearchQuery = useGetUniversitySearchByFilter(filterParams); + const textSearchQuery = useGetUniversitySearchByText(searchText ?? "", { enabled: isTextSearch }); + const filterSearchQuery = useGetUniversitySearchByFilter(filterParams, { enabled: !isTextSearch });해당 훅이 options 인자를 지원하지 않는다면, 훅 내부에서 enabled를 받을 수 있도록 소폭 개편하는 방안을 고려해 주세요.
src/components/layout/GlobalLayout/ui/ClientModal/index.tsx (1)
16-23: 2) 짧은 로딩에 의한 깜빡임(flicker) 완화 제안.
isFetching 토글이 잦다면 100~200ms 지연 후 표시하는 작은 디바운스를 두면 사용자 체감이 좋아질 수 있습니다.src/app/university/search/SearchBar.tsx (1)
74-74: 컴포넌트 이름 및 경로 중복/미스매치 정리 안내
파일명-컴포넌트명 불일치 정리
–src/app/university/SearchBar.tsx파일은 내부에서 기본 export가SearchForm으로 선언되어 있어, 파일명과 컴포넌트명이 일치하지 않습니다. 파일명을SearchForm.tsx로 변경하거나 컴포넌트명을SearchBar로 통일하는 것이 가독성·유지보수를 위해 좋습니다.사용되지 않는 검색 컴포넌트 제거 검토
–src/app/university/search/SearchBar.tsx는 코드베이스 내에서 import 혹은<SearchBar>사용처가 발견되지 않습니다. 불필요하다면 파일 삭제를 검토해 주세요.SearchForm 잔존 여부 확인 완료
–SearchForm컴포넌트는 오직 최상위src/app/university/SearchBar.tsx에서만 정의·사용되고 있으며, 다른 곳에는 import 되지 않습니다. 별도 추가 조치 불필요합니다.
search-results경로 참조 현황
–router.push('/university/search-results?...')호출은
•src/app/university/SearchBar.tsx
•src/app/university/search/SearchBar.tsx
•src/app/university/search/PageContent.tsx
에서 각각 사용 중입니다. 경로 변경 시 이 위치들을 함께 수정해야 합니다.src/app/university/search/page.tsx (1)
12-26: 1) async 제거로 의도 명확화 제안.
비동기 동작이 없으니 async 키워드를 제거하면 의미가 분명해집니다.-const Page = async () => { +const Page = () => {src/app/university/SearchBar.tsx (2)
53-53: 3) 콘솔 로그는 운영 가드 또는 제거 권장.검색어(사용자 입력) 로그 잔존은 운영 콘솔 노이즈 및 민감 데이터 흔적 리스크가 있습니다.
아래처럼 운영 차단 가드를 권장합니다.
- console.log("검색 실행:", queryString); + if (process.env.NODE_ENV !== "production") { + console.debug("[SearchForm] 검색 실행:", queryString); + }
62-66: 5) 에러 보더 동적 처리 훌륭함 + 공백 입력 방지용 스키마 강화 제안.현재
trim()은 쿼리 생성 시점에만 적용되어 공백만 입력해도 검증을 통과할 수 있습니다. 스키마에trim()을 추가해 UX/검증 일관성을 확보해 주세요.- searchText: z.string().min(1, "검색어를 입력해주세요.").max(50, "최대 50자까지 입력 가능합니다."), + searchText: z.string().trim().min(1, "검색어를 입력해주세요.").max(50, "최대 50자까지 입력 가능합니다."),
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (13)
src/app/community/[boardCode]/[postId]/PostPageContent.tsx(1 hunks)src/app/my/_ui/MyProfileContent/index.tsx(1 hunks)src/app/university/SearchBar.tsx(3 hunks)src/app/university/SearchResultsContent.tsx(4 hunks)src/app/university/application/ScorePageContent.tsx(2 hunks)src/app/university/application/apply/DoneStep.tsx(1 hunks)src/app/university/page.tsx(2 hunks)src/app/university/score/submit/gpa/GpaSubmitForm.tsx(1 hunks)src/app/university/search-results/page.tsx(0 hunks)src/app/university/search/PageContent.tsx(1 hunks)src/app/university/search/SearchBar.tsx(3 hunks)src/app/university/search/page.tsx(1 hunks)src/components/layout/GlobalLayout/ui/ClientModal/index.tsx(1 hunks)
💤 Files with no reviewable changes (1)
- src/app/university/search-results/page.tsx
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: manNomi
PR: solid-connection/solid-connect-web#242
File: src/components/ui/TabSelector.tsx:10-11
Timestamp: 2025-08-12T09:41:44.182Z
Learning: manNomi prefers to keep reusable UI components simple and focused on core functionality rather than adding many features. They don't want to over-engineer flexible/reusable UI components at the initial stage.
Learnt from: manNomi
PR: solid-connection/solid-connect-web#245
File: src/components/mentor/MentorChatCard/index.tsx:17-21
Timestamp: 2025-08-24T11:14:34.275Z
Learning: manNomi prefers not to receive accessibility suggestions or recommendations during code reviews.
🧬 Code graph analysis (1)
src/app/university/search/page.tsx (2)
src/app/university/page.tsx (1)
metadata(7-9)src/app/university/SearchResultsContent.tsx (1)
Page(99-105)
🔇 Additional comments (14)
src/app/university/score/submit/gpa/GpaSubmitForm.tsx (2)
80-82: 1) 완료 버튼 '홈으로' 전환 LGTM.완료 플로우에서 홈으로 빠르게 복귀하는 UX 의도와 일치합니다.
15-21: 제거 요청: ‘CustomDropdown 경로 확인 필요’ 주석 삭제
- ‘CustomDropdown 경로 확인 필요’ 주석을 삭제해 주세요.
해당 주석은src/app/university/score/submit/gpa/GpaSubmitForm.tsx15–21라인에 남아 있지만, 실제 경로가 이미 올바르므로 더 이상 필요하지 않습니다.@/app/university/CustomDropdown경로가src/app/university/CustomDropdown.tsx로 정확히 매핑됩니다.
추가적인 경로 조정이나 공용(ui) 경로 승격 없이도 정상적으로 빌드/런타임 오류 없이 동작합니다.src/app/university/SearchResultsContent.tsx (2)
7-7: 1) FloatingUpBtn 도입, 위치 적절합니다.결과 목록 하단 배치로 스크롤 복귀 동선이 개선됩니다.
94-95: 4) FloatingUpBtn 노출 위치 LGTM.결과 렌더 블록 뒤에 배치되어 스크롤 동작과 겹치지 않습니다.
src/app/university/page.tsx (2)
5-5: 1) SearchResultsContent를 상위 페이지로 통합한 방향 적합합니다.탑 네비게이션과 검색 결과가 한 페이지로 응집되어 전환 비용이 줄어듭니다.
15-16: 2) 페이지 컴포지션 간결합니다.불필요한 래퍼 없이 의도한 구성요소만 배치되어 유지보수성이 좋아졌습니다.
src/components/layout/GlobalLayout/ui/ClientModal/index.tsx (1)
21-23: 1) 로딩 스피너 오버레이 전체 화면 중앙 정렬 — OK.
요구사항대로 중앙 정렬·전체 뷰포트 커버가 잘 적용되었습니다. z-50로 모달 위계도 적절합니다.src/app/community/[boardCode]/[postId]/PostPageContent.tsx (1)
38-38: 1) KebabMenu 무조건 렌더링 — 권한 가드 존재 여부 확인 필요.
비소유자에게 수정/삭제가 노출되면 UX 혼란 또는 오작동 가능성이 있습니다. KebabMenu 내부에서 권한 기반으로 항목을 숨기거나, canManage 같은 플래그를 전달하는지 확인 부탁드립니다.다음과 같이 명시 플래그 전달을 고려할 수 있습니다(컴포넌트가 지원한다면):
- icon={<KebabMenu postId={postId} />} + icon={<KebabMenu postId={postId} canManage={post.isOwner} />}src/app/university/search/SearchBar.tsx (1)
58-69: 3) 에러 메시지 표시는 유지되나, 시각적 피드백 단순화 — 현재 형태 유지 OK.
밸리데이션은 동작하고 있고, 입력창 스타일을 단순화한 결정은 PR 목표와 맞습니다.src/app/university/search/page.tsx (2)
20-23: 3) 검색 페이지 내 통합 흐름 — 구성 OK.
상단 네비 + 검색바 + 폼의 병치가 새 구조와 일관됩니다.
8-10: 확인 완료: 메타데이터 타이틀 중복 없음
- 메타데이터 타이틀 전역 검색
-rg -nP "export\s+const\s+metadata:\s*Metadata\s*=\s*{[^}]*title:\s*['\"]파견 학교 목록['\"]" -g '*.tsx' -C2명령어로*.tsx파일을 전수 조사했습니다.- 검색 결과
- 추가로 “파견 학교 목록” 타이틀을 사용하는metadata정의를 찾지 못했습니다.따라서 동일한 헤더 표시나 SEO 충돌 우려가 없으니, 본 코멘트는 해결합니다.
src/app/university/application/apply/DoneStep.tsx (2)
9-16: 1) 완료 화면 카피/레이아웃 개선 — OK.
중앙 정렬과 단계적 타이포 강조가 명확하며, 디자인 의도에 부합합니다.
18-33: 2) 후속 액션 이원화 — 경로 동작 최종 확인 부탁.
"/university/application"과 "/" 경로가 최신 라우팅과 일치하는지만 한번 더 점검해 주세요.src/app/university/SearchBar.tsx (1)
59-59: 4) 레이아웃 여백 조정(LGTM).wrapper를
relative mb-2로 정리하여 오류 메시지와 입력 필드 간 간격이 안정적으로 확보됩니다.
| import { z } from "zod"; | ||
|
|
||
| import CustomDropdown from "./CustomDropdown"; | ||
| import CustomDropdown from "./search-results/CustomDropdown"; |
There was a problem hiding this comment.
1) CustomDropdown import 경로가 잘못되어 빌드 실패 가능성이 높습니다.
현재 파일 위치 기준 "./search-results/CustomDropdown"는 search/search-results 하위로 해석됩니다. 의도가 university/search-results 하위라면 상대 경로는 "../search-results/CustomDropdown"이어야 합니다.
- import CustomDropdown from "./search-results/CustomDropdown";
+ import CustomDropdown from "../search-results/CustomDropdown";📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import CustomDropdown from "./search-results/CustomDropdown"; | |
| import CustomDropdown from "../search-results/CustomDropdown"; |
🤖 Prompt for AI Agents
In src/app/university/search/PageContent.tsx at line 10 the import path for
CustomDropdown is incorrect: it uses "./search-results/CustomDropdown" which
resolves to search/search-results relative to this file; change the import to
the correct relative path "../search-results/CustomDropdown" (or the proper path
within university/search-results) so the module resolves and the build no longer
fails.
| } | ||
| // --- 폼 로직을 관리하는 부모 컴포넌트 --- | ||
| const SearchBar = ({ initText }: SearchBarProps) => { | ||
| const SearchForm = ({ initText }: SearchBarProps) => { |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
1) 컴포넌트명 변경에 따른 정합성 확보: 파일명(SearchBar.tsx) vs. 기본 export(SearchForm).
이름 불일치로 import 경로/자동 리팩토링에서 혼동 여지가 큽니다. 파일명을 SearchForm.tsx로 바꾸거나, 컴포넌트/기본 export를 SearchBar로 되돌리는 두 가지 중 하나로 정리해주세요.
아래 중 “B안”은 코드만으로 해결됩니다.
-const SearchForm = ({ initText }: SearchBarProps) => {
+const SearchBar = ({ initText }: SearchBarProps) => {
...
-export default SearchForm;
+export default SearchBar;레포 내 사용처 점검 스크립트:
🏁 Script executed:
#!/bin/bash
# SearchBar / SearchForm 사용처와 import 확인
rg -nP -C2 '\bSearchBar\b|\\bSearchForm\\b'
# SearchBar.tsx를 기본 import로 참조하는 위치 탐색
rg -nP -C2 'import\s+\w+\s+from\s+["\'][^"\']*SearchBar["\']'Length of output: 2088
스크립트 내부 정규식 따옴표 오류를 수정하고, SearchBar와 SearchForm의 사용처를 정확히 재확인하기 위해 아래 스크립트를 실행해 주세요.
🏁 Script executed:
#!/bin/bash
# 1) SearchBar 또는 SearchForm 키워드 사용 위치 전체 확인
rg -nP -C2 '\b(SearchBar|SearchForm)\b' src/app/university/
# 2) SearchBar.tsx를 기본 import로 참조한 구문 확인
rg -nP -C2 "import\s+\w+\s+from\s+['\"][^'\"]*SearchBar['\"]" src/app/university/Length of output: 3685
컴포넌트명과 파일명 일치화 제안
-
파일명 변경 제안
SearchBar.tsx를 SearchForm.tsx로 변경해 파일명과 기본 export(컴포넌트명)를 동기화합니다. -
컴포넌트명 변경 제안
src/app/university/SearchBar.tsx 내부 컴포넌트 및 export를 SearchForm에서 SearchBar로 수정해 파일명과 일치시킵니다.-const SearchForm = ({ initText }: SearchBarProps) => { +const SearchBar = ({ initText }: SearchBarProps) => { … -export default SearchForm; +export default SearchBar;
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const SearchForm = ({ initText }: SearchBarProps) => { | |
| // src/app/university/SearchBar.tsx | |
| const SearchBar = ({ initText }: SearchBarProps) => { | |
| … | |
| export default SearchBar; |
🤖 Prompt for AI Agents
In src/app/university/SearchBar.tsx around line 31, the component name and the
file name are out of sync (file is SearchBar.tsx but the component is declared
as SearchForm); update them to match by either renaming the file to
SearchForm.tsx or renaming the component and its default export to SearchBar. If
you choose renaming the component, change the function/const name and the export
identifier to SearchBar and update any imports across the codebase; if you
choose renaming the file, move/rename SearchBar.tsx to SearchForm.tsx and update
imports accordingly so the file name and exported component name are consistent.
| const queryString = queryParams.toString(); | ||
| console.log("검색 실행:", queryString); | ||
| router.push(`/university/search-results?${queryString}`); | ||
| }; |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
2) 라우팅 경로 재검증: /university/search-results 사용 여부 확인 필요.
PR 전반 설명에 ‘/university/search-results 제거, /university/search 신설’ 맥락이 있어 보입니다. 해당 페이지가 제거되었다면 현재 push 경로는 404를 유발할 수 있습니다.
확인 후 필요 시 아래로 교체해주세요.
- router.push(`/university/search-results?${queryString}`);
+ router.push(`/university/search?${queryString}`);경로 존재 여부 빠른 점검:
🏁 Script executed:
#!/bin/bash
# search-results 페이지/라우트 흔적
fd -t d 'search-results' -E node_modules
rg -nP -C2 '/university/search-results'
# 신규 /university/search 페이지 존재 확인
fd -t f 'page.tsx' app | rg -nP '/university/search'Length of output: 1238
안녕하세요! 이전 스크립트에서 app 디렉터리 경로가 누락된 것 같아, 실제 src/app/university/search 경로를 직접 검사하도록 수정했습니다.
- 경로 검증 스크립트 수정
-src/app/university/search/page.tsx파일의 존재 여부 확인
아래 스크립트를 실행하고 결과를 공유해주세요.
🏁 Script executed:
#!/bin/bash
# 1) /university/search 페이지 존재 여부 확인
if [ -f src/app/university/search/page.tsx ]; then
echo "✅ Found: src/app/university/search/page.tsx (routes /university/search)"
else
echo "❌ Missing: src/app/university/search/page.tsx - 경로가 없습니다."
fiLength of output: 200
검증 결과 /university/search 페이지가 정상적으로 존재하며 /university/search-results 페이지는 삭제된 상태입니다.
따라서 다음 세 가지 항목을 반영해 router.push 경로를 수정해야 합니다.
-
파일 목록
- src/app/university/search/SearchBar.tsx
- src/app/university/search/PageContent.tsx
-
변경 내용
- router.push 경로를
/university/search?${queryString}로 교체
- router.push 경로를
-
코드 스니펫
- router.push(`/university/search-results?${queryString}`); + router.push(`/university/search?${queryString}`);
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const queryString = queryParams.toString(); | |
| console.log("검색 실행:", queryString); | |
| router.push(`/university/search-results?${queryString}`); | |
| }; | |
| const queryString = queryParams.toString(); | |
| console.log("검색 실행:", queryString); | |
| router.push(`/university/search?${queryString}`); | |
| }; |
🤖 Prompt for AI Agents
In src/app/university/SearchBar.tsx around lines 52 to 55, the router.push
target uses the deleted route /university/search-results; update it to
router.push(`/university/search?${queryString}`) so the search query navigates
to the existing page; also scan src/app/university/search/PageContent.tsx for
any links or redirects still pointing to /university/search-results and change
them to /university/search?${queryString} (or the equivalent query construction
used there) to keep routing consistent.
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/app/university/SearchBar.tsx (1)
11-13: 2) 공백만 입력 시 통과하는 케이스 차단(스키마 trim + onSubmit 가드).
- 요약: 현재 zod는 공백을 유효로 판단합니다. .trim()을 스키마에 추가하고, onSubmit도 trim 값 기준으로 append하면 UX 혼란을 막을 수 있습니다. (단순화 선호 러닝을 반영해 최소 변경만 제안합니다.)
-const searchSchema = z.object({ - searchText: z.string().min(1, "검색어를 입력해주세요.").max(50, "최대 50자까지 입력 가능합니다."), -}); +const searchSchema = z.object({ + searchText: z.string().trim().min(1, "검색어를 입력해주세요.").max(50, "최대 50자까지 입력 가능합니다."), +}); const onSubmit: SubmitHandler<SearchFormData> = (data) => { const queryParams = new URLSearchParams(); - if (data.searchText) { - queryParams.append("searchText", data.searchText.trim()); - } + const text = data.searchText.trim(); + if (text) { + queryParams.append("searchText", text); + } const queryString = queryParams.toString(); - console.log("검색 실행:", queryString); router.push(`/university/search?${queryString}`); };Also applies to: 46-55
♻️ Duplicate comments (2)
src/app/university/application/ScorePageContent.tsx (1)
126-133: 렌더 사이드이펙트 분리 Good, StrictMode 2회 실행 가드 추가 권장개발 모드에서 useEffect가 2회 실행될 수 있어 알럿·리다이렉트가 중복될 여지가 있습니다. 간단한 ref 가드로 1회만 실행되도록 막아주세요.
- 변경 제안(diff: 해당 범위 내)
- useEffect(() => { - if (isLoading) return; - if (isError) { - alert("지원 현황을 불러오는 중에 오류가 발생했습니다. 지원 절차를 진행해주세요."); - router.replace("/university/application/apply"); - } - }, [isError, isLoading, router]); + useEffect(() => { + if (isLoading || !isError || redirectedRef.current) return; + redirectedRef.current = true; + alert("지원 현황을 불러오는 중에 오류가 발생했습니다. 지원 절차를 진행해주세요."); + router.replace("/university/application/apply"); + }, [isError, isLoading, router]);
- 보조 코드(범위 밖 추가): 상태 선언부 인근에 아래 1줄을 추가
const redirectedRef = useRef(false);src/app/university/SearchBar.tsx (1)
31-31: 1) 파일명(SearchBar.tsx) ↔ 컴포넌트명(SearchForm) 불일치 정리 바랍니다.
- 요약: 이전 코멘트와 동일 이슈입니다. 파일명과 기본 export를 일치시키면 IDE 탐색/자동 리팩터링이 수월해집니다. “컴포넌트명을 SearchBar로” 정리안을 제안합니다.
-const SearchForm = ({ initText }: SearchBarProps) => { +const SearchBar = ({ initText }: SearchBarProps) => { ... -export default SearchForm; +export default SearchBar;Also applies to: 77-77
🧹 Nitpick comments (5)
src/app/university/application/ScorePageContent.tsx (3)
37-37: 열리지 않는 ConfirmCancelModal 정리 or 실제 동작에 연결현재 showNeedApply가 어디서도 true로 변경되지 않아 모달은 절대 표시되지 않습니다. 유지 의도 없으면 제거, 유지라면 isError 분기와 연결 중 하나를 선택해주세요. 개인적으로 알럿을 유지한다면 제거가 깔끔합니다.
- 제거안(diff):
- import ConfirmCancelModal from "@/components/modal/ConfirmCancelModal";- const [showNeedApply, setShowNeedApply] = useState(false);- <ConfirmCancelModal - title="학교 지원이 필요합니다" - isOpen={showNeedApply} - handleCancel={() => router.push("/")} - handleConfirm={() => router.push("/university/application/apply")} - content={"점수 공유현황을 확인하려면 지원절차를\n진행해주세요."} - cancelText="확인" - approveText="학교 지원하기" - />Also applies to: 168-176, 6-6
54-61: 중복 제거 기준 확인 필요(현재 “마지막 데이터 우선”)Map([...]) 방식은 동일 koreanName 중 마지막 아이템이 남습니다. “지원자 수가 많은 항목을 우선”이 의도라면 아래처럼 보강을 권장합니다.
- 변경 제안(diff: 해당 범위 내)
- const uniqueByKoreanName = (data: ScoreSheetType[]) => { - // Map을 사용해 koreanName을 키로 하여 중복을 효율적으로 제거합니다. - const universityMap = new Map(data.map((sheet) => [sheet.koreanName, sheet])); - // Map의 값들만 다시 배열로 변환하여 반환합니다. - return Array.from(universityMap.values()); - }; + const uniqueByKoreanName = (data: ScoreSheetType[]) => { + const map = new Map<string, ScoreSheetType>(); + for (const sheet of data) { + const prev = map.get(sheet.koreanName); + if (!prev || sheet.applicants.length > prev.applicants.length) { + map.set(sheet.koreanName, sheet); + } + } + return [...map.values()]; + };
149-151: 바깥 래퍼의 gap 클래스는 무효(비-flex/grid); space-y로 교체 제안외곽 div에 gap-4만 있으나 flex/grid가 아니라 효과가 없습니다. 의도대로라면 space-y-4로 전환이 안전합니다.
- 변경 제안(diff):
- <div className="gap-4 px-5"> + <div className="space-y-4 px-5">src/app/university/search/PageContent.tsx (1)
48-56: 3) 선택한 ‘지역(regions)’도 쿼리에 포함하면 딥링크/새로고침 복원성이 좋아집니다.
- 요약: 현재 쿼리엔 searchText, languageTestType, countryCode만 포함됩니다. regions도 함께 append하는 것을 제안드립니다.
if (data.languageTestType) { queryParams.append("languageTestType", data.languageTestType); } + if (data.regions && data.regions.length > 0) { + data.regions.forEach((region) => queryParams.append("region", region)); + }src/app/university/SearchBar.tsx (1)
53-53: 3) console.log는 개발 단계에서만 사용하거나 제거해 주세요.
- 요약: 클라이언트 콘솔 노이즈를 줄이기 위해 제거 권장입니다. 필요 시 NODE_ENV 가드로 제한하세요.
- console.log("검색 실행:", queryString);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
src/app/university/SearchBar.tsx(3 hunks)src/app/university/application/ScorePageContent.tsx(4 hunks)src/app/university/search/PageContent.tsx(2 hunks)src/app/university/search/SearchBar.tsx(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/app/university/search/SearchBar.tsx
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: manNomi
PR: solid-connection/solid-connect-web#242
File: src/components/ui/TabSelector.tsx:10-11
Timestamp: 2025-08-12T09:41:44.182Z
Learning: manNomi prefers to keep reusable UI components simple and focused on core functionality rather than adding many features. They don't want to over-engineer flexible/reusable UI components at the initial stage.
Learnt from: manNomi
PR: solid-connection/solid-connect-web#245
File: src/components/mentor/MentorChatCard/index.tsx:17-21
Timestamp: 2025-08-24T11:14:34.297Z
Learning: manNomi prefers not to receive accessibility suggestions or recommendations during code reviews.
🔇 Additional comments (7)
src/app/university/application/ScorePageContent.tsx (3)
45-52: useGetApplicationsList 옵션 및 반환값 구조 활용 잘하셨습니다retry: false 적용과 isError 분기 도입이 PR 목적(실패 시 리다이렉트)에 부합합니다. 이 구간은 그대로 가시죠.
163-167: 리스트 컨테이너 레이아웃 OKmx-auto + w-full + flex-col + gap 구성으로 중앙 정렬·간격 모두 문제 없어 보입니다. koreanName을 key로 쓰는 것도 중복 제거 로직과 합치됩니다.
4-4: 훅 import 구성 적절useEffect/useMemo/useRef/useState 모두 실사용되고 있어 불필요 import 없음이 확인됩니다.
src/app/university/search/PageContent.tsx (3)
64-66: ✅ 라우팅 경로 반영 및 잔여 참조 확인 완료
- 페이지 존재 확인
src/app/university/search/page.tsx파일이 정상적으로 존재합니다.- 삭제된 경로 참조 없음 확인
- 코드 전반에서
/university/search-results에 대한 참조를 찾을 수 없습니다.모든 검증이 완료되었으므로 추가 조치가 필요하지 않습니다.
10-10: CustomDropdown 경로 및 디폴트 익스포트 확인 완료
- 커스텀 드롭다운 파일 존재 확인 완료.
–src/app/university/CustomDropdown.tsx경로에서 파일이 발견되었습니다.- 디폴트 익스포트 정의 확인 완료.
– 96–97행에서export default CustomDropdown;를 확인했습니다.이상으로 경로 변경과 디폴트 익스포트 모두 문제가 없으니 코드 변경을 승인합니다.
68-74: 검증 완료: COUNTRY_CODE_MAP과 REGION_TO_COUNTRIES_MAP 모두 ‘국가명’ 기준
- COUNTRY_CODE_MAP vs REGION_TO_COUNTRIES_MAP 기준 검증
두 상수 모두 국가명 문자열을 사용하여 비교 단위가 일치합니다.- 필터 로직 검토
name 기반 필터 로직이 정상 작동하므로 추가 수정이 필요 없습니다.src/app/university/SearchBar.tsx (1)
54-55: 4) 라우팅 경로 일치(/university/search) 반영 확인했습니다.
- 요약: 새 페이지 구조와 일관되며, PageContent.tsx와도 동일 경로로 정리되었습니다.
관련 이슈
• resolves: #이슈 번호
작업 내용
• Post 상세 페이지에서 Setting 버튼이 보이지 않던 버그 수정
• 지원 목록 불러오기 실패 시 지원하기 페이지로 이동하도록 수정
• 지원 완료 페이지 UI 및 동작 수정
• 검색 페이지 레이아웃 및 동작 개선
• 로딩 스피너 위치 중앙 정렬 리팩터링
특이 사항
• 에러 핸들링 로직이 일부 변경되었으니, 예상치 못한 페이지 이동이 없는지 확인 필요
• 검색 페이지 구조가 바뀌어서 다른 페이지와의 연동 영향 여부 점검 필요
리뷰 요구사항
• 페이지 전환 및 리다이렉트 동작이 의도대로 잘 되는지 집중적으로 검토 부탁드립니다.
• UI 위치(스피너, 버튼 등)가 디자인 시안과 일치하는지 확인 부탁드립니다.