Skip to content

✨Feat: header components 구현#32

Merged
jjangminii merged 15 commits intodevelopfrom
feat/#17/header-components
Oct 19, 2025
Merged

✨Feat: header components 구현#32
jjangminii merged 15 commits intodevelopfrom
feat/#17/header-components

Conversation

@jjangminii
Copy link
Copy Markdown
Contributor

@jjangminii jjangminii commented Oct 17, 2025

🔥 작업 내용

  • header components 구현

🤔 추후 작업 사항

  • 다른 컴포넌트 작업

🔗 이슈

PR Point (To Reviewer)

@shared/components/index.ts 배럴파일 추가

같은 위치에서 계속 컴포넌트를 가져오게된다면 import문이 많아질거라 생각이 들었어요.
그래서 index파일을 만들고 임포트 경로 단일화+더 짧게 사용할 수 있도록 했습니다.
나중에 사용할 때 한 줄이면 나중에 원하는 컴포넌트 가져올 수 있어요

import { Header, ControlBar } from '@/shared/components'

헤더

헤더 색상이 다른게 하나 있어 분기처리 해뒀습니다. color 옵셔널로 해둬서 따로 특별하지않은이상 디폴트 컬러로 됩니당
컬러는 따로 타입 설정해서 지정된 색 이외의 것은 사용하지 못하게 했어요

zindex 100으로 해뒀습니다 추후 위치나 스타일 조정할 수 있다 생각해 프롭스로 className 추가해뒀어요

컨트롤바

컨트롤바는 회원/비회원일 때를 판단하기위해 isLoggedIn을 boolen값으로 스타일 구분하고 비회원일 경우 onLogin으로 로그인 페이지로 이동 할 수 있게 해뒀어요.
모든 프롭스는 필수입니다 비회원일 때 userName 빈 문자열로 넘겨줘도 괜찮아서 그냥 모든 프롭스를 필수로 뒀는데 더 좋은 방식이 있다면 공유해주세요

사용방법

헤더

<Header title={'안녕 글다'} onClick={() => {}} color='mint50' /> // 이게 컬러 분기처리입니다
<Header title={'안녕 글다'} onClick={() => {}} />

컨트롤바

 <ControlBar isLoggedIn={false} onLogin={() => {}} userName={''} />
<ControlBar isLoggedIn={true} userName='홍길동' onLogin={() => {}} />

📸 피그마 스크린샷 or 기능 GIF

스크린샷 2025-10-17 오후 4 31 53 스크린샷 2025-10-17 오후 4 32 23 image

Summary by CodeRabbit

  • New Features

    • 상단 고정 헤더 추가: 뒤로가기 버튼, 중앙 타이틀, 민트 색상 계열 테마 지원
    • 사용자 상태에 따라 동작하는 컨트롤바 추가: 로그인 전 버튼 또는 사용자명 표시 및 접근성 속성 포함
    • 메인 화면에 헤더 및 컨트롤바 반영으로 UI 구성 업데이트
  • Other

    • 메인 콘텐츠 일부 아이콘 정리로 표시 간소화

@jjangminii jjangminii linked an issue Oct 17, 2025 that may be closed by this pull request
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Oct 17, 2025

Walkthrough

