Skip to content

[Feat] Table 컴포넌트 제작#14

Merged
KyeongJooni merged 18 commits into
mainfrom
feat/table-component-13
Jul 8, 2026
Merged

[Feat] Table 컴포넌트 제작#14
KyeongJooni merged 18 commits into
mainfrom
feat/table-component-13

Conversation

@KyeongJooni

@KyeongJooni KyeongJooni commented Jul 7, 2026

Copy link
Copy Markdown
Member

#️⃣ 연관된 이슈

Close #13

🚧 Work in Progress

  • 작업 진행 중

📌 주요 변경사항

  • 학회원 후기/블로그 후기 테이블과 멘토링 관리 화면에 필요한 재사용 컴포넌트 세트 추가
  • 기수·파트·상태를 표시하는 뱃지/칩 컴포넌트와 페이지네이션 계열 컴포넌트를 조합해 Figma 테이블 디자인을 그대로 구현
  • 멘토링 대시보드 목록 행과 멘토 지원자 관리 행 추가 (프로젝트 최초로 Base UI Select 드롭다운 도입)
  • 아이콘 빌드 스크립트가 하위 폴더의 SVG도 재귀적으로 인식하도록 개선

📝작업 내용

  • 기수/파트/상태 뱃지 컴포넌트 추가 (CohortBadge, PartBadge, StatusChip)
  • 파일 첨부 칩 컴포넌트 추가 (FileChip)
  • 페이지네이션과 테이블 footer 컴포넌트 추가 (Pagination, TableFooter) — Figma상 서로 다른 디자인 시스템 컴포넌트라 통합하지 않고 분리 구현
  • 후기 테이블 행과 테이블 컴포넌트 추가 (ReviewTableRow, ReviewTable) — 학회원 후기/블로그 후기 두 variant를 하나의 행 컴포넌트로 지원하고, 뱃지·칩·footer 컴포넌트를 조합해 테이블 전체 구성
  • 멘토링 대시보드 목록 행과 지원자 관리 행 추가 (MentoringListItem, MentorApplicationRow) — 상태 변경 드롭다운은 @kusitms.com/ui에 select 컴포넌트가 없어 Base UI Select primitive로 직접 구성
  • 첨부파일 아이콘 추가 및 아이콘 빌드 스크립트(build-icons.ts) 하위 폴더 재귀 스캔 지원
  • 검증: pnpm gen:index, tsc -b, eslint, prettier --check, vitest run(전체 통과), storybook build

📸 스크린샷 (선택)

image image image image image image image image

💬리뷰 요구사항(선택)

  • mentoring 도메인 reference 문서가 아직 없어, 실제 페이지 연동 시 .claude/references/domain에 추가가 필요합니다.
  • MentorApplicationRow의 상태값 스키마(엔드포인트)가 아직 정해지지 않아, statusOptions/status는 호출 쪽에서 주입하는 형태로 우선 구현했습니다.
  • 실제 후기/멘토링 관리 페이지 연동은 포함되어 있지 않습니다(컴포넌트 단위 구현).

Summary by CodeRabbit

  • New Features
    • CohortBadge, FileChip, Pagination, PartBadge, StatusChip, TableFooter, ReviewTable/ReviewTableRow, MentorApplicationRow, MentoringListItem 컴포넌트가 추가되었습니다.
    • 각 컴포넌트용 Storybook 기본 스토리(여러 상태/빈 데이터 케이스 포함)가 추가되었습니다.
  • Build/Workflow
    • 아이콘 빌드가 하위 폴더 SVG까지 함께 수집하도록 개선되었습니다.
  • Documentation
    • 아이콘 폴더 배치(최상위 평면 배치) 가이드가 업데이트되었습니다.
  • Tests
    • Pagination, TableFooter, ReviewTable/Row, MentorApplicationRow, MentoringListItem 테스트가 추가되었습니다.

