Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6eb7ed6
feat: 홈 화면 기본 구조 생성 (헤더, 일기 박스)
wjdalss21 Jun 17, 2026
f98f8f3
feat: Header variant 분리 (logo/title) 및 홈 화면 적용
wjdalss21 Jun 17, 2026
d959392
feat: 사건기록 페이지 생성 및 로고 헤더 적용 (/records)
wjdalss21 Jun 17, 2026
5a6643e
fix: diaryBox 고정 폭을 max-width + width 100%로 반응형 처리
wjdalss21 Jun 17, 2026
a04b781
feat: 감정일기 작성 버튼 /diary/new 네비게이션 연결
wjdalss21 Jun 17, 2026
6ab4d7e
feat: 홈 화면 캐릭터 이미지 교체 및 위치 조정
wjdalss21 Jun 17, 2026
24aed23
fix: 홈 화면 코드래빗 피드백 반영
wjdalss21 Jun 18, 2026
f67c9e9
refactor: 홈 화면 typography 믹신 적용
wjdalss21 Jun 18, 2026
2b194f9
fix: 비로그인 알아보기 박스 위치 수정
wjdalss21 Jun 18, 2026
e5188f7
feat: 홈 화면에 통계 섹션 및 구분선 통합
wjdalss21 Jun 18, 2026
f2154c6
chore: 개발 편의용 로그인 상태 강제 설정 (배포 전 제거 필요)
wjdalss21 Jun 18, 2026
47e7138
feat: 홈 화면 진행중인 사건 섹션 UI 구현
wjdalss21 Jun 18, 2026
a31fe0e
fix: dev 머지 충돌 해결 (ActiveCasesSection 유지)
wjdalss21 Jun 18, 2026
f02cec2
fix: 진행중인 사건 카드 수정 - CaseCard 원본 구조 유지, 좌측 컬러바 제거, Avatar 좌측 배치
wjdalss21 Jun 18, 2026
e92b35f
fix: CaseCard preview 텍스트 컬러 black-700으로 수정
wjdalss21 Jun 18, 2026
804f450
fix: 진행중인 사건 섹션 내 진행중 뱃지 제거
wjdalss21 Jun 18, 2026
fd1b1f3
fix: 진행중인 사건 카드 푸터 레이아웃 및 외곽선 black-700 2px inset 적용
wjdalss21 Jun 18, 2026
8561f05
fix: 진행중인 사건 카드 preview-footer 간격 8px 조정
wjdalss21 Jun 18, 2026
cca1afc
Merge remote-tracking branch 'origin/dev' into feature/homepage-jm
wjdalss21 Jun 18, 2026
2afe223
fix: 코드래빗 리뷰 반영 - 린트, loading/error 상태 처리, onClick li로 이동
wjdalss21 Jun 18, 2026
cff2117
Merge remote-tracking branch 'origin/dev' into feature/homepage-jm
wjdalss21 Jun 18, 2026
28c7139
chore: 홈 화면 캐릭터 이미지 추가
wjdalss21 Jun 18, 2026
200262e
refactor: 홈 페이지를 /home에서 / 루트 경로로 이동
wjdalss21 Jun 18, 2026
692170e
Merge remote-tracking branch 'origin/dev' into feature/homepage-jm
wjdalss21 Jun 18, 2026
80b320a
Merge remote-tracking branch 'origin/dev' into feature/homepage-jm
wjdalss21 Jun 18, 2026
c5eed1d
Merge remote-tracking branch 'origin/dev' into feature/homepage-jm
wjdalss21 Jun 18, 2026
b6f81f0
Merge remote-tracking branch 'origin/dev' into feature/homepage-jm
wjdalss21 Jun 18, 2026
7937e2c
feat: 홈 화면 새 사건 버튼 및 서비스 정보 푸터 구현
wjdalss21 Jun 18, 2026
12871f4
feat: 새 사건 버튼 카테고리 선택 모달 구현
wjdalss21 Jun 18, 2026
9408df5
fix: CodeRabbit 리뷰 반영 — isLoggedIn 하드코딩 제거, 서비스 링크 경로 교체, SCSS 빈 줄 정리
wjdalss21 Jun 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/app/page.module.scss
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
@use '@/styles/abstracts/variables' as v;
@use '@/styles/abstracts/mixins' as m;
@use '@/styles/abstracts/functions' as fn;

