Skip to content

feat: 새 사건 버튼 — POST /api/rooms 연결 및 roomId 전달 - #73

Merged
evenif99 merged 49 commits into
devfrom
feature/homepage-jm
Jun 19, 2026
Merged

evenif99 merged 49 commits into
devfrom
feature/homepage-jm

Conversation

@wjdalss21

@wjdalss21 wjdalss21 commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • 홈 화면 새 사건 버튼에서 카테고리 선택 시 POST /api/rooms 호출하여 방 생성
  • 성공 시 /disputes/{roomId}/statement?category={category} 로 이동
  • 방 생성 실패 시 fallback 이동 제거 → 에러 메시지 표시 후 패널 유지
  • 중복 클릭 방지 (isCreating 가드), AbortController 5초 타임아웃 적용
  • 빈 상태 이미지 <img> → Next.js <Image> 전환 + 장식용 alt="" 설정

변경 흐름

카테고리 선택
  → POST /api/rooms { categoryGroup }
  → 성공: /disputes/{roomId}/statement?category={category}
  → 실패: 에러 메시지 표시 (패널 유지, 재시도 가능)

CodeRabbit 피드백 반영

항목 처리
중복 클릭 시 room 중복 생성 isCreating 가드 + 버튼 disabled
타임아웃 없음 AbortController 5초 타임아웃
catch fallback 이동 에러 메시지 표시로 교체
/disputes/new/ 하드코딩 /disputes/{roomId}/ 동적 URL로 수정
장식용 이미지 alt 중복 alt="" 설정
<img> 태그 사용 Next.js <Image> priority 적용

Test plan

  • 로그인 상태에서 홈 화면 → 새 사건 + 버튼 클릭 → 카테고리 선택
  • Supabase DB에 DisputeRoom 레코드 생성 확인 (roomMode: AI_CHAT)
  • /disputes/{uuid}/statement?category=romance URL로 이동 확인
  • 카테고리 버튼 연속 클릭 시 room 중복 생성 안 됨 확인
  • 네트워크 오류 시 에러 메시지 표시 + 패널 유지 확인
  • 빈 상태 캐릭터 이미지 정상 노출 확인

🤖 Generated with Claude Code

Summary by CodeRabbit

  • 개선 사항
    • 새 사건 등록 시 카테고리 선택을 즉시 라우팅에서 비동기 처리로 변경하고, 방 생성 후 결과에 따라 상세 입력 화면으로 이동합니다.
    • 중복 실행을 방지하고 일정 시간 내 응답이 없으면 요청을 중단합니다.
    • 성공/실패에 따라 오류 메시지 표시 및 이동 경로를 분기합니다.
  • UI/스타일
    • 진행 중인 사건이 비었을 때 빈 상태를 이미지와 함께 표시하도록 개선하고, 빈 상태 레이아웃/여백 처리를 정리했습니다.
    • 새 사건 버튼의 오류 메시지 표시 스타일을 추가했습니다.

wjdalss21 and others added 30 commits June 17, 2026 17:52
- 헤더: 세션 유저명 + character-welcome.png 부엉이 이미지
- 일기 박스: 365x88, border black-700 2px, bg primary-100
- TODO: GangwonEduPower 폰트 추가 후 헤더 로고 텍스트 적용 필요

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Header.tsx에 variant prop 추가 (logo | title)
  - logo: 좌측 상단 말해부엉 로고 표시 (66x19, h:56, padding: 16px 20px)
  - title: 기존 뒤로가기 + 페이지 제목 형태 유지
- Header.module.scss에 __logo 스타일 추가
- home/page.tsx에 Header variant='logo' 적용
  - 헤더를 컨테이너 padding 밖으로 분리하여 상단 여백 제거
