[feat] 알바찾기 행정구역 UI구현 및 API 연동 - #59
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
Next review available in: 33 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthrough공고 목록에 지역·정렬·급여 필터와 응답 정규화가 추가되었습니다. 즐겨찾기 저장·해제 API와 낙관적 토글이 구현되었으며, 스크랩 목록 페이지·카드·해제 모달·마이페이지 메뉴·라우트가 연결되었습니다. Changes공고 필터와 API
스크랩 목록 페이지
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ 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.
Actionable comments posted: 4
🤖 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 `@src/features/job-lookup-map/api/posting.ts`:
- Around line 38-40: Validate the response array and every posting item against
the established posting schema before assigning data in the posting lookup flow
at src/features/job-lookup-map/api/posting.ts lines 38-40; throw on missing,
non-array, or invalid data instead of defaulting to an empty list. Apply the
same array and scrap-item schema validation in the scrap lookup flow at
src/features/job-lookup-map/api/posting.ts lines 176-178, also propagating an
exception for invalid responses.
- Around line 49-54: Normalize empty-string cursors to null in both cursor
mappings at src/features/job-lookup-map/api/posting.ts lines 49-54 and 187-192,
covering the fetchPostings and fetchFavoritePostings paths. Preserve existing
string conversion for non-empty values and null handling for absent cursors.
In `@src/features/job-lookup-map/common/SalarySelectDrawer.tsx`:
- Around line 68-71: Update handleApply in SalarySelectDrawer so it validates
the draft salary range before calling onApply: when both values are present and
min exceeds max, prevent applying and keep the drawer open (or use the existing
validation behavior). Preserve normal application and closing for valid ranges.
In `@src/pages/my/index.tsx`:
- Around line 28-33: Update the MENU_ITEMS rendering in src/pages/my/index.tsx
so the ‘스크랩한 알바’ entry identified by ROUTES.MY.SCRAPPED_POSTINGS is included
only when the current scope is USER. Preserve all other menu items and their
existing rendering behavior.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: c1adf905-2e30-414d-b4c3-b523bf954213
📒 Files selected for processing (25)
src/app/App.tsxsrc/features/job-lookup-map/api/posting.tssrc/features/job-lookup-map/common/AlbaFindCategoryBar.tsxsrc/features/job-lookup-map/common/Albabox.tsxsrc/features/job-lookup-map/common/FilterDrawerShell.tsxsrc/features/job-lookup-map/common/RegionSelectDrawer.tsxsrc/features/job-lookup-map/common/SalarySelectDrawer.tsxsrc/features/job-lookup-map/common/SortSelectDrawer.tsxsrc/features/job-lookup-map/hooks/useAddFavoritePosting.tssrc/features/job-lookup-map/hooks/usePosting.tssrc/features/job-lookup-map/hooks/usePostingFilterOptions.tssrc/features/job-lookup-map/hooks/useRemoveFavoritePosting.tssrc/features/job-lookup-map/hooks/useScrappedPostings.tssrc/features/job-lookup-map/hooks/useToggleFavoritePosting.tssrc/features/job-lookup-map/lib/postingFilters.tssrc/features/job-lookup-map/lib/postingToAlbaboxProps.tssrc/features/job-lookup-map/lib/regionOptions.tssrc/features/job-lookup-map/types/posting.tssrc/pages/my/components/MenuListItem.tsxsrc/pages/my/index.tsxsrc/pages/my/scrapped/components/ScrappedPostingCard.tsxsrc/pages/my/scrapped/index.tsxsrc/pages/user/job-lookup-map-detail/index.tsxsrc/pages/user/job-lookup-map/index.tsxsrc/shared/constants/routes.ts
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/features/job-lookup-map/common/RegionSelectDrawer.tsx (1)
118-128: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value'전체' 라벨 문자열을 분기 키로 쓰는 대신
option.code == null을 쓰는 편이 안전합니다.서버 주소 데이터에 동일 이름이 내려오면 오분기하고, 라벨 문구 변경 시
regionOptions.ts와 이 파일이 함께 깨집니다. sentinel 옵션은code: null로 구분되니 그 조건으로 판정하세요.🤖 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 `@src/features/job-lookup-map/common/RegionSelectDrawer.tsx` around lines 118 - 128, In the sigungu branch of RegionSelectDrawer, replace the option.name === '전체' discriminator with a null-code check using option.code == null. Keep the existing draft reset behavior unchanged for the sentinel option and allow named regions with non-null codes to follow the normal path.
🤖 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 `@src/features/job-lookup-map/api/posting.ts`:
- Around line 76-81: Strengthen the keywords and schedules normalization in the
posting mapping logic so each array element is validated against the required
Keyword or Schedule fields before inclusion. Keep only elements with the
expected shapes, drop malformed entries, and avoid asserting the entire API
array directly to the domain types.
In `@src/features/job-lookup-map/common/RegionSelectDrawer.tsx`:
- Around line 98-103: Update handleSelect’s 전국(전체) branch and the related
canApply logic so selecting 전국, which clears the region filter via
EMPTY_REGION_SELECTION, remains applicable instead of disabling the Apply
button. Preserve the existing formatRegionLabel behavior and ensure normal
sido/sigungu/dong selections still require a complete region selection.
In `@src/features/job-lookup-map/hooks/useAddresses.ts`:
- Around line 5-18: Update useAddresses so its isLoading value represents active
fetching rather than disabled-query pending state, using the React Query v5
loading condition (isPending && isFetching) or an equivalent enabled-aware
check. Keep the existing addresses, fetching, error, and refetch behavior
unchanged.
---
Nitpick comments:
In `@src/features/job-lookup-map/common/RegionSelectDrawer.tsx`:
- Around line 118-128: In the sigungu branch of RegionSelectDrawer, replace the
option.name === '전체' discriminator with a null-code check using option.code ==
null. Keep the existing draft reset behavior unchanged for the sentinel option
and allow named regions with non-null codes to follow the normal path.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: c8cc0635-cc12-4941-8b42-b59178f79c60
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (10)
src/features/job-lookup-map/api/posting.tssrc/features/job-lookup-map/common/AlbaFindCategoryBar.tsxsrc/features/job-lookup-map/common/RegionSelectDrawer.tsxsrc/features/job-lookup-map/common/SalarySelectDrawer.tsxsrc/features/job-lookup-map/common/SortSelectDrawer.tsxsrc/features/job-lookup-map/hooks/useAddresses.tssrc/features/job-lookup-map/lib/regionOptions.tssrc/features/job-lookup-map/types/posting.tssrc/pages/my/index.tsxsrc/pages/user/job-lookup-map/index.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
- src/features/job-lookup-map/common/SalarySelectDrawer.tsx
- src/pages/user/job-lookup-map/index.tsx
- src/features/job-lookup-map/common/AlbaFindCategoryBar.tsx
| keywords: Array.isArray(record.keywords) | ||
| ? (record.keywords as PostingListResponse['data'][number]['keywords']) | ||
| : [], | ||
| schedules: Array.isArray(record.schedules) | ||
| ? (record.schedules as PostingListResponse['data'][number]['schedules']) | ||
| : [], |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# keywords/schedules 소비 지점 확인
rg -nP --type=tsx --type=ts -C3 '\b(keywords|schedules)\b' src/features/job-lookup-map src/pages/user | head -80Repository: alter-app/alter-client
Length of output: 192
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files | rg '(^src/features/job-lookup-map|src/pages/user)' | sed -n '1,120p'
echo "== api posting outline and relevant lines =="
if [ -f src/features/job-lookup-map/api/posting.ts ]; then
ast-grep outline src/features/job-lookup-map/api/posting.ts --view compact || true
sed -n '1,180p' src/features/job-lookup-map/api/posting.ts
fi
echo "== keyword/schedule usage =="
rg -n -C 4 -g '*.ts' -g '*.tsx' '\b(keywords|schedules)\b' src/features/job-lookup-map src/pages/user | sed -n '1,220p'Repository: alter-app/alter-client
Length of output: 17199
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== posting types =="
sed -n '1,80p' src/features/job-lookup-map/types/posting.ts
echo "== albabox props conversion =="
sed -n '1,130p' src/features/job-lookup-map/lib/postingToAlbaboxProps.ts
echo "== all map/list keyword usage =="
rg -n -C 3 -g '*.ts' -g '*.tsx' '\bkeywords\b' src/features/job-lookup-map src/pages/user/job-lookup-map src/pages/user/job-lookup-map-apply | sed -n '1,180p'
echo "== detailed schedule keyword-like usage =="
rg -n -C 3 -g '*.ts' -g '*.tsx' 'keywords|position|workingDays|startTime|endTime|id' src/pages/user/job-lookup-map-apply/index.tsx | sed -n '1,180p'Repository: alter-app/alter-client
Length of output: 9428
keywords/schedules 배열 요소를 안전하게 정규화하세요.
현재는 Array.isArray 만 통과하면 그대로 도메인 타입으로 단언해서, API 요소가 Keyword/Schedule과 다른 형태일 때 카드 렌더(name, id, workingDays, startTime 등)에서 런타임 오류가 발생할 수 있습니다. 각 요소별로 필요 필드를 검사하고 정상 요소만 유지하거나 불량 요소는 드롭하도록 파싱을 강화하세요.
🤖 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 `@src/features/job-lookup-map/api/posting.ts` around lines 76 - 81, Strengthen
the keywords and schedules normalization in the posting mapping logic so each
array element is validated against the required Keyword or Schedule fields
before inclusion. Keep only elements with the expected shapes, drop malformed
entries, and avoid asserting the entire API array directly to the domain types.
| const handleSelect = (option: RegionOption) => { | ||
| if (step === 'sido') { | ||
| if (option.name === '전국(전체)') { | ||
| setDraft(EMPTY_REGION_SELECTION) | ||
| return | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
'전국(전체)'를 고르면 적용 버튼이 영구 비활성 — 지역 필터를 해제할 수 없습니다.
option.name === '전국(전체)'일 때 draft를 EMPTY_REGION_SELECTION으로 되돌리는데, canApply는 isRegionSelectionComplete(draft)(sido/sigungu/dong 모두 non-null)라서 그 즉시 false가 됩니다. 결과적으로 사용자가 전국(=필터 해제)을 선택해 적용하는 경로가 막힙니다. 전국 선택을 별도 상태로 표시하고 적용을 허용하거나, sigungu/dong을 '전체'로 채워 완결 상태로 만드세요.
🐛 예시 수정
if (option.name === '전국(전체)') {
- setDraft(EMPTY_REGION_SELECTION)
+ setDraft({
+ ...EMPTY_REGION_SELECTION,
+ sido: '전국(전체)',
+ sigungu: '전체',
+ dong: '전체',
+ })
return
}formatRegionLabel이 sido === '전국(전체)'를 '지역 선택'으로 되돌리므로 라벨 표기도 그대로 유지됩니다.
📝 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 handleSelect = (option: RegionOption) => { | |
| if (step === 'sido') { | |
| if (option.name === '전국(전체)') { | |
| setDraft(EMPTY_REGION_SELECTION) | |
| return | |
| } | |
| const handleSelect = (option: RegionOption) => { | |
| if (step === 'sido') { | |
| if (option.name === '전국(전체)') { | |
| setDraft({ | |
| ...EMPTY_REGION_SELECTION, | |
| sido: '전국(전체)', | |
| sigungu: '전체', | |
| dong: '전체', | |
| }) | |
| return | |
| } |
🤖 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 `@src/features/job-lookup-map/common/RegionSelectDrawer.tsx` around lines 98 -
103, Update handleSelect’s 전국(전체) branch and the related canApply logic so
selecting 전국, which clears the region filter via EMPTY_REGION_SELECTION, remains
applicable instead of disabling the Apply button. Preserve the existing
formatRegionLabel behavior and ensure normal sido/sigungu/dong selections still
require a complete region selection.
| export function useAddresses(code?: string, enabled = true) { | ||
| const { data, isPending, isError, isFetching, refetch } = useQuery({ | ||
| queryKey: ['jobLookupMap', 'addresses', code ?? 'root'] as const, | ||
| queryFn: () => fetchAddresses(code), | ||
| enabled, | ||
| }) | ||
|
|
||
| return { | ||
| addresses: data ?? [], | ||
| isLoading: isPending, | ||
| isFetching, | ||
| isError, | ||
| refetch, | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
TanStack Query v5 isPending vs isLoading when enabled false
💡 Result:
In TanStack Query v5, isPending and isLoading behave differently when a query is disabled (enabled: false), primarily because they track different states of the query lifecycle [1][2]. isPending isPending is a derived boolean from the query status [2]. It is true whenever the query has no data [3]. If a query is disabled and has no cached data, it will start in the pending status [1][4]. Therefore, when enabled is false and there is no cached data, isPending will be true, even though the query is not currently fetching [4]. It indicates that the query is in an initial state and lacks data, not necessarily that it is actively loading [1][3]. isLoading isLoading is a derived boolean specifically representing the initial loading state [2][5]. It is calculated as isPending && isFetching [1][5]. Because isFetching is false when a query is disabled (as the query function is not executing), isLoading will be false when enabled is false [1][6]. Summary of differences: - isPending: True if the query has no data, regardless of whether it is currently fetching [4][3]. When disabled and lacking data, it is true [1][4]. - isLoading: True only if the query is both in the pending state and actively fetching data [1][5]. When disabled, it is always false because the query is not fetching [1][6]. For most scenarios, the documentation recommends using isPending for state management because it provides reliable TypeScript type-narrowing (guaranteeing that data is undefined while pending) [3][7]. However, if you specifically need a flag to trigger a loading spinner for a query that might be disabled or lazy, isLoading is the appropriate choice, as it will remain false when the query is not actively fetching [1].
Citations:
- 1: https://tanstack.com/query/v5/docs/framework/react/guides/disabling-queries
- 2: https://tanstack.com/query/v5/docs/framework/react/reference/useQuery
- 3: https://tanstack.com/query/v5/docs/framework/react/guides/queries
- 4: isPending true even when query is not enabled TanStack/query#7329
- 5: https://tanstack.com/query/v5/docs/framework/react/guides/migrating-to-v5
- 6: useQuery enabled not working as expected TanStack/query#6461
- 7: Why do the docs recommend `isPending` instead of `isLoading`? TanStack/query#6297
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== files =="
fd -a 'useAddresses\.ts|RegionSelectDrawer|package\.json' . | sed 's#^\./##'
echo
echo "== useAddresses outline/contents =="
file="$(fd 'useAddresses\.ts' . | head -n 1 || true)"
if [ -n "${file:-}" ]; then
wc -l "$file"
cat -n "$file"
fi
echo
echo "== package react-query version =="
if [ -f package.json ]; then
node -e 'const p=require("./package.json"); console.log(JSON.stringify({dep:p.dependencies,`@tanstack`:p.dependencies?["`@tanstack/react-query`"]:null,dev:p.devDependencies?["`@tanstack/react-query`"]:null},null,2))'
fi
echo
echo "== usages of useAddresses / addressesEnabled / isLoading =="
rg -n "useAddresses|addressesEnabled|isLoading|RegionSelectDrawer" src package.json 2>/dev/null || trueRepository: alter-app/alter-client
Length of output: 1784
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== files =="
fd -a 'useAddresses\.ts|RegionSelectDrawer|package\.json' . | sed 's#^\./##'
echo
echo "== useAddresses outline/contents =="
file="$(fd 'useAddresses\.ts' . | head -n 1 || true)"
if [ -n "${file:-}" ]; then
wc -l "$file"
cat -n "$file"
fi
echo
echo "== package react-query version =="
if [ -f package.json ]; then
node -e 'const p=require("./package.json"); console.log(JSON.stringify({dep:p.dependencies["`@tanstack/react-query`"],dev:p.devDependencies["`@tanstack/react-query`"]}, null, 2))'
fi
echo
echo "== usages of useAddresses / addressesEnabled / isLoading =="
rg -n "useAddresses|addressesEnabled|isLoading|RegionSelectDrawer" src package.json 2>/dev/null || trueRepository: alter-app/alter-client
Length of output: 14108
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== RegionSelectDrawer relevant sections =="
sed -n '60,95p;220,255p;305,325p' src/features/job-lookup-map/common/RegionSelectDrawer.tsx | cat -n
echo
echo "== TanStack Query v5 package API snippets in node_modules if present =="
if [ -d node_modules/@tanstack/react-query ]; then
rg -n "function isLoading|isLoading\\s*=|isPending|isFetching" node_modules/@tanstack/react-query -g '*.js' -g '*.mjs' -g '*.cjs' -g '*.d.ts' | head -n 40
else
echo "node_modules/@tanstack/react-query not present"
fiRepository: alter-app/alter-client
Length of output: 3828
isLoading은 활성 클라이언트 상태와 맞아야 합니다.
enabled: false로 쿼리를 비활성화하는 단계에서도 isPending은 없으면 계속 true므로, RegionSelectDrawer가 isLoading ? "지역 정보를 불러오는 중…"을 보여준 뒤 선택 옵션을 표시하지 못할 수 있습니다. v5의 isLoading(isPending && isFetching)을 쓰거나, isPending 노출 시 호출부에서 enabled && status === 'pending' == true처럼 활성 로딩 조건을 맞춰주세요.
🤖 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 `@src/features/job-lookup-map/hooks/useAddresses.ts` around lines 5 - 18,
Update useAddresses so its isLoading value represents active fetching rather
than disabled-query pending state, using the React Query v5 loading condition
(isPending && isFetching) or an equivalent enabled-aware check. Keep the
existing addresses, fetching, error, and refetch behavior unchanged.
There was a problem hiding this comment.
이 훅 쓰는 곳 없는 것 같은데 무엇을 위해 작성된 훅일까요
ID
변경 내용
구현 사항
알바 찾기 필터
GET /app/postings/filter-options,GET /app/postings쿼리 파라미터 연동스크랩
스크랩한 알바메뉴 추가 (알바생만 노출)GET /app/users/me/postings/favorites목록 조회 및 카드 UIPOST/DELETE /app/users/me/postings/favorites/{postingId}스크랩을 해제할까요?) 후 DELETE 호출구현 시연 (필요 시)
2026-07-22.3.14.56.mov
참고 사항 (필요 시)
(예: 확인 사항, 참조 링크 등)
Summary by CodeRabbit