.page {
position: relative;
display: flex;
flex-direction: column;
min-height: 100dvh;
overflow-x: hidden;
}

Expand All @@ -23,6 +27,7 @@
display: flex;
flex-direction: column;
padding: 20px 16px;
padding-bottom: fn.r(60);
gap: 16px;
}

Expand Down Expand Up @@ -109,6 +114,12 @@
margin-top: 4px;
}

// 서비스 정보 박스 — 탭바 뒤에 위치, 스크롤로 노출
.serviceInfoWrapper {
margin-top: auto;
padding-bottom: fn.r(65);
}

// 비로그인 알아보기 박스
.introBox {
display: flex;
Expand Down
17 changes: 13 additions & 4 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ import Link from 'next/link'
import { getServerSession } from 'next-auth'
import { authOptions } from '@/lib/auth'
import Header from '@/components/layout/Header'
import BottomNavigation from '@/components/layout/BottomNavigation'
import StatsCategorySection from '@/components/home/StatsCategorySection'
import ActiveCasesSection from '@/components/home/ActiveCasesSection'
import NewCaseButton from '@/components/home/NewCaseButton'
import HomeServiceInfo from '@/components/home/HomeServiceInfo'
import styles from './page.module.scss'

export default async function HomePage() {
const session = await getServerSession(authOptions)
// TODO: [개발 완료 후 반드시 제거] 개발 편의를 위해 로그인 상태 강제 설정
// 실제 배포 전 아래 줄을 삭제하고 const isLoggedIn = !!session 으로 교체할 것
const isLoggedIn = true
const userName = session?.user?.name ?? '테스트유저'
const isLoggedIn = !!session
const userName = session?.user?.name ?? ''
Comment on lines +15 to +16

@coderabbitai coderabbitai Bot Jun 18, 2026 •

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 | 🟡 Minor | ⚡ Quick win

로그인 사용자 이름이 비어 있을 때 인사 문구가 깨집니다.

Line 16에서 userName을 빈 문자열로 기본 처리하면, Line 33에서 로그인 상태일 때 "님"만 렌더링될 수 있습니다. 이름이 없으면 비로그인과 동일한 인사로 폴백하도록 분기를 추가해 주세요.

수정 예시
-  const userName = session?.user?.name ?? ''
+  const userName = session?.user?.name?.trim() ?? ''

-          <p className={styles.userName}>{isLoggedIn ? `${userName}님` : '안녕하세요'}</p>
+          <p className={styles.userName}>
+            {isLoggedIn && userName ? `${userName}님` : '안녕하세요'}
+          </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/app/page.tsx` around lines 15 - 16, The greeting message breaks when a
logged-in user has no name because userName is set to an empty string as a
fallback. Instead of just checking isLoggedIn status, add an additional
condition to verify that userName is not empty before rendering the logged-in
greeting with the "님" suffix. When userName is empty, the greeting should fall
back to the non-logged-in message regardless of the isLoggedIn status. Update
the conditional logic where the greeting is rendered to check both that the user
is logged in AND that userName has a non-empty value.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

이 리뷰 반영해주세요 폴백처리 중요해요

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.

@lyla-bae, 바로 반영하겠습니다!

  • src/app/page.tsx Line 16: session?.user?.name 에 .trim() 추가
  • src/app/page.tsx Line 33: isLoggedIn && userName 조건으로 인사 폴백 처리

The requested changes have been implemented and a pull request has been created: View PR


return (
<div className={styles.page}>
Expand Down Expand Up @@ -63,6 +64,14 @@ export default async function HomePage() {
</Link>
)}
</main>

{/* 서비스 정보 푸터 — 스크롤 시 탭바 바로 위에 sticky */}
<div className={styles.serviceInfoWrapper}>
<HomeServiceInfo />
</div>

{isLoggedIn && <NewCaseButton />}
<BottomNavigation />
</div>
)
}
44 changes: 44 additions & 0 deletions src/components/home/HomeServiceInfo.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
@use '@/styles/abstracts/variables' as v;
@use '@/styles/abstracts/mixins' as m;
@use '@/styles/abstracts/functions' as fn;

.box {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
background-color: var(--text-primary);
border-radius: 0;
padding: fn.r(20) fn.r(16) fn.r(20);
box-sizing: border-box;
}

.logo {
display: block;
width: fn.r(66);
height: fn.r(19);
object-fit: contain;
}

.links {
display: flex;
align-items: center;
gap: fn.r(10);
margin-top: fn.r(10);
}

.link {
@include m.text-caption;

color: v.$color-black-200;
text-decoration: none;
white-space: nowrap;
}

.copyright {
@include m.text-caption;

color: v.$color-black-400;
margin-top: fn.r(10);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
text-align: center;
}
31 changes: 31 additions & 0 deletions src/components/home/HomeServiceInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Image from 'next/image'
import styles from './HomeServiceInfo.module.scss'

const LINKS = [
{ label: '서비스 소개', href: '#' },
{ label: '개인정보 처리방침', href: '/privacy' },
{ label: '이용약관', href: '/terms' },
{ label: '고객문의', href: '#' },
Comment on lines +4 to +8

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

푸터 링크가 모두 임시 #라 실제 탐색이 불가능합니다.

현재 클릭해도 유효한 페이지로 이동하지 않아 사용자가 서비스 정보/약관/문의에 접근할 수 없습니다. 출시 전 실제 경로로 교체가 필요합니다.

Also applies to: 22-25

🤖 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/HomeServiceInfo.tsx` around lines 4 - 8, The LINKS array
in the HomeServiceInfo component contains placeholder href values set to '#' for
all footer navigation items (서비스 소개, 개인정보 처리방침, 이용약관, and 고객문의), which prevents
users from navigating to the actual pages. Replace each '#' href with the
corresponding valid page paths or routes for the service information, privacy
policy, terms of service, and customer inquiry pages respectively.

]

export default function HomeServiceInfo() {
return (
<div className={styles.box}>
<Image
src="/images/common/logo.png"
alt="말해부엉"
width={66}
height={19}
className={styles.logo}
/>
<nav className={styles.links} aria-label="서비스 정보">
{LINKS.map(({ label, href }) => (
<a key={label} href={href} className={styles.link}>
{label}
</a>
))}
</nav>
<p className={styles.copyright}>Copyright ⓒ 말해부엉. ALL Rights Reserved.</p>
</div>
)
}
94 changes: 94 additions & 0 deletions src/components/home/NewCaseButton.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
@use '@/styles/abstracts/variables' as v;
@use '@/styles/abstracts/mixins' as m;
@use '@/styles/abstracts/functions' as fn;

// ─── 새 사건 + 버튼 ─────────────────────────────────────────
.button {
position: fixed;
bottom: fn.r(81);
right: max(fn.r(16), calc((100vw - #{v.$container-max-width}) / 2 + #{fn.r(16)}));

display: flex;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
align-items: center;
justify-content: center;
width: fn.r(115);
height: fn.r(48);

background-color: v.$color-black-700;
border: none;
border-radius: fn.r(100);
cursor: pointer;
z-index: 101;

@include m.text-title-s;

color: #ffffff;
white-space: nowrap;
}

// ─── 카테고리 선택 모달 ──────────────────────────────────────
.overlay {
position: fixed;
inset: 0;

// 페이지 배경을 불투명 베이스로 깔아 콘텐츠가 비치지 않게 하고,
// 그 위에 color-black-700 40% 틴트를 적용
background-color: var(--bg-page);
background-image: linear-gradient(rgba(26, 29, 31, 0.4), rgba(26, 29, 31, 0.4));
z-index: 200;
}

// 카테고리 박스 + X버튼 컨테이너 — 새 사건 + 버튼과 동일 위치 기준
.panel {
position: absolute;
bottom: fn.r(81);
right: max(fn.r(16), calc((100vw - #{v.$container-max-width}) / 2 + #{fn.r(16)}));

display: flex;
flex-direction: column;
align-items: flex-end;
gap: fn.r(16);
}

.categoryBox {
width: fn.r(133);
height: fn.r(176);
background-color: #ffffff;
border-radius: fn.r(12);
box-sizing: border-box;
padding: fn.r(20) fn.r(16);

display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: fn.r(8);
}

.item {
display: flex;
align-items: center;
gap: fn.r(9);
text-decoration: none;
}

.itemLabel {
@include m.text-body-m;

color: var(--text-primary);
}

.closeButton {
width: fn.r(48);
height: fn.r(48);
border-radius: 50%;
background-color: #ffffff;
border: none;
cursor: pointer;

display: flex;
align-items: center;
justify-content: center;
color: v.$color-black-700;
flex-shrink: 0;
}
69 changes: 69 additions & 0 deletions src/components/home/NewCaseButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
'use client'

import { useState, useEffect } from 'react'
import CloseIcon from '@mui/icons-material/Close'
import CategoryIcon from '@/components/ui/CategoryIcon'
import type { CategoryGroup } from '@/types/common'
import styles from './NewCaseButton.module.scss'

const CATEGORY_ITEMS: { category: CategoryGroup; label: string }[] = [
{ category: 'romance', label: '연인관계' },
{ category: 'work', label: '직장관계' },
{ category: 'friend', label: '친구관계' },
{ category: 'family', label: '가족관계' },
]

// TODO: 새 사건 작성 페이지(/rooms/new 등) 생성 후 카테고리별 실제 경로로 교체
// 현재는 페이지가 없어 '#'으로 임시 처리
function getCategoryHref(_category: CategoryGroup): string {
return '#'
}
Comment on lines +16 to +20

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

카테고리 선택 후 실제 생성 페이지로 이동하지 못합니다.

getCategoryHref가 항상 #를 반환해 카테고리 클릭이 기능적으로 완료되지 않습니다. 새 사건 생성 플로우의 핵심 경로이므로 실제 라우트 매핑이 필요합니다.

Also applies to: 41-43

🤖 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` around lines 16 - 20, The
`getCategoryHref` function is currently returning a hardcoded placeholder '#'
instead of mapping the `_category` parameter to actual navigation routes.
Replace the function body to use the `_category` parameter to determine and
return the appropriate route path for each CategoryGroup type (e.g., different
routes for criminal cases, civil cases, etc.). Ensure all category types have
corresponding route paths defined so that clicking a category actually navigates
to the correct case creation page instead of staying on the current page.


export default function NewCaseButton() {
const [isOpen, setIsOpen] = useState(false)

useEffect(() => {
document.body.style.overflow = isOpen ? 'hidden' : ''
return () => { document.body.style.overflow = '' }
}, [isOpen])

return (
<>
{isOpen && (
<div
className={styles.overlay}
onClick={() => setIsOpen(false)}
role="dialog"
aria-modal="true"
>
<div className={styles.panel} onClick={(e) => e.stopPropagation()}>
<div className={styles.categoryBox}>
{CATEGORY_ITEMS.map(({ category, label }) => (
<a key={category} href={getCategoryHref(category)} className={styles.item}>
<CategoryIcon category={category} />
<span className={styles.itemLabel}>{label}</span>
</a>
))}
</div>
<button
className={styles.closeButton}
onClick={() => setIsOpen(false)}
aria-label="카테고리 선택 닫기"
>
<CloseIcon style={{ width: 24, height: 24 }} />
</button>
</div>
</div>
)}
{!isOpen && (
<button
className={styles.button}
onClick={() => setIsOpen(true)}
aria-label="새 사건 작성"
>
새 사건 +
</button>
)}
</>
)
}