Conversation
📝 WalkthroughWalkthrough에디터의 빈 콘텐츠 감지 로직 개선, 네비게이션 가드의 ref 기반 리팩토링(이벤트 리스너의 마운트 시 등록 및 히스토리 엔트리 관리 개선), 그리고 취소 버튼의 라우팅 호출을 브라우저 Changes
Sequence Diagram(s)sequenceDiagram
participant Browser as 브라우저
participant Guard as useNavigationGuard
participant History as History API
participant App as 애플리케이션
Note over Guard: 마운트 시 refs 초기화
Guard->>Guard: enabledRef, hasGuardEntry 설정
rect rgba(100, 200, 150, 0.5)
Note over Browser,App: 링크 클릭 / beforeunload
Browser->>Guard: 클릭/이벤트 발생
Guard->>Guard: enabledRef.current 확인
Guard->>History: guard 엔트리 삽입 (조건부)
Guard->>Guard: hasGuardEntry = true
end
rect rgba(100, 150, 200, 0.5)
Note over Browser,Guard: popstate 처리
Browser->>Guard: popstate 발생
Guard->>Guard: 현재 state가 guard 엔트리인지 검사
alt 엔트리이고 가드 활성화
Guard->>App: 확인 다이얼로그 표시
else 가드 비활성화 또는 엔트리 스킵 필요
Guard->>History: history.back() 호출 (스킵)
Guard->>Guard: hasGuardEntry = false
end
end
rect rgba(200, 100, 100, 0.5)
Note over App,Guard: 확인/취소 처리
App->>Guard: 사용자 확인/취소
Guard->>Guard: hasGuardEntry = false 설정 및 엔트리 정리
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 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. Review rate limit: 0/1 reviews remaining, refill in 60 minutes.Comment |
🤖 Claude 테스트 제안
변경된 컴포넌트에 대해 Claude가 생성한 테스트 코드입니다. 검토 후 적합한 부분만 사용하세요.
|
PR 테스트 결과✅ Jest: 통과 🎉 모든 테스트를 통과했습니다! |
PR 검증 결과✅ TypeScript: 통과 🎉 모든 검증을 통과했습니다! |
|
구현한 기능 Preview: https://weeth-7wlxfq88k-weethsite-4975s-projects.vercel.app |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/hooks/useNavigationGuard.ts`:
- Around line 31-35: The hook useNavigationGuard currently initializes
hasGuardEntry as a local ref which resets on remount and can miss existing
history guard entries; update the hook to synchronize hasGuardEntry.current with
isGuardEntry() on mount and whenever enabled changes (especially when enabled
=== false initial run) so the hook recognizes existing guard entries across
remounts. Concretely, in useNavigationGuard (references: hasGuardEntry,
allowNavigation, isGuardEntry, enabledRef) call hasGuardEntry.current =
isGuardEntry() inside a useEffect that runs on mount and when enabled changes,
and ensure any early-return logic (the branch that skips guard entry when
disabled) uses that synchronized value so allowNavigation() and subsequent back
navigation behave correctly.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 193e18a8-44ef-46dd-bd46-077dcec0cb22
📒 Files selected for processing (3)
src/components/board/PostEditorShell.tsxsrc/components/layout/header/PostingActions.tsxsrc/hooks/useNavigationGuard.ts
🤖 Claude 테스트 제안
변경된 컴포넌트에 대해 Claude가 생성한 테스트 코드입니다. 검토 후 적합한 부분만 사용하세요.
|
PR 테스트 결과✅ Jest: 통과 🎉 모든 테스트를 통과했습니다! |
PR 검증 결과✅ TypeScript: 통과 🎉 모든 검증을 통과했습니다! |
|
구현한 기능 Preview: https://weeth-idvwuib3l-weethsite-4975s-projects.vercel.app |
woneeeee
left a comment
There was a problem hiding this comment.
제발............... 이제 그만 수정이 되기를.. .. . . . .. . . .ㅜ.ㅜ 파이팅입니당!!
PR 테스트 결과✅ Jest: 통과 🎉 모든 테스트를 통과했습니다! |
🤖 Claude 테스트 제안
변경된 컴포넌트에 대해 Claude가 생성한 테스트 코드입니다. 검토 후 적합한 부분만 사용하세요.
|
|
구현한 기능 Preview: https://weeth-jb24hffvo-weethsite-4975s-projects.vercel.app |
PR 검증 결과✅ TypeScript: 통과 🎉 모든 검증을 통과했습니다! |
🤖 Claude 테스트 제안
변경된 컴포넌트에 대해 Claude가 생성한 테스트 코드입니다. 검토 후 적합한 부분만 사용하세요.
|
PR 테스트 결과✅ Jest: 통과 🎉 모든 테스트를 통과했습니다! |
|
구현한 기능 Preview: https://weeth-9gaa7rkli-weethsite-4975s-projects.vercel.app |
PR 검증 결과✅ TypeScript: 통과 🎉 모든 검증을 통과했습니다! |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
src/components/board/ImageList/ImageCard.tsx (1)
50-56: ⚡ Quick win
<img>대신next/image로 전환해 주세요이 블록은 여전히 네이티브
<img>와 lint disable에 의존하고 있습니다. 이번 변경 범위(이미지 카드 렌더링)에서next/image로 맞춰 두는 게 좋습니다.제안 diff
+import Image from 'next/image'; import { CloseCircleIcon } from '@/assets/icons'; import { Icon } from '@/components/ui'; import { cn } from '@/lib/cn'; import type { DisplayFile } from '@/types/board'; @@ - {/* eslint-disable-next-line `@next/next/no-img-element` */} - <img + <Image src={item.fileUrl} alt={item.fileName} + fill + sizes="(max-width: 768px) 100vw, 33vw" draggable={false} className={cn('object-cover', item.uploaded === false && 'opacity-50', imgClassName)} />As per coding guidelines,
**/*.{ts,tsx}: Use next/image for image optimization and next/font for font loading.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/board/ImageList/ImageCard.tsx` around lines 50 - 56, The ImageCard component still uses a raw <img> with an eslint-disable; replace it with Next.js Image from 'next/image' to comply with project rules: import Image and use it in place of the <img>, passing item.fileUrl as src, item.fileName as alt, draggable={false} behavior via onDragStart preventDefault or draggable prop if supported, and apply classes via className (preserve cn('object-cover', item.uploaded === false && 'opacity-50', imgClassName)); ensure image layout/width/height or fill is set per Next/Image requirements and keep the existing imgClassName and uploaded opacity logic.src/hooks/useCodeHighlight.ts (2)
46-51: 💤 Low valueStatic analysis 경고 검토: innerHTML 할당
Static analysis에서 XSS 위험으로 플래그되었지만, 현재 코드는 안전합니다:
- 상위 컴포넌트(
PostCardBody)에서 이미DOMPurify.sanitize()로 콘텐츠를 정제codeEl.textContent는 순수 텍스트만 반환 (HTML 태그 제거됨)toHtml()은 HAST를 HTML로 변환 시 텍스트 노드를 적절히 이스케이프미래 유지보수자를 위해 이 안전성 근거를 주석으로 명시하면 좋겠습니다.
📝 안전성 주석 추가 제안
const html = toHtml(result); if (!html || html.trim() === '') return; + // 안전: textContent는 HTML 태그를 제외한 순수 텍스트만 반환하고, + // toHtml()은 텍스트 노드를 적절히 이스케이프함 codeEl.innerHTML = html; codeEl.setAttribute('data-highlighted', '');🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/hooks/useCodeHighlight.ts` around lines 46 - 51, Add a concise inline comment near the innerHTML assignment in useCodeHighlight explaining why this use of codeEl.innerHTML is safe: note that the source content is already sanitized in the parent PostCardBody via DOMPurify.sanitize, that codeEl.textContent returns only text nodes, and that toHtml (used to convert HAST to HTML) properly escapes text nodes—mention these specific symbols (useCodeHighlight, toHtml, PostCardBody, DOMPurify.sanitize, codeEl.textContent, codeEl.innerHTML) so future maintainers understand the sanitization chain and why the XSS static-analysis warning can be safely ignored.
24-25: 💤 Low value중복 체크 로직 확인 필요
Line 15-17에서 모든
data-highlighted속성을 먼저 제거하고, line 19에서:not([data-highlighted])셀렉터로 요소를 선택합니다. 따라서 이forEach루프 내에서codeEl.hasAttribute('data-highlighted')는 항상false가 됩니다.실질적인 중복 처리 방지는 line 22의
span체크가 담당하고 있습니다. 이 조건은 방어적 코드로 남겨둘 수 있지만, 의도가 있다면 주석으로 명시하면 좋겠습니다.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/hooks/useCodeHighlight.ts` around lines 24 - 25, The duplicate-guard check inside useCodeHighlight's forEach loop (the codeEl.hasAttribute('data-highlighted') check) is redundant because earlier logic removes all data-highlighted attributes and then selects elements with :not([data-highlighted]), so that condition will never be true; either remove that check to simplify the loop or keep it but add a clear comment next to the codeEl.hasAttribute('data-highlighted') check explaining it is intentionally defensive (reference symbols: useCodeHighlight, codeEl, the forEach loop and the earlier :not([data-highlighted]) selection) so future readers understand why it remains.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/components/board/ImageList/ImageCard.tsx`:
- Around line 50-56: The ImageCard component still uses a raw <img> with an
eslint-disable; replace it with Next.js Image from 'next/image' to comply with
project rules: import Image and use it in place of the <img>, passing
item.fileUrl as src, item.fileName as alt, draggable={false} behavior via
onDragStart preventDefault or draggable prop if supported, and apply classes via
className (preserve cn('object-cover', item.uploaded === false && 'opacity-50',
imgClassName)); ensure image layout/width/height or fill is set per Next/Image
requirements and keep the existing imgClassName and uploaded opacity logic.
In `@src/hooks/useCodeHighlight.ts`:
- Around line 46-51: Add a concise inline comment near the innerHTML assignment
in useCodeHighlight explaining why this use of codeEl.innerHTML is safe: note
that the source content is already sanitized in the parent PostCardBody via
DOMPurify.sanitize, that codeEl.textContent returns only text nodes, and that
toHtml (used to convert HAST to HTML) properly escapes text nodes—mention these
specific symbols (useCodeHighlight, toHtml, PostCardBody, DOMPurify.sanitize,
codeEl.textContent, codeEl.innerHTML) so future maintainers understand the
sanitization chain and why the XSS static-analysis warning can be safely
ignored.
- Around line 24-25: The duplicate-guard check inside useCodeHighlight's forEach
loop (the codeEl.hasAttribute('data-highlighted') check) is redundant because
earlier logic removes all data-highlighted attributes and then selects elements
with :not([data-highlighted]), so that condition will never be true; either
remove that check to simplify the loop or keep it but add a clear comment next
to the codeEl.hasAttribute('data-highlighted') check explaining it is
intentionally defensive (reference symbols: useCodeHighlight, codeEl, the
forEach loop and the earlier :not([data-highlighted]) selection) so future
readers understand why it remains.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 767201b1-cbf7-4f7e-8b1f-99f7adb5204b
📒 Files selected for processing (4)
src/components/board/Editor/index.tsxsrc/components/board/ImageList/ImageCard.tsxsrc/hooks/useCodeHighlight.tssrc/hooks/useNavigationGuard.ts
✅ Files skipped from review due to trivial changes (1)
- src/components/board/Editor/index.tsx
✅ PR 유형
어떤 변경 사항이 있었나요?
📌 관련 이슈번호
✅ Key Changes
📸 스크린샷 or 실행영상
내비 가드 문제
2026-04-30.141621.mp4
코드블록
🎸 기타 사항 or 추가 코멘트
이게 로컬에서는 잘 되어도... 배포 환경에서 말썽인 경우가 꽤 있어서 ㅠㅠ
vercel 미리보기로 한번 더 확인해보겟습니당....
Summary by CodeRabbit
요약
버그 수정
개선사항