Skip to content

[Feat] WTH-211 : 출석 메인 페이지(USER) UI 구현#25

Merged
nabbang6 merged 21 commits intodevelopfrom
WTH-211-출석-메인-페이지-USER-UI-구현
Mar 22, 2026

Hidden character warning

The head ref may contain hidden characters: "WTH-211-\ucd9c\uc11d-\uba54\uc778-\ud398\uc774\uc9c0-USER-UI-\uad6c\ud604"
Merged

[Feat] WTH-211 : 출석 메인 페이지(USER) UI 구현#25
nabbang6 merged 21 commits intodevelopfrom
WTH-211-출석-메인-페이지-USER-UI-구현

Conversation

@nabbang6
Copy link
Collaborator

@nabbang6 nabbang6 commented Mar 20, 2026

✅ PR 유형

어떤 변경 사항이 있었나요?

  • 새로운 기능 추가
  • 버그 수정
  • 코드에 영향을 주지 않는 변경사항(오타 수정, 탭 사이즈 변경, 변수명 변경)
  • 코드 리팩토링
  • 주석 추가 및 수정
  • 문서 수정
  • 빌드 부분 혹은 패키지 매니저 수정
  • 파일 혹은 폴더명 수정
  • 파일 혹은 폴더 삭제

📌 관련 이슈번호

  • Closed #211

✅ Key Changes

  • 출석 메인 페이지 구현: 출석률 표시, 오늘의 출석 카드, 출석 기록 링크 등 출석 페이지 전체 UI 구현
  • 출석 코드 입력 모달: 6자리 OTP 입력, 카운트다운 타이머, 시간 만료 처리
  • 출석 완료 상태 UI: isChecked prop에 따라 완료 배너 표시 및 "이미 출석을 완료했네요!" 모달 연동
  • Dialog 구조 개선: DialogHeader에 아이콘/오버라인 지원, DialogFooter에 구분선/설명 텍스트 추가, 오버레이
    색상 변경
  • Card 컴포넌트 확장: buttonSet variant에 children 슬롯 및 조건부 primary 버튼 지원
  • 시간 유틸 및 훅: formatTime 유틸, useRemainingTime 카운트다운 훅 추가
  • 접근성 개선: InputOTP에 aria-label, AttendanceProgressBar에 role="progressbar"aria-* 속성 추가

📸 스크린샷 or 실행영상

default.mp4

/attendance 에서 확인 가능합니당!


🎸 기타 사항 or 추가 코멘트

  • 관리자 출석코드 확인 기능은 별도 브랜치에서 구현 예정 (TODO 주석 표시)

  • 목 데이터 때문에 현재는 출석 가능 시간이 10분 이상으로 표시되고 있는데...
    new Date(endTime).getTime() - Date.now();으로 계산해서 출력되게 해뒀습니당

  • complete.svg는 피그마에 있던 임시 아이콘 그대로 넣어둔 건데... 추후에 교체될 예정입니다!

  • 피그마에 헤더 변경 사항이 있길래... 겸사겸사 조금 수정해뒀어용 (관리자 서비스 -> 관리자, 글쓰기 아이콘 수정)

  • card, dialog, breadcrumb 공통 컴포넌트에서 Icon 컴포넌트 사용하게 일괄적으로 수정

Summary by CodeRabbit

새로운 출석 시스템 릴리스

  • New Features

    • 6자리 출석 코드 입력 UI, 남은시간 카운트다운, 출석 확인 및 완료 모달 추가
    • 오늘 출석 카드, 출석 상태 및 출석률 진행바 추가
    • 개인용 출석 페이지(모의 데이터) 추가; 기존 공개 출석 페이지 제거
  • UI/UX Improvements

    • 아이콘 교체 및 헤더 문구 간결화
    • 빵글(브레드크럼) 홈 링크 옵션 추가 및 모달 레이아웃/오버레이 개선
    • 날짜·시간 표시 형식 개선 및 전반적 디자인 정리

@nabbang6 nabbang6 requested review from JIN921, dalzzy and woneeeee March 20, 2026 14:27
@nabbang6 nabbang6 self-assigned this Mar 20, 2026
@nabbang6 nabbang6 added ✨ Feature 기능 개발 🎨 Html&css 마크업 & 스타일링 🔨 Refactor 코드 리팩토링 labels Mar 20, 2026
@github-actions
Copy link

PR 테스트 결과

Jest: 통과

🎉 모든 테스트를 통과했습니다!

@github-actions
Copy link

🤖 Claude 테스트 제안

모델: claude-sonnet-4-6 | 토큰: 0 입력 / 0 출력

변경된 컴포넌트에 대해 Claude가 생성한 테스트 코드입니다. 검토 후 적합한 부분만 사용하세요.

src/app/(private)/(main)/attendance/page.tsx

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


src/app/(public)/attendance/page.tsx

오류: ENOENT: no such file or directory, open 'src/app/(public)/attendance/page.tsx'


src/components/attendance/AttendanceCodeModal.tsx

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


src/components/attendance/AttendanceCompleteModal.tsx

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


src/components/attendance/AttendanceContent.tsx

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


이 코멘트는 Claude API를 통해 자동 생성되었습니다. 반드시 검토 후 사용하세요.

@github-actions
Copy link

PR 검증 결과

TypeScript: 통과
ESLint: 통과
Prettier: 실패
Build: 통과

⚠️ 일부 검증에 실패했습니다. 확인 후 수정해주세요.

@coderabbitai
Copy link

coderabbitai bot commented Mar 20, 2026

📝 Walkthrough

Walkthrough

출석 기능 관련 타입·훅·컴포넌트(OTP 입력, 코드/완료 모달, 진행률 등)를 추가하고 공개 출석 페이지를 제거하여 개인 영역용 출석 페이지로 대체했습니다. UI primitives(breadcrumb, card, dialog)와 아이콘 바렐도 아이콘 기반 렌더링으로 변경되었습니다.

Changes