Header와 ControlBar 컴포넌트를 src/shared/components/header/*에 추가하고 src/shared/components/index.ts에 재수출했으며, src/pages/index.tsx에 통합해 일부 아이콘을 제거하고 상단 제어바들을 삽입했습니다. (≤50단어)

Changes

Cohort / File(s) 요약
헤더 컴포넌트
src/shared/components/header/Header.tsx
고정 상단 Header 컴포넌트 추가. 뒤로가기 버튼(onClick), 중앙 제목, 우측 스페이서, color variants(mint300/mint50), cva 기반 스타일링, Caret 아이콘 사용, default export.
컨트롤바 컴포넌트
src/shared/components/header/ControlBar.tsx
인증 상태에 따라 다른 우측 제어를 렌더하는 ControlBar 추가. props: isLoggedIn, onLogin, userName, className. guest일 땐 로그인 버튼, loggedIn일 땐 사용자 표시(아이콘 + 축약된 이름 + 님). ARIA 레이블 포함, default export.
공용 재수출
src/shared/components/index.ts
HeaderControlBar를 각각 ./header/Header./header/ControlBar에서 재수출하도록 추가.
페이지 통합 변경
src/pages/index.tsx
Header, ControlBar를 임포트하여 페이지 상단에 삽입. 기존의 일부 아이콘(CalendarBlank, 일부 User 아이콘)이 제거되고 두 개의 ControlBar가 사용됨. 기존 h1 및 주요 레이아웃 구조는 유지.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Page as MainPage (`src/pages/index.tsx`)
  participant Header as Header (`Header.tsx`)
  participant Control as ControlBar (`ControlBar.tsx`)
  participant User as User

  Note over Page,Header: 페이지 렌더링 시 상단 컴포넌트 삽입
  Page->>Header: render(title, onClick)
  Page->>Control: render(isLoggedIn, userName, onLogin)

  alt 뒤로가기 클릭
    User->>Header: click back
    Header-->>Page: invoke onClick()
  end

  alt 비인증 상태
    User->>Control: click "로그인"
    Control-->>Page: invoke onLogin()
  else 인증 상태
    User->>Control: view userName/icon
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–30 minutes

Poem

🐇 깡충, 새 헤더 하나 얹었네,
뒤로 폴짝, 가운데 제목 환하게,
오른편엔 누군가의 이름 또는 버튼,
아이콘 몇 개는 길 떠나보냈지,
민트빛 바람에 페이지가 웃네 ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Out of Scope Changes Check ✅ Passed 모든 코드 변경사항이 연결된 이슈 #17(헤더 및 컨트롤바 컴포넌트 제작)의 범위 내에 있습니다. Header 및 ControlBar 컴포넌트 구현, 배럴파일을 통한 임포트 경로 통합, 그리고 페이지에서의 컴포넌트 사용 예시 추가는 모두 이슈의 목표 달성과 직접 관련이 있습니다. raw_summary에서 확인되는 모든 파일 변경(Header.tsx, ControlBar.tsx, index.ts, pages/index.tsx)이 이슈 해결에 필수적인 변경들입니다.
Description Check ✅ Passed PR 설명은 제공된 템플릿의 모든 필수 섹션을 포함하고 있습니다. 🔥 작업 내용, 🤔 추후 작업 사항, 🔗 이슈 항목이 모두 작성되었으며, PR Point 섹션에서 배럴파일 추가 의도, 헤더 컴포넌트 색상 분기 처리, 컨트롤바 회원/비회원 분기 처리에 대한 상세한 설명이 제공됩니다. 추가로 구체적인 사용 예시 코드와 피그마 스크린샷 3장이 첨부되어 있어 검토자가 변경사항을 명확히 이해할 수 있습니다.
Title Check ✅ Passed 제목 "header components 구현"은 changeset의 주요 변경을 정확하게 반영합니다. 실제로 Header와 ControlBar 두 개의 새로운 헤더 컴포넌트가 구현되었으며, 이들이 공유 컴포넌트 인덱스를 통해 내보내지고 있습니다. 제목은 구체적이고 명확하여 팀원이 변경 이력을 스캔할 때 주요 변경을 쉽게 이해할 수 있습니다.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#17/header-components

Comment @coderabbitai help to get the list of available commands and usage tips.

@vercel
Copy link
Copy Markdown

vercel bot commented Oct 17, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
af-fe Ready Ready Preview Comment Oct 17, 2025 9:28am

@github-actions
Copy link
Copy Markdown

🏷️ Labeler has automatically applied labels based on your PR title, branch name, or commit message.
Please verify that they are correct before merging.

@github-actions github-actions bot added the comment 필요한 주석 추가 및 변경 label Oct 17, 2025
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/shared/components/header/Header.tsx (1)

33-33: 다국어 지원 시 aria-label도 i18n 처리를 고려하세요.

현재 aria-label이 한국어로 하드코딩되어 있습니다. 향후 다국어 지원이 필요한 경우, 이 텍스트도 번역 파일로 분리하는 것을 권장합니다.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d2d7fba and 5813236.

📒 Files selected for processing (2)
  • src/pages/index.tsx (1 hunks)
  • src/shared/components/header/Header.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/pages/index.tsx (2)
src/shared/icons/components/icon.tsx (1)
  • Icon (54-101)
src/shared/icons/index.ts (1)
  • Icon (18-18)
src/shared/components/header/Header.tsx (1)
src/shared/lib/utils.ts (1)
  • cn (71-73)
🔇 Additional comments (4)
src/shared/components/header/Header.tsx (3)

1-10: LGTM! 타입 정의가 올바릅니다.

imports와 interface 정의가 깔끔하고, CVA의 VariantProps를 사용한 color prop 타입 지정이 정확합니다.


40-50: LGTM! 레이아웃 구조가 우수합니다.

Grid 레이아웃으로 제목을 중앙 정렬하고 양쪽에 동일한 크기의 요소를 배치하여 균형을 맞춘 접근 방식이 훌륭합니다. 빈 spacer div에 aria-hidden을 적절하게 적용했습니다.


31-38: 리뷰 의견이 부정확합니다.

이 코드베이스의 Caret.svg 파일을 검토한 결과, Caret 아이콘은 이미 왼쪽을 가리키고 있습니다 (SVG 경로: M15 19.5 L7.5 12 L15 4.5). 따라서 뒤로 가기 버튼으로 사용할 때 rotate prop이 필요하지 않습니다. 또한 Icon 컴포넌트는 rotate prop을 지원하고 있으므로, 필요한 경우 회전을 적용할 수 있습니다.

현재 코드는 올바르게 구현되어 있습니다.

Likely an incorrect or invalid review comment.

src/pages/index.tsx (1)

1-1: LGTM! import가 올바릅니다.

Header 컴포넌트의 import가 정확합니다.

<>
<div className='flex flex-col items-center justify-center min-h-screen py-2 bg-gray-50'>
<main className='flex flex-col items-center justify-center w-full flex-1 px-4 sm:px-20 text-center'>
<Header title={'안녕 글다'} onClick={() => {}} className='' />
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

불필요한 빈 className prop과 빈 onClick 핸들러를 제거하세요.

  1. className=''은 선택적 prop이므로 빈 문자열을 전달할 필요가 없습니다.
  2. onClick 핸들러는 데모용이지만, 실제로는 페이지 네비게이션 로직(예: router.back())이 필요합니다.

다음과 같이 수정하는 것을 권장합니다:

-          <Header title={'안녕 글다'} onClick={() => {}} className='' />
+          <Header title={'안녕 글다'} onClick={() => window.history.back()} />

또는 Next.js router 사용:

import { useRouter } from 'next/router';

export default function Home() {
  const router = useRouter();
  
  return (
    <>
      {/* ... */}
      <Header title={'안녕 글다'} onClick={() => router.back()} />
      {/* ... */}
    </>
  );
}
🤖 Prompt for AI Agents
In src/pages/index.tsx around line 9: remove the unnecessary empty className
prop and replace the empty onClick handler with real navigation — import
useRouter from 'next/router', call const router = useRouter() inside the Home
component, and pass onClick={() => router.back()} to Header; update imports
accordingly and remove className='' from the Header JSX.

Comment on lines +12 to +25
const headerStyle = cva(
'w-full h-[11.8rem] px-[1.6rem] pb-[1.8rem] pt-[7.6rem] fixed top-0 left-0 right-0 z-[100]',
{
variants: {
color: {
mint300: 'bg-mint-300',
mint50: 'bg-mint-50',
},
},
defaultVariants: {
color: 'mint300',
},
},
);
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

고정 헤더로 인한 콘텐츠 겹침 문제가 발생할 수 있습니다.

헤더가 fixed 포지션으로 top-0에 고정되어 있고 높이가 11.8rem이므로, 페이지 콘텐츠가 헤더 아래에 가려질 수 있습니다. 페이지 본문에 헤더 높이만큼의 padding-top 또는 margin-top을 추가해야 합니다.

예를 들어, 이 Header를 사용하는 페이지의 main 컨텐츠에 pt-[11.8rem] 클래스를 추가하거나, body 레이아웃 컴포넌트에서 처리하는 것을 권장합니다.

🤖 Prompt for AI Agents
In src/shared/components/header/Header.tsx around lines 12 to 25, the header is
positioned fixed at top-0 with a height of 11.8rem which will overlap page
content; update the layout so main page content gets a top offset equal to the
header height — either add pt-[11.8rem] (or margin-top: 11.8rem) to the main
container where Header is used, or export a headerHeight constant from this
module and apply that value to the body/main wrapper (or a layout component) so
all pages consistently receive the correct padding-top to avoid content being
hidden under the fixed header.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
src/shared/components/header/ControlBar.tsx (2)

28-29: 불필요한 타입 단언을 제거하세요.

조건 연산자의 결과는 이미 리터럴 타입으로 추론되므로 as const 단언이 불필요합니다. 코드를 간결하게 유지하세요.

다음과 같이 수정하세요:

-  const rightState = isLoggedIn ? 'loggedIn' : ('guest' as const);
-  const iconColor = isLoggedIn ? 'mint-600' : ('gray-400' as const);
+  const rightState = isLoggedIn ? 'loggedIn' : 'guest';
+  const iconColor = isLoggedIn ? 'mint-600' : 'gray-400';

12-20: 고정 너비 값의 반응형 대응을 검토하세요.

여러 곳에서 고정 너비(w-[7.8rem], w-[5.3rem])가 사용되고 있습니다. 작은 화면에서는 레이아웃이 깨질 수 있으므로 반응형 디자인을 고려하세요.

예를 들어, 최소/최대 너비를 활용하거나 미디어 쿼리를 추가할 수 있습니다:

-const rightStyle = cva('flex items-center gap-[0.6rem] transition w-[7.8rem]', {
+const rightStyle = cva('flex items-center gap-[0.6rem] transition min-w-[7.8rem] max-w-[12rem]', {

Also applies to: 43-43, 46-46

src/pages/index.tsx (1)

16-16: 불필요한 빈 줄을 제거하세요.

코드 일관성을 위해 불필요한 빈 줄을 제거하세요.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5813236 and c3c916e.

📒 Files selected for processing (3)
  • src/pages/index.tsx (1 hunks)
  • src/shared/components/header/ControlBar.tsx (1 hunks)
  • src/shared/components/index.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/pages/index.tsx (2)
src/shared/icons/index.ts (1)
  • Icon (18-18)
src/shared/icons/components/icon.tsx (1)
  • Icon (54-101)
src/shared/components/header/ControlBar.tsx (1)
src/shared/lib/utils.ts (1)
  • cn (71-73)
🔇 Additional comments (3)
src/shared/components/header/ControlBar.tsx (2)

34-37: 플레이스홀더 요소의 목적을 명확히 하거나 제거를 고려하세요.

현재 하드코딩된 회색 박스(bg-gray-200)가 왼쪽에 배치되어 있습니다. 이 요소의 목적이 명확하지 않으며, 향후 실제 컨텐츠(예: 로고, 네비게이션 버튼)로 교체될 예정이라면 prop으로 받거나 주석으로 설명을 추가하는 것이 좋습니다.

이 플레이스홀더가 디자인 시안에 따른 것인지, 향후 교체될 요소인지 확인해주세요.


39-41: 중복된 제목 렌더링을 검토하세요.

ControlBarHeader 컴포넌트 모두 제목을 렌더링하는 것으로 보입니다. ControlBar의 h1 요소에 하드코딩된 '글다' 제목이 있고, Header 컴포넌트도 별도의 title prop을 받습니다. 이는 의도된 설계인지 확인이 필요합니다.

  • ControlBarHeader가 함께 사용되는 경우 제목이 중복되지 않는지 확인하세요.
  • 제목이 prop으로 커스터마이징 가능해야 하는지 검토하세요.
src/shared/components/index.ts (1)

1-2: LGTM!

표준 배럴 익스포트 패턴이 올바르게 적용되었습니다. 컴포넌트를 패키지 루트에서 import할 수 있도록 깔끔하게 재수출하고 있습니다.

Comment on lines +9 to +11
<Header onClick={() => {}} className='' title={'글다'} />
<ControlBar isLoggedIn={false} onLogin={() => {}} />
<ControlBar isLoggedIn={true} userName='홍길동' />
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

데모용 코드를 실제 로직으로 교체하세요.

현재 Header와 두 개의 ControlBar가 동시에 렌더링되고 있으며, 빈 핸들러와 빈 className이 전달되고 있습니다. 이는 테스트/데모 목적으로 보이며, 프로덕션 코드에서는 다음과 같이 수정되어야 합니다:

  1. 실제 로그인 상태에 따라 하나의 ControlBar만 렌더링
  2. onClick 핸들러에 실제 네비게이션 로직 구현
  3. 불필요한 빈 className 제거

다음과 같이 수정하는 것을 권장합니다:

import { useRouter } from 'next/router';

export default function Home() {
  const router = useRouter();
  // 실제 로그인 상태는 context나 store에서 가져와야 함
  const isLoggedIn = false; // 예시
  const userName = '홍길동'; // 실제 유저 정보

  return (
    <>
      <div className='flex flex-col items-center justify-center min-h-screen py-2 bg-gray-50'>
        <main className='flex flex-col items-center justify-center w-full flex-1 px-4 sm:px-20 text-center pt-[11.8rem]'>
          <Header 
            title='글다' 
            onClick={() => router.back()} 
          />
          <ControlBar 
            isLoggedIn={isLoggedIn}
            onLogin={() => router.push('/login')}
            userName={userName}
          />
          {/* ... */}
🤖 Prompt for AI Agents
In src/pages/index.tsx around lines 9-11, replace the demo code that renders
Header and two ControlBar components with a production-ready implementation:
render only one ControlBar selected by real auth state (from context/store or a
hook), remove the empty className on Header, and implement real navigation
handlers using next/router (e.g., router.back() for Header onClick and
router.push('/login') for onLogin); pass userName only when logged in and ensure
handlers call router methods rather than empty functions.

Comment on lines +5 to +10
interface ControlBarProps {
isLoggedIn: boolean;
onLogin?: () => void;
userName?: string;
className?: string;
}
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

인터페이스와 기본값 불일치를 수정하세요.

isLoggedIn이 인터페이스에서는 필수 prop(boolean)으로 정의되어 있지만, 컴포넌트에서는 기본값(false)을 제공합니다. 인터페이스에서도 선택적으로 변경해야 일관성이 유지됩니다.

다음과 같이 수정하세요:

 interface ControlBarProps {
-  isLoggedIn: boolean;
+  isLoggedIn?: boolean;
   onLogin?: () => void;
   userName?: string;
   className?: string;
 }
📝 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
interface ControlBarProps {
isLoggedIn: boolean;
onLogin?: () => void;
userName?: string;
className?: string;
}
interface ControlBarProps {
isLoggedIn?: boolean;
onLogin?: () => void;
userName?: string;
className?: string;
}
🤖 Prompt for AI Agents
src/shared/components/header/ControlBar.tsx around lines 5 to 10: the
ControlBarProps interface declares isLoggedIn as a required boolean but the
component provides a default value (false); make the interface consistent by
changing isLoggedIn to an optional prop (isLoggedIn?: boolean) so the prop
signature matches the component's defaulting behavior.

const iconColor = isLoggedIn ? 'mint-600' : ('gray-400' as const);

return (
<header className={cn('bg-none w-full h-[5.4rem]', className)} role='group'>
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

role='group' 속성을 제거하세요.

<header> 요소는 이미 landmark 역할을 가지고 있어 추가적인 role='group'은 불필요하며 접근성을 오히려 저해할 수 있습니다.

다음과 같이 수정하세요:

-    <header className={cn('bg-none w-full h-[5.4rem]', className)} role='group'>
+    <header className={cn('bg-none w-full h-[5.4rem]', className)}>
📝 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
<header className={cn('bg-none w-full h-[5.4rem]', className)} role='group'>
<header className={cn('bg-none w-full h-[5.4rem]', className)}>
🤖 Prompt for AI Agents
In src/shared/components/header/ControlBar.tsx around line 32, remove the
redundant role='group' attribute from the <header> element (leave the className
and other props intact) so the header retains its native landmark semantics and
does not override or harm accessibility.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/pages/index.tsx (1)

1-1: 사용되지 않는 import 제거 필요

파일 전체를 검토한 결과 HeaderControlBar 컴포넌트를 import하고 있으나 파일의 어디에서도 사용되지 않고 있습니다. 이 import들을 제거하세요:

-import { ControlBar, Header } from '@/shared/components';
 import { Icon } from '@/shared/icons';
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c3c916e and 5c6f604.

📒 Files selected for processing (1)
  • src/pages/index.tsx (2 hunks)

@jjangminii jjangminii added the feat 새로운 기능 추가 / 퍼블리싱 label Oct 17, 2025
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
src/pages/index.tsx (1)

9-11: 데모 코드를 실제 구현으로 교체하세요.

현재 코드는 여전히 데모 상태입니다:

  • onClick={() => {}} 핸들러
  • 불필요한 빈 className=''
  • 두 개의 ControlBar가 동시에 렌더링됨
  • onLogin 핸들러들

프로덕션 환경에서는 실제 인증 상태에 따라 하나의 ControlBar만 조건부로 렌더링하고, 실제 라우팅 로직을 구현해야 합니다.

import { useRouter } from 'next/router';

export default function Home() {
  const router = useRouter();
  const isLoggedIn = false; // 실제 인증 상태로 교체
  const userName = '홍길동'; // 실제 사용자 정보로 교체

  return (
    <>
      <div className='flex flex-col items-center justify-center  min-h-screen py-2 bg-gray-50'>
        <main className='flex flex-col items-center justify-center w-full flex-1 px-4 sm:px-20 text-center'>
          <Header title='글다' onClick={() => router.back()} />
          <ControlBar 
            isLoggedIn={isLoggedIn}
            onLogin={() => router.push('/login')}
            userName={userName}
          />
src/shared/components/header/ControlBar.tsx (2)

5-10: 인터페이스와 실제 사용의 불일치를 수정하세요.

인터페이스와 컴포넌트 구현 간에 여러 불일치가 있습니다:

  1. isLoggedIn이 필수 prop이지만 컴포넌트에서 기본값을 제공 (이전 리뷰에서도 지적됨)
  2. onLogin이 필수 prop이지만 Line 57에서 onLogin?.()로 선택적으로 사용됨
  3. userName이 필수 prop이지만 Line 25에서 기본값 '글다'를 제공

다음과 같이 수정하세요:

 interface ControlBarProps {
-  isLoggedIn: boolean;
-  onLogin: () => void;
-  userName: string;
+  isLoggedIn?: boolean;
+  onLogin?: () => void;
+  userName?: string;
   className?: string;
 }

32-32: role='group' 속성을 제거하세요.

<header> 요소는 이미 landmark 역할을 가지고 있어 추가적인 role='group'은 불필요하며 접근성을 저해할 수 있습니다.

-    <header className={cn('bg-none w-full h-[5.4rem]', className)} role='group'>
+    <header className={cn('bg-none w-full h-[5.4rem]', className)}>
🧹 Nitpick comments (1)
src/shared/components/header/ControlBar.tsx (1)

28-29: 불필요한 타입 단언을 제거하세요.

TypeScript는 문자열 리터럴의 타입을 자동으로 추론하므로 as const 단언이 불필요합니다.

-  const rightState = isLoggedIn ? 'loggedIn' : ('guest' as const);
-  const iconColor = isLoggedIn ? 'mint-600' : ('gray-400' as const);
+  const rightState = isLoggedIn ? 'loggedIn' : 'guest';
+  const iconColor = isLoggedIn ? 'mint-600' : 'gray-400';
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a7cf7b4 and 1dc2915.

📒 Files selected for processing (2)
  • src/pages/index.tsx (1 hunks)
  • src/shared/components/header/ControlBar.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/shared/components/header/ControlBar.tsx (1)
src/shared/lib/utils.ts (1)
  • cn (71-73)
src/pages/index.tsx (1)
src/shared/icons/components/icon.tsx (1)
  • Icon (54-101)
🔇 Additional comments (1)
src/shared/components/header/ControlBar.tsx (1)

34-37: 플레이스홀더 요소의 목적을 명확히 하거나 제거를 고려하세요.

회색 배경의 플레이스홀더 div가 명확한 목적 없이 렌더링되고 있습니다. 이것이 향후 기능을 위한 공간 예약인지, 아니면 제거해야 하는 임시 요소인지 확인이 필요합니다.

이 요소가 디자인 명세의 일부인지 확인해주세요. 만약 향후 기능을 위한 것이라면 주석으로 설명을 추가하거나, 불필요하다면 제거하는 것을 권장합니다.

const ControlBar = ({
onLogin,
isLoggedIn,
userName = '글다',
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot Oct 17, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

userName 기본값이 의미상 적절하지 않습니다.

사용자 이름의 기본값으로 '글다'를 사용하는 것은 의미상 적절하지 않습니다. 서비스 이름을 사용자 이름 기본값으로 사용하면 혼란을 야기할 수 있습니다.

다음 중 하나로 수정하는 것을 권장합니다:

-  userName = '글다',
+  userName = '사용자',

또는 기본값 없이 빈 문자열로 처리:

-  userName = '글다',
+  userName = '',
📝 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
userName = '글다',
userName = '사용자',
Suggested change
userName = '글다',
userName = '',
🤖 Prompt for AI Agents
In src/shared/components/header/ControlBar.tsx at line 25, the default prop
userName is set to '글다' which is semantically misleading; change the default to
a neutral value (e.g., 'Guest') or an empty string/undefined so the service name
isn't used as a username, and update any related render logic to gracefully
handle the empty/undefined value (show placeholder text or omit the name).

Copy link
Copy Markdown
Contributor Author

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.

@jjangminii, 이해했습니다! 서비스명을 기본 사용자이름으로 사용하는 것이 의도된 디자인이었군요. 설명해주셔서 감사합니다. 제안을 철회하겠습니다. 😊

   🐰
  (^.^)
 (     )
  |   |
 ~~~ ~~~

✏️ Learnings added
Learnt from: jjangminii
PR: geulDa/FE#32
File: src/shared/components/header/ControlBar.tsx:25-25
Timestamp: 2025-10-18T07:48:47.811Z
Learning: In the geulDa/FE project, the service name '글다' is intentionally used as the default userName in the ControlBar component (src/shared/components/header/ControlBar.tsx). This is a deliberate design decision to display the service name as the default username.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@jjangminii jjangminii changed the title Feat: header components 구현 ✨Feat: header components 구현 Oct 17, 2025
Copy link
Copy Markdown
Contributor

@skyblue1232 skyblue1232 left a comment

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

@KongMezu KongMezu left a comment

Choose a reason for hiding this comment

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

빨리 작업해주신 덕분에 코드 보면서 cn,cva 공부할 수 있었습니다. 헤더 부분이라 크게 남길 코멘트는 없어서 바로 approve 했습니다 :)

@jjangminii jjangminii merged commit b49ac52 into develop Oct 19, 2025
7 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Oct 29, 2025
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comment 필요한 주석 추가 및 변경 feat 새로운 기능 추가 / 퍼블리싱

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] 헤더(컨트롤바)

3 participants