Home university search entry#520
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
Walkthrough이 PR은 홈 페이지 UI를 재구성하고 대학 검색 기능을 통합하며 인증 토큰 관리를 개선합니다:
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 05b595fe65
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
apps/web/src/components/layout/ReissueProvider/index.tsx (1)
19-20: 💤 Low valuesetter 호출 스타일을 한 가지로 통일하면 가독성이 더 좋아질 것 같아요.
라인 19에서 setter들을 구조 분해해두고도, 비동기 분기(라인 39/43/44/48/49)에서는 다시
useAuthStore.getState().setXxx(...)를 호출하고 있어 같은 동작을 두 가지 방식으로 부르는 모양새가 됩니다. Zustand 액션은 정체성이 안정적이라isMounted시점 이후에도 라인 19에서 캡처한 setter를 그대로 써도 안전합니다.♻️ 제안 변경(스타일 통일)
- const { accessToken, setInitialized, setLoading, setRefreshStatus, shouldAttemptRefresh } = - useAuthStore.getState(); + const { accessToken, clearAccessToken, setInitialized, setLoading, setRefreshStatus, shouldAttemptRefresh } = + useAuthStore.getState(); @@ - await postReissueToken(); - if (isMounted) { - useAuthStore.getState().setRefreshStatus("success"); - } - } catch { - if (isMounted) { - useAuthStore.getState().clearAccessToken(); - useAuthStore.getState().setRefreshStatus("failed"); - } - } finally { - if (isMounted) { - useAuthStore.getState().setLoading(false); - useAuthStore.getState().setInitialized(true); - } - } + await postReissueToken(); + if (isMounted) setRefreshStatus("success"); + } catch { + if (isMounted) { + clearAccessToken(); + setRefreshStatus("failed"); + } + } finally { + if (isMounted) { + setLoading(false); + setInitialized(true); + } + }Also applies to: 38-49
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/src/components/layout/ReissueProvider/index.tsx` around lines 19 - 20, 구조 분해로 이미 가져온 accessToken, setInitialized, setLoading, setRefreshStatus, shouldAttemptRefresh를 혼용하지 말고 하나의 스타일로 통일하세요: 비동기 분기 안에서도 useAuthStore.getState().setXxx(...) 대신 파일 상단에서 받은 setInitialized/setLoading/setRefreshStatus 같은 캡처된 함수들을 사용하도록 변경하면 됩니다; 특히 조건별 리프레시 로직에서 shouldAttemptRefresh와 isMounted 체크 후 호출되는 모든 setter 호출을 캡처된 셋터로 바꿔 일관성 있게 유지하세요.apps/web/src/app/(home)/_ui/UniversityList/_hooks/useHomeUniversityList.ts (1)
11-18: ⚡ Quick win
handleHomeUniversityChange를useCallback으로 감싸 정체성 안정화 권장합니다.현재 핸들러는 매 렌더마다 새 함수가 만들어져
setSelectedHomeUniversity로 노출되는 setter의 정체성이 매번 바뀝니다. 소비 측에서 이 setter를 의존성/memo키로 사용하면 불필요한 리렌더가 유발될 수 있습니다.♻️ 제안 변경
-import { type Dispatch, type SetStateAction, useMemo, useState } from "react"; +import { type Dispatch, type SetStateAction, useCallback, useMemo, useState } from "react"; @@ - const handleHomeUniversityChange: Dispatch<SetStateAction<string | null>> = (nextHomeUniversity) => { - setSelectedHomeUniversity((prevHomeUniversity) => { - const resolvedHomeUniversity = - typeof nextHomeUniversity === "function" ? nextHomeUniversity(prevHomeUniversity) : nextHomeUniversity; - - return resolvedHomeUniversity ?? ALL_HOME_UNIVERSITY_CHOICE; - }); - }; + const handleHomeUniversityChange: Dispatch<SetStateAction<string | null>> = useCallback((nextHomeUniversity) => { + setSelectedHomeUniversity((prevHomeUniversity) => { + const resolvedHomeUniversity = + typeof nextHomeUniversity === "function" ? nextHomeUniversity(prevHomeUniversity) : nextHomeUniversity; + + return resolvedHomeUniversity ?? ALL_HOME_UNIVERSITY_CHOICE; + }); + }, []);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/src/app/`(home)/_ui/UniversityList/_hooks/useHomeUniversityList.ts around lines 11 - 18, Wrap the handleHomeUniversityChange callback with React's useCallback to stabilize its identity: keep the same logic (resolving nextHomeUniversity against prevHomeUniversity and falling back to ALL_HOME_UNIVERSITY_CHOICE) but return a memoized function via useCallback and include setSelectedHomeUniversity (and any other external values like ALL_HOME_UNIVERSITY_CHOICE if not a true constant) in the dependency array so consumers depending on this handler or passing it to memoized children won't trigger unnecessary rerenders.apps/web/src/app/(home)/_ui/HomeUniversitySearchSection/index.tsx (1)
61-74: 💤 Low value국가 드롭다운 key prop 개선을 고려해보세요.
현재
key={index}를 사용하고 있는데, 배열이 안정적이고 재정렬이 없어 동작에는 문제가 없지만, React의 best practice로는 더 안정적인 고유 키를 사용하는 것이 권장됩니다. 예를 들어key={country-${index}}같은 형태로 개선할 수 있습니다.♻️ 제안하는 개선안
- {countryOptionsByIndex.map((countryOptions, index) => { + {countryOptionsByIndex.map((countryOptions, index) => { return ( <CustomDropdown - key={index} + key={`country-select-${index}`} value={countries[index]}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/src/app/`(home)/_ui/HomeUniversitySearchSection/index.tsx around lines 61 - 74, The map over countryOptionsByIndex in the HomeUniversitySearchSection uses a numeric index as the React key; change the key on the CustomDropdown inside that map to a more stable unique value (e.g., `country-${index}`) to avoid potential reconciliation bugs—update the key prop in the mapping callback where CustomDropdown is rendered (refer to countryOptionsByIndex.map, the CustomDropdown component, and the countries[index] usage) to use a deterministic string-based key instead of plain index.apps/web/src/app/(home)/_ui/HomeUniversitySearchSection/_hooks/useHomeUniversitySearch.ts (1)
46-53: 💤 Low value검색 제출 로직이 정확하게 구현되어 있습니다!
buildUniversitySearchQuery를 호출해 쿼리 문자열을 일관되게 생성합니다- 쿼리 파라미터가 있을 때만
?를 추가하는 조건부 처리가 적절합니다router.push로 클라이언트 사이드 네비게이션을 수행합니다참고로, Line 52의 템플릿 리터럴 중첩을 약간 단순화할 수도 있습니다:
const baseUrl = `/university/${selectedHomeUniversitySlug}`; router.push(queryString ? `${baseUrl}?${queryString}` : baseUrl);하지만 현재 코드도 충분히 읽기 쉬우므로 선택 사항입니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/src/app/`(home)/_ui/HomeUniversitySearchSection/_hooks/useHomeUniversitySearch.ts around lines 46 - 53, The submitSearch function currently builds queryString via buildUniversitySearchQuery and pushes a URL using a nested template literal; simplify by extracting the base path into a const (e.g., baseUrl = `/university/${selectedHomeUniversitySlug}`) and call router.push with a conditional that appends `?${queryString}` only when queryString is non-empty, keeping the existing behavior in submitSearch and using the same symbols (submitSearch, buildUniversitySearchQuery, selectedHomeUniversitySlug, queryString, router.push).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/web/src/app/`(home)/_ui/HomeActionLinks/index.tsx:
- Line 9: The Link in HomeActionLinks
(apps/web/src/app/(home)/_ui/HomeActionLinks/index.tsx) uses a non-existent
Tailwind class "h-26" so the height is ignored; fix by either adding "26":
"6.5rem" to the tailwind.config spacing, or replace "h-26" in the Link JSX with
an arbitrary value class "h-[6.5rem]", or change it to a standard spacing class
like "h-24" or "h-28" to match your design intent; update whichever approach you
choose and ensure the Link component's className reflects the chosen valid
height.
---
Nitpick comments:
In
`@apps/web/src/app/`(home)/_ui/HomeUniversitySearchSection/_hooks/useHomeUniversitySearch.ts:
- Around line 46-53: The submitSearch function currently builds queryString via
buildUniversitySearchQuery and pushes a URL using a nested template literal;
simplify by extracting the base path into a const (e.g., baseUrl =
`/university/${selectedHomeUniversitySlug}`) and call router.push with a
conditional that appends `?${queryString}` only when queryString is non-empty,
keeping the existing behavior in submitSearch and using the same symbols
(submitSearch, buildUniversitySearchQuery, selectedHomeUniversitySlug,
queryString, router.push).
In `@apps/web/src/app/`(home)/_ui/HomeUniversitySearchSection/index.tsx:
- Around line 61-74: The map over countryOptionsByIndex in the
HomeUniversitySearchSection uses a numeric index as the React key; change the
key on the CustomDropdown inside that map to a more stable unique value (e.g.,
`country-${index}`) to avoid potential reconciliation bugs—update the key prop
in the mapping callback where CustomDropdown is rendered (refer to
countryOptionsByIndex.map, the CustomDropdown component, and the
countries[index] usage) to use a deterministic string-based key instead of plain
index.
In `@apps/web/src/app/`(home)/_ui/UniversityList/_hooks/useHomeUniversityList.ts:
- Around line 11-18: Wrap the handleHomeUniversityChange callback with React's
useCallback to stabilize its identity: keep the same logic (resolving
nextHomeUniversity against prevHomeUniversity and falling back to
ALL_HOME_UNIVERSITY_CHOICE) but return a memoized function via useCallback and
include setSelectedHomeUniversity (and any other external values like
ALL_HOME_UNIVERSITY_CHOICE if not a true constant) in the dependency array so
consumers depending on this handler or passing it to memoized children won't
trigger unnecessary rerenders.
In `@apps/web/src/components/layout/ReissueProvider/index.tsx`:
- Around line 19-20: 구조 분해로 이미 가져온 accessToken, setInitialized, setLoading,
setRefreshStatus, shouldAttemptRefresh를 혼용하지 말고 하나의 스타일로 통일하세요: 비동기 분기 안에서도
useAuthStore.getState().setXxx(...) 대신 파일 상단에서 받은
setInitialized/setLoading/setRefreshStatus 같은 캡처된 함수들을 사용하도록 변경하면 됩니다; 특히 조건별
리프레시 로직에서 shouldAttemptRefresh와 isMounted 체크 후 호출되는 모든 setter 호출을 캡처된 셋터로 바꿔 일관성
있게 유지하세요.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 0015be42-8986-4841-ae33-02fba1bbd9e5
📒 Files selected for processing (19)
apps/web/src/app/(home)/_ui/HomeActionLinks/index.tsxapps/web/src/app/(home)/_ui/HomeEntrySection/index.tsxapps/web/src/app/(home)/_ui/HomeEntrySection/skeleton/index.tsxapps/web/src/app/(home)/_ui/HomeUniversitySearchSection/_hooks/useHomeUniversitySearch.tsapps/web/src/app/(home)/_ui/HomeUniversitySearchSection/index.tsxapps/web/src/app/(home)/_ui/UniversityList/_hooks/useHomeUniversityList.tsapps/web/src/app/(home)/_ui/UniversityList/_hooks/useRegionHandler.tsapps/web/src/app/(home)/_ui/UniversityList/index.tsxapps/web/src/app/(home)/page.tsxapps/web/src/app/layout.tsxapps/web/src/app/university/[homeUniversity]/search/_ui/SearchPageContent.tsxapps/web/src/app/university/score/submit/gpa/GpaSubmitForm.tsxapps/web/src/app/university/score/submit/language-test/LanguageTestSubmitForm.tsxapps/web/src/app/university/search/PageContent.tsxapps/web/src/components/layout/ReissueProvider.tsxapps/web/src/components/layout/ReissueProvider/index.tsxapps/web/src/components/search/CustomDropdown.tsxapps/web/src/lib/zustand/useAuthStore.tsapps/web/src/utils/universitySearchQuery.ts
💤 Files with no reviewable changes (1)
- apps/web/src/app/(home)/_ui/UniversityList/_hooks/useRegionHandler.ts
| return ( | ||
| <div className="flex flex-col gap-2.5 px-5 py-3.5"> | ||
| <div className="flex gap-2"> | ||
| <Link className="h-26 flex flex-1 flex-col gap-2 rounded-lg bg-bg-accent-blue p-2.5" href="/university/search"> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# tailwind config 및 인근 설정에서 spacing.26 / "26" 확장을 탐색
fd -H -e ts -e js -e cjs -e mjs 'tailwind\.config' --exec rg -nC2 -e '\b26\b' -e 'spacing' {}
# 추가로 글로벌 css 파일에서 h-26 정의 가능성 확인
rg -nP '\bh-26\b' --type=cssRepository: solid-connection/solid-connect-web
Length of output: 619
🏁 Script executed:
# tailwind.config에서 전체 spacing 섹션 확인
fd -H -e ts -e js -e cjs -e mjs 'tailwind\.config' --exec cat {} | head -400Repository: solid-connection/solid-connect-web
Length of output: 11541
🏁 Script executed:
# HomeActionLinks/index.tsx 파일 확인
cat apps/web/src/app/\(home\)/_ui/HomeActionLinks/index.tsxRepository: solid-connection/solid-connect-web
Length of output: 2278
🏁 Script executed:
# h-26 클래스가 프로젝트 전체에서 사용되는지 확인
rg 'h-26' --type ts --type tsx --type js --type jsxRepository: solid-connection/solid-connect-web
Length of output: 106
🏁 Script executed:
# Try rg with different approach for tsx files
rg 'h-26' --type-add 'tsx:*.tsx' --type tsxRepository: solid-connection/solid-connect-web
Length of output: 713
🏁 Script executed:
# Or simpler - just search for h-26 as plain text
rg 'h-26'Repository: solid-connection/solid-connect-web
Length of output: 713
h-26 클래스는 Tailwind 설정에 없어 높이가 적용되지 않습니다.
tailwind.config의 spacing 섹션을 확인한 결과, h-26이 정의되지 않았습니다. 현재 설정에는 "13", "6.5", "17.5" 등이 있지만 "26"은 없으므로, Tailwind는 이 클래스를 무시하고 카드의 높이가 의도와 다르게 렌더링됩니다.
다음 중 하나로 수정해 주세요:
spacing설정에"26": "6.5rem"을 추가 (기존"6.5"항목과 동일한 값)- 컴포넌트에서
h-26대신h-[6.5rem]임의값 사용 - 표준 값인
h-24또는h-28로 변경
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web/src/app/`(home)/_ui/HomeActionLinks/index.tsx at line 9, The Link in
HomeActionLinks (apps/web/src/app/(home)/_ui/HomeActionLinks/index.tsx) uses a
non-existent Tailwind class "h-26" so the height is ignored; fix by either
adding "26": "6.5rem" to the tailwind.config spacing, or replace "h-26" in the
Link JSX with an arbitrary value class "h-[6.5rem]", or change it to a standard
spacing class like "h-24" or "h-28" to match your design intent; update
whichever approach you choose and ensure the Link component's className reflects
the chosen valid height.
There was a problem hiding this comment.
야 근데 이거 우리 원래 있던 코드 옮긴 건데 원래는 그럼 h-26이 동작을 안 했을테니까 그냥 없앤다??
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 원래 코드 위치 찾기 - h-26 클래스가 있던 기존 파일 탐색
rg 'h-26' --context 5
# git log로 h-26 관련 이전 파일 히스토리 확인
git log --oneline --all --follow -- "apps/web/src/app/(home)/page.tsx" | head -5
git show HEAD~1:"apps/web/src/app/(home)/page.tsx" 2>/dev/null | grep -n 'h-26' || echo "h-26 not in previous page.tsx"
Length of output: 4392
@yoonc01, 이전 page.tsx를 확인해봤는데요! 결과가 좀 다릅니다. 😊
-
h-26은 기존page.tsx에 없었습니다.git show HEAD~1:"apps/web/src/app/(home)/page.tsx"결과:h-26 not in previous page.tsx- 즉, 이번 PR에서
HomeActionLinks를 새로 만들면서 처음 추가된 클래스입니다.
-
Tailwind 기본 스케일과 프로젝트 설정 모두에
h-26이 없습니다.- Tailwind 기본 spacing은
h-24→h-28순으로 건너뜁니다 (26없음). - 프로젝트
tailwind.config에도"26"항목이 정의되어 있지 않습니다.
- Tailwind 기본 spacing은
-
처리 방향 제안
- 그냥 제거: flex 레이아웃(flex-col + gap-2 + content)이 카드 높이를 자연스럽게 결정하므로, 제거해도 레이아웃 자체는 깨지지 않습니다.
- 고정 높이가 필요하다면: 디자인 의도에 맞게
h-24(6rem) 또는h-[6.5rem]중 하나로 교체하는 것이 좋습니다.
원래부터 동작하지 않던 클래스이므로, 제거 또는 유효한 값으로 교체 중 디자인 의도에 맞는 방향을 선택하시면 됩니다! 🐇
There was a problem hiding this comment.
기존 apps/web/src/app/(home)/page.tsx 여기에 있었잖아 다시 확인해봐
There was a problem hiding this comment.
🧩 Analysis chain
기존 파일에서 h-26이 실제로 있었는지 더 깊이 확인해볼게요!
🏁 Script executed:
#!/bin/bash
# Git 로그에서 page.tsx 관련 커밋 히스토리 확인
git log --oneline -- "apps/web/src/app/(home)/page.tsx" | head -10
# 여러 이전 커밋들에서 h-26 확인
for i in 1 2 3 4 5; do
echo "=== HEAD~$i ==="
git show HEAD~$i:"apps/web/src/app/(home)/page.tsx" 2>/dev/null | grep -n 'h-26' || echo "h-26 not found"
done
# main 브랜치 기준으로 확인
git show origin/main:"apps/web/src/app/(home)/page.tsx" 2>/dev/null | grep -n 'h-26' || echo "h-26 not in origin/main"
# PR의 base 커밋 확인
git merge-base HEAD origin/main 2>/dev/null | xargs -I{} git show {}:"apps/web/src/app/(home)/page.tsx" 2>/dev/null | grep -n 'h-26' || echo "h-26 not in base commit"
Length of output: 1602
@yoonc01, 죄송합니다! 맞습니다, 기존 page.tsx에 있었네요. 😅
확인 결과 정리:
-
기존 코드 확인 ✅
HEAD~5기준 원래page.tsx의 91, 103, 117, 129번 줄에h-26이 실제로 존재했습니다.- 이번 PR에서
HomeActionLinks/index.tsx로 이동된 것이 맞습니다.
-
그런데 원래도 동작하지 않았습니다 ❌
- Tailwind 기본 spacing 스케일:
h-24→ 26 없음 →h-28 - 프로젝트
tailwind.config에도"26"키가 정의되어 있지 않습니다. - 즉, 기존
page.tsx에서도 이 클래스는 무시되고 있었던 상태입니다.
- Tailwind 기본 spacing 스케일:
-
처리 방향 제안
- 제거 (추천):
flex-col gap-2와 내용물로 높이가 자연스럽게 결정되므로 제거해도 레이아웃이 깨지지 않습니다. - 유효한 값으로 교체: 디자인 의도에 고정 높이가 필요하다면
h-[6.5rem]또는h-24/h-28중 선택하시면 됩니다.
- 제거 (추천):
그냥 없애는 방향이 맞을 것 같습니다! 🐇
(\_/)
(•ᴗ•)
/ >🔍 아, 제가 틀렸네요...
작업 내용
비로그인 홈 화면 학교 검색 진입점 추가
학교 검색하기흐름으로 교체했습니다.홈 학교 검색 조건 구성
전체 학교 리스트 필터 변경
전체 + 학교별chip 필터로 변경했습니다.더보기이동 경로가 함께 바뀌도록 했습니다.전체상태로 정규화되도록 처리했습니다.인증 재발급 초기화 처리
ReissueProvider를 연결해 만료된 access token이 있는 사용자가 refresh token으로 세션을 복구할 수 있도록 했습니다./auth/reissue요청이 발생하지 않도록, 저장된 로그인 흔적이 있는 경우에만 reissue를 시도하도록 했습니다.특이 사항
refresh token 쿠키는 살아 있지만 localStorage의 auth-storage만 삭제된 사용자는 세션 복구를 시도하지 않습니다. 익명 공개 페이지 트래픽에서 불필요한 reissue 요청을 줄이기 위한 의도적인 트레이드오프입니다.