Cohort / File(s) Summary
페이지 라우팅
src/app/(private)/(main)/attendance/page.tsx, src/app/(public)/attendance/page.tsx
공개 출석 페이지((public)/attendance/page.tsx) 삭제 및 개인 영역용 출석 페이지((private)/attendance/page.tsx) 추가(목업 데이터 사용, API 통합 TODO).
출석 컴포넌트 (메인)
src/components/attendance/AttendanceContent.tsx, src/components/attendance/index.ts
AttendanceContent 추가 및 attendance 컴포넌트 바렐(export 집계) 추가. 중앙 조립 로직과 isChecked 상태 포함.
출석 컴포넌트 (상태/진행/카드)
src/components/attendance/AttendanceStatus.tsx, src/components/attendance/AttendanceProgressBar.tsx, src/components/attendance/AttendanceTodayCard.tsx
AttendanceStatus·ProgressBar(aria 속성 포함)·TodayCard 추가. TodayCard는 내부적으로 코드/완료 모달을 제어하고 onAttendanceComplete 콜백을 호출.
모달·입력 관련
src/components/attendance/AttendanceCodeModal.tsx, src/components/attendance/AttendanceCompleteModal.tsx, src/components/attendance/InputOTP.tsx
6자리 OTP 입력 컴포넌트, 코드 입력 모달(타이머/유효성/클리어 동작), 완료 모달 추가. 모달 제어는 외부 open/onOpenChange로 이루어짐.
아이콘 및 UI primitives 변경
src/assets/icons/index.ts, src/components/ui/breadcrumb.tsx, src/components/ui/card.tsx, src/components/ui/dialog.tsx, src/components/layout/Header.tsx
아이콘 바렐에 아이콘 추가 및 breadcrumb/card/dialog에서 lucide 대신 공용 Icon 사용으로 렌더링 변경. Dialog에 icon prop 추가, close 버튼/레이아웃/오버레이 조정. Header 텍스트·아이콘 일부 교체.
훅·유틸·타입
src/hooks/useRemainingTime.ts, src/hooks/index.ts, src/lib/formatTime.ts, src/types/attendance.ts, src/types/common.ts, src/types/index.ts
남은 시간 계산 훅 추가 및 재내보내기. 시간/날짜 포맷 유틸 추가. 출석 도메인 타입(AttendanceData/Status/Response)과 ApiResponse 제네릭 타입 추가.
기타 변경
src/components/ui/..., src/components/...
Card/Dialog 내부 구조·클래스 조정 및 버튼/arrow 렌더링을 Icon 컴포넌트로 교체(여러 UI 파일에 영향).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant AttendancePage
    participant AttendanceContent
    participant AttendanceTodayCard
    participant AttendanceCodeModal
    participant useRemainingTime
    participant AttendanceCompleteModal

    User->>AttendancePage: 출석 페이지 요청
    AttendancePage->>AttendanceContent: props(attendance, name)
    AttendanceContent->>AttendanceTodayCard: 렌더(세션 정보)
    User->>AttendanceTodayCard: 출석 확인 버튼 클릭
    alt 아직 출석 안함
        AttendanceTodayCard->>AttendanceCodeModal: open modal
        AttendanceCodeModal->>useRemainingTime: start(endTime)
        useRemainingTime-->>AttendanceCodeModal: minutes, seconds, isExpired
        User->>AttendanceCodeModal: OTP 입력/확인
        AttendanceCodeModal->>AttendanceTodayCard: onConfirm(code) & close
        AttendanceTodayCard->>AttendanceCompleteModal: open complete modal
        AttendanceCompleteModal-->>User: 완료 메시지 표시
    else 이미 출석
        AttendanceTodayCard->>AttendanceCompleteModal: open complete modal
        AttendanceCompleteModal-->>User: 완료 메시지 표시
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • dalzzy
  • JIN921
  • woneeeee

🐰 출석 버튼에 폴짝 뛰어,
여섯 자리 숫자 반짝반짝,
모달은 시계 소리 따라,
아이콘 옷 입은 UI 반겨,
완료 눌러 웃음 번지네.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 출석 메인 페이지(USER) UI 구현이라는 주요 변경사항을 명확하게 설명하고 있으며, 이슈 번호(WTH-211)도 포함되어 있습니다.
Description check ✅ Passed PR 설명이 템플릿의 모든 필수 섹션을 포함하고 있으며, 변경 유형, 이슈 번호, 주요 변경사항, 스크린샷이 상세하게 제공되어 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch WTH-211-출석-메인-페이지-USER-UI-구현

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.

Tip

CodeRabbit can enforce grammar and style rules using `languagetool`.

Configure the reviews.tools.languagetool setting to enable/disable rules and categories. Refer to the LanguageTool Community to learn more.

@github-actions
Copy link

구현한 기능 Preview: https://weeth-3ciyy7a9m-weethsite-4975s-projects.vercel.app

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: 17

🧹 Nitpick comments (2)
src/lib/formatTime.ts (1)

19-23: 날짜 파싱 실패가 그대로 UI에 노출될 수 있습니다.

여기서는 start/end를 바로 new Date(...)로 넘기고 있어서, 실데이터 포맷이 조금만 달라도 카드/모달에 NaN년 NaN월 NaN일이나 Invalid Date가 그대로 보일 수 있습니다. 파싱 helper에서 유효성을 먼저 확인하고, 실패 시 대체 문구를 주거나 상위에서 에러를 처리하는 쪽이 안전합니다. 실데이터가 ISO-8601로 고정되는지도 같이 확인해 주세요.