- home/page.module.scss diaryBox에 align-self: center 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- width: 365px → width: 100% + max-width: 365px
- 작은 화면에서 좌우 패딩과 결합 시 오버플로우 방지

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 일기 박스 전체를 Link로 변경 (텍스트 + 버튼 모두 클릭 가능)
- diaryBox에 text-decoration: none, cursor: pointer 추가
- /diary/new 경로는 임시 지정 (담당자 확인 후 수정 예정)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- character-welcome.png → character-home.png 교체 (169x138)
- 캐릭터 절대 위치 적용 (top: 41px, right: -20px)
- 캐릭터가 일기 박스 뒤에 위치하도록 z-index 조정 (character: 0, container: 1)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 캐릭터 이미지 가로 스크롤 방지: .page에 overflow-x: hidden 추가
- 비로그인 사용자 분기 처리: 말해부엉 알아보기 박스 추가 (/login 이동)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- greetingText, diaryTitle, diarySubtitle에 typography 믹신 사용
- 개별 font 속성 직접 선언 → @include m.text-* 토큰으로 교체

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 인사/일기 박스는 로그인 여부 무관하게 항상 표시
- 말해부엉 알아보기 박스를 진행중인 사건 위치(구분선 아래)로 이동
- 비로그인 인사: '안녕하세요' 표시

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- StatsCategorySection, useStatistics, QueryProvider 병합
- 고민 카테고리 TOP4 통계 섹션 추가
- 통계 섹션 하단 구분선 추가 (h:8px, black-100, gap:42px)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- isLoggedIn = true 하드코딩으로 로그인 상태 유지
- TODO 주석으로 배포 전 제거 안내 표시

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ActiveCasesSection 컴포넌트 추가
  - 진행중인 사건 목록 표시 (waiting_opponent / opponent_joined / both_submitted)
  - CaseCard 공통 컴포넌트 재사용
  - 좌측 카테고리 컬러 accent bar
  - 카드 간격 12px
- useActiveCases 훅 추가 (mock 데이터, TODO: 실 API 연동)
- CaseCard에 participants prop 추가 (AvatarGroup 렌더링)
- CategoryIcon의 CATEGORY_COLOR_MAP export 추가
- 홈 페이지에 로그인 시 ActiveCasesSection 표시
- 구분선 ↔ 섹션 간격 20px 적용

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CaseCard 원본 구조 완전 원복 (participants prop 제거, div 래퍼 제거)
- CategoryIcon CATEGORY_COLOR_MAP export 원복
- 불필요한 좌측 카테고리 accent bar 제거
- Avatar absolute 오버레이 우측→좌측 하단 변경

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
변경 이유:
- src/app/page.tsx: 홈 화면 콘텐츠를 루트 경로(/)에서 서빙하도록 이동
  → Next.js App Router에서 루트 경로는 src/app/page.tsx가 담당하므로
    기존 (page)/home/page.tsx 대신 루트로 이동하는 것이 구조적으로 올바름
- src/app/page.module.scss: (page)/home/page.module.scss를 루트로 이동
  → page.tsx와 동일 위치에서 관리하도록 이동 (git rename으로 추적됨)
- src/app/(page)/home/page.tsx: redirect('/')로 교체
  → 기존 /home URL 접근 시 /로 리다이렉트하여 북마크/공유 링크 호환성 유지
- src/app/(page)/login/page.tsx: callbackUrl '/home' → '/'
  → 로그인 성공 후 이동 경로를 변경된 홈 경로(/)에 맞게 수정
- src/components/layout/BottomNavigation.tsx: href '/home' → '/'
  → 하단 탭 홈 버튼이 올바른 경로를 가리키도록 수정
  → pathname.startsWith('/') 는 모든 경로에서 true이므로
    홈 탭 활성 조건을 pathname === '/' 로 변경하여 활성 상태 오류 수정
- src/components/home/StatsCategorySection.module.scss: width 100%로 변경
  → 고정 픽셀(346px) 대신 width: 100%로 반응형 처리
- src/middleware.ts: 개발 환경 인증 bypass 추가
  → PR #50 카카오 로그인 병합 후 next-auth/middleware가 모든 경로를 차단하게 됨
  → 개발 편의를 위해 NODE_ENV === development 일 때 인증 없이 접근 허용
  → 배포 전 반드시 제거 필요 (TODO 주석 명시)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- NewCaseButton: 홈 화면 우측 하단 고정 플로팅 버튼 추가
  (w115 h48, color/black-700, border-radius 100, text-title-s)
  새 사건 작성 페이지 생성 후 href 연결 필요 (TODO 주석)
- HomeServiceInfo: 서비스 정보 박스 구현
  (로고 w66 h19, 서비스 소개/개인정보처리방침/이용약관/고객문의 링크,
  Copyright 텍스트, 전체 너비 반응형, 탭바 뒤에 위치)
- BottomNavigation: 홈 페이지에 탭바 추가, z-index 100 유지
  (서비스 정보 박스보다 앞에 렌더링)
