[FEAT] 동네 추천 코스 등록 지연 이미지 업로드 및 최종 등록 플로우 구현 - #186
Conversation
…ndation-draft-store
…at/local-recommendation-place-selection # Conflicts: # src/store/localRecommendation.store.ts
…at/local-recommendation-tag-selection
…cal-recommendation-tag-selection
…at/local-recommendation-visit-order-selection # Conflicts: # src/store/localRecommendation.store.ts
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
Next review available in: 22 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 (9)
📝 WalkthroughWalkthrough지역 추천 코스 등록 흐름이 실제 장소 검색, 태그·이미지 보류, 방문 순서 구성, 이미지 병렬 업로드, 코스 등록과 상세 페이지 이동을 사용하도록 변경되었습니다. Changes지역 추천 코스 등록
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant PlaceSelectionPage
participant usePlaceSearch
participant KakaoPlaces
participant LocalRecommendationStore
PlaceSelectionPage->>usePlaceSearch: 검색어 변경
usePlaceSearch->>KakaoPlaces: keywordSearch 호출
KakaoPlaces-->>usePlaceSearch: 장소 결과 반환
usePlaceSearch-->>PlaceSelectionPage: PlaceItem 목록 전달
PlaceSelectionPage->>LocalRecommendationStore: 장소와 pending 이미지 저장
sequenceDiagram
participant VisitOrderPage
participant useVisitOrderSelection
participant uploadCourseImages
participant buildCourseRequest
VisitOrderPage->>useVisitOrderSelection: 등록 요청
useVisitOrderSelection->>uploadCourseImages: 이미지 병렬 업로드
uploadCourseImages-->>useVisitOrderSelection: 이미지 키 반환
useVisitOrderSelection->>buildCourseRequest: 방문 이벤트와 이미지 키 전달
buildCourseRequest-->>useVisitOrderSelection: 코스 생성 요청 반환
useVisitOrderSelection-->>VisitOrderPage: courseId 반환
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/pages/local-recommendation/tag-selection/index.tsx (1)
101-127: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
handleComplete에 오류 처리가 없어 실패 시 재시도가 막힙니다.
submitError는 105행에서 빈 문자열로 초기화되는 것 외에는 전체 파일에서 채워지지 않습니다.handleComplete에는 try/catch가 없어,setTagSelection이나mapTagIdsToHashtagIds에서 예기치 않은 예외가 발생하면isSubmitting이true로 남아 제출 버튼이 영구히 비활성화됩니다.이는 PR 목표인 "등록 실패 시 입력값과 이미지를 유지해 재시도할 수 있도록 합니다"와 어긋납니다. 이 결함의 다운스트림 영향으로, 181-192행의 오류 메시지 UI도 실제로는 표시되지 않는 죽은 코드가 됩니다.
🔧 제안하는 수정 방향
- const handleComplete = () => { + const handleComplete = () => { if (!photo || !isReady || isSubmitting) return; setIsSubmitting(true); setSubmitError(''); - const hashtagIds = mapTagIdsToHashtagIds( - Array.from(selectedTagIds), - hashtags, - (tagId) => tagDefinitionMap[tagId]?.label - ); - - setTagSelection({ - tagIds: Array.from(selectedTagIds), - hashtagIds, - coverImageKey: null, - }); - - completeTagSelection({ - photo, - selectedTagIds, - photoKey: '', - hashtagIds, - onComplete, - navigate, - }); + try { + const hashtagIds = mapTagIdsToHashtagIds( + Array.from(selectedTagIds), + hashtags, + (tagId) => tagDefinitionMap[tagId]?.label + ); + + setTagSelection({ + tagIds: Array.from(selectedTagIds), + hashtagIds, + coverImageKey: null, + }); + + completeTagSelection({ + photo, + selectedTagIds, + photoKey: '', + hashtagIds, + onComplete, + navigate, + }); + } catch (error) { + setSubmitError('등록에 실패했습니다. 다시 시도해 주세요.'); + setIsSubmitting(false); + } };🤖 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/pages/local-recommendation/tag-selection/index.tsx` around lines 101 - 127, Update handleComplete to wrap the tag-mapping, setTagSelection, and completeTagSelection flow in try/catch; on any exception, restore isSubmitting to false and populate submitError with an appropriate failure message so the existing error UI appears and the user can retry without losing the selected input or photo.
🧹 Nitpick comments (5)
src/vite-env.d.ts (1)
53-70: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
src/types/kakao-maps.d.ts와 동일한 카카오 장소 검색 타입이 여기에도 선언되어 있습니다.
KakaoPlacesSearchResult,Places.keywordSearch,Status가src/types/kakao-maps.d.ts의Window.kakao.maps선언과 필드까지 동일하게 중복됩니다. 두 파일 중 하나로 소스를 일원화하세요.Also applies to: 79-91
🤖 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/vite-env.d.ts` around lines 53 - 70, Remove the duplicated Kakao Places declarations from the services namespace in src/vite-env.d.ts, including KakaoPlacesSearchResult usage, Places.keywordSearch, and Status, and rely on the existing canonical declarations in src/types/kakao-maps.d.ts instead.src/types/kakao-maps.d.ts (1)
8-55: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win카카오 장소 검색 SDK 타입이 두 파일에 중복 선언되어 있습니다.
KakaoPlacesSearchResult,Places.keywordSearch,Status가Window.kakao.maps(kakao-maps.d.ts)와 전역namespace kakao.maps(vite-env.d.ts)에 필드까지 동일하게 각각 선언되어 있습니다. 근본 원인은 동일한 외부 API 표면을 한곳에서 관리하지 않는 것입니다.
src/types/kakao-maps.d.ts#L8-L55: 이 파일을 카카오 장소 검색 타입의 단일 소스로 유지하세요. 실제 소비 코드(placeSearch.ts)가 이 선언(Window.kakao.maps.services)을 사용합니다.src/vite-env.d.ts#L53-L91: 중복된KakaoPlacesSearchResult,Places.keywordSearch,Status선언을 제거하고, 필요하면src/types/kakao-maps.d.ts의 타입을 재사용하도록 정리하세요.🤖 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/types/kakao-maps.d.ts` around lines 8 - 55, Keep src/types/kakao-maps.d.ts lines 8-55 as the single source for Kakao place-search types, including KakaoPlacesSearchResult, Places.keywordSearch, and Status. In src/vite-env.d.ts lines 53-91, remove the duplicate declarations and reuse the types from kakao-maps.d.ts where needed, preserving the existing Window.kakao.maps.services consumer contract.tests/place-search.test.ts (1)
20-45: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
searchPlaces의 상태 분기 테스트가 없습니다.
mapKakaoPlaceToItem만 테스트되고,searchPlaces의OK/ZERO_RESULT/오류 상태 분기와 SDK 로드 실패 경로는 테스트되지 않습니다. 이 로직이 이번 레이어의 핵심 신규 동작입니다.
window.kakao.maps.services.Places와Status를 목(mock)으로 만들어 세 가지 분기를 검증하는 테스트를 추가하세요.🤖 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 `@tests/place-search.test.ts` around lines 20 - 45, searchPlaces의 핵심 상태 분기와 SDK 로드 실패 경로에 대한 테스트를 추가하세요. window.kakao.maps.services.Places와 Status를 목으로 구성하고 OK, ZERO_RESULT, 오류 상태에서 각각의 반환 동작을 검증하며, SDK 로드 실패 시의 처리도 확인하세요. 기존 mapKakaoPlaceToItem 테스트는 유지하세요.src/apis/files.ts (1)
71-78: 🩺 Stability & Availability | 🔵 Trivial부분 업로드 실패 후 재시도 시 고아 오브젝트가 누적될 수 있습니다.
uploadCourseImages는 모든 파일을Promise.all로 병렬 업로드합니다. 배치 중 하나라도 실패하면 이미 성공한 업로드는 되돌리지 않습니다.useVisitOrderSelection.handleRegister는 실패 시 초안과 대기 이미지를 유지해 재시도를 허용합니다. 사용자가 재시도하면 이전에 성공한 파일도 다시 업로드되어 새 오브젝트 키가 생성됩니다. 이전 업로드는 참조가 끊긴 채 스토리지에 남습니다.스토리지 쪽에 미참조 오브젝트 정리 정책(TTL, 배치 정리 작업 등)을 두는 것을 검토하십시오.
🤖 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/apis/files.ts` around lines 71 - 78, Review the upload flow around uploadCourseImages and useVisitOrderSelection.handleRegister to add a storage-side cleanup policy for orphaned objects created by failed or retried batches, such as an appropriate TTL or scheduled batch cleanup. Ensure objects uploaded before a partial failure and replaced during retry are eventually removed without affecting successfully referenced uploads.src/pages/local-recommendation/visit-order-selection/buildCourseRequest.ts (1)
8-36: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win매핑 테이블 키를
basicInfo의 실제 리터럴 타입으로 좁히십시오.
DURATION_TYPE_MAP,TRANSPORT_TYPE_MAP,COMPANION_TYPE_MAP은Record<string, ...>로 선언되어 있습니다. 키 타입이string이므로basicInfo.duration등의 실제 값이 매핑 테이블에 없는 키라도 컴파일러가 감지하지 못합니다. 키 타입을basicInfo.duration등의 실제 유니언 타입으로 좁히면, 값 집합이 바뀔 때 누락된 매핑을 컴파일 시점에 발견할 수 있습니다.🤖 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/pages/local-recommendation/visit-order-selection/buildCourseRequest.ts` around lines 8 - 36, Update DURATION_TYPE_MAP, TRANSPORT_TYPE_MAP, and COMPANION_TYPE_MAP to use the corresponding basicInfo.duration, basicInfo.transport, and basicInfo.companion literal union types as their key types instead of string, while preserving the existing mapped values and enabling compile-time detection of missing keys.
🤖 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/pages/local-recommendation/place-selection/hooks/usePlaceSearch.ts`:
- Around line 50-60: Update setQuery so setIsLoading(true) runs only when
nextQuery differs from the current query state; preserve the existing
empty-query reset behavior and avoid marking loading for repeated submissions
that do not trigger the useEffect search flow.
In `@src/pages/local-recommendation/tag-selection/index.tsx`:
- Around line 59-74: Update the hashtag-loading flow around useEffect and
handleComplete so submission cannot map tags while fetchHashtags is still
pending. Track or reuse the fetch promise and have handleComplete await its
completion before calling mapTagIdsToHashtagIds with the loaded hashtags, while
preserving the existing behavior when the request fails.
In `@src/pages/local-recommendation/visit-order-selection/buildCourseRequest.ts`:
- Around line 63-91: Update buildCourseRequest to resolve the duration,
transport, and companion values from DURATION_TYPE_MAP, TRANSPORT_TYPE_MAP, and
COMPANION_TYPE_MAP before constructing the request; return null if any mapped
value is undefined, and reuse the validated results in the payload.
In
`@src/pages/local-recommendation/visit-order-selection/components/SubmitCourseButton.tsx`:
- Around line 27-32: Remove the minimum clamp from the fontSize property in
SubmitCourseButton’s style and calculate it directly as BUTTON_TEXT_SIZE
multiplied by scale. Keep the 44px minimum clamp on height unchanged.
---
Outside diff comments:
In `@src/pages/local-recommendation/tag-selection/index.tsx`:
- Around line 101-127: Update handleComplete to wrap the tag-mapping,
setTagSelection, and completeTagSelection flow in try/catch; on any exception,
restore isSubmitting to false and populate submitError with an appropriate
failure message so the existing error UI appears and the user can retry without
losing the selected input or photo.
---
Nitpick comments:
In `@src/apis/files.ts`:
- Around line 71-78: Review the upload flow around uploadCourseImages and
useVisitOrderSelection.handleRegister to add a storage-side cleanup policy for
orphaned objects created by failed or retried batches, such as an appropriate
TTL or scheduled batch cleanup. Ensure objects uploaded before a partial failure
and replaced during retry are eventually removed without affecting successfully
referenced uploads.
In `@src/pages/local-recommendation/visit-order-selection/buildCourseRequest.ts`:
- Around line 8-36: Update DURATION_TYPE_MAP, TRANSPORT_TYPE_MAP, and
COMPANION_TYPE_MAP to use the corresponding basicInfo.duration,
basicInfo.transport, and basicInfo.companion literal union types as their key
types instead of string, while preserving the existing mapped values and
enabling compile-time detection of missing keys.
In `@src/types/kakao-maps.d.ts`:
- Around line 8-55: Keep src/types/kakao-maps.d.ts lines 8-55 as the single
source for Kakao place-search types, including KakaoPlacesSearchResult,
Places.keywordSearch, and Status. In src/vite-env.d.ts lines 53-91, remove the
duplicate declarations and reuse the types from kakao-maps.d.ts where needed,
preserving the existing Window.kakao.maps.services consumer contract.
In `@src/vite-env.d.ts`:
- Around line 53-70: Remove the duplicated Kakao Places declarations from the
services namespace in src/vite-env.d.ts, including KakaoPlacesSearchResult
usage, Places.keywordSearch, and Status, and rely on the existing canonical
declarations in src/types/kakao-maps.d.ts instead.
In `@tests/place-search.test.ts`:
- Around line 20-45: searchPlaces의 핵심 상태 분기와 SDK 로드 실패 경로에 대한 테스트를 추가하세요.
window.kakao.maps.services.Places와 Status를 목으로 구성하고 OK, ZERO_RESULT, 오류 상태에서 각각의
반환 동작을 검증하며, SDK 로드 실패 시의 처리도 확인하세요. 기존 mapKakaoPlaceToItem 테스트는 유지하세요.
🪄 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: 9413ba47-3cce-44bc-a89b-1536269a687a
📒 Files selected for processing (30)
src/apis/files.tssrc/components/common/SearchBar.tsxsrc/components/kakaomap/utils/kakaoMap.tssrc/pages/local-recommendation/components/SelectionPageLayout.tsxsrc/pages/local-recommendation/place-selection/components/PlacePhotoModal.tsxsrc/pages/local-recommendation/place-selection/components/PlacePhotoUploader.tsxsrc/pages/local-recommendation/place-selection/components/PlaceSearchSection.tsxsrc/pages/local-recommendation/place-selection/components/SelectedPlaceSection.tsxsrc/pages/local-recommendation/place-selection/constants/referencePlaces.tssrc/pages/local-recommendation/place-selection/hooks/usePlaceSearch.tssrc/pages/local-recommendation/place-selection/hooks/useSelectedPlaces.tssrc/pages/local-recommendation/place-selection/index.tsxsrc/pages/local-recommendation/place-selection/placeSearch.tssrc/pages/local-recommendation/place-selection/types.tssrc/pages/local-recommendation/tag-selection/hashtagMapping.tssrc/pages/local-recommendation/tag-selection/index.tsxsrc/pages/local-recommendation/tag-selection/navigation.tssrc/pages/local-recommendation/tag-selection/types.tssrc/pages/local-recommendation/visit-order-selection/buildCourseRequest.tssrc/pages/local-recommendation/visit-order-selection/buildVisitEvents.tssrc/pages/local-recommendation/visit-order-selection/components/SubmitCourseButton.tsxsrc/pages/local-recommendation/visit-order-selection/constants.tssrc/pages/local-recommendation/visit-order-selection/hooks/useVisitOrderSelection.tssrc/pages/local-recommendation/visit-order-selection/index.tsxsrc/store/localRecommendation.store.tssrc/types/kakao-maps.d.tssrc/utils/imageCompression.tssrc/vite-env.d.tstests/place-search.test.tstests/tag-selection-navigation.test.ts
💤 Files with no reviewable changes (1)
- src/pages/local-recommendation/place-selection/constants/referencePlaces.ts
📜 Review details
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2026-07-26T17:09:23.387Z
Learnt from: KJun-2
Repo: yeogido/frontend PR: 125
File: src/pages/local-recommendation/course-basic-info/components/CompanionSelector.tsx:82-90
Timestamp: 2026-07-26T17:09:23.387Z
Learning: 이 프로젝트의 반응형 스케일 정책에서는 텍스트(폰트) 크기를 설계 기준 값에 전역 `scale`을 곱해 비율대로 스케일하세요. `12px`, `14px`처럼 특정 최소 하한을 강제로 적용하거나(클램프/바닥값) 임의의 픽셀 값으로 제한하지 마세요. 즉, 기준값(디자인 스펙) × `scale` 방식으로 계산해 비율이 유지되도록 구현합니다.
Applied to files:
src/pages/local-recommendation/place-selection/components/PlacePhotoModal.tsxsrc/pages/local-recommendation/place-selection/components/PlacePhotoUploader.tsxsrc/pages/local-recommendation/visit-order-selection/components/SubmitCourseButton.tsxsrc/pages/local-recommendation/visit-order-selection/index.tsxsrc/components/common/SearchBar.tsxsrc/pages/local-recommendation/place-selection/components/PlaceSearchSection.tsxsrc/pages/local-recommendation/place-selection/components/SelectedPlaceSection.tsxsrc/pages/local-recommendation/components/SelectionPageLayout.tsxsrc/pages/local-recommendation/place-selection/index.tsxsrc/pages/local-recommendation/tag-selection/index.tsx
📚 Learning: 2026-07-26T17:09:27.685Z
Learnt from: KJun-2
Repo: yeogido/frontend PR: 125
File: src/pages/local-recommendation/course-basic-info/components/TransportSelector.tsx:84-91
Timestamp: 2026-07-26T17:09:27.685Z
Learning: In this project’s 390px-based continuous responsive scaling, do not apply an artificial minimum lower bound to text sizes (e.g., avoid clamping via Math.max/min-font-size patterns). Instead, compute typography using proportional ratio scaling: render font sizes as `VALUE * scale` (for example, `DESCRIPTION_FONT_SIZE * scale`). During review, flag any code that enforces a hard minimum text size that breaks the intended proportional scaling.
Applied to files:
src/pages/local-recommendation/place-selection/components/PlacePhotoModal.tsxsrc/pages/local-recommendation/place-selection/components/PlacePhotoUploader.tsxsrc/pages/local-recommendation/visit-order-selection/components/SubmitCourseButton.tsxsrc/pages/local-recommendation/visit-order-selection/index.tsxsrc/components/common/SearchBar.tsxsrc/pages/local-recommendation/place-selection/components/PlaceSearchSection.tsxsrc/pages/local-recommendation/place-selection/components/SelectedPlaceSection.tsxsrc/pages/local-recommendation/components/SelectionPageLayout.tsxsrc/pages/local-recommendation/place-selection/index.tsxsrc/pages/local-recommendation/tag-selection/index.tsx
📚 Learning: 2026-07-26T17:09:32.991Z
Learnt from: KJun-2
Repo: yeogido/frontend PR: 125
File: src/pages/local-recommendation/tag-selection/components/KeywordSelectionSection.tsx:51-56
Timestamp: 2026-07-26T17:09:32.991Z
Learning: When implementing responsive scaling in this project, prefer direct proportional calculations (e.g., using `VALUE * scale`) without applying artificial minimum lower bounds (clamps) to text sizes or other visual dimensions. Only introduce a lower bound when there is an explicitly documented exception; the primary allowed example is enforcing a 44px minimum touch target for interactive elements. In review, flag new/minimum clamps for text/visual dimensions unless they match an explicitly documented exception.
Applied to files:
src/pages/local-recommendation/place-selection/components/PlacePhotoModal.tsxsrc/pages/local-recommendation/place-selection/components/PlacePhotoUploader.tsxsrc/pages/local-recommendation/visit-order-selection/components/SubmitCourseButton.tsxsrc/pages/local-recommendation/visit-order-selection/index.tsxsrc/components/common/SearchBar.tsxsrc/pages/local-recommendation/place-selection/components/PlaceSearchSection.tsxsrc/pages/local-recommendation/place-selection/components/SelectedPlaceSection.tsxsrc/pages/local-recommendation/components/SelectionPageLayout.tsxsrc/pages/local-recommendation/place-selection/index.tsxsrc/pages/local-recommendation/tag-selection/index.tsx
📚 Learning: 2026-07-26T17:09:40.303Z
Learnt from: KJun-2
Repo: yeogido/frontend PR: 125
File: src/pages/local-recommendation/tag-selection/components/RepresentativePhotoSection.tsx:107-122
Timestamp: 2026-07-26T17:09:40.303Z
Learning: yeogido/frontend의 반응형 스케일 정책에 맞춰, 텍스트를 포함한 UI 치수는 (디자인 기준값) × 전역 `scale`로 “연속적으로” 계산하고, 12px·14px 같은 최소 폰트/사이즈 하한(floor) 클램프를 적용하지 않는다. `scaleValue`를 쓰더라도 텍스트에 임의의 minimum floor를 추가하거나 `Math.max(value, 12/14)` 같은 보정을 넣지 말 것.
Applied to files:
src/pages/local-recommendation/place-selection/components/PlacePhotoModal.tsxsrc/pages/local-recommendation/place-selection/components/PlacePhotoUploader.tsxsrc/pages/local-recommendation/visit-order-selection/components/SubmitCourseButton.tsxsrc/pages/local-recommendation/visit-order-selection/index.tsxsrc/components/common/SearchBar.tsxsrc/pages/local-recommendation/place-selection/components/PlaceSearchSection.tsxsrc/pages/local-recommendation/place-selection/components/SelectedPlaceSection.tsxsrc/pages/local-recommendation/components/SelectionPageLayout.tsxsrc/pages/local-recommendation/place-selection/index.tsxsrc/pages/local-recommendation/tag-selection/index.tsx
🔇 Additional comments (28)
src/components/kakaomap/utils/kakaoMap.ts (1)
15-17: LGTM!Also applies to: 36-36, 89-89
src/pages/local-recommendation/place-selection/types.ts (1)
6-11: LGTM!src/pages/local-recommendation/place-selection/placeSearch.ts (1)
1-5: LGTM!Also applies to: 7-25, 27-58
src/pages/local-recommendation/place-selection/hooks/usePlaceSearch.ts (1)
1-6: LGTM!Also applies to: 14-48, 62-67
src/components/common/SearchBar.tsx (1)
27-27: LGTM!Also applies to: 38-38, 103-103, 174-176
src/pages/local-recommendation/components/SelectionPageLayout.tsx (1)
37-37: LGTM!Also applies to: 57-57, 131-131
src/pages/local-recommendation/place-selection/components/PlacePhotoUploader.tsx (1)
56-56: LGTM!tests/place-search.test.ts (1)
5-44: LGTM!Also applies to: 57-64
src/pages/local-recommendation/place-selection/components/PlaceSearchSection.tsx (1)
32-37: 🗄️ Data Integrity & Integration
onSearchChange와onQueryChange가 동일한 핸들러를 참조하는 부분을 확인하세요.
onSearchChange와onQueryChange에 동일한onSearchChange함수를 전달합니다.SelectionPageLayout이 동일한 사용자 입력에 대해 두 콜백을 모두 호출하면setQuery가 중복 실행됩니다.setQuery는 상태를 다시 같은 값으로 설정하므로 즉시 오류는 발생하지 않지만, 의도한 동작인지SelectionPageLayout의 구현을 확인해야 합니다.#!/bin/bash # Description: SelectionPageLayout에서 onQueryChange와 onSearchChange의 호출 시점을 확인합니다. fd -a 'SelectionPageLayout.tsx' | xargs -I{} rg -n -C6 'onQueryChange|onSearchChange' {}src/pages/local-recommendation/place-selection/components/PlacePhotoModal.tsx (1)
60-60: LGTM!src/utils/imageCompression.ts (1)
1-74: LGTM!src/store/localRecommendation.store.ts (3)
7-9: LGTM!Also applies to: 24-24
47-57: 🗄️ Data Integrity & Integration
pendingImages가 새로고침 후draft.places와 불일치할 수 있는지 확인하세요.
persist설정의partialize는draft만 localStorage에 저장하고pendingImages는 메모리에만 유지합니다. 사용자가 장소를 선택한 뒤 페이지를 새로고침하면draft.places는 복원되지만 해당 장소의pendingImages항목(원본 파일, 압축 파일, previewUrl)은 사라집니다.후속 단계에서
draft.places에 있는 장소를 실제 사진 업로드 대상으로 사용한다면, 새로고침 이후에는 업로드할 파일이 없는 상태로 코스 등록이 진행될 수 있습니다.visit-order-selection레이어에서 이 경우를 어떻게 처리하는지 확인해야 합니다.#!/bin/bash # Description: visit-order-selection 레이어에서 pendingImages 누락을 어떻게 처리하는지 확인합니다. fd -a 'buildCourseRequest.ts|useVisitOrderSelection.ts' | xargs -I{} rg -n -C6 'pendingImages|compressedFile|originalFile' {}Also applies to: 68-73, 93-93
164-224: LGTM!src/pages/local-recommendation/place-selection/hooks/useSelectedPlaces.ts (1)
3-87: LGTM!src/pages/local-recommendation/place-selection/components/SelectedPlaceSection.tsx (1)
5-42: LGTM!src/pages/local-recommendation/place-selection/index.tsx (1)
32-58: LGTM!src/pages/local-recommendation/tag-selection/index.tsx (3)
4-19: LGTM!Also applies to: 33-34
43-58: LGTM!Also applies to: 76-89
167-167: LGTM!Also applies to: 178-192
src/pages/local-recommendation/tag-selection/hashtagMapping.ts (1)
1-31: LGTM!src/pages/local-recommendation/tag-selection/navigation.ts (1)
6-33: 🗄️ Data Integrity & Integration
photoKey가 실제 업로드 키로 채워지는지 확인이 필요합니다.
CompleteTagSelectionOptions.photoKey의 주석은 "업로드 완료 후 얻은 대표 사진의 오브젝트 키"라고 설명합니다. 그러나 제공된 그래프 컨텍스트에 따르면tag-selection/index.tsx의 호출부는photoKey: ''처럼 빈 문자열을 그대로 전달합니다.completeTagSelection은 이 값을 검증 없이TagSelectionResult.photoKey에 전달합니다.최종 등록 단계(
useVisitOrderSelection.handleRegister)는coverImageKey를 별도로 계산해 덮어쓰므로, 현재는 이 값이 최종 요청에 영향을 주지 않을 수 있습니다. 하지만 문서 주석과 실제 값이 어긋나 있어 혼동을 줄 수 있습니다. 이 필드가 실제 업로드 키로 채워질 예정인지, 아니면 더 이상 필요 없는 필드인지 확인하십시오.#!/bin/bash # photoKey 사용처와 tag-selection/index.tsx 호출부를 확인합니다. fd -a 'index.tsx' src/pages/local-recommendation/tag-selection --exec rg -n -C6 'photoKey' rg -n -C3 'photoKey' --glob '*.ts' --glob '*.tsx'src/pages/local-recommendation/tag-selection/types.ts (1)
10-17: LGTM!tests/tag-selection-navigation.test.ts (1)
8-75: LGTM!src/pages/local-recommendation/visit-order-selection/buildVisitEvents.ts (1)
1-52: LGTM!src/pages/local-recommendation/visit-order-selection/constants.ts (1)
5-27: LGTM!src/pages/local-recommendation/visit-order-selection/hooks/useVisitOrderSelection.ts (1)
9-67: LGTM!Also applies to: 69-135, 146-147
src/pages/local-recommendation/visit-order-selection/index.tsx (1)
27-38: LGTM!Also applies to: 64-72



작업 내용
pendingImages메모리 전용 Zustand 상태에 원본 파일, 압축 파일, Object URL, 압축 Promise를 보관하도록 구성했습니다.pendingImages는persist의partialize에서 제외해 localStorage 직렬화 대상에 포함되지 않습니다.thumbnailKey와 각 장소의imageKey에 매핑합니다.변경 화면
/local-recommendation/tag-selection/local-recommendation/place-selection/local-recommendation/visit-order-selection확인 방법
/local-recommendation/tag-selection에서 대표 사진과 태그를 선택합니다./local-recommendation/place-selection에서 장소명을 입력합니다./local-recommendation/visit-order-selection에서 순서를 조정한 뒤 등록합니다.체크리스트
스크린샷
참고 사항
관련 이슈
Closes #185
Summary by CodeRabbit
새로운 기능
개선 사항