Also applies to: 30-32

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/formatTime.ts` around lines 19 - 23, The formatAttendanceDescription
function currently constructs Date objects directly from start/end which can
produce Invalid Date/NaN output in the UI; update the function to validate
parsing before formatting (use a parsing helper or check new
Date(start).getTime() and new Date(end).getTime()), handle invalid parses by
returning a safe fallback string (e.g. "날짜 정보 없음" or throw to the caller), and
ensure formatKoreanDate/formatTime are only called with valid Date objects; also
confirm or enforce ISO-8601 input expectations for start/end and apply the same
validation to the related code at the other occurrence (lines ~30-32).
src/components/attendance/AttendanceCodeModal.tsx (1)

37-37: 모달이 닫혀 있어도 타이머 훅이 계속 동작할 수 있습니다.

Line 37은 open 상태와 무관하게 카운트다운을 시작합니다. open일 때만 ticking 하도록 훅에 enabled 플래그를 추가하는 편이 좋습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/attendance/AttendanceCodeModal.tsx` at line 37, The timer
still runs when the modal is closed; in AttendanceCodeModal pass an enabled flag
(tied to the modal's open state) into useRemainingTime so it only ticks while
open, e.g., call useRemainingTime(endTime, { enabled: open }) and update the
hook signature (useRemainingTime) to accept and honor that enabled flag (stop
intervals/timers when enabled is false and resume when true), ensuring the hook
uses the flag to subscribe/unsubscribe its ticking logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/app/`(private)/(main)/attendance/page.tsx:
- Line 9: Update the mock attendance entry in page.tsx so its "code" field
matches the 6-digit OTP format used by the flow: find the mock object (the
attendance/mock data where "code: 1234" is defined) and change it to a 6-digit
value (e.g., "code: 001234" or 6-digit numeric 123456) to avoid QA/design
confusion; ensure the type (string vs number) matches how the production OTP is
handled by the component that reads "code".

In `@src/components/attendance/AttendanceCodeModal.tsx`:
- Line 50: The modal component AttendanceCodeModal contains hardcoded Tailwind
arbitrary values in its className (h-[565px] w-[508px]) and a gap (gap-[10px])
that violate the design-token rule; replace these arbitrary pixel values with
the appropriate design tokens (CSS variables) used across the project (e.g.,
height, width, spacing tokens) by swapping the arbitrary classes for
token-backed classes or utility references, and if the exact token does not
exist, stop and ask before adding new tokens to the design system; locate the
className on the AttendanceCodeModal component and update both the container
height/width and the gap usage accordingly to use tokens instead of hardcoded
pixels.

In `@src/components/attendance/AttendanceCompleteModal.tsx`:
- Line 25: The modal in AttendanceCompleteModal (className on the container with
"h-[565px] w-[508px]") uses hardcoded pixel heights/widths; replace these with
the project’s design token utility classes (e.g., existing height/width token
classes) so no raw h-[...] or w-[...] values remain, and if appropriate tokens
are missing open a quick design-token PR/discussion and then apply the agreed
token names to the container className; ensure the change is made in the
AttendanceCompleteModal component and that no other hardcoded h-[565px] or
w-[508px] remain in the file.

In `@src/components/attendance/AttendanceContent.tsx`:
- Around line 34-35: The Link in AttendanceContent (the <Link> wrapping Icon
with HomeIcon) is icon-only and lacks an accessible name; add an accessible name
such as aria-label="홈" (or an equivalent localized label) to the Link component
(or include visually hidden text inside) so screen readers can announce its
purpose while keeping the existing Icon and className intact.
- Line 24: The AttendanceContent component currently defaults the isAdmin prop
to true which risks showing admin UI to regular users; change the default value
in the AttendanceContent function signature to false (function
AttendanceContent({ attendance, isAdmin = false }: AttendanceContentProps)) and
audit callers of AttendanceContent to explicitly pass isAdmin={true} only where
admin behavior is intended (update any pages/tests that relied on the implicit
true); ensure any prop types or usages in children that depend on isAdmin
continue to work with the new default.
- Line 29: The div in AttendanceContent.tsx uses a hardcoded width class
max-w-[1025px]; replace this with the appropriate design token or semantic
utility (e.g., a token-based max-width class or CSS variable) instead of a
hardcoded pixel value, updating the className on the element that contains
"mx-auto flex w-full max-w-[1025px] flex-col gap-700 pt-600" to use the
project’s token (or an existing semantic class) for max width; if no suitable
token exists, ask before adding a new design token and follow the repo’s token
naming conventions when creating it, then verify styles still match visually.

In `@src/components/attendance/AttendanceStatus.tsx`:
- Around line 11-15: The component AttendanceStatus currently hardcodes "김위드님의"
causing incorrect display for other users; update the AttendanceStatus component
to accept a user name (e.g., add a prop like userName: string in the
AttendanceStatus props/interface) and replace the hardcoded "김위드님의" text with a
rendered value using that prop (or pull the name from session/context where
AttendanceStatus is used), and update all call sites to pass the correct
userName so attendanceRate remains displayed as before.

In `@src/components/attendance/AttendanceTodayCard.tsx`:
- Line 24: The container in AttendanceTodayCard has a hardcoded utility class
`gap-[10px]` inside the className string ("bg-background flex items-start
gap-[10px] rounded-md p-300"); replace that hardcoded spacing with the project’s
design-token spacing utility (use the appropriate gap token class or CSS
variable token used elsewhere, e.g., the token equivalent for 10px) so it
conforms to the rule "Always use design tokens"; update only the className in
the AttendanceTodayCard component to use the token-based gap class.
- Around line 55-71: The AttendanceCodeModal confirm path isn't wired to update
attendance state: add an onConfirm prop to AttendanceCodeModal and pass a
handler from AttendanceTodayCard that closes the modal and updates the checked
state (or invokes a provided onChecked/onComplete callback) so that isChecked
becomes true and the complete flow opens setCompleteModalOpen(true) as needed;
update AttendanceCodeModal (confirm button handler at AttendanceCodeModal.tsx
lines ~94-102) to call props.onConfirm() after successful code validation, and
update AttendanceTodayCard to pass that onConfirm handler while still
controlling codeModalOpen via setCodeModalOpen.
- Around line 57-60: The secondary button is currently rendered for admins with
a no-op handler (onSecondaryClick={() => {}}) which harms UX; change the logic
in AttendanceTodayCard so the secondary action is only rendered when a real
handler exists (e.g., pass onSecondaryClick as undefined unless a valid handler
like handleShowAttendanceCode is provided) or introduce a prop
(showSecondaryButton / onSecondaryClick) and render the secondaryButtonText
button only when that prop/handler is truthy; remove the empty arrow function
and ensure isAdmin alone does not trigger rendering of the inactive button.

In `@src/components/attendance/InputOTP.tsx`:
- Around line 95-107: Run Prettier to fix style issues in the InputOTP
component: format the file containing the InputOTP component (which includes
symbols inputRefs, handleInputChange, handleKeyDown, handlePaste) by executing
prettier --write for that file (or the repository) and commit the changes so the
CI Prettier check passes; ensure no behavioral changes are made to the JSX props
(preserve attributes like autoComplete, onPaste, onFocus, etc.) while fixing
only formatting.
- Line 93: In InputOTP component replace the hardcoded utility w-[41px] on the
div with the project's spacing/size design-token class (i.e., use an existing
token-based width class instead of a raw pixel value) by updating the div with
key={index} in InputOTP; if no existing token matches 41px, ask before
introducing a new token and use the token name consistent with the project's
size/spacing scale when making the change.

In `@src/components/layout/Header.tsx`:
- Line 78: The Icon in Header.tsx is passing alt="check" which duplicates the
visible button label; change the decorative icon to use an empty alt (alt="") on
the Icon component (the instance using SendIcon) so screen readers won't
announce a redundant name; locate the Icon invocation (Icon src={SendIcon}
size={20} className="text-icon-inverse") and replace the alt prop value with an
empty string.

In `@src/components/ui/dialog.tsx`:
- Line 37: The shared Dialog component contains hardcoded utility values
('bg-black/60', 'gap-[10px]', 'pt-[10px]') in the class string (see the class
passed in the dialog container in src/components/ui/dialog.tsx and the other
occurrence at the later block) — replace these with existing design token
classes (or coordinate to add new tokens before using them) so the component
uses tokenized spacing and color utilities instead of raw values; update both
occurrences (the class string containing data-[state=...] and the other
occurrence around line 178) to use token names and remove literal values.
- Around line 100-104: Replace the plain <button> close implementation so it
uses Radix's DialogPrimitive.Close asChild wrapper: render the close button when
showClose is true (no longer require onClose) by wrapping the existing button
JSX with <DialogPrimitive.Close asChild> and keep onClose only as an optional
extra callback (call it inside the button's onClick if provided) so the button
triggers Radix's automatic close/focus-restoration flow; update the closeButton
variable (and any usage in DialogHeader) to reference showClose and
DialogPrimitive.Close asChild while preserving the Icon/DeleteIcon markup and
classNames.

In `@src/hooks/useRemainingTime.ts`:
- Around line 15-35: The hook useRemainingTime currently assumes new
Date(endTime) yields a valid time; detect invalid endTime (isNaN(new
Date(endTime).getTime())) and treat it as already expired or default to 0
seconds: update the initial state computation for remaining to check for NaN and
return 0 when invalid, and in the useEffect interval callback do the same check
before computing seconds (if NaN, setRemaining(0) and clearInterval), so
minutes/seconds/isExpired never become NaN; adjust references to endTime,
remaining, setRemaining, and the interval-clear logic accordingly.

In `@src/types/attendance.ts`:
- Line 7: Change the attendance type so the attendance code is a string rather
than a number: update the declaration of the property named "code" on the
attendance type/interface (the "code: number;" line) to use string so 6-digit
OTPs with leading zeros are preserved and treated as identifiers rather than
numeric values.

---

Nitpick comments:
In `@src/components/attendance/AttendanceCodeModal.tsx`:
- Line 37: The timer still runs when the modal is closed; in AttendanceCodeModal
pass an enabled flag (tied to the modal's open state) into useRemainingTime so
it only ticks while open, e.g., call useRemainingTime(endTime, { enabled: open
}) and update the hook signature (useRemainingTime) to accept and honor that
enabled flag (stop intervals/timers when enabled is false and resume when true),
ensuring the hook uses the flag to subscribe/unsubscribe its ticking logic.

In `@src/lib/formatTime.ts`:
- Around line 19-23: The formatAttendanceDescription function currently
constructs Date objects directly from start/end which can produce Invalid
Date/NaN output in the UI; update the function to validate parsing before
formatting (use a parsing helper or check new Date(start).getTime() and new
Date(end).getTime()), handle invalid parses by returning a safe fallback string
(e.g. "날짜 정보 없음" or throw to the caller), and ensure formatKoreanDate/formatTime
are only called with valid Date objects; also confirm or enforce ISO-8601 input
expectations for start/end and apply the same validation to the related code at
the other occurrence (lines ~30-32).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 595c5754-4350-4ec3-bcca-08382b457f64

📥 Commits

Reviewing files that changed from the base of the PR and between c0ede3a and 0f2de09.

⛔ Files ignored due to path filters (4)
  • src/assets/icons/complete.svg is excluded by !**/*.svg
  • src/assets/icons/home.svg is excluded by !**/*.svg
  • src/assets/icons/more-horiz.svg is excluded by !**/*.svg
  • src/assets/icons/send.svg is excluded by !**/*.svg
📒 Files selected for processing (19)
  • src/app/(private)/(main)/attendance/page.tsx
  • src/app/(public)/attendance/page.tsx
  • src/assets/icons/index.ts
  • src/components/attendance/AttendanceCodeModal.tsx
  • src/components/attendance/AttendanceCompleteModal.tsx
  • src/components/attendance/AttendanceContent.tsx
  • src/components/attendance/AttendanceProgressBar.tsx
  • src/components/attendance/AttendanceStatus.tsx
  • src/components/attendance/AttendanceTodayCard.tsx
  • src/components/attendance/InputOTP.tsx
  • src/components/attendance/index.ts
  • src/components/layout/Header.tsx
  • src/components/ui/breadcrumb.tsx
  • src/components/ui/card.tsx
  • src/components/ui/dialog.tsx
  • src/hooks/index.ts
  • src/hooks/useRemainingTime.ts
  • src/lib/formatTime.ts
  • src/types/attendance.ts
💤 Files with no reviewable changes (1)
  • src/app/(public)/attendance/page.tsx

<Dialog open={open} onOpenChange={handleOpenChange}>
<DialogContent
showCloseButton={false}
className="bg-background flex h-[565px] w-[508px] flex-col"
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

모달 레이아웃의 하드코딩 간격/크기를 토큰으로 통일해 주세요.

Line 50의 h-[565px] w-[508px], Line 62의 gap-[10px]는 토큰 규칙과 맞지 않습니다.

As per coding guidelines, src/**/*.{css,ts,tsx}: "Always use design tokens (CSS variables) for values; do not hardcode values. Ask user before adding new tokens".

Also applies to: 62-62

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/attendance/AttendanceCodeModal.tsx` at line 50, The modal
component AttendanceCodeModal contains hardcoded Tailwind arbitrary values in
its className (h-[565px] w-[508px]) and a gap (gap-[10px]) that violate the
design-token rule; replace these arbitrary pixel values with the appropriate
design tokens (CSS variables) used across the project (e.g., height, width,
spacing tokens) by swapping the arbitrary classes for token-backed classes or
utility references, and if the exact token does not exist, stop and ask before
adding new tokens to the design system; locate the className on the
AttendanceCodeModal component and update both the container height/width and the
gap usage accordingly to use tokens instead of hardcoded pixels.

<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent
showCloseButton={false}
className="bg-background flex h-[565px] w-[508px] flex-col"
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

하드코딩된 모달 크기 값을 디자인 토큰으로 바꿔주세요.

Line 25의 h-[565px] w-[508px]는 토큰 기반 스타일 규칙과 충돌합니다. 기존 토큰 클래스 조합으로 치환하고, 필요한 토큰이 없다면 먼저 토큰 추가 합의를 거친 뒤 반영해 주세요.

As per coding guidelines, src/**/*.{css,ts,tsx}: "Always use design tokens (CSS variables) for values; do not hardcode values. Ask user before adding new tokens".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/attendance/AttendanceCompleteModal.tsx` at line 25, The modal
in AttendanceCompleteModal (className on the container with "h-[565px]
w-[508px]") uses hardcoded pixel heights/widths; replace these with the
project’s design token utility classes (e.g., existing height/width token
classes) so no raw h-[...] or w-[...] values remain, and if appropriate tokens
are missing open a quick design-token PR/discussion and then apply the agreed
token names to the container className; ensure the change is made in the
AttendanceCompleteModal component and that no other hardcoded h-[565px] or
w-[508px] remain in the file.

const description = formatAttendanceDescription(start, end, location);

return (
<div className="mx-auto flex w-full max-w-[1025px] flex-col gap-700 pt-600">
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

레이아웃 폭 값을 토큰 기반으로 교체해 주세요.

Line 29의 max-w-[1025px]는 하드코딩 값입니다. 공용 토큰/시맨틱 클래스 기반으로 치환해 주세요.

As per coding guidelines, src/**/*.{css,ts,tsx}: "Always use design tokens (CSS variables) for values; do not hardcode values. Ask user before adding new tokens".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/attendance/AttendanceContent.tsx` at line 29, The div in
AttendanceContent.tsx uses a hardcoded width class max-w-[1025px]; replace this
with the appropriate design token or semantic utility (e.g., a token-based
max-width class or CSS variable) instead of a hardcoded pixel value, updating
the className on the element that contains "mx-auto flex w-full max-w-[1025px]
flex-col gap-700 pt-600" to use the project’s token (or an existing semantic
class) for max width; if no suitable token exists, ask before adding a new
design token and follow the repo’s token naming conventions when creating it,
then verify styles still match visually.