- page.tsx: NewCaseButton, HomeServiceInfo, BottomNavigation 렌더링 추가
- page.module.scss: container padding-bottom 60px, serviceInfoWrapper 스타일

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 새 사건 + 버튼 클릭 시 카테고리 선택 모달 표시
- 모달 오버레이: color-black-700 40% 틴트 + bg-page 불투명 베이스
  (배경 콘텐츠가 비치지 않도록 레이어드 배경 처리)
- 카테고리 박스: w133 h176, 흰 배경, 4개 카테고리 항목 가운데 정렬
  (CategoryIcon 공통 컴포넌트 사용, 연인관계/직장관계/친구관계/가족관계)
  (텍스트: text-body-m, text/primary, 아이콘과 9px 간격)
- X 닫기 버튼: 48x48 흰 원형, CloseIcon 24x24
- 모달 오픈 시 body overflow hidden으로 스크롤 잠금
- 카테고리 href: '#' 임시 처리 (새 사건 작성 페이지 생성 후 교체 필요)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- isLoggedIn = true → !!session 으로 교체, 개발용 TODO 주석 제거
- HomeServiceInfo /privacy, /terms 실제 경로 연결
- page.module.scss 불필요 인라인 주석 제거
- HomeServiceInfo.module.scss .link/.copyright @include 뒤 빈 줄 추가
- NewCaseButton.module.scss @include 뒤 빈 줄, 주석/선언 그룹 간격 정리

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- isCreating 상태로 in-flight 중 재진입 차단 및 버튼 비활성화
- AbortController 5초 타임아웃으로 네트워크 지연 시 fallback 보장

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/components/home/ActiveCasesSection.tsx`:
- Around line 33-36: The alt attribute on the Image component in
ActiveCasesSection.tsx is describing the empty state rather than the image
content itself, causing redundancy with the text below and poor accessibility
for screen readers. Either set alt="" to mark the image as decorative (Option 1,
preferred), or replace the alt text with a description of the actual image
content that matches the filename pattern like "말해부엉 캐릭터" instead of describing
the empty state (Option 2). Choose the appropriate approach based on whether the
image serves a functional purpose or is purely decorative.
🪄 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 (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 80be2cc6-51bb-4582-9474-c23e61c80a5d

📥 Commits

Reviewing files that changed from the base of the PR and between 7485cea and 3d13b90.

⛔ Files ignored due to path filters (1)
  • public/images/characters/character-case.png is excluded by !**/*.png
📒 Files selected for processing (2)
  • src/components/home/ActiveCasesSection.module.scss
  • src/components/home/ActiveCasesSection.tsx

Comment thread src/components/home/ActiveCasesSection.tsx
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/components/home/ActiveCasesSection.tsx (1)

32-36: ⚡ Quick win

Next.js Image 컴포넌트 사용을 권장합니다.

네이티브 <img> 태그 대신 Next.js의 Image 컴포넌트를 사용하면 다음과 같은 이점을 얻을 수 있습니다:

  • 자동 이미지 최적화 (WebP 변환 등)
  • 지연 로딩 (lazy loading)
  • 레이아웃 시프트 방지 (CLS 개선)
🖼️ Next.js Image 컴포넌트로 변경 제안
+import Image from 'next/image'
+
 export default function ActiveCasesSection() {
   // ...
   
         <div className={styles.emptyState}>
-          <img
+          <Image
             src="/images/characters/character-case.png"
             alt="진행중인 사건 없음"
+            width={80}
+            height={80}
             className={styles.emptyImage}
           />
           <p className={styles.empty}>아직 진행중인 사건이 없어요</p>
🤖 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/components/home/ActiveCasesSection.tsx` around lines 32 - 36, Replace the
native `<img>` tag that displays the character-case.png image in the
ActiveCasesSection component with Next.js's Image component. First, import Image
from next/image at the top of the file. Then, replace the `<img>` element with
an `<Image>` component, ensuring you add the required width and height props to
specify dimensions, keep the src and alt props (alt already has "진행중인 사건 없음"),
and apply the emptyImage className. This will enable automatic image
optimization, lazy loading, and prevent layout shifts.
🤖 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.

Nitpick comments:
In `@src/components/home/ActiveCasesSection.tsx`:
- Around line 32-36: Replace the native `<img>` tag that displays the
character-case.png image in the ActiveCasesSection component with Next.js's
Image component. First, import Image from next/image at the top of the file.
Then, replace the `<img>` element with an `<Image>` component, ensuring you add
the required width and height props to specify dimensions, keep the src and alt
props (alt already has "진행중인 사건 없음"), and apply the emptyImage className. This
will enable automatic image optimization, lazy loading, and prevent layout
shifts.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: e99f44aa-180a-4ca3-a7f9-81703c8d23a4

