feat : 노래 검색 및 곡 선택 플로우 구현 - #58
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthrough곡 목업 데이터와 프리뷰 유틸을 추가하고, 곡 목록·상세 페이지 및 라우트를 구현했습니다. 곡 선택 BottomSheet의 풀페이지 확장 API와 관련 카드 UI도 변경했습니다. Changes곡 등록 흐름
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant SongListPage
participant SongDetailPage
participant SongSelectSheet
participant BottomSheet
User->>SongListPage: 곡 카드 선택
SongListPage->>SongDetailPage: 상세 경로로 이동
User->>SongDetailPage: 곡 선택 시트 열기
SongDetailPage->>SongSelectSheet: 시트 렌더링
SongSelectSheet->>BottomSheet: 선택 시트 표시
User->>SongSelectSheet: 곡 선택
SongSelectSheet->>SongDetailPage: 선택 곡 상세 경로로 이동
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 2 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (2 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: 2
🧹 Nitpick comments (2)
src/features/pin/components/SongDetailContent.tsx (2)
197-210: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win
song.albumImageUrl이 앨범 이미지 렌더링에 사용되지 않음앨범 아트가 항상
rectangleBg로 고정되어 있어, 이번 PR에서Song타입에 추가된albumImageUrl필드가 실제로 소비되지 않습니다.waveformPeaks처럼 폴백 패턴을 적용하는 것이 일관성 있습니다.-<img src={rectangleBg} alt="" className="size-16 rounded-md object-cover" /> +<img src={song.albumImageUrl ?? rectangleBg} alt="" className="size-16 rounded-md object-cover" />🤖 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/pin/components/SongDetailContent.tsx` around lines 197 - 210, Update the album image in the SongDetailContent album art block to use song.albumImageUrl, falling back to rectangleBg when the URL is unavailable, consistent with the existing waveformPeaks fallback pattern. Keep the current image styling and edit-button structure unchanged.
88-120: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win미리듣기 계산이 실제
song.duration을 반영하지 않고, 재생 버튼도 동작하지 않음
SongPreviewSection이song.duration대신 하드코딩된MOCK_PREVIEW_DURATION으로 트림 구간을 계산합니다. 지금은 목데이터가 통일되어 문제가 드러나지 않지만, 실제 곡마다 길이가 다를 경우 트림 시작/끝 시간(초 단위)이 실제 재생 시간과 어긋나게 됩니다.waveformPeaks에 적용된song.waveformPeaks ?? MOCK_WAVEFORM_PEAKS폴백 패턴과 동일하게song.duration ?? MOCK_PREVIEW_DURATION을 사용하는 것이 좋습니다.또한 재생 버튼(Line 104-110)에
onClick이 없어song.previewUrl이 전혀 사용되지 않는데, 오디오 재생 기능이 이후 작업으로 예정되어 있는지 확인이 필요합니다.♻️ duration 폴백 적용 예시
function SongPreviewSection({ waveformPeaks }: SongPreviewSectionProps) { + const duration = song.duration ?? MOCK_PREVIEW_DURATION; const trim = peaksToTrimRange( DEFAULT_TRIM_START_INDEX, DEFAULT_TRIM_END_INDEX, waveformPeaks, - MOCK_PREVIEW_DURATION, + duration, ); - const trimStartPercent = timeToPercent(trim.start, MOCK_PREVIEW_DURATION); - const trimEndPercent = timeToPercent(trim.end, MOCK_PREVIEW_DURATION); + const trimStartPercent = timeToPercent(trim.start, duration); + const trimEndPercent = timeToPercent(trim.end, duration);(
SongPreviewSection이song을 props로 받도록 시그니처 조정 필요)🤖 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/pin/components/SongDetailContent.tsx` around lines 88 - 120, Update SongPreviewSection to receive the song data and calculate trim percentages using song.duration with MOCK_PREVIEW_DURATION as the fallback, matching the existing waveformPeaks fallback pattern. Also wire the preview button to song.previewUrl only if the current preview playback behavior is supported; otherwise leave playback for the planned follow-up rather than adding unrelated functionality.
🤖 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/pin/components/SongDetailContent.tsx`:
- Around line 21-25: Update SongDetailContentProps and the registration flow so
onRegister accepts a SongRegistration containing song, introduction, tags, and
isFeedPublic. In SongDetailContent, pass the locally edited introduction,
selectedTags, and feed visibility state when registering; update SongBottom’s
handleRegister and onSelect forwarding to propagate the complete registration
payload instead of only the original Song.
In `@src/features/pin/constants/songPreview.ts`:
- Around line 33-44: Remove the placeholder value '태그' from the TAG_OPTIONS
constant, leaving only the actual mood-tag options as selectable choices.
---
Nitpick comments:
In `@src/features/pin/components/SongDetailContent.tsx`:
- Around line 197-210: Update the album image in the SongDetailContent album art
block to use song.albumImageUrl, falling back to rectangleBg when the URL is
unavailable, consistent with the existing waveformPeaks fallback pattern. Keep
the current image styling and edit-button structure unchanged.
- Around line 88-120: Update SongPreviewSection to receive the song data and
calculate trim percentages using song.duration with MOCK_PREVIEW_DURATION as the
fallback, matching the existing waveformPeaks fallback pattern. Also wire the
preview button to song.previewUrl only if the current preview playback behavior
is supported; otherwise leave playback for the planned follow-up rather than
adding unrelated functionality.
🪄 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: 6d446bb8-ff0d-4982-a76b-c1844d51c261
⛔ Files ignored due to path filters (3)
src/assets/Rectangle.pngis excluded by!**/*.pngsrc/assets/icons/pencil.svgis excluded by!**/*.svgsrc/assets/icons/play.svgis excluded by!**/*.svg
📒 Files selected for processing (6)
src/components/ui/BottomSheet.tsxsrc/features/pin/components/PinCard.tsxsrc/features/pin/components/SongBottom.tsxsrc/features/pin/components/SongDetailContent.tsxsrc/features/pin/constants/songPreview.tssrc/types/pin.ts
| type SongDetailContentProps = { | ||
| song: Song; | ||
| onCancel: () => void; | ||
| onRegister: () => void; | ||
| }; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
등록 시 소개/태그/피드공개 데이터가 소실됩니다
onRegister: () => void는 인자를 받지 않아, 이 컴포넌트 내부에서 관리하는 introduction, selectedTags, isFeedPublic 상태가 등록 시 상위로 전달될 방법이 없습니다. 실제로 SongBottom.tsx의 handleRegister는 onSelect?.(selectedSong)처럼 원본 Song 객체만 전달하며, 사용자가 입력한 소개 문구/태그/피드 공개 여부는 그대로 사라집니다. Song 타입에도 이 필드들을 담을 자리가 없습니다.
onRegister가 편집된 데이터를 인자로 전달하도록 시그니처를 변경하고, 상위(SongBottom.tsx)에서 이를 onSelect 콜백에 실어 넘기는 구조로 수정이 필요합니다.
type SongRegistration = {
song: Song;
introduction: string;
tags: string[];
isFeedPublic: boolean;
};
type SongDetailContentProps = {
song: Song;
onCancel: () => void;
onRegister: (registration: SongRegistration) => void;
};Also applies to: 151-170
🤖 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/pin/components/SongDetailContent.tsx` around lines 21 - 25,
Update SongDetailContentProps and the registration flow so onRegister accepts a
SongRegistration containing song, introduction, tags, and isFeedPublic. In
SongDetailContent, pass the locally edited introduction, selectedTags, and feed
visibility state when registering; update SongBottom’s handleRegister and
onSelect forwarding to propagate the complete registration payload instead of
only the original Song.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/features/pin/data/songPreview.ts (1)
41-55: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win빈 파형과 잘못된 인덱스를 정규화하세요.
peaks가 비어 있으면 0으로 나누어 CSS에NaN%가 전달됩니다. 인덱스도 배열 범위로 제한해 트림 구간이duration을 벗어나지 않게 하세요.수정 예시
export function peaksToTrimRange( startIndex: number, endIndex: number, peaks: readonly number[], duration: number, ) { + if (peaks.length === 0 || duration <= 0) { + return { start: 0, end: 0 }; + } + + const lastIndex = peaks.length - 1; + const start = Math.min(Math.max(startIndex, 0), lastIndex); + const end = Math.min(Math.max(endIndex, start), lastIndex); + return { - start: (startIndex / peaks.length) * duration, - end: ((endIndex + 1) / peaks.length) * duration, + start: (start / peaks.length) * duration, + end: ((end + 1) / peaks.length) * 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/features/pin/data/songPreview.ts` around lines 41 - 55, Update peaksToTrimRange to handle an empty peaks array without division by zero, returning a zero-length range. Clamp startIndex and endIndex to valid peak indices, and ensure the calculated trim range remains within 0 and duration; leave timeToPercent unchanged.src/pages/SongDetailPage.tsx (1)
127-145: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win스위치에 접근 가능한 이름을 추가하세요.
인접 텍스트는 스위치와 연결되지 않아 스크린 리더에서 이름 없는 스위치로 읽힙니다.
<button type="button" role="switch" + aria-label="피드 공개" aria-checked={checked}🤖 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/SongDetailPage.tsx` around lines 127 - 145, Update the switch button’s accessible naming in the JSX by adding an accessible name that identifies the setting controlled by this toggle. Keep the existing role, aria-checked state, click behavior, and visual styling unchanged.
🤖 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/SongListPage.tsx`:
- Around line 14-29: Connect SearchInput to local search state by supplying its
value and onChange handler, then derive the rendered song list from
MOCK_SONG_CARD_LIST filtered by matching title or artist text. Update the map in
SongListPage to render the filtered results while preserving existing navigation
behavior.
In `@src/routes/index.tsx`:
- Around line 52-55: Remove the standalone `pin/search` route from the route
configuration near `PinPlaceSearchPage`, leaving only the `MapLayout` route
hierarchy with the `mapOverlay` handle for this path. Preserve the overlay
route’s existing behavior and avoid defining `/app/pin/search` in a second
route.
---
Outside diff comments:
In `@src/features/pin/data/songPreview.ts`:
- Around line 41-55: Update peaksToTrimRange to handle an empty peaks array
without division by zero, returning a zero-length range. Clamp startIndex and
endIndex to valid peak indices, and ensure the calculated trim range remains
within 0 and duration; leave timeToPercent unchanged.
In `@src/pages/SongDetailPage.tsx`:
- Around line 127-145: Update the switch button’s accessible naming in the JSX
by adding an accessible name that identifies the setting controlled by this
toggle. Keep the existing role, aria-checked state, click behavior, and visual
styling unchanged.
🪄 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: dfcdce59-54df-4d3d-8425-afa345021631
📒 Files selected for processing (8)
src/components/ui/BottomSheet.tsxsrc/features/pin/components/SongCard.tsxsrc/features/pin/components/SongSelectSheet.tsxsrc/features/pin/data/songPreview.tssrc/features/pin/types.tssrc/pages/SongDetailPage.tsxsrc/pages/SongListPage.tsxsrc/routes/index.tsx
There was a problem hiding this comment.
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 (3)
src/pages/SongDetailPage.tsx (3)
127-131: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winswitch에 접근 가능한 이름을 연결하세요.
role="switch"와aria-checked는 있지만aria-label또는aria-labelledby가 없어 스크린 리더가 이 컨트롤의 의미를 알 수 없습니다.aria-label="피드 공개"를 추가하거나 Line 276의 텍스트를aria-labelledby로 연결하세요.🤖 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/SongDetailPage.tsx` around lines 127 - 131, SongDetailPage의 switch 버튼에 접근 가능한 이름이 없습니다. 해당 button에 aria-label="피드 공개"를 추가하거나, Line 276의 관련 텍스트를 가리키는 aria-labelledby를 연결하여 스크린 리더가 컨트롤의 의미를 인식하도록 수정하세요.
85-94: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win선택된 곡의 프리뷰 데이터를 사용해야 합니다.
현재
SongDetailPage는 항상MOCK_WAVEFORM_PEAKS와MOCK_PREVIEW_DURATION을 사용합니다. 따라서 곡을 변경해도 제목·커버만 바뀌고 waveform 및 trim 시간은 이전 mock 계약과 무관하게 고정됩니다.song.waveformPeaks와song.duration을SongPreviewSection에 전달하세요.Also applies to: 159-160
🤖 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/SongDetailPage.tsx` around lines 85 - 94, Update SongDetailPage and SongPreviewSection to use the selected song’s preview data instead of mock constants: pass song.waveformPeaks and song.duration into SongPreviewSection, then use those props for peaksToTrimRange and timeToPercent. Remove the preview calculations’ dependency on MOCK_WAVEFORM_PEAKS and MOCK_PREVIEW_DURATION while preserving the existing trim indices.
154-157: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win곡 변경 시 이전 곡의 편집 상태를 초기화해야 합니다.
SongDetailPage는useParams의songId를 받지만useEffect나key로 곡 ID 변경을 감지하지 않아, 곡 선택으로 이동해도introduction,selectedTags,isFeedPublic이 이전 곡의 값으로 유지됩니다. 새로운 곡의 저장 폼 상태는 초기화하고, 저장 데이터는songId를 저장할 때만 적용하세요.🤖 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/SongDetailPage.tsx` around lines 154 - 157, Update SongDetailPage to detect songId changes from useParams and reset introduction, selectedTags, and isFeedPublic to the new song’s defaults when the selected song changes. Apply persisted saved data only for the current songId, and ensure the form state cannot carry over from the previously selected song.
🤖 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/pin/components/SongCard.tsx`:
- Around line 15-17: Update the thumbnail wrapper in SongCard to include
overflow-hidden alongside rounded-[4px], ensuring the img respects the wrapper’s
rounded corners while preserving the existing sizing and styling.
---
Outside diff comments:
In `@src/pages/SongDetailPage.tsx`:
- Around line 127-131: SongDetailPage의 switch 버튼에 접근 가능한 이름이 없습니다. 해당 button에
aria-label="피드 공개"를 추가하거나, Line 276의 관련 텍스트를 가리키는 aria-labelledby를 연결하여 스크린 리더가
컨트롤의 의미를 인식하도록 수정하세요.
- Around line 85-94: Update SongDetailPage and SongPreviewSection to use the
selected song’s preview data instead of mock constants: pass song.waveformPeaks
and song.duration into SongPreviewSection, then use those props for
peaksToTrimRange and timeToPercent. Remove the preview calculations’ dependency
on MOCK_WAVEFORM_PEAKS and MOCK_PREVIEW_DURATION while preserving the existing
trim indices.
- Around line 154-157: Update SongDetailPage to detect songId changes from
useParams and reset introduction, selectedTags, and isFeedPublic to the new
song’s defaults when the selected song changes. Apply persisted saved data only
for the current songId, and ensure the form state cannot carry over from the
previously selected song.
🪄 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: 44d3a911-af83-48c5-8b39-ab72003989a8
📒 Files selected for processing (3)
src/features/pin/components/SongCard.tsxsrc/features/pin/components/SongSelectSheet.tsxsrc/pages/SongDetailPage.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- src/features/pin/components/SongSelectSheet.tsx
|
|
||
| function SongWaveform({ peaks, trimStartIndex, trimEndIndex }: SongWaveformProps) { | ||
| return ( | ||
| <div className="flex h-[72px] items-center gap-[2px]" aria-hidden> |
|
|
||
| <SongPreviewSection waveformPeaks={waveformPeaks} /> | ||
| </div> | ||
| </div> | ||
| </section> | ||
|
|
||
| <section className="flex flex-col gap-3 px-[15px]"> | ||
| <h3 className="body-15-r text-grayscale-300">소개</h3> | ||
| <div className="relative rounded-xl bg-pli-black-85 p-5"> | ||
| <label htmlFor="song-intro" className="sr-only"> | ||
| 소개 | ||
| </label> | ||
| <textarea | ||
| id="song-intro" | ||
| value={introduction} | ||
| onChange={(event) => setIntroduction(event.target.value.slice(0, INTRO_MAX_LENGTH))} | ||
| placeholder="이 음악을 들었을 때 나의 기분은?" | ||
| className="body-17-r min-h-[120px] w-full resize-none text-grayscale-300 outline-none placeholder:text-grayscale-1100" |
| <textarea | ||
| id="song-intro" | ||
| value={introduction} | ||
| onChange={(event) => setIntroduction(event.target.value.slice(0, INTRO_MAX_LENGTH))} | ||
| placeholder="이 음악을 들었을 때 나의 기분은?" | ||
| className="body-17-r min-h-[120px] w-full resize-none text-grayscale-300 outline-none placeholder:text-grayscale-1100" |
There was a problem hiding this comment.
이거 textarea의 min-height가 120px로 설정되어 있는데 피그마에서는 88px부터 시작인 것 같아요!
There was a problem hiding this comment.
피그마에 textarea 높이가 156px이라 맞게 수정 하였습니다.
| <div className="flex flex-wrap justify-between gap-y-3 pt-3"> | ||
| {TAG_OPTIONS.map((tag) => { | ||
| const isSelected = selectedTags.includes(tag); | ||
|
|
||
| return ( | ||
| <Tag | ||
| key={tag} | ||
| variant={isSelected ? 'selected' : 'default'} | ||
| onClick={() => toggleTag(tag)} | ||
| > | ||
| #{tag} | ||
| </Tag> | ||
| ); | ||
| })} | ||
| </div> |
There was a problem hiding this comment.
justify-start로 주면 gap도 추가 필요한데 전에 gap 넣으면 디자인 패딩과 맞지가 않아서 다른 문제가 발생합니다. 전에 fs데이에서 태그는 8개로만 고정이라고 들은거 같은데 기획자랑 디자이너 얘기 한 번 다시 해보겠습니다.
There was a problem hiding this comment.
아 지금 보니까 화면 줄이고 나서군요 수정 해보겠습니다.
33fab6c to
47ee46e
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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/pin/components/PinCard.tsx`:
- Around line 38-45: PinCard의 버튼 표시에서 정의되지 않은 pinCount 참조를 제거하고, 주변 데이터 구조에 맞춰
pin.pinCount를 사용하도록 수정하세요.
🪄 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: 95edad43-35c7-4cef-bad0-25bb915aab02
📒 Files selected for processing (6)
src/features/pin/components/PinCard.tsxsrc/features/pin/components/SongCard.tsxsrc/features/pin/data/songPreview.tssrc/pages/SongDetailPage.tsxsrc/pages/SongListPage.tsxsrc/routes/index.tsx
💤 Files with no reviewable changes (1)
- src/routes/index.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
- src/features/pin/data/songPreview.ts
- src/features/pin/components/SongCard.tsx
- src/pages/SongListPage.tsx
- src/pages/SongDetailPage.tsx
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
src/pages/SongDetailPage.tsx (4)
127-131: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win스위치에 접근 가능한 이름을 부여하세요.
현재
role="switch"버튼에는aria-label이나aria-labelledby가 없어 스크린 리더에서 이름 없는 스위치로 인식됩니다.aria-label="피드 공개"등을 추가해 주세요.수정 예시
<button type="button" role="switch" + aria-label="피드 공개" aria-checked={checked}🤖 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/SongDetailPage.tsx` around lines 127 - 131, Update the switch button in SongDetailPage around the checked/onChange handlers to provide an accessible name, using an appropriate aria-label such as “피드 공개” or an existing associated label via aria-labelledby. Preserve the current switch role, checked state, and toggle behavior.
150-152: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win잘못된
songId를 첫 번째 곡으로 대체하지 마세요.존재하지 않는 ID로 접근하면 사용자가 요청한 곡 대신 첫 번째 곡이 표시됩니다. 잘못된 ID는 Not Found 화면을 보여주거나 곡 목록으로 리다이렉트해야 합니다.
🤖 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/SongDetailPage.tsx` around lines 150 - 152, Update the song lookup in SongDetailPage so an invalid songId does not fall back to MOCK_SONG_CARD_LIST[0]. Preserve the found song behavior, and render the existing Not Found state or redirect to the song list when no matching item exists.
85-94: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win선택된 곡의 프리뷰 데이터를 사용해야 합니다.
현재 다른 곡을 선택해도
MOCK_WAVEFORM_PEAKS와MOCK_PREVIEW_DURATION으로 웨이브폼과 트림 위치를 계산합니다. 제목과 커버만 바뀌고 프리뷰는 고정된 곡의 데이터로 표시됩니다. 선택된song의waveformPeaks와duration을SongPreviewSection에 전달하세요.Also applies to: 110-113, 159-160
🤖 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/SongDetailPage.tsx` around lines 85 - 94, SongPreviewSection currently calculates the preview with fixed MOCK_WAVEFORM_PEAKS and MOCK_PREVIEW_DURATION instead of the selected song’s data. Update SongDetailPage and SongPreviewSection to pass and use the selected song’s waveformPeaks and duration, including trim and waveform rendering paths, while preserving the existing preview behavior for the provided song data.
154-156: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win곡 변경 시 상세 상태를 초기화하거나 곡별로 분리해야 합니다.
같은 라우트에서
songId만 변경되므로useState값은 유지됩니다. 따라서 곡 A의 소개·태그·공개 설정이 곡 B에 그대로 남을 수 있습니다.songId변경 시 상태를 초기화하거나 곡별 상태로 관리하세요.Also applies to: 283-285
🤖 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/SongDetailPage.tsx` around lines 154 - 156, SongDetailPage의 introduction, selectedTags, isFeedPublic 상태가 songId 변경 시 유지되지 않도록 songId를 의존성으로 하는 초기화 처리를 추가하세요. 곡이 바뀌면 세 상태를 각 상태의 기본값으로 재설정하거나 새 곡의 상세 데이터로 갱신하고, 기존 곡 내 편집 흐름은 유지하세요.
🤖 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.
Outside diff comments:
In `@src/pages/SongDetailPage.tsx`:
- Around line 127-131: Update the switch button in SongDetailPage around the
checked/onChange handlers to provide an accessible name, using an appropriate
aria-label such as “피드 공개” or an existing associated label via aria-labelledby.
Preserve the current switch role, checked state, and toggle behavior.
- Around line 150-152: Update the song lookup in SongDetailPage so an invalid
songId does not fall back to MOCK_SONG_CARD_LIST[0]. Preserve the found song
behavior, and render the existing Not Found state or redirect to the song list
when no matching item exists.
- Around line 85-94: SongPreviewSection currently calculates the preview with
fixed MOCK_WAVEFORM_PEAKS and MOCK_PREVIEW_DURATION instead of the selected
song’s data. Update SongDetailPage and SongPreviewSection to pass and use the
selected song’s waveformPeaks and duration, including trim and waveform
rendering paths, while preserving the existing preview behavior for the provided
song data.
- Around line 154-156: SongDetailPage의 introduction, selectedTags, isFeedPublic
상태가 songId 변경 시 유지되지 않도록 songId를 의존성으로 하는 초기화 처리를 추가하세요. 곡이 바뀌면 세 상태를 각 상태의
기본값으로 재설정하거나 새 곡의 상세 데이터로 갱신하고, 기존 곡 내 편집 흐름은 유지하세요.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: be8f1f83-6757-4299-86b6-6a09ccb12968
📒 Files selected for processing (3)
src/components/ui/tag.tsxsrc/features/pin/components/PinCard.tsxsrc/pages/SongDetailPage.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- src/features/pin/components/PinCard.tsx




변경 내용
SongBottom: 검색 리스트 ↔ 상세 스텝 전환 (search/detail)SongDetailContent: 미리보기 웨이브폼, 트림 구간, 소개글, 태그 선택 UI 추가Song타입에 미리보기 관련 필드 확장 (previewUrl,duration,waveformPeaks등)관련 이슈
Closes #29
변경 사항
테스트
스크린샷 (UI 변경시)
체크리스트
pnpm format)pnpm lint:fix)코드 품질 확인
PR 제출 전에 다음 명령어를 실행하여 코드 품질을 확인해주세요:
Summary by CodeRabbit