</Button>
<Button variant="primary" size="md" type="submit" className="typo-button1 gap-100">
<Image src={CheckRoundIcon} alt="check" width={20} height={20} />
<Icon src={SendIcon} size={20} alt="check" className="text-icon-inverse" />
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

아이콘 alt를 비워서 버튼 이름을 깨끗하게 유지해 주세요.

이 버튼은 이미 게시하기 텍스트로 이름이 충분한데, alt="check"가 붙어 있어서 스크린 리더에 잘못된/중복된 이름이 들어갈 수 있습니다. 장식용 아이콘이면 빈 alt가 더 안전합니다.

제안 수정
-                  <Icon src={SendIcon} size={20} alt="check" className="text-icon-inverse" />
+                  <Icon src={SendIcon} size={20} alt="" className="text-icon-inverse" />
📝 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
<Icon src={SendIcon} size={20} alt="check" className="text-icon-inverse" />
<Icon src={SendIcon} size={20} alt="" className="text-icon-inverse" />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/layout/Header.tsx` at line 78, The Icon in Header.tsx is
passing alt="check" which duplicates the visible button label; change the
decorative icon to use an empty alt (alt="") on the Icon component (the instance
using SendIcon) so screen readers won't announce a redundant name; locate the
Icon invocation (Icon src={SendIcon} size={20} className="text-icon-inverse")
and replace the alt prop value with an empty string.

data-slot="dialog-overlay"
className={cn(
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50',
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/60',
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

공유 Dialog에 하드코딩된 색상/간격 값이 들어왔습니다.

bg-black/60, gap-[10px], pt-[10px]는 모두 토큰 밖의 값이라 공유 UI에서 계속 퍼지기 쉽습니다. 기존 토큰 클래스로 맞추거나, 꼭 필요한 값이면 먼저 토큰 추가 여부를 확인해 주세요.

As per coding guidelines, src/**/*.{css,ts,tsx} 규칙상 값은 디자인 토큰만 사용해야 하고, 새 토큰이 필요하면 먼저 확인해야 합니다.

Also applies to: 178-178

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/ui/dialog.tsx` at line 37, The shared Dialog component
contains hardcoded utility values ('bg-black/60', 'gap-[10px]', 'pt-[10px]') in
the class string (see the class passed in the dialog container in
src/components/ui/dialog.tsx and the other occurrence at the later block) —
replace these with existing design token classes (or coordinate to add new
tokens before using them) so the component uses tokenized spacing and color
utilities instead of raw values; update both occurrences (the class string
containing data-[state=...] and the other occurrence around line 178) to use
token names and remove literal values.

@github-actions
Copy link

🤖 Claude 테스트 제안

모델: claude-sonnet-4-6 | 토큰: 0 입력 / 0 출력

변경된 컴포넌트에 대해 Claude가 생성한 테스트 코드입니다. 검토 후 적합한 부분만 사용하세요.

src/app/(private)/(main)/attendance/page.tsx

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


src/app/(public)/attendance/page.tsx

오류: ENOENT: no such file or directory, open 'src/app/(public)/attendance/page.tsx'


src/components/attendance/AttendanceCodeModal.tsx

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


src/components/attendance/AttendanceCompleteModal.tsx

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


src/components/attendance/AttendanceContent.tsx

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


이 코멘트는 Claude API를 통해 자동 생성되었습니다. 반드시 검토 후 사용하세요.

@github-actions
Copy link

PR 테스트 결과

Jest: 통과

🎉 모든 테스트를 통과했습니다!

@github-actions
Copy link

PR 검증 결과

TypeScript: 통과
ESLint: 통과
Prettier: 통과
Build: 통과

🎉 모든 검증을 통과했습니다!

@github-actions
Copy link

구현한 기능 Preview: https://weeth-31hgw9tbu-weethsite-4975s-projects.vercel.app

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: 3

♻️ Duplicate comments (1)
src/components/attendance/InputOTP.tsx (1)

96-96: ⚠️ Potential issue | 🟠 Major

Line 96의 w-[41px]는 토큰 규칙 위반입니다.

임의 픽셀 값 대신 프로젝트의 size/spacing 토큰 클래스로 치환해 주세요. 기존 코멘트와 동일 이슈로 보입니다.

As per coding guidelines, src/**/*.{css,ts,tsx}: "Always use design tokens (CSS variables) for values; do not hardcode values. Ask user before adding new tokens".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/attendance/InputOTP.tsx` at line 96, The hardcoded width class
"w-[41px]" in the InputOTP component's div (the element with key={index})
violates token rules; replace it with the appropriate project size/spacing token
class (e.g., a preexisting token like "w-token-XX" or the nearest matching
spacing token) so that no raw pixel value remains, and if no existing token
matches the needed 41px use-case, ask the product/design team before adding a
new token and follow the project's token naming conventions when creating it.
🧹 Nitpick comments (1)
src/components/attendance/AttendanceStatus.tsx (1)

11-12: 루트 스타일 정의를 cva 패턴으로 맞추는 것을 권장합니다.

현재는 문자열 클래스를 직접 cn에 넣고 있어, 컴포넌트 스타일링 규칙 일관성이 떨어집니다. 이 파일도 cva로 기본 스타일를 선언해두면 이후 variant 확장 시 유지보수가 쉬워집니다.

리팩터링 예시
+import { cva } from 'class-variance-authority';
 import { cn } from '@/lib/cn';
 import { AttendanceProgressBar } from '@/components/attendance/AttendanceProgressBar';
 
+const attendanceStatusVariants = cva('flex flex-col gap-300');
+
 interface AttendanceStatusProps extends React.HTMLAttributes<HTMLDivElement> {
   name: string;
   attendanceRate: number;
 }
 
 function AttendanceStatus({ name, attendanceRate, className, ...props }: AttendanceStatusProps) {
   return (
-    <div className={cn('flex flex-col gap-300', className)} {...props}>
+    <div className={cn(attendanceStatusVariants(), className)} {...props}>

As per coding guidelines, src/components/**/*.{ts,tsx}: Use Tailwind CSS v4 with class-variance-authority (cva) for styling components.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/attendance/AttendanceStatus.tsx` around lines 11 - 12, The
root div in AttendanceStatus currently inlines "flex flex-col gap-300" via cn
which breaks the cva styling convention; create a cva-based root style (e.g.,
const attendanceStatusRoot = cva('flex flex-col gap-300') near the top of the
file), then replace the inline usage in the AttendanceStatus component (the div
using cn('flex flex-col gap-300', className)) with cn(attendanceStatusRoot(),
className) (or attendanceStatusRoot({ className }) if you prefer cva merging),
so the component uses CVA for base styles and remains ready for variants.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/app/`(private)/(main)/attendance/page.tsx:
- Line 17: The AttendanceContent call currently hardcodes the user name ("김위드")
which will display the same name for all users; update the usage in page.tsx to
supply a non-personal placeholder or a session-derived username instead of the
string literal: replace the literal "김위드" passed to AttendanceContent (name
prop) with a neutral placeholder like "사용자" or the server/session value (e.g.,
currentUser.name) obtained from your auth/session helper before rendering,
keeping the mockAttendance prop as-is until the API is available.
- Around line 10-11: 목 데이터의 start/end가 고정된 절대 타임스탬프로 되어 있어 시간이 지나면 항상 만료로 표시됩니다;
src/app/(private)/(main)/attendance/page.tsx에 정의된 목 객체의 start 및 end 필드를 절대값 대신
현재 시각을 기준으로 동적으로 생성하도록 변경하세요 (예: Date.now()에 원하는 오프셋(분/시간/일)을 더하거나 빼서 new
Date(...).toISOString()으로 설정). 해당 변경은 목 데이터 선언부(참조되는 변수명/객체 내 start, end 속성)를 찾아
적용하고, 여러 테스트 시나리오가 필요하면 시작을 현재 시간보다 과거로, 종료를 현재 시간보다 미래로 계산하는 유틸(예:
generateMockAttendance 또는 getRelativeIso)로 추출해 재사용하세요.

In `@src/components/attendance/AttendanceStatus.tsx`:
- Around line 9-17: The attendance text can disagree with the visual bar because
AttendanceProgressBar normalizes the incoming attendanceRate but the component
prints the raw value; fix by normalizing/clamping the value once inside
AttendanceStatus (e.g., compute normalizedRate = Math.max(0, Math.min(100,
attendanceRate)) or use an existing clamp util) and use normalizedRate both in
the displayed text and when passing attendanceRate to AttendanceProgressBar so
both show the same bounded value.

---

Duplicate comments:
In `@src/components/attendance/InputOTP.tsx`:
- Line 96: The hardcoded width class "w-[41px]" in the InputOTP component's div
(the element with key={index}) violates token rules; replace it with the
appropriate project size/spacing token class (e.g., a preexisting token like
"w-token-XX" or the nearest matching spacing token) so that no raw pixel value
remains, and if no existing token matches the needed 41px use-case, ask the
product/design team before adding a new token and follow the project's token
naming conventions when creating it.

---

Nitpick comments:
In `@src/components/attendance/AttendanceStatus.tsx`:
- Around line 11-12: The root div in AttendanceStatus currently inlines "flex
flex-col gap-300" via cn which breaks the cva styling convention; create a
cva-based root style (e.g., const attendanceStatusRoot = cva('flex flex-col
gap-300') near the top of the file), then replace the inline usage in the
AttendanceStatus component (the div using cn('flex flex-col gap-300',
className)) with cn(attendanceStatusRoot(), className) (or
attendanceStatusRoot({ className }) if you prefer cva merging), so the component
uses CVA for base styles and remains ready for variants.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cbd06577-623b-4568-93f3-b0e931a3b36c

📥 Commits

Reviewing files that changed from the base of the PR and between 0f2de09 and aad545b.

📒 Files selected for processing (10)
  • src/app/(private)/(main)/attendance/page.tsx
  • src/components/attendance/AttendanceCodeModal.tsx
  • src/components/attendance/AttendanceContent.tsx
  • src/components/attendance/AttendanceStatus.tsx
  • src/components/attendance/AttendanceTodayCard.tsx
  • src/components/attendance/InputOTP.tsx
  • src/components/layout/Header.tsx
  • src/components/ui/dialog.tsx
  • src/hooks/useRemainingTime.ts
  • src/types/attendance.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • src/components/layout/Header.tsx
  • src/types/attendance.ts
  • src/hooks/useRemainingTime.ts
  • src/components/attendance/AttendanceContent.tsx
  • src/components/ui/dialog.tsx
  • src/components/attendance/AttendanceTodayCard.tsx
  • src/components/attendance/AttendanceCodeModal.tsx

Comment on lines +9 to +17
function AttendanceStatus({ name, attendanceRate, className, ...props }: AttendanceStatusProps) {
return (
<div className={cn('flex flex-col gap-300', className)} {...props}>
<h2 className="typo-h3 text-text-strong">
{name}님의
<br />
출석률은 {attendanceRate}%
</h2>
<AttendanceProgressBar attendanceRate={attendanceRate} />
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

출석률 텍스트와 ProgressBar 값이 불일치할 수 있습니다.

Line 15는 attendanceRate 원본을 출력하고, Line 17의 AttendanceProgressBar는 내부에서 0~100으로 보정합니다. 값이 범위를 벗어나면 텍스트와 바가 서로 다른 수치를 보여줄 수 있습니다.

수정 제안
 function AttendanceStatus({ name, attendanceRate, className, ...props }: AttendanceStatusProps) {
+  const safeAttendanceRate = Math.min(100, Math.max(0, attendanceRate));
+
   return (
     <div className={cn('flex flex-col gap-300', className)} {...props}>
       <h2 className="typo-h3 text-text-strong">
         {name}님의
         <br />
-        출석률은 {attendanceRate}%
+        출석률은 {safeAttendanceRate}%
       </h2>
-      <AttendanceProgressBar attendanceRate={attendanceRate} />
+      <AttendanceProgressBar attendanceRate={safeAttendanceRate} />
     </div>
   );
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/attendance/AttendanceStatus.tsx` around lines 9 - 17, The
attendance text can disagree with the visual bar because AttendanceProgressBar
normalizes the incoming attendanceRate but the component prints the raw value;
fix by normalizing/clamping the value once inside AttendanceStatus (e.g.,
compute normalizedRate = Math.max(0, Math.min(100, attendanceRate)) or use an
existing clamp util) and use normalizedRate both in the displayed text and when
passing attendanceRate to AttendanceProgressBar so both show the same bounded
value.