📥 Commits

Reviewing files that changed from the base of the PR and between 3d13b90 and b41e750.

📒 Files selected for processing (1)
  • src/components/home/ActiveCasesSection.tsx

{cases.length === 0 ? (
<p className={styles.empty}>아직 진행중인 사건이 없어요</p>
<div className={styles.emptyState}>
<img

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요것도 Next.js Image 로 변경해줘요

const handleCategoryClick = async (category: CategoryGroup) => {
if (isCreating) return
setIsOpen(false)
router.push(`/disputes/test/statement?category=${category}`)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앜 여기 /test/ 말고 /[id] 로 변경해줘요

Comment thread src/components/home/NewCaseButton.tsx Outdated
if (!json.success) throw new Error()
router.push(`/disputes/new/statement?category=${category}&roomId=${json.data.id}`)
} catch {
router.push(`/disputes/new/statement?category=${category}`)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

catch에... 왜 ...? 카테고리 클릭시 무조건 room 생성이기때문에 throw.error 해줘야해용

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

error message 보여주고요 사용자한테

wjdalss21 and others added 2 commits June 19, 2026 14:45
- NewCaseButton: catch fallback 이동 제거 → 에러 메시지 표시로 교체
- NewCaseButton: 성공 시 URL /disputes/new/ → /disputes/[roomId]/ 수정
- ActiveCasesSection: <img> → Next.js <Image> priority 적용
- ActiveCasesSection: 장식용 이미지 alt='' 설정

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 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/components/home/NewCaseButton.tsx`:
- Line 44: The navigation path in the NewCaseButton component after successful
case creation does not align with the PR objectives. Currently, the router.push
call navigates to /disputes/${json.data.id}/statement?category=${category}, but
according to the PR goals, it should navigate to /disputes/${roomId}/ instead.
Update the router.push call to use the correct destination path without the
/statement suffix and category parameter, ensuring the navigation takes the user
to the disputes page as intended.
- Around line 45-47: The catch block in NewCaseButton.tsx is directly exposing
the raw error message from exceptions (err.message), which can leak internal
technical details like AbortError or parsing errors to users. Instead of using
err.message directly, only show error messages that are intentionally provided
by the server response, and use the generic fallback message for all other
unexpected errors. Check if the error is a structured response from the server
with an error message property, and only use that message if it exists,
otherwise always fall back to the fixed user-friendly message passed to
setErrorMessage.
🪄 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 (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 95d5eb2f-7957-475e-89ea-0a89da53b4b7

📥 Commits

Reviewing files that changed from the base of the PR and between b41e750 and 770ae62.

📒 Files selected for processing (3)
  • src/components/home/ActiveCasesSection.tsx
  • src/components/home/NewCaseButton.module.scss
  • src/components/home/NewCaseButton.tsx
✅ Files skipped from review due to trivial changes (1)
  • src/components/home/NewCaseButton.module.scss
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/home/ActiveCasesSection.tsx

})
const json = await res.json()
if (!json.success) throw new Error(json.error?.message)
router.push(`/disputes/${json.data.id}/statement?category=${category}`)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

성공 시 이동 경로가 PR 목표(/disputes/[roomId]/)와 다릅니다.

현재는 /disputes/${json.data.id}/statement?category=...로 이동합니다. 제공된 PR 목표/테스트 계획 기준이면 생성 성공 후 /disputes/${roomId}/로 이동해야 해서 요구사항 불일치 가능성이 큽니다.

제안 패치
-      router.push(`/disputes/${json.data.id}/statement?category=${category}`)
+      router.push(`/disputes/${json.data.id}/`)
📝 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.

Suggested change
router.push(`/disputes/${json.data.id}/statement?category=${category}`)
router.push(`/disputes/${json.data.id}/`)
🤖 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/components/home/NewCaseButton.tsx` at line 44, The navigation path in the
NewCaseButton component after successful case creation does not align with the
PR objectives. Currently, the router.push call navigates to
/disputes/${json.data.id}/statement?category=${category}, but according to the
PR goals, it should navigate to /disputes/${roomId}/ instead. Update the
router.push call to use the correct destination path without the /statement
suffix and category parameter, ensuring the navigation takes the user to the
disputes page as intended.

Comment thread src/components/home/NewCaseButton.tsx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants