Skip to content

Conversation

@constantly-dev
Copy link
Member

@constantly-dev constantly-dev commented Sep 10, 2025

📌 Related Issues

관련된 Issue를 태그해주세요. (e.g. - close #25)

📄 Tasks

  • remind page card sorting
  • myBookmark card sorting
  • sidebar와 main page layout 구현

⭐ PR Point (To Reviewer)

크게 어려운 내용은 없을 것 같아요!
remind 페이지랑 myBookmark 페이지 2개에서 카드가 피그마 명세대로 row당 최대 4개까지 정렬되도록 했습니다. 그리고 정민님이 작업해주신 sidebar받아서 Layout.tsx에 main페이지와 sidebar 레이아웃 잡았습니다.

📷 Screenshot

image image

Summary by CodeRabbit

  • New Features

    • Remind 및 MyBookmark 페이지가 정적에서 인터랙티브 UI로 전환되어 배지 클릭으로 읽음/안 읽음·전체 필터를 즉시 전환할 수 있습니다.
    • 카드 뷰로 제목·내용·남은 시간·카테고리를 한눈에 확인 가능하며 초기(mock) 데이터로 목록을 미리봅니다.
    • 일부 배지가 활성 상태로 시각적으로 표시됩니다.
  • Style

    • 크로스브라우저 스크롤바 숨김 유틸리티가 추가되어 화면이 더 깔끔해졌습니다.
  • Other

    • 레이아웃이 스크롤 가능한 메인 영역으로 개선되어 콘텐츠 탐색이 부드러워졌습니다.

@coderabbitai
Copy link

coderabbitai bot commented Sep 10, 2025

Walkthrough

Remind/MyBookmark을 정적 UI에서 상태 기반 상호작용 UI로 변경하고 Badge를 제어형으로 전환했으며 REMIND_MOCK_DATA로 Card 목록을 렌더링하고 Layout 구조를 flex + 스크롤 가능한 main으로 재구성하고 scrollbar-hide 유틸을 추가했습니다.

Changes

Cohort / File(s) Summary
Remind 페이지 구현
apps/client/src/pages/remind/Remind.tsx
정적 플레이스홀더 대체: activeBadge 상태 및 handleBadgeClick 추가, 제어형 Badge 2개 렌더, REMIND_MOCK_DATACard 목록 렌더링, 헤더/레이아웃 구조 및 API 통합 TODO.
Remind 모의 데이터
apps/client/src/pages/remind/constants/index.ts
REMIND_MOCK_DATA 신규 추가(16개 객체: id, title, content, timeRemaining, category) 및 export.
Badge 제어형 API 변경
packages/design-system/src/components/badge/Badge.tsx
내부 클릭 상태 제거. BadgePropsisActive: boolean, onClick?: () => void 추가. 스타일 variant 키 clickactive로 변경. 호출자가 상태를 제어하도록 수정.
Badge 스토리북 업데이트
packages/design-system/src/components/badge/Badge.stories.tsx
isActive/onClick args 및 argTypes 추가, 상태ful ActiveBadge 스토리 추가(렌더 함수로 내부 토글 시연).
MyBookmark 페이지 구현
apps/client/src/pages/myBookmark/MyBookmark.tsx
플레이스홀더 대체: activeBadge 상태, Badges 및 REMIND_MOCK_DATA 기반 Card 목록 렌더링, 레이아웃/스타일 추가 및 API TODO.
Layout 구조 변경
apps/client/src/layout/Layout.tsx
최상위에 div.flex.h-screen 추가 및 Outletmain.flex-1.overflow-y-auto로 래핑해 스크롤 가능한 메인 영역으로 재구성. 일부 TODO 주석 제거.
Level 페이지 Badge 사용 업데이트
apps/client/src/pages/level/Level.tsx
Badge 호출에 isActive={true} 전달로 활성 상태 표시 추가(로직 변경 없음).
공용 스타일 유틸 추가
packages/tailwind-config/shared-styles.css
.scrollbar-hide 유틸 추가: ::-webkit-scrollbar 숨김 및 -ms-overflow-style, scrollbar-width 규칙 추가(크로스 브라우저).

Sequence Diagram(s)

sequenceDiagram
    actor U as 사용자
    participant RP as RemindPage
    participant B1 as Badge("안 읽음")
    participant B2 as Badge("읽음")
    participant DS as REMIND_MOCK_DATA
    participant UI as CardList

    U->>RP: 페이지 접근
    RP->>DS: REMIND_MOCK_DATA 읽기
    RP->>UI: Card 목록 렌더(데이터 바인딩)
    RP->>B1: props { isActive, onClick }
    RP->>B2: props { isActive, onClick }

    U->>B2: 클릭
    B2->>RP: onClick()
    RP->>RP: setState(activeBadge)
    RP->>UI: 재렌더(선택 반영)
    note right of RP: 서버 필터링은 TODO(현재 로컬 상태만 반영)
Loading
sequenceDiagram
    participant Parent as 상위 컴포넌트
    participant Badge as Badge(Controlled)

    Parent->>Badge: props { text, countNum, isActive, onClick }
    Note right of Badge: 내부 상태 제거 → 이벤트는 부모로 전달
    U->>Badge: 클릭 이벤트
    Badge->>Parent: onClick()
    Parent->>Parent: isActive 업데이트(setState)
    Parent->>Badge: updated props (re-render)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

🛠️ Feature, frontend, 정민

Suggested reviewers

  • jjangminii
  • jllee000

Pre-merge checks (3 passed, 2 warnings)

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Linked Issues Check ⚠️ Warning PR은 대시보드 레이아웃 관련 요구사항을 충족합니다([#50] — Layout.tsx 수정 및 remind/myBookmark 카드 정렬 적용). 그러나 linked_issues에 포함된 #25(Progress 컴포넌트 구현) 요구사항은 코드 변경 내역에서 확인되지 않으며 Progress 컴포넌트, Storybook 데모, 또는 @radix-ui/react-progress 의존성 추가가 없습니다. 따라서 제공된 모든 연결 이슈의 요구사항을 완전히 만족하지 못합니다. 해결: 이 PR에서 #25 구현이 의도된 사항이 아니라면 linked_issues에서 #25를 제거하거나, #25 구현이 필요하면 별도 PR로 Progress 컴포넌트와 관련 문서·의존성을 추가한 후 해당 PR에 링크하세요. 또한 PR 본문 상단에 처리된 이슈 목록을 명확히 기재해 리뷰어 혼선을 줄이세요.
Out of Scope Changes Check ⚠️ Warning 검토 결과 PR에는 대시보드 레이아웃 및 카드 정렬과 직접 관련된 변경 외에 범위를 벗어난 수정이 포함되어 있습니다. 특히 packages/design-system의 Badge 컴포넌트 API 변경(isActive/onClick 추가) 및 Badge Storybook 수정은 공개 인터페이스를 변경하는 브레이킹 가능성이 있어 레이아웃 이슈(#50)와 직접 관련이 없으므로 분리하는 것이 적절합니다. 또한 packages/tailwind-config/shared-styles.css에 scrollbar-hide 유틸 추가와 Storybook·디자인 시스템 관련 파일 변경도 레이아웃 구현의 핵심 목표와는 별개로 보입니다. 해결: design-system 관련 변경은 별도 PR로 분리하거나 PR 본문에 해당 변경의 의도와 브레이킹 여부, 마이그레이션 가이드를 명확히 기재해 소비자 코드가 안전하게 업데이트되도록 하세요. 또한 레이아웃·페이지 변경만 포함한 최소한의 PR로 분할해 리뷰 범위를 좁히는 것을 권장합니다.
✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed 제목 'Feat(client): 대시보드 레이아웃 구현'은 PR의 주요 목적(대시보드/레이아웃 구현, 관련 이슈 #50)을 명확하고 간결하게 요약하며 한 문장으로 핵심 변경을 잘 드러내어 히스토리 스캔 시 이해하기 쉽습니다. 다만 변경내역을 보면 design-system의 Badge 공개 API 변경 등 레이아웃 범위를 벗어나는 영향력이 큰 수정도 포함되어 있어 제목만으로는 PR의 전체 범위를 완전히 전달하지는 않습니다.
Description Check ✅ Passed PR 본문은 템플릿의 필수 섹션(관련 이슈, 작업 목록, PR 포인트, 스크린샷)을 포함해 전반적으로 양식에 맞게 작성되어 있으며 remind/myBookmark 카드 정렬과 레이아웃 통합 목적을 명확히 서술하고 있어 대부분의 검토 목적에는 충분합니다. 다만 변경 내역 요약에는 design-system의 Badge API 변경, Storybook 수정, 전역 스타일(css) 추가 등 영향 범위가 큰 항목들이 포함되어 있으나 본문에 언급되어 있지 않아 브레이킹 여부와 소비자 수정 필요성을 즉시 파악하기 어렵습니다.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

Poem

풀밭에 앉아 코드 훑는 토끼,
배지 클릭에 마음이 깡충깡충,
카드가 줄지어 춤을 추네,
스크롤 숨기니 보기가 깔끔해,
배포 전 당근 한 입, 홧팅! 🐇✨

✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#50/dashboard-layout

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.

❤️ Share

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

@github-actions github-actions bot added the feat 기능 개발하라 개발 달려라 달려 label Sep 10, 2025
@github-actions
Copy link

github-actions bot commented Sep 10, 2025

✅ Storybook chromatic 배포 확인:
🐿️ storybook

Copy link

@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

🧹 Nitpick comments (7)
packages/tailwind-config/shared-styles.css (1)

161-169: scrollbar-hide는 Tailwind 레이어(@layer utilities) 안에 선언 권장

Tailwind 빌드/정렬 우선순위 및 purge 안정성을 위해 유틸리티는 @layer utilities 안에 두는 것이 안전합니다. 아래처럼 감싸 주세요.

- .scrollbar-hide::-webkit-scrollbar {
-   display: none;
- }
-
- /* 기타 브라우저용 (IE, Edge 구버전, Firefox) */
- .scrollbar-hide {
-   -ms-overflow-style: none;  /* IE and Edge */
-   scrollbar-width: none;  /* Firefox */
- }
+@layer utilities {
+  .scrollbar-hide::-webkit-scrollbar {
+    display: none;
+  }
+
+  /* 기타 브라우저용 (IE, Edge 구버전, Firefox) */
+  .scrollbar-hide {
+    -ms-overflow-style: none;  /* IE and Edge */
+    scrollbar-width: none;     /* Firefox */
+  }
+}
apps/client/src/pages/remind/constants/index.ts (1)

108-113: 15/16번 항목이 동일한 콘텐츠로 중복됨

의도된 중복이 아니라면 샘플 다양성을 위해 하나를 변경하는 편이 좋습니다.

   {
     id: 16,
-    title: '팀 회의록 정리',
-    content: '어제 진행된 스프린트 계획 회의 내용 정리해서 공유',
+    title: '팀 회의록 최종 검토',
+    content: '피드백 반영 후 최종본 정리 및 공유',
     timeRemaining: '완료',
     category: '업무',
   },
packages/design-system/src/components/badge/Badge.tsx (1)

5-6: onClick을 필수로 두면 비대화형 배지 재사용성이 떨어집니다

HTMLButton 속성을 확장하고 onClick을 선택으로 두면 범용성이 올라갑니다. 위 diff와 함께 적용해 주세요.

-import { cva } from 'class-variance-authority';
+import { cva } from 'class-variance-authority';
+import type { ButtonHTMLAttributes } from 'react';
 
-export interface BadgeProps {
+export interface BadgeProps extends ButtonHTMLAttributes<HTMLButtonElement> {
   text: string;
   countNum?: number;
-  isActive: boolean;
-  onClick: () => void;
+  isActive?: boolean;
 }
apps/client/src/pages/remind/Remind.tsx (4)

6-10: activeBadge에 리터럴 유니온 타입 적용으로 오타 방지

문자열 상수 대신 유니온 타입으로 제약하면 안전합니다.

-  const [activeBadge, setActiveBadge] = useState('notRead');
+  type BadgeType = 'notRead' | 'read';
+  const [activeBadge, setActiveBadge] = useState<BadgeType>('notRead');
 
-  const handleBadgeClick = (badgeType: string) => {
+  const handleBadgeClick = (badgeType: BadgeType) => {
     setActiveBadge(badgeType);
   };

16-27: 배지 카운트 하드코딩 — 데이터 기반으로 계산하도록 후속 처리

API 연동 시 읽음/안읽음 플래그를 기준으로 countNum을 계산하도록 TODO 남겨두는 것이 좋습니다.

원하시면 mock에 isRead 필드를 추가해 필터링/카운팅 로직까지 같이 제안드릴게요.


30-42: 스크롤바 완전 숨김 사용은 접근성/발견성 저하 우려

가능하면 기본은 .ds-scrollbar를 쓰고, 캐러셀 등 제한 케이스에만 .scrollbar-hide를 적용하세요. 이미 .ds-scrollbar 유틸이 있으므로 우선 적용 검토를 권장합니다.


32-32: 미사용 변수(index) 제거하여 lint 경고 해결

map 콜백에서 index를 쓰지 않습니다. 제거해 주세요.

-        {REMIND_MOCK_DATA.map((data, index) => (
+        {REMIND_MOCK_DATA.map((data) => (
           <Card
             key={data.id}
             type="remind"
             title={data.title}
             content={data.content}
             timeRemaining={data.timeRemaining}
             category={data.category}
           />
         ))}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6149315 and e0b98cf.

📒 Files selected for processing (4)
  • apps/client/src/pages/remind/Remind.tsx (1 hunks)
  • apps/client/src/pages/remind/constants/index.ts (1 hunks)
  • packages/design-system/src/components/badge/Badge.tsx (1 hunks)
  • packages/tailwind-config/shared-styles.css (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#2
File: pnpm-workspace.yaml:3-3
Timestamp: 2025-08-18T13:48:59.065Z
Learning: constantly-dev는 docs 디렉터리를 컨벤션 문서 추가용으로 사용할 예정이라고 명시했습니다.
🧬 Code graph analysis (1)
apps/client/src/pages/remind/Remind.tsx (2)
packages/design-system/src/components/card/Card.stories.tsx (1)
  • Remind (42-53)
apps/client/src/pages/remind/constants/index.ts (1)
  • REMIND_MOCK_DATA (1-114)
🪛 GitHub Check: lint
apps/client/src/pages/remind/Remind.tsx

[warning] 32-32:
'index' is defined but never used

🔇 Additional comments (3)
apps/client/src/pages/remind/constants/index.ts (1)

1-114: satisfies를 활용한 목데이터 타입 안전성 적용 가능 확인됨
루트와 design-system 패키지의 TypeScript 버전이 모두 5.9.2로 satisfies 사용이 가능합니다. 제안된 RemindItem 타입 정의 및 export const REMIND_MOCK_DATA satisfies ReadonlyArray<RemindItem> = […] as const; 변경을 적용하세요.

packages/design-system/src/components/badge/Badge.tsx (1)

21-34: CVA variant를 active로 통일한 점 깔끔합니다

텍스트/카운트 스타일 모두 동일 키로 제어되어 유지보수가 용이합니다.

apps/client/src/pages/remind/Remind.tsx (1)

1-4: PR 제목(대시보드 레이아웃)과 변경 내용(Remind 페이지/Badge/공용 스타일)이 불일치

리뷰어/릴리즈 노트 혼선을 줄이기 위해 제목 또는 PR 범위를 정렬해 주세요. 필요 시 Remind 관련 변경은 별도 PR로 분리 권장.

Comment on lines +36 to +47
const Badge = ({ text, countNum, isActive, onClick }: BadgeProps) => {
return (
<div
className="flex cursor-pointer items-center justify-center gap-[0.8rem]"
onClick={() => setIsClick(true)}
onClick={onClick}
>
<span className={BadgeTxtStyleVariants({ click: isClick })}>{text}</span>
<span className={BadgeStyleVariants({ click: isClick })}>{countNum}</span>
<span className={BadgeTxtStyleVariants({ active: isActive })}>
{text}
</span>
<span className={BadgeStyleVariants({ active: isActive })}>
{countNum}
</span>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

div+onClick은 키보드 접근 불가 — 네이티브 button으로 교체 필요

현재 구조는 스크린리더/키보드 사용자가 접근하기 어렵습니다. design-system 컴포넌트이므로 초기에 바로잡는 게 좋습니다.

-const Badge = ({ text, countNum, isActive, onClick }: BadgeProps) => {
+const Badge = ({ text, countNum, isActive = false, onClick, ...rest }: BadgeProps) => {
   return (
-    <div
-      className="flex cursor-pointer items-center justify-center gap-[0.8rem]"
-      onClick={onClick}
-    >
+    <button
+      type="button"
+      aria-pressed={isActive}
+      onClick={onClick}
+      className="flex cursor-pointer items-center justify-center gap-[0.8rem] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main500 focus-visible:ring-offset-2"
+      {...rest}
+    >
       <span className={BadgeTxtStyleVariants({ active: isActive })}>
         {text}
       </span>
       <span className={BadgeStyleVariants({ active: isActive })}>
         {countNum}
       </span>
-    </div>
+    </button>
   );
 };
🤖 Prompt for AI Agents
In packages/design-system/src/components/badge/Badge.tsx around lines 36 to 47,
the interactive element is a div with an onClick which is not
keyboard-accessible or semantic; replace the outer div with a native <button>
element, move the className and onClick onto that button, add type="button" to
avoid form submit behavior, preserve styling (including focus/hover states
instead of cursor-pointer), and ensure any needed ARIA attributes/keyboard
handlers are removed because the native button provides accessibility by
default.

@constantly-dev constantly-dev force-pushed the feat/#50/dashboard-layout branch from e0b98cf to 84faa8d Compare September 10, 2025 15:15
Copy link

@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

♻️ Duplicate comments (1)
packages/design-system/src/components/badge/Badge.tsx (1)

36-49: div+onClick → 네이티브 button으로 교체 (키보드 접근성/의미론)
현재 div에 onClick을 사용해 포커스/키보드 접근이 불가합니다. design-system 컴포넌트이므로 버튼 요소로 전환하고 aria-pressed 및 포커스 링을 제공합니다. 이전 커멘트와 동일 이슈입니다.

적용 제안(diff):

-const Badge = ({ text, countNum, isActive, onClick }: BadgeProps) => {
+const Badge = ({ text, countNum, isActive = false, onClick }: BadgeProps) => {
   return (
-    <div
-      className="flex cursor-pointer items-center justify-center gap-[0.8rem]"
-      onClick={onClick}
-    >
-      <span className={BadgeTxtStyleVariants({ active: isActive })}>
-        {text}
-      </span>
-      <span className={BadgeStyleVariants({ active: isActive })}>
-        {countNum}
-      </span>
-    </div>
+    <button
+      type="button"
+      aria-pressed={isActive}
+      onClick={onClick}
+      className="flex items-center justify-center gap-[0.8rem] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main500 focus-visible:ring-offset-2"
+    >
+      <span className={BadgeTxtStyleVariants({ active: isActive })}>{text}</span>
+      {typeof countNum === 'number' && (
+        <span className={BadgeStyleVariants({ active: isActive })}>{countNum}</span>
+      )}
+    </button>
   );
 };
🧹 Nitpick comments (5)
packages/design-system/src/components/badge/Badge.tsx (2)

5-6: isActive를 선택(provided-optional)으로 전환하거나 기본값 지정
호출 측 단순화를 위해 isActive를 선택 속성으로 두고, 컴포넌트에서 기본값 false를 처리하세요.

-export interface BadgeProps {
+export interface BadgeProps {
   text: string;
   countNum?: number;
-  isActive: boolean;
-  onClick: () => void;
+  isActive?: boolean;
+  onClick: () => void;
 }

(함수 파라미터에서 isActive = false 기본값은 위 버튼 변환 diff에 포함되어 있습니다.)


42-47: countNum가 undefined일 때 뱃지 숨김 처리
현재 undefined가 렌더링될 수 있습니다. 조건부 렌더링으로 UI 안정화하세요. 상단 버튼 변환 diff에서 이미 반영했습니다.

apps/client/src/layout/Layout.tsx (1)

7-12: 레이아웃 리팩터: main에 min-w-0 추가 및 불필요 Fragment 제거

  • 긴 콘텐츠에서 수평 오버플로 방지를 위해 flex row 자식인 main에 min-w-0 권장.
  • 최상위 Fragment는 불필요합니다.
-    <>
-    <div className="flex h-screen">
+    <div className="flex h-screen">
       <Sidebar />
-      <main className="flex-1 overflow-y-auto">
+      <main className="min-w-0 flex-1 overflow-y-auto">
         <Outlet />
       </main>
-    </div>
-    </>
+    </div>

추가로, 모바일 브라우저 주소창 수축 이슈를 고려하면 h-screen 대신 h-dvh 사용을 검토해 주세요. (Tailwind 버전/브라우저 타겟에 따라 선택)

apps/client/src/pages/remind/Remind.tsx (2)

6-10: 상태/핸들러에 유니온 타입 적용으로 타입 안정성 강화
가능한 값이 제한적이므로 유니온 타입으로 명확히 표현하세요.

-  const [activeBadge, setActiveBadge] = useState('notRead');
+  type BadgeType = 'notRead' | 'read';
+  const [activeBadge, setActiveBadge] = useState<BadgeType>('notRead');

-  const handleBadgeClick = (badgeType: string) => {
-    setActiveBadge(badgeType);
-  };
+  const handleBadgeClick = (badgeType: BadgeType) => {
+    setActiveBadge(badgeType);
+  };

30-33: 사용되지 않는 index 제거 (lint 경고 해결)
불필요한 파라미터를 제거해 린트 경고를 없애세요.

-        {REMIND_MOCK_DATA.map((data, index) => (
+        {REMIND_MOCK_DATA.map((data) => (
           <Card
             key={data.id}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e0b98cf and 84faa8d.

📒 Files selected for processing (5)
  • apps/client/src/layout/Layout.tsx (1 hunks)
  • apps/client/src/pages/remind/Remind.tsx (1 hunks)
  • apps/client/src/pages/remind/constants/index.ts (1 hunks)
  • packages/design-system/src/components/badge/Badge.tsx (1 hunks)
  • packages/tailwind-config/shared-styles.css (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/client/src/pages/remind/constants/index.ts
  • packages/tailwind-config/shared-styles.css
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#2
File: pnpm-workspace.yaml:3-3
Timestamp: 2025-08-18T13:48:59.065Z
Learning: constantly-dev는 docs 디렉터리를 컨벤션 문서 추가용으로 사용할 예정이라고 명시했습니다.
📚 Learning: 2025-07-15T20:00:13.756Z
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#80
File: apps/client/src/shared/components/ui/modalPop/ModalPop.tsx:36-41
Timestamp: 2025-07-15T20:00:13.756Z
Learning: In apps/client/src/shared/components/ui/modalPop/ModalPop.tsx, the InfoBox component uses hardcoded values for title, location, and icon URL as temporary test data. These should be replaced with dynamic data from props when implementing actual functionality and should be marked with TODO comments for future changes.

Applied to files:

  • apps/client/src/pages/remind/Remind.tsx
🧬 Code graph analysis (2)
apps/client/src/layout/Layout.tsx (1)
apps/client/src/shared/components/sidebar/Sidebar.tsx (1)
  • Sidebar (27-150)
apps/client/src/pages/remind/Remind.tsx (2)
packages/design-system/src/components/card/Card.stories.tsx (1)
  • Remind (42-53)
apps/client/src/pages/remind/constants/index.ts (1)
  • REMIND_MOCK_DATA (1-114)
🪛 GitHub Check: lint
apps/client/src/pages/remind/Remind.tsx

[warning] 32-32:
'index' is defined but never used

🔇 Additional comments (3)
packages/design-system/src/components/badge/Badge.tsx (1)

11-19: 스타일 variant 리네이밍(click→active) 및 기본값 설정 LGTM
variant 명세와 기본값이 명확하며, 텍스트/카운트 모두 동일한 active 상태를 공유하도록 구성된 점 좋습니다.

Also applies to: 25-33

apps/client/src/pages/remind/Remind.tsx (2)

16-27: Badge 제어형(isActive/onClick) 연결 LGTM
상태와 props 연결이 간결하고 의도 명확합니다.


30-42: 중첩 스크롤 여부 확인 요청 (main과 섹션 모두 overflow-y-auto)
Layout의 main과 본 섹션 모두 세로 스크롤을 갖습니다. UX 의도에 따라 하나만 스크롤되도록 정리하는 것이 일반적입니다. 메인만 스크롤하려면 본 섹션의 overflow-y-auto 제거를 권장합니다.

Copy link

@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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 84faa8d and 38700f0.

📒 Files selected for processing (3)
  • apps/client/src/pages/level/Level.tsx (1 hunks)
  • apps/client/src/pages/remind/Remind.tsx (1 hunks)
  • packages/design-system/src/components/badge/Badge.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/design-system/src/components/badge/Badge.tsx
  • apps/client/src/pages/remind/Remind.tsx
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#2
File: pnpm-workspace.yaml:3-3
Timestamp: 2025-08-18T13:48:59.065Z
Learning: constantly-dev는 docs 디렉터리를 컨벤션 문서 추가용으로 사용할 예정이라고 명시했습니다.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: storybook

</div>

<Badge text="오늘 모은 도토리 개수" countNum={acorns} />
<Badge text="오늘 모은 도토리 개수" countNum={acorns} isActive={true} />
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

불리언 리터럴 제거(축약형 사용) + 활성 상태 의도 확인

JSX에서는 isActivetrue일 때 속성 축약이 가능합니다. 또한 이 배지가 Level 페이지에서 항상 활성 스타일이어야 하는지 의도를 한 번만 확인해주세요(토글/선택 개념이 아니라 상시 표시라면 OK).

다음처럼 간소화 가능:

-            <Badge text="오늘 모은 도토리 개수" countNum={acorns} isActive={true} />
+            <Badge text="오늘 모은 도토리 개수" countNum={acorns} isActive />

리팩터 후 디자인시스템 변경(isActive 필수)에 따라 다른 사용처 누락이 없는지 확인하려면 아래 스크립트를 실행하세요.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Badge를 import하는 파일 나열
mapfile -t FILES < <(rg -nP --type=ts --type=tsx 'import\s*{\s*Badge\s*}\s*from' -o --no-filename | cut -d: -f1 | sort -u)
if [ "${#FILES[@]}" -eq 0 ]; then
  # fallback: 파일 경로를 함께 뽑기
  mapfile -t FILES < <(rg -nP --type=ts --type=tsx 'import\s*{\s*Badge\s*}\s*from' | cut -d: -f1 | sort -u)
fi

# 2) 각 파일에서 <Badge ...> 사용시 isActive 존재 여부 확인
for f in "${FILES[@]}"; do
  echo "=== $f ==="
  rg -nP -C2 '<Badge\b' "$f" || true
  if ! rg -nP '(<Badge\b[^>]*\bisActive\b)' "$f" >/dev/null; then
    echo "[WARN] isActive prop 누락 가능성: $f"
  fi
done

Length of output: 84


기존 스크립트가 bash의 프로세스 치환과 rg --type=tsx 인식 오류로 실패했습니다. 아래 스크립트로 Badge 사용처를 다시 조회하고 isActive 누락 여부를 확인해 주세요.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Badge를 import하는 파일 나열 (*.ts, *.tsx)
mapfile -t FILES < <(rg -l -g '*.ts' -g '*.tsx' "import\s*{\s*Badge\s*}\s*from")

if [ "${#FILES[@]}" -eq 0 ]; then
  echo "Badge를 import한 파일이 없습니다."
  exit 0
fi

# 2) 각 파일에서 <Badge ...> 사용 시 isActive 존재 여부 확인
for f in "${FILES[@]}"; do
  echo "=== $f ==="
  rg -nC2 '<Badge\b' "$f" || true
  if ! rg -q '<Badge\b[^>]*\bisActive\b' "$f"; then
    echo "[WARN] isActive prop 누락 의심: $f"
  fi
done

Length of output: 178


아래 스크립트는 중괄호를 이스케이프하고 PCRE 옵션(-P)을 사용해 Badge import 파일을 찾은 뒤 isActive 누락 여부를 확인합니다. 실행 후 결과를 공유해주세요.


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Badge를 import하는 파일 검색 (*.ts, *.tsx)
rg -lP -g '*.ts' -g '*.tsx' 'import\s*\{\s*Badge\s*\}\s*from' | while IFS= read -r f; do
  echo "=== $f ==="
  rg -nP -C2 '<Badge\b' "$f" || true
  if ! rg -qP '<Badge\b[^>]*\bisActive\b' "$f"; then
    echo "[WARN] isActive prop 누락 의심: $f"
  fi
done

Length of output: 280


아래 스크립트로 Badge 사용처를 다시 검사하고, isActive 속성 누락 여부를 확인해주세요. 실행 후 결과를 공유해 주세요.


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# 1) Badge를 import하는 파일 검색 (*.ts, *.tsx)
FILES=$(rg -lP -g '*.ts' -g '*.tsx' 'import\s*\{\s*Badge\s*\}\s*from')
if [ -z "$FILES" ]; then
  echo "Badge를 import한 파일이 없습니다."
  exit 0
fi

# 2) 각 파일에서 <Badge ...> 사용 줄별로 확인
for f in $FILES; do
  echo "=== $f ==="
  rg -nP '<Badge\b[^>]*>' "$f" | while IFS= read -r line; do
    echo "$line"
    if [[ "$line" != *isActive* ]]; then
      # line 형식: 파일경로:라인번호:코드
      location="${line%%:*}:${line#*:}"
      echo "[WARN] isActive prop 누락 의심: $location"
    fi
  done
done

Length of output: 60


아래 스크립트로 Badge 사용처 전부를 나열하고 isActive 누락 여부를 동시에 확인해 보세요. 실행 후 결과를 공유해 주세요.


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "▶ Badge 사용처 및 isActive 누락 점검"

# 모든 ts/tsx 파일에서 <Badge 사용 줄 찾기
rg -nP '<Badge\b' -g '*.{ts,tsx}' | while IFS= read -r line; do
  # 파일:라인:코드 분리
  file=${line%%:*}
  rest=${line#*:}
  lineno=${rest%%:*}
  code=${rest#*:*}
  
  # 출력
  echo "$file:$lineno: $code"
  
  # isActive 포함 여부 확인
  if ! echo "$code" | grep -q 'isActive'; then
    echo "[WARN] isActive prop 누락 의심: $file:$lineno"
  fi
done

Length of output: 387


Badge 컴포넌트 isActive prop 일관성 적용

  • apps/client/src/pages/level/Level.tsx (45): isActive={true}isActive로 축약
  • apps/client/src/pages/remind/Remind.tsx (16, 22): isActive prop 누락 → 디자인 시스템 변경(isActive 필수)에 따라 추가 필요
  • Level 페이지 배지가 항상 활성 상태로 유지되는 것이 의도된 동작인지 확인
🤖 Prompt for AI Agents
In apps/client/src/pages/level/Level.tsx around line 45 and
apps/client/src/pages/remind/Remind.tsx around lines 16 and 22, the Badge
component usage must follow the design-system change that makes the isActive
prop required; replace verbose isActive={true} with the shorthand isActive in
Level.tsx (if the badge should always be active) and add isActive (true or false
as appropriate) to the two Badge usages in Remind.tsx; also confirm with product
whether the Level page badge is intended to always be active—if not, set
isActive based on the correct state/logic.

Copy link

@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: 2

🧹 Nitpick comments (3)
apps/client/src/pages/myBookmark/MyBookmark.tsx (3)

30-30: 중첩 스크롤 제거 권장

페이지 레이아웃(main)에서 이미 스크롤을 담당한다면, 내부 그리드에 overflow-y-auto를 주면 UX가 나빠집니다.

-      <div className="scrollbar-hide mt-[2.6rem] flex flex-wrap gap-[1.6rem] overflow-y-auto scroll-smooth max-w-[104rem]">
+      <div className="scrollbar-hide mt-[2.6rem] flex flex-wrap gap-[1.6rem] scroll-smooth max-w-[104rem]">

1-1: 리마인드 목데이터에 대한 의존 분리

북마크 페이지가 리마인드 전용 목데이터에 의존하고 있습니다. 북마크 전용 BOOKMARK_MOCK_DATA(또는 shared mock)로 분리하거나 API 스키마에 맞춘 타입을 정의해 주세요.

원하시면 shared mock 모듈/타입 초안을 만들어 드릴게요.


39-39: 하드코딩된 날짜 제거

고정 문자열 대신 데이터 필드(예: bookmarkedAt)를 받아 포맷팅하거나, 최소한 유틸 함수를 통해 처리해 주세요.

// 예시
// <Card date={formatDate(data.bookmarkedAt)} ... />
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 38700f0 and f87db9d.

📒 Files selected for processing (1)
  • apps/client/src/pages/myBookmark/MyBookmark.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#2
File: pnpm-workspace.yaml:3-3
Timestamp: 2025-08-18T13:48:59.065Z
Learning: constantly-dev는 docs 디렉터리를 컨벤션 문서 추가용으로 사용할 예정이라고 명시했습니다.
🧬 Code graph analysis (1)
apps/client/src/pages/myBookmark/MyBookmark.tsx (1)
apps/client/src/pages/remind/constants/index.ts (1)
  • REMIND_MOCK_DATA (1-114)
🔇 Additional comments (2)
apps/client/src/pages/myBookmark/MyBookmark.tsx (2)

16-27: Badge 접근성(aria) 확인 요청

isActive 토글 시 Badge가 aria-pressed 등 상태를 노출하는지 확인이 필요합니다. 키보드 포커스 스타일도 점검해 주세요.


5-5: PR 범위 정합성 확인

PR 타이틀/이슈(#50 대시보드 레이아웃) 대비 MyBookmark 수정 범위가 포함되는지 확인 부탁드립니다. 범위 밖이면 분리 권장.

@@ -1,5 +1,47 @@
import { REMIND_MOCK_DATA } from "@pages/remind/constants";
import { Badge, Card } from "@pinback/design-system/ui";
import { useState } from "react";
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

배지 상태가 리스트/카운트에 반영되지 않습니다

배지 클릭 시 state는 바뀌지만 목록은 필터링되지 않고 배지 카운트도 하드코딩되어 있습니다. 최소한 현재 목데이터 기준(예: timeRemaining !== '완료'를 미열람으로 간주)으로 동작하도록 보완해 주세요.

-import { useState } from "react";
+import { useMemo, useState } from "react";
-  const [activeBadge, setActiveBadge] = useState('all');
+  const [activeBadge, setActiveBadge] = useState<'all' | 'notRead'>('all');
-  const handleBadgeClick = (badgeType: string) => {
+  const handleBadgeClick = (badgeType: 'all' | 'notRead') => {
     setActiveBadge(badgeType);
   };
-          countNum={5}
+          countNum={counts.all}
-          countNum={10}
+          countNum={counts.notRead}
-{REMIND_MOCK_DATA.map((data) => (
+{filtered.map((data) => (

아래 코드를 Line 10 바로 아래에 추가해 주세요(새 라인 추가):

// 임시 기준: '완료'가 아닌 항목을 '안 읽음'으로 간주
const filtered = useMemo(() => {
  if (activeBadge === 'notRead') {
    return REMIND_MOCK_DATA.filter((item) => item.timeRemaining !== '완료');
  }
  return REMIND_MOCK_DATA;
}, [activeBadge]);

const counts = useMemo(() => {
  const all = REMIND_MOCK_DATA.length;
  const notRead = REMIND_MOCK_DATA.filter((item) => item.timeRemaining !== '완료').length;
  return { all, notRead };
}, []);

Also applies to: 6-6, 8-10, 18-18, 24-24, 32-32

🤖 Prompt for AI Agents
In apps/client/src/pages/myBookmark/MyBookmark.tsx around line 3 and insert at
line 10, the badge state changes but the list and counts are not updated; update
the import to include useMemo (import { useState, useMemo } from "react"), then
add two useMemo hooks just below line 10: one that computes filtered list based
on activeBadge (treat items with timeRemaining !== '완료' as "notRead") and one
that computes counts (all and notRead) from REMIND_MOCK_DATA; ensure the
counts/useMemo dependency array references REMIND_MOCK_DATA and the filtered
useMemo depends on activeBadge and REMIND_MOCK_DATA, and replace any hardcoded
badge counts and list source with these new values.

Copy link
Collaborator

@jllee000 jllee000 left a comment

Choose a reason for hiding this comment

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

확인했습니다! 목데이터 따로 만드셔서 작업하셨네요 굿굿 이후에 해당 파일은 꼭 지우기!
고생하셨습니다 :)

Comment on lines +37 to +40
content={data.content}
category={data.category}
date="2024.08.15"
/>
Copy link
Collaborator

Choose a reason for hiding this comment

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

요거 static한 데이터!! 추후에 바꿔주세요

Copy link
Member Author

Choose a reason for hiding this comment

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

넵~ 일단 카드에 쓰인 데이터 모두 mock data여서 api연결 후에 바꾸겠습니다 👍

Comment on lines 4 to +6
countNum?: number;
isActive: boolean;
onClick?: () => void;
Copy link
Collaborator

Choose a reason for hiding this comment

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

활성 제어를 위해서 추가가 필요했군녀

Copy link
Member Author

Choose a reason for hiding this comment

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

맞아요! 실제 작동하는 로직은 외부에 책임을 두고 내부에서는 isActive를 통해 활성화가 되었는지만 담당합니다!
이에 따라 스타일만 변경하면 되는 구조여서 이렇게 수정하게 되었습니다.

Copy link

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/design-system/src/components/badge/Badge.stories.tsx (1)

38-40: 문서 설명과 실제 동작 불일치(토글) — 문구 수정 필요

설명은 “토글 아님”인데, ActiveBadge는 토글을 시연합니다. 혼동을 줄이기 위해 문구를 업데이트하세요.

-          '클릭 시 내부 state(isClick)가 true로 바뀌며 스타일이 활성화됩니다. 토글 방식은 아닙니다.',
+          '제어형 컴포넌트입니다. isActive prop으로 스타일을 제어하며, 예시 스토리(ActiveBadge)는 onClick으로 토글합니다.',
🧹 Nitpick comments (4)
packages/design-system/src/components/badge/Badge.stories.tsx (4)

10-15: 기본 onClick(alert) 제거 및 기본 활성 상태는 false 권장

alert는 스토리 실행/CI에 방해가 되고 액션 패널/스파이와도 불일치합니다. 기본값은 fn()으로, isActive는 비활성 기본값이 자연스럽습니다.

다음처럼 바꾸세요:

-    onClick: () => alert('onClick 실행'),
-    isActive: true,
+    onClick: fn(),
+    isActive: false,

23-34: onClick argTypes에 타입 요약 추가

Docs 테이블에 함수 시그니처를 노출하면 이해가 빠릅니다. (ActiveBadge는 story args로 fn()을 주입하므로 action 중첩 영향은 없습니다.)

     onClick: {
       action: 'clicked',
       description: '뱃지 클릭 시 호출되는 콜백 함수(옵션)',
+      table: { type: { summary: '() => void' } },
     },

58-76: render 내부에서 컴포넌트 정의 → 필요 시 외부로 hoist 제안

현재도 문제 없지만, 내부에서 컴포넌트를 매 렌더마다 재정의합니다. 가독성과 디프 줄이기 목적이라면 바깥으로 hoist하는 방법도 고려해보세요.

예시(파일 어딘가 상단/하단에 배치):

function ActiveBadgeInner(args: React.ComponentProps<typeof Badge>) {
  const [isActive, setIsActive] = useState(false);
  return (
    <Badge
      {...args}
      isActive={isActive}
      onClick={() => {
        setIsActive((prev) => !prev);
        args.onClick?.();
      }}
    />
  );
}
// 사용처:
// render: (args) => <ActiveBadgeInner {...args} />,

2-2: play 단계에 단언 추가로 상호작용 검증 강화

클릭만 수행하고 검증이 없어 회귀를 잡기 어렵습니다. onClick 호출 횟수를 단언하고, 이를 위해 expect 임포트를 추가하세요.

-import { within, userEvent, fn } from '@storybook/test';
+import { within, userEvent, fn, expect } from '@storybook/test';
   const canvas = within(canvasElement);
   await userEvent.click(await canvas.findByText(String(args.text)));
+  await expect(args.onClick).toHaveBeenCalledTimes(1);

Also applies to: 82-85

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ca0b933 and 5b6fb0e.

📒 Files selected for processing (1)
  • packages/design-system/src/components/badge/Badge.stories.tsx (3 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#2
File: pnpm-workspace.yaml:3-3
Timestamp: 2025-08-18T13:48:59.065Z
Learning: constantly-dev는 docs 디렉터리를 컨벤션 문서 추가용으로 사용할 예정이라고 명시했습니다.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: storybook
🔇 Additional comments (4)
packages/design-system/src/components/badge/Badge.stories.tsx (4)

4-4: useState 임포트 적절

제어형 스토리 구현에 필요한 최소 임포트로 적절합니다.


51-52: 0 카운트 케이스 스토리 추가 좋습니다

빈/0 상태를 명시적으로 검증할 수 있어 유용합니다.


77-81: 스파이(fn)로 onClick 검증 준비 완료

상호작용 테스트에서 호출 여부를 단언하기에 적절한 설정입니다.


88-89: 스토리 설명 간결하고 명확합니다

ActiveBadge의 동작을 짧게 요약해 문맥 파악에 도움이 됩니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat 기능 개발하라 개발 달려라 달려

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] dashboard page layout 구현

3 participants