Copy link
Member

@dalzzy dalzzy left a comment

Choose a reason for hiding this comment

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

꺄악 수고하셨습니다 !!! 나영님 아니였으면 울면서 밤샘 작업할 뻔 했습니다 ,,🥹👍🏻 최고의 프론트

code: number;
message: string;
data: AttendanceData;
}
Copy link
Member

Choose a reason for hiding this comment

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

저희 공통 api-response 타입 정의해둔게 아직 없었나욤..??

interface ApiResponse<T> {
  code: number;
  message: string;
  data: T;
}

AttendanceResponse에 직접 선언하기보다 이렇게 공통 ApiResponse<T> 타입으로 분리해 제네릭으로 사용하는 게 더 좋을 것 같습니당

type AttendanceResponse = ApiResponse<AttendanceData>;

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ApiResponse<T>types/common.ts에 추가하고, AttendanceResponseApiResponse<AttendanceData>로 교체하는 방향으로 수정했습니당! b

Copy link
Collaborator

@JIN921 JIN921 left a comment

Choose a reason for hiding this comment

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

작업속도가 우뜨케 이렇게 빨라요 짱짱..

const description = formatAttendanceDescription(start, end, location);

// eslint-disable-next-line @typescript-eslint/no-unused-vars
function handleAttendanceComplete(code: string) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

_code: string로 prefix하면 lint 규칙을 비활성화하지 않아도 된대용!

Copy link
Collaborator

Choose a reason for hiding this comment

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