@github-actions github-actions Bot changed the title Feat/table component 13 [Feat] Table 컴포넌트 제작 Jul 7, 2026
@github-actions github-actions Bot added the ✨Feature 새로운 기능 label Jul 7, 2026
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

CI 결과

항목 결과
TypeScript 🟢 통과
Prettier 🟢 통과
Generated 🟢 통과
ESLint 🟢 통과
Test 🟢 통과
Build 🟢 통과

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

공통 표시 컴포넌트, 페이지네이션/테이블, 멘토링 행 UI가 추가되고 상위 배럴 export로 노출됩니다. 아이콘 수집 스크립트는 하위 폴더까지 재귀 탐색하도록 바뀌었고, 아이콘 배치 규칙과 PR 템플릿 문구가 수정됩니다.

Changes

공통 UI 컴포넌트와 멘토링 컴포넌트

Layer / File(s) Summary
뱃지·칩 컴포넌트
src/components/common/CohortBadge/*, src/components/common/FileChip/*, src/components/common/PartBadge/*, src/components/common/StatusChip/*
기수, 파일명, 파트, 상태를 표시하는 공통 컴포넌트와 스토리/인덱스 재노출이 추가됩니다.
페이지네이션과 테이블 푸터
src/components/common/Pagination/*, src/components/common/TableFooter/*
페이지 목록 생성, 이전·다음 버튼 비활성화, 현재 페이지 표시를 포함한 Pagination과 TableFooter가 스토리, 테스트와 함께 추가됩니다.
리뷰 행 렌더링
src/components/common/ReviewTableRow/*
리뷰 행이 기수·파트·파일 칩·삭제 버튼을 조합해 블로그/멤버 타입별로 다른 내용을 렌더링하고, 행 단위 스토리와 테스트가 추가됩니다.
리뷰 테이블 조합
src/components/common/ReviewTable/*
리뷰 테이블이 타입별 헤더, 행 목록, 빈 상태, 테이블 푸터를 결합하고 관련 스토리·테스트·인덱스 재노출이 추가됩니다.
멘토링 행과 목록 항목
src/components/mentoring/MentorApplicationRow/*, src/components/mentoring/MentoringListItem/*
멘토 신청 행이 상태 선택, 파일 칩, 삭제 동작을 포함해 렌더링되고, 멘토링 목록 항목이 멘토·멘티 아바타와 상태 칩을 결합해 렌더링합니다.
배럴 export 연결
src/components/common/index.ts, src/components/index.ts, src/components/mentoring/index.ts
공통 컴포넌트와 멘토링 모듈이 상위 배럴 파일을 통해 재노출되도록 갱신됩니다.

아이콘 빌드 규칙과 수집

Layer / File(s) Summary
재귀 수집과 문서 문구
scripts/build-icons.ts, .claude/rules/generated-workflows.md, .github/PULL_REQUEST_TEMPLATE.md
SVG 소스 수집이 하위 디렉터리까지 확장되고, 아이콘 배치 규칙과 PR 템플릿의 헤딩 표기만 변경됩니다.

관련 이슈: #13
제안 라벨: feature, ui-components
제안 리뷰어: 프런트엔드 컴포넌트 담당자

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning 테이블 범위를 넘는 멘토링 UI, 아이콘 빌드 스크립트, PR 템플릿 변경이 함께 포함되어 있습니다. 테이블 관련 컴포넌트와 테스트만 유지하고, 멘토링 UI와 설정·템플릿 수정은 별도 PR로 분리하세요.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목이 Table 컴포넌트 제작이라는 핵심 변경을 간결하게 요약합니다.
Linked Issues check ✅ Passed 연결 이슈 #13의 Table 컴포넌트 제작 요구를 테이블/행/푸터 구현으로 충족합니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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 feat/table-component-13

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

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

CI 결과

항목 결과
TypeScript 🟢 통과
Prettier 🟢 통과
Generated 🟢 통과
ESLint 🟢 통과
Test 🟢 통과
Build 🟢 통과

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

CI 결과

항목 결과
TypeScript 🟢 통과
Prettier 🟢 통과
Generated 🟢 통과
ESLint 🟢 통과
Test 🟢 통과
Build 🟢 통과

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 9

Caution

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

⚠️ Outside diff range comments (1)
scripts/build-icons.ts (1)

56-85: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

재귀 순회에 대한 테스트 부재.

하위 폴더 스캔·병합·정렬 동작이 새로 추가됐지만 해당 로직을 검증하는 테스트가 보이지 않습니다. readIconSourcespnpm icons:build/icons:check가 의존하는 핵심 로직이므로, 중첩 디렉터리 케이스(빈 디렉터리, 동일 파일명 충돌 등)에 대한 단위 테스트를 추가하면 회귀를 조기에 잡을 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/build-icons.ts` around lines 56 - 85, The new recursive directory
traversal in readIconSources lacks tests for the added scan/merge/sort behavior.
Add unit tests for readIconSources that cover nested subdirectories, empty
directories, and same-name collisions, and verify that SVG files from subfolders
are included and the final IconSource list is sorted by componentName. Use the
readIconSources helper and related icon source shape symbols so the tests
directly exercise the logic used by pnpm icons:build and icons:check.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/build-icons.ts`:
- Around line 68-84: The recursive icon collection in readIconSources is already
producing the correct set of entries, but the local sort at the end of that
function is redundant because main() re-sorts the combined results later. Remove
the sort from readIconSources and keep only the final ordering in main(), so the
recursive merge simply returns [...files, ...nested.flat()] while preserving the
same output behavior with less repeated work.

In `@src/components/common/Pagination/Pagination.tsx`:
- Line 11: Pagination.tsx의 pages 생성 로직이 totalPages 전체를 항상 렌더링해 버튼 수가 과도하게 늘어나는
문제입니다. Pagination 컴포넌트에서 Array.from({ length: totalPages }, ...) 대신 현재 페이지를 기준으로
표시 개수를 제한하는 페이지 구간/ellipsis 방식으로 바꾸고, totalPages가 커도 일정 수의 버튼만 렌더링되도록 수정하세요.

In `@src/components/common/ReviewTable/ReviewTable.tsx`:
- Around line 6-23: ReviewTable currently hardcodes blog-only behavior, so it
cannot render memberReview rows. Update ReviewTable and ReviewTableRowData to
support a type discriminator and include memberReview-only fields like fileName
and phone, then pass the appropriate type through to ReviewTableRow instead of
always using blogReview. Ensure the shared row model and props in ReviewTable,
along with the ReviewTableRow usage, can handle both blogReview and memberReview
variants cleanly.

In `@src/components/common/StatusChip/StatusChip.tsx`:
- Around line 4-24: `statusChipVariants`와 `dotVariants`가 동일한 status 키를 각각 따로 관리해
변경 시 중복 수정이 필요합니다. `StatusChip`에서 `tv()` 정의를 하나로 합치고 `tailwind-variants`의
`slots`를 사용해 컨테이너와 dot 스타일을 함께 반환하도록 리팩터링하세요. `statusChipVariants`와
`dotVariants`에 해당하는 상태 매핑을 한 곳으로 모아 `StatusChip` 컴포넌트가 단일 variant 정의만 참조하도록 정리하면
됩니다.

In `@src/components/common/TableFooter/TableFooter.test.tsx`:
- Around line 39-45: The TableFooter test suite is missing the symmetric check
for the last-page state, so add a test in TableFooter.test.tsx that renders
TableFooter with page equal to totalPages and verifies the “다음 페이지” button is
disabled. Reuse the existing TableFooter, render, and screen.getByRole patterns
from the current tests, and assert the disabled state that matches the
disabled={page >= totalPages} logic in TableFooter.

In `@src/components/common/TableFooter/TableFooter.tsx`:
- Line 18: The page list generation in TableFooter currently renders every page
number from totalPages, which can overflow the UI for large datasets. Update the
paging logic in TableFooter.tsx to cap the visible buttons and add
truncation/ellipsis behavior in the page rendering path (including the page list
used around the pages array and the related render logic in the later section)
so only a small, manageable subset of pages is shown at once.

In `@src/components/mentoring/MentorApplicationRow/MentorApplicationRow.tsx`:
- Around line 145-153: The delete button in MentorApplicationRow is rendered
even when onDelete is not provided, which can leave a non-functional action in
the UI. Update MentorApplicationRow so the button is only shown when onDelete
exists, or render it disabled when the handler is absent; use the onDelete prop
check around the button markup and keep DeleteIcon behavior unchanged.
- Around line 155-159: The conditional rendering around fileName in
MentorApplicationRow changes the table layout depending on whether an attachment
exists. Keep the final flex-1 column always rendered in MentorApplicationRow and
only conditionally render the FileChip or a placeholder/empty state inside it so
the row structure stays consistent. Use the existing fileName check and the
surrounding flex container to preserve alignment across rows.

In `@src/components/mentoring/MentoringListItem/MentoringListItem.test.tsx`:
- Around line 5-51: MentoringListItem 테스트에 avatarUrl 분기와 LongTitle 케이스가 빠져 있습니다.
MentoringListItem 렌더링 테스트를 확장해 avatarUrl이 전달될 때 이미지가 표시되는지 검증하고, 긴 제목이 들어오는
LongTitle 스토리와 동일한 상황에서 truncate 처리 결과가 유지되는지도 확인하세요. 기존 MentoringListItem
스냅샷/텍스트 검증에 더해 avatarUrl, title 관련 렌더링 분기를 직접 찾을 수 있도록 추가 테스트를 넣어 주세요.

---

Outside diff comments:
In `@scripts/build-icons.ts`:
- Around line 56-85: The new recursive directory traversal in readIconSources
lacks tests for the added scan/merge/sort behavior. Add unit tests for
readIconSources that cover nested subdirectories, empty directories, and
same-name collisions, and verify that SVG files from subfolders are included and
the final IconSource list is sorted by componentName. Use the readIconSources
helper and related icon source shape symbols so the tests directly exercise the
logic used by pnpm icons:build and icons:check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e067f322-e3d0-4b32-9a21-c1642488d818

📥 Commits

Reviewing files that changed from the base of the PR and between ea0d626 and 2744aa8.

⛔ Files ignored due to path filters (4)
  • src/assets/icons/generated/.gitkeep is excluded by !**/generated/**
  • src/assets/icons/generated/AttachFileIcon.tsx is excluded by !**/generated/**
  • src/assets/icons/generated/index.ts is excluded by !**/generated/**
  • src/assets/icons/svg/attach_file.svg is excluded by !**/*.svg, !**/*.svg
📒 Files selected for processing (42)
  • .claude/rules/generated-workflows.md
  • .github/PULL_REQUEST_TEMPLATE.md
  • scripts/build-icons.ts
  • src/components/common/CohortBadge/CohortBadge.stories.tsx
  • src/components/common/CohortBadge/CohortBadge.tsx
  • src/components/common/CohortBadge/index.ts
  • src/components/common/FileChip/FileChip.stories.tsx
  • src/components/common/FileChip/FileChip.tsx
  • src/components/common/FileChip/index.ts
  • src/components/common/Pagination/Pagination.stories.tsx
  • src/components/common/Pagination/Pagination.test.tsx
  • src/components/common/Pagination/Pagination.tsx
  • src/components/common/Pagination/index.ts
  • src/components/common/PartBadge/PartBadge.stories.tsx
  • src/components/common/PartBadge/PartBadge.tsx
  • src/components/common/PartBadge/index.ts
  • src/components/common/ReviewTable/ReviewTable.stories.tsx
  • src/components/common/ReviewTable/ReviewTable.test.tsx
  • src/components/common/ReviewTable/ReviewTable.tsx
  • src/components/common/ReviewTable/index.ts
  • src/components/common/ReviewTableRow/ReviewTableRow.stories.tsx
  • src/components/common/ReviewTableRow/ReviewTableRow.test.tsx
  • src/components/common/ReviewTableRow/ReviewTableRow.tsx
  • src/components/common/ReviewTableRow/index.ts
  • src/components/common/StatusChip/StatusChip.stories.tsx
  • src/components/common/StatusChip/StatusChip.tsx
  • src/components/common/StatusChip/index.ts
  • src/components/common/TableFooter/TableFooter.stories.tsx
  • src/components/common/TableFooter/TableFooter.test.tsx
  • src/components/common/TableFooter/TableFooter.tsx
  • src/components/common/TableFooter/index.ts
  • src/components/common/index.ts
  • src/components/index.ts
  • src/components/mentoring/MentorApplicationRow/MentorApplicationRow.stories.tsx
  • src/components/mentoring/MentorApplicationRow/MentorApplicationRow.test.tsx
  • src/components/mentoring/MentorApplicationRow/MentorApplicationRow.tsx
  • src/components/mentoring/MentorApplicationRow/index.ts
  • src/components/mentoring/MentoringListItem/MentoringListItem.stories.tsx
  • src/components/mentoring/MentoringListItem/MentoringListItem.test.tsx
  • src/components/mentoring/MentoringListItem/MentoringListItem.tsx
  • src/components/mentoring/MentoringListItem/index.ts
  • src/components/mentoring/index.ts

Comment thread scripts/build-icons.ts Outdated
}

export function Pagination({ page, totalPages, onPageChange, className }: PaginationProps) {
const pages = Array.from({ length: totalPages }, (_, index) => index + 1)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoff

totalPages가 클 경우 버튼 개수 무제한 증가

Array.from({ length: totalPages }, ...)로 전체 페이지 번호를 항상 다 렌더링합니다. totalPages가 커지면(예: 수십~수백) DOM 노드가 그만큼 늘어나 성능 및 UX(가로 스크롤 등) 문제가 생길 수 있습니다. 현재 스토리/테스트는 최대 6페이지까지만 검증하고 있어 실제 운영 데이터 규모에서 안전한지 확인이 필요합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/common/Pagination/Pagination.tsx` at line 11, Pagination.tsx의
pages 생성 로직이 totalPages 전체를 항상 렌더링해 버튼 수가 과도하게 늘어나는 문제입니다. Pagination 컴포넌트에서
Array.from({ length: totalPages }, ...) 대신 현재 페이지를 기준으로 표시 개수를 제한하는 페이지
구간/ellipsis 방식으로 바꾸고, totalPages가 커도 일정 수의 버튼만 렌더링되도록 수정하세요.

Comment thread src/components/common/ReviewTable/ReviewTable.tsx
Comment thread src/components/common/StatusChip/StatusChip.tsx Outdated
Comment thread src/components/common/TableFooter/TableFooter.test.tsx
totalLabel,
className,
}: TableFooterProps) {
const pages = Array.from({ length: totalPages }, (_, index) => index + 1)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoff

totalPages가 클 경우 페이지 버튼이 무한정 렌더링됨

pages 배열이 truncation/ellipsis 없이 totalPages 전체만큼 생성됩니다. 현재 스토리/테스트는 3~6페이지 정도만 다루지만, 페이지 수가 커지면 UI가 깨질 수 있습니다.

Also applies to: 39-60

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/common/TableFooter/TableFooter.tsx` at line 18, The page list
generation in TableFooter currently renders every page number from totalPages,
which can overflow the UI for large datasets. Update the paging logic in
TableFooter.tsx to cap the visible buttons and add truncation/ellipsis behavior
in the page rendering path (including the page list used around the pages array
and the related render logic in the later section) so only a small, manageable
subset of pages is shown at once.

Comment thread src/components/mentoring/MentorApplicationRow/MentorApplicationRow.tsx Outdated
Comment on lines +5 to +51
describe('MentoringListItem', () => {
it('멘토와 멘티 이름, 역할을 렌더링한다', () => {
render(
<MentoringListItem
mentor={{ name: '김도윤', role: '멘토' }}
mentee={{ name: '이서준', role: '멘티' }}
dateRange="2026.05.12 14:00 - 2026.05.12 14:00"
title="[워크숍] 디자인 트렌드"
status="progress"
/>,
)

expect(screen.getByText('김도윤')).toBeTruthy()
expect(screen.getByText('멘토')).toBeTruthy()
expect(screen.getByText('이서준')).toBeTruthy()
expect(screen.getByText('멘티')).toBeTruthy()
})

it('일시와 제목을 렌더링한다', () => {
render(
<MentoringListItem
mentor={{ name: '김도윤', role: '멘토' }}
mentee={{ name: '이서준', role: '멘티' }}
dateRange="2026.05.12 14:00 - 2026.05.12 14:00"
title="[워크숍] 디자인 트렌드"
status="progress"
/>,
)

expect(screen.getByText('2026.05.12 14:00 - 2026.05.12 14:00')).toBeTruthy()
expect(screen.getByText('[워크숍] 디자인 트렌드')).toBeTruthy()
})

it('상태 칩을 렌더링한다', () => {
render(
<MentoringListItem
mentor={{ name: '김도윤', role: '멘토' }}
mentee={{ name: '이서준', role: '멘티' }}
dateRange="2026.05.12 14:00 - 2026.05.12 14:00"
title="[워크숍] 디자인 트렌드"
status="completed"
/>,
)

expect(screen.getByText('완료')).toBeTruthy()
})
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

avatarUrl 제공 케이스와 LongTitle 스토리 대응 테스트 누락.

현재 테스트는 이름/역할/일시/제목/상태만 검증합니다. avatarUrl이 있을 때 <img>가 렌더링되는 분기와 truncate 적용 여부는 테스트되지 않습니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/mentoring/MentoringListItem/MentoringListItem.test.tsx` around
lines 5 - 51, MentoringListItem 테스트에 avatarUrl 분기와 LongTitle 케이스가 빠져 있습니다.
MentoringListItem 렌더링 테스트를 확장해 avatarUrl이 전달될 때 이미지가 표시되는지 검증하고, 긴 제목이 들어오는
LongTitle 스토리와 동일한 상황에서 truncate 처리 결과가 유지되는지도 확인하세요. 기존 MentoringListItem
스냅샷/텍스트 검증에 더해 avatarUrl, title 관련 렌더링 분기를 직접 찾을 수 있도록 추가 테스트를 넣어 주세요.

@KyeongJooni KyeongJooni requested a review from leemanjae02 July 7, 2026 15:01
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

CI 결과

항목 결과
TypeScript 🟢 통과
Prettier 🟢 통과
Generated 🟢 통과
ESLint 🟢 통과
Test 🟢 통과
Build 🟢 통과

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
src/components/mentoring/MentoringListItem/MentoringListItem.test.tsx (1)

52-65: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

avatarUrl 테스트는 적절하나 LongTitle(truncate) 케이스는 여전히 누락.

과거 리뷰에서 avatarUrl과 LongTitle 스토리 대응 테스트 모두 부족하다고 지적됐는데, 이번엔 avatarUrl만 추가됨. title이 긴 경우 truncate 스타일이 유지되는지 검증하는 테스트도 추가하면 좋겠습니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/mentoring/MentoringListItem/MentoringListItem.test.tsx` around
lines 52 - 65, The current MentoringListItem test covers avatarUrl rendering but
still misses the long-title truncate case. Add a test in
MentoringListItem.test.tsx that renders MentoringListItem with an intentionally
long title and asserts the truncate-related styling/class behavior is preserved
on the title element, using the existing MentoringListItem component and title
prop as the key symbols to locate the coverage.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@src/components/mentoring/MentoringListItem/MentoringListItem.test.tsx`:
- Around line 52-65: The current MentoringListItem test covers avatarUrl
rendering but still misses the long-title truncate case. Add a test in
MentoringListItem.test.tsx that renders MentoringListItem with an intentionally
long title and asserts the truncate-related styling/class behavior is preserved
on the title element, using the existing MentoringListItem component and title
prop as the key symbols to locate the coverage.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ebc3e751-a1c7-429d-9744-cf06f28921d8

📥 Commits

Reviewing files that changed from the base of the PR and between 2744aa8 and f0e0060.

📒 Files selected for processing (6)
  • scripts/build-icons.ts
  • src/components/common/StatusChip/StatusChip.tsx
  • src/components/common/TableFooter/TableFooter.test.tsx
  • src/components/mentoring/MentorApplicationRow/MentorApplicationRow.test.tsx
  • src/components/mentoring/MentorApplicationRow/MentorApplicationRow.tsx
  • src/components/mentoring/MentoringListItem/MentoringListItem.test.tsx

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

type이 blogReview로 고정돼 있어서 memberReview는 이 컴포넌트로 못 그릴 것 같아요
pr에는 두 variant 모두 지원이라고 되어있지만 코드상 누락이 있는 것 같아 확인 부탁드려요 :)

))}
</div>

<div className="flex w-full flex-col items-start">

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

rows 배열이 빈 배열일 경우 빈화면만 렌더링 될 것 같아서 배열의 길이가 0인 경우 처리가 추가되면 좋을 것 같아요!

@leemanjae02 leemanjae02 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

고생하셨습니다! 코멘트 남겨드렸으니 확인 부탁드려요😀

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

CI 결과

항목 결과
TypeScript 🟢 통과
Prettier 🟢 통과
Generated 🟢 통과
ESLint 🟢 통과
Test 🟢 통과
Build 🟢 통과

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (2)
src/components/common/ReviewTable/ReviewTable.tsx (2)

6-27: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

category/phone/fileNametype과 연동되지 않는 타입

ReviewTableRowData는 모든 필드가 optional이라, type: 'blogReview'인데 phone/fileName을 넘기거나 그 반대여도 타입 에러가 나지 않습니다. 유니온으로 판별 가능하게 만들면 잘못된 필드 조합을 컴파일 타임에 막을 수 있습니다.

🔧 제안: discriminated union으로 분리
-interface ReviewTableRowData {
-  id: string
-  name: string
-  generation: number
-  part: PartBadgeType
-  title: string
-  category?: string
-  phone?: string
-  fileName?: string
-}
-
-interface ReviewTableProps {
-  type: 'blogReview' | 'memberReview'
-  rows: ReviewTableRowData[]
+interface BaseReviewTableRowData {
+  id: string
+  name: string
+  generation: number
+  part: PartBadgeType
+  title: string
+}
+
+type ReviewTableProps = (
+  | { type: 'blogReview'; rows: (BaseReviewTableRowData & { category?: string })[] }
+  | {
+      type: 'memberReview'
+      rows: (BaseReviewTableRowData & { phone?: string; fileName?: string })[]
+    }
+) & {
   onDeleteRow?: (id: string) => void
   page: number
   totalPages: number
   onPageChange: (page: number) => void
   totalLabel: string
   emptyMessage?: string
   className?: string
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/common/ReviewTable/ReviewTable.tsx` around lines 6 - 27,
`ReviewTableRowData` currently allows `category`, `phone`, and `fileName` for
every row regardless of `ReviewTableProps.type`, so invalid field combinations
slip through. Update the row typing in `ReviewTable.tsx` to a discriminated
union keyed by `type` (or split the row shape by `blogReview` vs `memberReview`)
and make `ReviewTableProps.rows` depend on that union. Keep `ReviewTableProps`
and any row-rendering logic in `ReviewTable` aligned with the new
`type`-specific row type so the compiler rejects mismatched fields.

60-104: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

div 기반 테이블에 ARIA 시맨틱 누락

ReviewTable/ReviewTableRow<table> 대신 div로 그리드를 구성하는데, role="table", role="row", role="columnheader", role="cell" 등이 전혀 없습니다. 스크린리더 사용자는 헤더-데이터 관계를 인식할 수 없습니다.

🦻 제안: role 속성 추가
       <div
-        className={cn('bg-fill-netural flex h-12 w-full items-start', !isMemberReview && 'gap-1')}
+        role="row"
+        className={cn('bg-fill-netural flex h-12 w-full items-start', !isMemberReview && 'gap-1')}
       >
         {columns.map((column) => (
           <div
             key={column.label}
+            role="columnheader"
             className={cn('flex shrink-0 flex-col items-start px-[18px] py-3.5', column.className)}

ReviewTableRow.tsx의 행 컨테이너에도 role="row", 각 셀 div에 role="cell"을 추가해야 합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/common/ReviewTable/ReviewTable.tsx` around lines 60 - 104,
`ReviewTable` and `ReviewTableRow` are building a table-like layout with divs
but missing ARIA semantics, so add the appropriate roles to preserve header/data
relationships for assistive tech. Update the main wrapper and header container
in `ReviewTable` to expose table and rowgroup/row semantics as needed, and in
`ReviewTableRow` add `role="row"` on the row container plus
`role="cell"`/`role="columnheader"` on the individual cell/header elements. Use
the existing `ReviewTable` and `ReviewTableRow` components to locate the
div-based table structure and keep the visual layout unchanged.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/components/common/ReviewTable/ReviewTable.tsx`:
- Around line 6-27: `ReviewTableRowData` currently allows `category`, `phone`,
and `fileName` for every row regardless of `ReviewTableProps.type`, so invalid
field combinations slip through. Update the row typing in `ReviewTable.tsx` to a
discriminated union keyed by `type` (or split the row shape by `blogReview` vs
`memberReview`) and make `ReviewTableProps.rows` depend on that union. Keep
`ReviewTableProps` and any row-rendering logic in `ReviewTable` aligned with the
new `type`-specific row type so the compiler rejects mismatched fields.
- Around line 60-104: `ReviewTable` and `ReviewTableRow` are building a
table-like layout with divs but missing ARIA semantics, so add the appropriate
roles to preserve header/data relationships for assistive tech. Update the main
wrapper and header container in `ReviewTable` to expose table and rowgroup/row
semantics as needed, and in `ReviewTableRow` add `role="row"` on the row
container plus `role="cell"`/`role="columnheader"` on the individual cell/header
elements. Use the existing `ReviewTable` and `ReviewTableRow` components to
locate the div-based table structure and keep the visual layout unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 58ef25f7-c9aa-44c4-977f-0ec00bc95c28

📥 Commits

Reviewing files that changed from the base of the PR and between f0e0060 and 2650bd9.

📒 Files selected for processing (4)
  • src/components/common/ReviewTable/ReviewTable.stories.tsx
  • src/components/common/ReviewTable/ReviewTable.test.tsx
  • src/components/common/ReviewTable/ReviewTable.tsx
  • src/components/common/ReviewTableRow/ReviewTableRow.tsx

@KyeongJooni KyeongJooni merged commit 8f78b4d into main Jul 8, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨Feature 새로운 기능

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] #13 - Table 컴포넌트 제작

2 participants