Conversation
WalkthroughNotificationBadge 컴포넌트와 Storybook 스토리가 추가되었고, TimerCreationContent의 BELL 섹션이 배지와 아코디언(확장/축소) 패널, 벨 추가/삭제 로직을 포함하도록 재구성되었으며, Tailwind 설정에 색상 토큰 Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor U as 사용자
participant T as TimerCreationContent
participant S as 로컬상태
participant B as NotificationBadge
U->>T: 벨 확장 버튼 클릭
T->>S: isBellExpanded 토글
T->>T: 재렌더
T->>B: props.count = bells.length
B-->>T: 배지 렌더(0이면 숨김, >99면 "99+")
alt 확장된 상태
U->>T: 벨 입력 후 Add 클릭
T->>S: bells[]에 항목 추가
T->>T: 리스트 및 배지 재렌더
U->>T: 벨 항목 Delete 클릭
T->>S: bells[]에서 항목 제거
T->>T: 리스트 및 배지 재렌더
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (9)
src/components/NotificationBadge/NotificationBadge.tsx (3)
12-17: count 방어적 처리(음수/NaN 클램프) 권장.외부에서 음수나 NaN이 유입될 경우 표시가 비정상일 수 있습니다. 0으로 클램프하고, 99+ 로직은 클램프된 값 기준으로 수행하는 편이 안전합니다.
적용 예시:
- if (count === 0) { + const safeCount = Number.isFinite(count) ? Math.max(0, count) : 0; + if (safeCount === 0) { return null; } - const displayCount = count > 99 ? '99+' : count; + const displayCount = safeCount > 99 ? '99+' : safeCount;
19-26: 배지 접근성(a11y) 속성 추가 제안.보조기기가 읽을 수 있도록 role/aria를 부여하면 좋습니다.
적용 예시:
return ( <span className={clsx( 'inline-flex h-4 min-w-[16px] items-center justify-center rounded-full bg-red-500 px-1 text-[10px] font-bold leading-none text-white', className, )} + role="status" + aria-live="polite" + aria-label={`알림 ${displayCount}개`} > {displayCount} </span> );
21-23: 디자인 토큰 사용 일관성.배경색을 tailwind 기본(red-500) 대신 프로젝트 토큰(예: semantic.error)로 통일하면 테마 변경에 유리합니다.
적용 예시:
- '... bg-red-500 ...' + '... bg-semantic-error ...'src/page/TableComposition/components/TimerCreationContent/TimerCreationContent.tsx (6)
435-438: 토글 핸들러는 함수형 업데이트로 안정화하세요.현재 클로저 의존 패턴은 불필요한 재생성을 유발합니다.
적용 예시:
-const handleBellExpandButtonClick = useCallback(() => { - setIsBellExpanded(!isBellExpanded); -}, [isBellExpanded]); +const handleBellExpandButtonClick = useCallback(() => { + setIsBellExpanded((prev) => !prev); +}, []);
675-681: 아코디언 토글 버튼에 a11y 속성과 회전 애니메이션을 추가하세요.type="button"으로 폼 제출 방지, aria-expanded/controls 제공, 아이콘 회전으로 상태 인디케이션 강화.
적용 예시:
-<button - className="h-full" - onClick={() => handleBellExpandButtonClick()} -> - <DTExpand className="h-full rounded-full p-[8px] text-default-black transition-colors duration-300 hover:bg-default-disabled/hover" /> -</button> +<button + type="button" + className="h-full" + onClick={handleBellExpandButtonClick} + aria-expanded={isBellExpanded} + aria-controls="bell-settings-panel" + aria-label={isBellExpanded ? '종소리 설정 접기' : '종소리 설정 펼치기'} +> + <DTExpand + className={clsx( + 'h-full rounded-full p-[8px] text-default-black transition-colors duration-300 hover:bg-default-disabled/hover', + 'transition-transform', + { 'rotate-180': isBellExpanded }, + )} + /> +</button>
685-685: 패널에 id/role 추가로 접근성 보강.적용 예시:
-{isBellExpanded && ( - <div className="flex w-full flex-col space-y-[8px] rounded-[12px] bg-default-dim2 p-[8px]"> +{isBellExpanded && ( + <div + id="bell-settings-panel" + role="region" + aria-label="종소리 설정 영역" + className="flex w-full flex-col space-y-[8px] rounded-[12px] bg-default-dim2 p-[8px]" + >
703-719: 분 입력 NaN/빈값 처리 보강.Number(e.target.value)가 NaN일 수 있으므로 기존 값 유지가 안전합니다. inputMode도 지정해주세요.
적용 예시:
- <input - type="number" + <input + type="number" + inputMode="numeric" min={0} max={59} className="w-[52px] rounded-[4px] border border-default-border p-[8px]" value={bellInput.min} - onChange={(e) => - setBellInput((prev) => ({ - ...prev, - min: Math.max( - 0, - Math.min(59, Number(e.target.value)), - ), - })) - } + onChange={(e) => { + const next = Number(e.target.value); + setBellInput((prev) => ({ + ...prev, + min: Number.isNaN(next) ? prev.min : Math.max(0, Math.min(59, next)), + })); + }} placeholder="분" />
722-739: 초 입력도 동일한 NaN/빈값 처리.적용 예시:
- <input - type="number" + <input + type="number" + inputMode="numeric" min={0} max={59} className="w-[52px] rounded-[4px] border border-default-border p-[8px]" value={bellInput.sec} - onChange={(e) => - setBellInput((prev) => ({ - ...prev, - sec: Math.max( - 0, - Math.min(59, Number(e.target.value)), - ), - })) - } + onChange={(e) => { + const next = Number(e.target.value); + setBellInput((prev) => ({ + ...prev, + sec: Number.isNaN(next) ? prev.sec : Math.max(0, Math.min(59, next)), + })); + }} placeholder="초" />
771-801: 리스트 key로 index 사용은 삭제 시 리렌더링 부작용 가능.간단한 UI라 큰 문제는 아니지만, 가능하면 고유 id를 사용하세요.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
src/components/NotificationBadge/NotificationBadge.stories.tsx(1 hunks)src/components/NotificationBadge/NotificationBadge.tsx(1 hunks)src/page/TableComposition/components/TimerCreationContent/TimerCreationContent.tsx(4 hunks)tailwind.config.js(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/components/NotificationBadge/NotificationBadge.stories.tsx (1)
src/components/NotificationBadge/NotificationBadge.tsx (1)
NotificationBadge(8-28)
src/page/TableComposition/components/TimerCreationContent/TimerCreationContent.tsx (7)
src/components/NotificationBadge/NotificationBadge.tsx (1)
NotificationBadge(8-28)src/components/icons/Expand.tsx (1)
DTExpand(3-25)src/components/DropdownMenu/DropdownMenu.tsx (1)
DropdownMenu(19-129)src/type/type.ts (2)
BellType(6-6)BellTypeToString(25-29)src/components/icons/Bell.tsx (1)
DTBell(3-61)src/components/icons/Add.tsx (1)
DTAdd(3-25)src/components/icons/Close.tsx (1)
DTClose(3-35)
🔇 Additional comments (5)
tailwind.config.js (1)
84-85: 새 색상 토큰(dim2) 추가 LGTM.디자인 토큰/가이드(Figma, 문서)와 값 동기화만 확인해주세요.
src/components/NotificationBadge/NotificationBadge.stories.tsx (1)
1-33: 스토리 구성 깔끔합니다.0/1/100/일반 케이스로 동작이 명확히 드러납니다.
src/page/TableComposition/components/TimerCreationContent/TimerCreationContent.tsx (3)
27-28: 신규 컴포넌트/아이콘 import LGTM.
151-153: 아코디언 상태 추가 LGTM.
662-674: 배지 배치 적절.relative 컨테이너 내 absolute 포지셔닝이 안정적으로 보입니다.
src/page/TableComposition/components/TimerCreationContent/TimerCreationContent.tsx
Show resolved
Hide resolved
useon
left a comment
There was a problem hiding this comment.
숀 ! 아코디언 구현 빠르게 해 주셔서 감사해요 !!! 쉭쉭 돌아가는 애니메이션도 너무 좋은데요? 몇 가지 코멘트만 달았고 동작에는 문제 없어서 바로 어프루브 합니다 !!!!!!
| return null; | ||
| } | ||
|
|
||
| const displayCount = safeCount > 99 ? '99+' : safeCount; |
|
|
||
| const handleBellExpandButtonClick = useCallback(() => { | ||
| setIsBellExpanded((prev) => !prev); | ||
| }, []); |
| ? '종소리 설정 접기' | ||
| : '종소리 설정 펼치기' | ||
| } | ||
| onClick={() => handleBellExpandButtonClick()} |
There was a problem hiding this comment.
onClick={handleBellExpandButtonClick} 새로운 익명함수를 생성하는 대신에 이렇게 바로 함수를 참조하는 것은 어떨까요? 인수를 전달하지 않아서 매번 새로운 인스턴스를 생성하지 않아도 될 것 같아서요 !!
| <span className="flex w-full flex-row items-center space-x-[4px]"> | ||
| {/* 벨 유형 */} | ||
| <DropdownMenu | ||
| className="" |
There was a problem hiding this comment.
className 전달할 것이 없으면 명시하지 않아도 되지 않을까요? 클래스네임은 옵셔널이라 괜찮을 것 같아서요!
There was a problem hiding this comment.
헉 이건 까먹은거네요 찾아주셔서 감사합니다 지워뒀어요!
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
src/page/TableComposition/components/TimerCreationContent/TimerCreationContent.tsx (1)
758-769: 타종 횟수 입력의% 10보정 관련해당 보정은 값 왜곡을 유발할 수 있어 제거 권장되어 왔습니다만, 본 PR에서는 입력 로직 개선을 별도 PR로 진행하기로 하셨으므로 여기서는 패스합니다.
🧹 Nitpick comments (3)
src/page/TableComposition/components/TimerCreationContent/TimerCreationContent.tsx (3)
676-684: 접힘/펼침 접근성(ARIA) 보강 제안토글 버튼에
aria-expanded/aria-controls, 패널에id/role="region"/aria-labelledby를 연결하면 스크린리더 친화도가 높아집니다.적용 예시:
@@ - <div className="relative flex items-center space-x-[8px]"> - <p className="text-body w-[80px] font-medium"> + <div className="relative flex items-center space-x-[8px]"> + <p + id="bell-settings-heading" + className="text-body w-[80px] font-medium" + > 종소리 설정 </p> @@ - <button + <button className="h-full" type="button" aria-label={ isBellExpanded ? '종소리 설정 접기' : '종소리 설정 펼치기' } + aria-expanded={isBellExpanded} + aria-controls="bell-settings-panel" onClick={handleBellExpandButtonClick} > @@ - {isBellExpanded && ( - <div className="flex w-full flex-col space-y-[8px] rounded-[12px] bg-default-dim2 p-[8px]"> + {isBellExpanded && ( + <div + id="bell-settings-panel" + role="region" + aria-labelledby="bell-settings-heading" + className="flex w-full flex-col space-y-[8px] rounded-[12px] bg-default-dim2 p-[8px]" + >Also applies to: 699-699, 665-667
685-694: 아이콘 크기/트랜지션 미세 최적화
h-full대신 고정 크기와transition-transform만 지정하면 레이아웃 영향이 줄고 성능이 미세 개선됩니다.- <DTExpand - className={clsx( - 'h-full transform rounded-full p-[8px] text-default-black transition-all duration-300 ease-in-out hover:bg-default-disabled/hover', + <DTExpand + className={clsx( + 'w-[16px] h-[16px] transform rounded-full p-[8px] text-default-black transition-transform duration-300 ease-in-out hover:bg-default-disabled/hover', { 'rotate-180': isBellExpanded, 'rotate-0': !isBellExpanded, }, )} />
788-789: 하드코딩 색상 → 토큰 사용으로 통일성 확보
bg-[#FFF2D0]는 테마/다크모드 대응에 취약합니다. 이번 PR에서 도입한 토큰을 활용해보세요.- className="relative flex w-full flex-row rounded-[4px] border border-default-border bg-[#FFF2D0] px-[12px] py-[4px]" + className="relative flex w-full flex-row rounded-[4px] border border-default-border bg-default-dim2 px-[12px] py-[4px]"시각적 강조가 더 필요하다면
bg-semantic-material/10등 의미 기반 토큰도 고려 가능합니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
src/page/TableComposition/components/TimerCreationContent/TimerCreationContent.tsx(4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-08T14:21:17.745Z
Learnt from: i-meant-to-be
PR: debate-timer/debate-timer-fe#335
File: src/page/TimerPage/components/NormalTimer.tsx:50-54
Timestamp: 2025-08-08T14:21:17.745Z
Learning: Progress 퍼센트(원형 게이지)는 컴포넌트가 아닌 훅(src/page/TimerPage/hooks/useCircularTimerAnimation.ts)에서 0–100으로 clamp한다. 향후 리뷰에서는 컴포넌트 레벨에서의 중복 clamp 제안 대신 훅 사용을 권장한다.
Applied to files:
src/page/TableComposition/components/TimerCreationContent/TimerCreationContent.tsx
📚 Learning: 2025-09-03T14:25:28.457Z
Learnt from: i-meant-to-be
PR: debate-timer/debate-timer-fe#359
File: src/page/TableComposition/components/TimerCreationContent/TimerCreationContent.tsx:745-758
Timestamp: 2025-09-03T14:25:28.457Z
Learning: 사용자 i-meant-to-be는 PR #359에서 종소리 입력들(분, 초, 횟수 등)에 관한 리뷰를 생략하고 다른 PR에서 정리할 예정이라고 명시했다. 이런 입력 처리 로직 개선은 별도 PR로 분리하는 것을 선호한다.
Applied to files:
src/page/TableComposition/components/TimerCreationContent/TimerCreationContent.tsx
🧬 Code graph analysis (1)
src/page/TableComposition/components/TimerCreationContent/TimerCreationContent.tsx (7)
src/components/NotificationBadge/NotificationBadge.tsx (1)
NotificationBadge(8-32)src/components/icons/Expand.tsx (1)
DTExpand(3-25)src/components/DropdownMenu/DropdownMenu.tsx (1)
DropdownMenu(19-129)src/type/type.ts (2)
BellType(6-6)BellTypeToString(25-29)src/components/icons/Bell.tsx (1)
DTBell(3-61)src/components/icons/Add.tsx (1)
DTAdd(3-25)src/components/icons/Close.tsx (1)
DTClose(3-35)
🔇 Additional comments (3)
src/page/TableComposition/components/TimerCreationContent/TimerCreationContent.tsx (3)
27-28: NotificationBadge/DTExpand 도입 👍두 컴포넌트 import 및 사용 방향 모두 적절합니다.
151-153: 아코디언 상태 도입 적절
isBellExpanded기본값과 토글 구조 직관적입니다.
435-438: 토글 핸들러 안정화(Lambda 생성 회피) 잘 처리됨
useCallback으로 안정화했고, 호출부에서도 함수 참조를 직접 넘겨 불필요한 렌더를 피합니다.
jaeml06
left a comment
There was a problem hiding this comment.
넵 확인했습니다. dev환경에서도 정상작동합니다. 고생하셨습니다
🚩 연관 이슈
closed #358
📝 작업 내용
새로운 색상 추가
아코디언 UI에 사용된 새로운 배경 색상
default-dim2를 추가했습니다.알림 배지 컴포넌트 추가
앱 곳곳에서 공통적으로 사용할 수 있게
NotificationBadge컴포넌트를 추가했습니다.타임박스 추가 모달의 종소리 설정 영역에 아코디언 UI 적용
통합 회의에서 논의된 대로 아코디언 UI를 적용했습니다. 여러분의 이해를 돕기 위해 간단하게 변경된 코드를 설명하겠습니다:
상태 값 추가
isBellExpanded변수를 통해, 종소리 영역이 보이는지 여부를 저장합니다.true일 경우 보이는 거고,false일 경우 가려진 상태입니다.버튼 클릭 시 이벤트 추가
버튼 클릭 시 동작하는 토글 함수를 추가했습니다. 단순하게, 현재
isBellExpanded의 반대 값으로 변경하는 로직입니다.종소리 영역에 아코디언 UI 구조 적용
이해를 돕기 위해 스타일 태그는 간소화해 작성해 뒀습니다. 전체 코드는 Files Changed 탭에서 확인하실 수 있구요. 새로 추가한
NotificationBadge컴포넌트를 사용하여 코드를 작성했습니다. 이 배지 컴포넌트 같은 경우, 아래와 같이 동작합니다:확장 버튼과 종소리 설정 추가 버튼에 간단한 애니메이션을 적용하여 심미성도 높였습니다.
추가로, 입력 필드들의 너비를 기존 60 px에서 더 줄였는데요. 이 부분은 종소리 설정 부분에 회색 배경이 들어오면서 양옆으로 패딩이 붙어버리는 바람에, 종소리 영역이 열렸을 때 모달 오른쪽의 입력 영역의 너비가 크게 늘어나서 타이머 샘플 사진이 너무 쪼그라들었기 때문입니다. 코드 리뷰하실 때 참고하시면 될 것 같아요.
🏞️ 스크린샷 (선택)
닫혔을 때
열렸을 때
🗣️ 리뷰 요구사항 (선택)
동작 잘 되는지
npm run dev로 한 번만 확인해주세요!Summary by CodeRabbit
신규 기능
스타일
문서
작업