저희 브레드 크럼 쓸 때 home은 다 기본으로 들어가잖아요,, props로 홈을 기본으로 표시할지 안 할지 넣어 보는 거 어떠세용??

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

왓 좋습니다,,, bb 브레드 크럼에 showHome?: boolean props 추가했고 false 설정해주면 hoem 아이콘은 표시되지 않게 설정했어용! ^__^ b

@github-actions
Copy link

🤖 Claude 테스트 제안

모델: claude-sonnet-4-6 | 토큰: 0 입력 / 0 출력

변경된 컴포넌트에 대해 Claude가 생성한 테스트 코드입니다. 검토 후 적합한 부분만 사용하세요.

src/app/(private)/(main)/attendance/page.tsx

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


src/app/(public)/attendance/page.tsx

오류: ENOENT: no such file or directory, open 'src/app/(public)/attendance/page.tsx'


src/components/attendance/AttendanceCodeModal.tsx

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


src/components/attendance/AttendanceCompleteModal.tsx

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


src/components/attendance/AttendanceContent.tsx

오류: Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits.


이 코멘트는 Claude API를 통해 자동 생성되었습니다. 반드시 검토 후 사용하세요.

@github-actions
Copy link

PR 테스트 결과

Jest: 통과

🎉 모든 테스트를 통과했습니다!

@github-actions
Copy link

PR 검증 결과

TypeScript: 통과
ESLint: 통과
Prettier: 통과
Build: 통과

🎉 모든 검증을 통과했습니다!

@github-actions
Copy link

구현한 기능 Preview: https://weeth-gl11f2ra0-weethsite-4975s-projects.vercel.app

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/ui/breadcrumb.tsx`:
- Around line 13-17: The default prop showHome on BreadcrumbList is currently
true and is unintentionally adding a home breadcrumb in existing usages; either
change BreadcrumbList to default showHome=false or update the three call sites
(CategorySelector, AttendanceContent, and the landing page) to pass
showHome={false} — for the landing page specifically, remove the manually added
home link if you prefer keeping showHome default true to avoid rendering two
home items and duplicate separators; pick one approach (change the default in
BreadcrumbList or explicitly set showHome={false} in the three components /
remove the manual home link on the landing page) and apply consistently.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 54e2558b-fd25-442c-8af8-ccc116c08060

📥 Commits

Reviewing files that changed from the base of the PR and between aad545b and cf8632f.

📒 Files selected for processing (7)
  • src/app/(private)/(main)/attendance/page.tsx
  • src/assets/icons/index.ts
  • src/components/attendance/AttendanceContent.tsx
  • src/components/ui/breadcrumb.tsx
  • src/types/attendance.ts
  • src/types/common.ts
  • src/types/index.ts
✅ Files skipped from review due to trivial changes (4)
  • src/types/common.ts
  • src/assets/icons/index.ts
  • src/types/attendance.ts
  • src/types/index.ts

Comment on lines +13 to +17
interface BreadcrumbListProps extends React.ComponentProps<'ol'> {
showHome?: boolean;
}

function BreadcrumbList({ className, showHome = true, children, ...props }: BreadcrumbListProps) {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: BreadcrumbList를 사용하는 모든 파일에서 showHome prop 사용 여부 확인

rg -n "BreadcrumbList" --type=tsx -A 3 -B 1

Repository: Team-Weeth/weeth-client

Length of output: 94


🏁 Script executed:

#!/bin/bash
# Find all BreadcrumbList usages in the codebase
rg "BreadcrumbList" -A 5 -B 2

Repository: Team-Weeth/weeth-client

Length of output: 7397


🏁 Script executed:

cat -n src/components/ui/breadcrumb.tsx | head -80

Repository: Team-Weeth/weeth-client

Length of output: 2706


🏁 Script executed:

sed -n '1,120p' src/app/\(public\)/\(landing\)/page.tsx | tail -60

Repository: Team-Weeth/weeth-client

Length of output: 3024


🏁 Script executed:

rg "BreadcrumbList" src/app/\(public\)/\(landing\)/page.tsx -B 5 -A 8

Repository: Team-Weeth/weeth-client

Length of output: 1907


🏁 Script executed:

rg "BreadcrumbList" -c

Repository: Team-Weeth/weeth-client

Length of output: 262


showHome 기본값 true로 인한 기존 사용처 동작 변경 확인 필요

showHome 기본값이 true로 설정되어 있어, 다음 세 곳의 기존 사용처에서 의도하지 않은 홈 아이콘이 추가됩니다:

  • CategorySelector: 게시판/채널 네비게이션에 홈 breadcrumb 추가 (불필요)
  • AttendanceContent: 출석 페이지에 홈 breadcrumb 추가 (불필요)
  • landing/page.tsx: 수동으로 입력한 홈 링크와 중복되어 홈 breadcrumb 2개 + separator 2개가 렌더링됨 (중대한 문제)

각 사용처에서 showHome={false}를 명시하거나, landing/page.tsx의 수동 홈 링크를 제거해야 합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/ui/breadcrumb.tsx` around lines 13 - 17, The default prop
showHome on BreadcrumbList is currently true and is unintentionally adding a
home breadcrumb in existing usages; either change BreadcrumbList to default
showHome=false or update the three call sites (CategorySelector,
AttendanceContent, and the landing page) to pass showHome={false} — for the
landing page specifically, remove the manually added home link if you prefer
keeping showHome default true to avoid rendering two home items and duplicate
separators; pick one approach (change the default in BreadcrumbList or
explicitly set showHome={false} in the three components / remove the manual home
link on the landing page) and apply consistently.

Copy link
Member

@woneeeee woneeeee left a comment

Choose a reason for hiding this comment

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

우왓 늦은 피알 리뷰 죄송합니당 ㅜㅜㅜ 수고하셨어욤!!! 🍀👍🏻

@nabbang6 nabbang6 merged commit 2849a92 into develop Mar 22, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 기능 개발 🎨 Html&css 마크업 & 스타일링 🔨 Refactor 코드 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants