[feat] 달력 카테고리 분류 추가#118
Hidden character warning
Conversation
📝 WalkthroughWalkthroughExtracted schedule category color and label constants into Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/pages/Schedule/components/ScheduleDetail.tsx (2)
61-65: Unnecessary wrapper div can be simplified.The outer
flex flex-row gap-1wrapper contains only a single child, so the flex layout has no effect. Consider removing the redundant wrapper.♻️ Suggested simplification
<div className="flex flex-col gap-1"> - <div className="flex flex-row gap-1"> - <div className="text-[14px] leading-4 font-bold"> - [{SCHEDULE_LABEL[scheduleCategory]}] {title} - </div> - </div> + <div className="text-[14px] leading-4 font-bold"> + [{SCHEDULE_LABEL[scheduleCategory]}] {title} + </div> <div className="text-[13px] leading-3 text-indigo-300">{formatScheduleTime({ startedAt, endedAt })}</div> </div>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/Schedule/components/ScheduleDetail.tsx` around lines 61 - 65, In ScheduleDetail, remove the redundant outer wrapper div with className "flex flex-row gap-1" (it only has one child so flex/gap do nothing); keep the inner text div (the element that renders "[{SCHEDULE_LABEL[scheduleCategory]}] {title}") and, if any layout styles are required, move them to that inner div (update its className accordingly). This touches the JSX around the SCHEDULE_LABEL[scheduleCategory] and title rendering—delete the outer node and ensure the remaining div preserves necessary classes.
18-23: Consider aligning the type withSCHEDULE_COLORfor type safety.
SCHEDULE_COLORis typed implicitly with specific keys, whileSCHEDULE_LABELusesRecord<string, string>. This loses type safety - a typo inscheduleCategorywould silently returnundefined. Consider using the same typing approach or extracting a sharedScheduleCategorytype.♻️ Suggested refactor
-const SCHEDULE_LABEL: Record<string, string> = { +const SCHEDULE_LABEL = { UNIVERSITY: '학사일정', CLUB: '동아리', COUNCIL: '총동아리', DORM: '기숙사', -}; +} as const;Or extract a shared type:
type ScheduleCategory = 'UNIVERSITY' | 'CLUB' | 'COUNCIL' | 'DORM'; const SCHEDULE_LABEL: Record<ScheduleCategory, string> = { ... }; const SCHEDULE_COLOR: Record<ScheduleCategory, string> = { ... };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/Schedule/components/ScheduleDetail.tsx` around lines 18 - 23, SCHEDULE_LABEL is currently typed as Record<string, string>, losing type safety compared to the implicitly-typed SCHEDULE_COLOR; define a shared literal union type (e.g., ScheduleCategory = 'UNIVERSITY' | 'CLUB' | 'COUNCIL' | 'DORM') and change both SCHEDULE_LABEL and SCHEDULE_COLOR to use Record<ScheduleCategory, string> (or extract the existing keys into a ScheduleCategory type) so lookups by scheduleCategory are type-checked and typos surface at compile time.
🤖 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/pages/Home/index.tsx`:
- Around line 149-155: Extract the duplicated SCHEDULE_LABEL (and the related
SCHEDULE_COLOR) into a shared constants module (e.g., create
src/constants/schedule.ts), export a ScheduleCategory type and both
SCHEDULE_LABEL and SCHEDULE_COLOR as Record<ScheduleCategory, string>, then
replace the inline SCHEDULE_LABEL in Home (index.tsx) and the duplicate in
ScheduleDetail.tsx with imports from that module so the constants are not
recreated on every render and remain single source of truth.
---
Nitpick comments:
In `@src/pages/Schedule/components/ScheduleDetail.tsx`:
- Around line 61-65: In ScheduleDetail, remove the redundant outer wrapper div
with className "flex flex-row gap-1" (it only has one child so flex/gap do
nothing); keep the inner text div (the element that renders
"[{SCHEDULE_LABEL[scheduleCategory]}] {title}") and, if any layout styles are
required, move them to that inner div (update its className accordingly). This
touches the JSX around the SCHEDULE_LABEL[scheduleCategory] and title
rendering—delete the outer node and ensure the remaining div preserves necessary
classes.
- Around line 18-23: SCHEDULE_LABEL is currently typed as Record<string,
string>, losing type safety compared to the implicitly-typed SCHEDULE_COLOR;
define a shared literal union type (e.g., ScheduleCategory = 'UNIVERSITY' |
'CLUB' | 'COUNCIL' | 'DORM') and change both SCHEDULE_LABEL and SCHEDULE_COLOR
to use Record<ScheduleCategory, string> (or extract the existing keys into a
ScheduleCategory type) so lookups by scheduleCategory are type-checked and typos
surface at compile time.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/pages/Schedule/components/DateBox.tsx (1)
44-54:⚠️ Potential issue | 🟡 MinorUsing
titleas key may cause issues if schedules have duplicate titles.If two schedules on the same day have identical titles, React will emit a warning and may not correctly reconcile the list. Consider using a unique identifier if available.
🛠️ Suggested fix (if a unique ID is available)
- visibleSchedules.map((s) => ( + visibleSchedules.map((s, index) => ( <div - key={s.title} + key={s.id ?? `${s.title}-${index}`} className="flex-1"If schedules have an
idfield, prefer that. Otherwise, combining title with index provides a stable fallback.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/Schedule/components/DateBox.tsx` around lines 44 - 54, The map over visibleSchedules in DateBox.tsx currently uses s.title as the React key which can collide; change the key in the visibleSchedules.map callback (the function that returns the div with className "flex-1" and style using SCHEDULE_COLOR[s.scheduleCategory]) to use a unique identifier if the schedule objects expose one (e.g., s.id), otherwise use a stable fallback such as `${s.title}-${index}` by taking the map index parameter to avoid duplicate keys and ensure proper reconciliation.src/pages/Schedule/components/ScheduleDetail.tsx (1)
21-28:⚠️ Potential issue | 🔴 CriticalBug: Uses current system year instead of the
yearprop.Line 22 uses
new Date().getFullYear()to construct the target date, ignoring theyearprop passed to the component. This will cause incorrect filtering when viewing schedules from a different year.🐛 Proposed fix
const dailySchedules = schedules?.schedules?.filter(({ startedAt, endedAt }) => { - const target = new Date(new Date().getFullYear(), month - 1, day); + const target = new Date(year, month - 1, day); const start = parseDateOnly(startedAt); const end = parseDateOnly(endedAt);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/Schedule/components/ScheduleDetail.tsx` around lines 21 - 28, The filter for dailySchedules incorrectly builds target using new Date().getFullYear(); update it to use the component's year prop instead (use the numeric year value passed into the component) so the target date reflects props year/month/day; specifically, in the schedules?.schedules?.filter callback that references target, replace creation of target with new Date(year, month - 1, day) (ensuring year is parsed/validated as a number if needed) so parseDateOnly(startedAt)/parseDateOnly(endedAt) comparisons are done against the correct year.
🧹 Nitpick comments (3)
src/constants/schedule.ts (1)
1-13: Consider adding explicit type annotations for better type safety.Both constants use the same keys, but
SCHEDULE_LABELis typed asRecord<string, string>, which loses type safety. Components likeDateBox.tsxdefinescheduleCategoryas a literal union type'UNIVERSITY' | 'CLUB' | 'COUNCIL' | 'DORM'. Consider extracting a shared type and usingas constfor stricter typing.♻️ Suggested improvement
+export type ScheduleCategory = 'UNIVERSITY' | 'CLUB' | 'COUNCIL' | 'DORM'; + -export const SCHEDULE_COLOR = { +export const SCHEDULE_COLOR: Record<ScheduleCategory, string> = { UNIVERSITY: '#AEDCBA', CLUB: '#FDE49B', COUNCIL: '#E9F2FA', DORM: '#B9ADEF', }; -export const SCHEDULE_LABEL: Record<string, string> = { +export const SCHEDULE_LABEL: Record<ScheduleCategory, string> = { UNIVERSITY: '학사일정', CLUB: '동아리', COUNCIL: '총동아리', DORM: '기숙사', };This allows
DateBox.tsxand other components to import and reuseScheduleCategoryinstead of duplicating the union type.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/constants/schedule.ts` around lines 1 - 13, Extract a literal union type and tighten both constant types: change SCHEDULE_COLOR and SCHEDULE_LABEL to use "as const" and export a shared type alias (e.g., export type ScheduleCategory = keyof typeof SCHEDULE_COLOR) so both objects keep exact keys and DateBox.tsx can import ScheduleCategory instead of duplicating the union; update SCHEDULE_LABEL's type from Record<string,string> to Record<ScheduleCategory,string> (or infer via typeof) to restore full type safety and reuse across components.src/pages/Schedule/components/ScheduleDetail.tsx (2)
15-19: Variable shadowing:year,month,dayshadow component props.The destructured variables inside
parseDateOnlyshadow the component's props. While currently not problematic (the function is self-contained), this can lead to subtle bugs if the function is later modified to reference outer scope.♻️ Suggested rename
const parseDateOnly = (value: string) => { const [date] = value.split(' '); - const [year, month, day] = date.split('.').map(Number); - return new Date(year, month - 1, day); + const [y, m, d] = date.split('.').map(Number); + return new Date(y, m - 1, d); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/Schedule/components/ScheduleDetail.tsx` around lines 15 - 19, The destructured names year, month, day inside parseDateOnly shadow the component props; rename those local variables (e.g., dateYear, dateMonth, dateDay or y, m, d) inside parseDateOnly and update the new Date(...) call to use the renamed locals so the function remains self-contained without shadowing the component-level props referenced elsewhere in this file; locate parseDateOnly in ScheduleDetail.tsx and change the destructure and the new Date call accordingly.
48-52: Unnecessary wrapper div.The outer
<div className="flex flex-row gap-1">wraps a single child element, making the flex and gap styles ineffective. This can be simplified.♻️ Suggested simplification
<div className="flex flex-col gap-1"> - <div className="flex flex-row gap-1"> - <div className="text-[14px] leading-4 font-bold"> - [{SCHEDULE_LABEL[scheduleCategory]}] {title} - </div> - </div> + <div className="text-[14px] leading-4 font-bold"> + [{SCHEDULE_LABEL[scheduleCategory]}] {title} + </div> <div className="text-[13px] leading-3 text-indigo-300">{formatScheduleTime({ startedAt, endedAt })}</div> </div>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/Schedule/components/ScheduleDetail.tsx` around lines 48 - 52, The outer wrapper div with className="flex flex-row gap-1" around the single child in ScheduleDetail.tsx is unnecessary; remove that wrapper and move any needed classes to the remaining element (the div rendering "[{SCHEDULE_LABEL[scheduleCategory]}] {title}") so styling is preserved, e.g., keep the text div and ensure it contains the necessary classes instead of keeping an extra flex container around the single child.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@src/pages/Schedule/components/DateBox.tsx`:
- Around line 44-54: The map over visibleSchedules in DateBox.tsx currently uses
s.title as the React key which can collide; change the key in the
visibleSchedules.map callback (the function that returns the div with className
"flex-1" and style using SCHEDULE_COLOR[s.scheduleCategory]) to use a unique
identifier if the schedule objects expose one (e.g., s.id), otherwise use a
stable fallback such as `${s.title}-${index}` by taking the map index parameter
to avoid duplicate keys and ensure proper reconciliation.
In `@src/pages/Schedule/components/ScheduleDetail.tsx`:
- Around line 21-28: The filter for dailySchedules incorrectly builds target
using new Date().getFullYear(); update it to use the component's year prop
instead (use the numeric year value passed into the component) so the target
date reflects props year/month/day; specifically, in the
schedules?.schedules?.filter callback that references target, replace creation
of target with new Date(year, month - 1, day) (ensuring year is parsed/validated
as a number if needed) so parseDateOnly(startedAt)/parseDateOnly(endedAt)
comparisons are done against the correct year.
---
Nitpick comments:
In `@src/constants/schedule.ts`:
- Around line 1-13: Extract a literal union type and tighten both constant
types: change SCHEDULE_COLOR and SCHEDULE_LABEL to use "as const" and export a
shared type alias (e.g., export type ScheduleCategory = keyof typeof
SCHEDULE_COLOR) so both objects keep exact keys and DateBox.tsx can import
ScheduleCategory instead of duplicating the union; update SCHEDULE_LABEL's type
from Record<string,string> to Record<ScheduleCategory,string> (or infer via
typeof) to restore full type safety and reuse across components.
In `@src/pages/Schedule/components/ScheduleDetail.tsx`:
- Around line 15-19: The destructured names year, month, day inside
parseDateOnly shadow the component props; rename those local variables (e.g.,
dateYear, dateMonth, dateDay or y, m, d) inside parseDateOnly and update the new
Date(...) call to use the renamed locals so the function remains self-contained
without shadowing the component-level props referenced elsewhere in this file;
locate parseDateOnly in ScheduleDetail.tsx and change the destructure and the
new Date call accordingly.
- Around line 48-52: The outer wrapper div with className="flex flex-row gap-1"
around the single child in ScheduleDetail.tsx is unnecessary; remove that
wrapper and move any needed classes to the remaining element (the div rendering
"[{SCHEDULE_LABEL[scheduleCategory]}] {title}") so styling is preserved, e.g.,
keep the text div and ensure it contains the necessary classes instead of
keeping an extra flex container around the single child.
* feat: 알림설정 구현 (#108) * chore: min-w 추가 * [chore] 코드래빗 설정 파일 추가 (#110) * chore: 코드래빗 설정 파일 추가 * chore: 불필요한 tools 설정 제거 * [feat] preMember 목록 분리 및 삭제 기능 추가 (#115) * feat: preMember 목록 분리 및 삭제 기능 추가 * chore: Pascal case * chore: 변경된 변수명 반영 * feat: 학번 숫자 필터링 추가 * [feat] 채팅 목차 알림 상태 추가 (#113) * chore: svg 추가 * feat: 채팅목록 알림 끄기 설정시 UI 추가 * feat: 목차 열릴시 애니메이션 추가 * [feat] 달력 카테고리 분류 추가 (#118) * feat: 카테고리 추가 * chore: 불필요한 코드 삭제 * [refactor] 관리자 페이지 및 마이페이지 UI 수정 및 리팩토링 (#117) * feat: 정보 카드에서 정보 페이지로 이동하도록 기능 추가 * feat: 토스트 전역상태 추가 * refactor: query 훅 분리 및 onSuccess 콜백 옵션 제거 * refactor: query 훅 사용처 수정 * refactor: 사용처 수정 2 * fix: 채팅창 스크롤 초기화 문제 수정 및 줄바꿈 기준 변경 * feat: 토글 스위치 구현 * refactor: 모집 공고 관련 목록 페이지 디자인 수정 * feat: 컴포넌트 구현 및 icon 추가 * refactor: z-index 값 수정 * refactor: API 필드 변경 사항 반영 * refactor: 모집 공고 페이지 디자인 수정 및 라우트 백 수정 * refactor: 학교 목록에 없을 시 문구 디자인 수정 * fix: lint error * fix: 타입 변경 * feat: 모집 관련 페이지 API 추가사항 반영 * refactor: 토스트 타이머 클린업 추라 * refactor: 전역토스트 사용 변경 * refactor: 관리자 클럽 조회 훅 호출 범위 줄이기 * feat: onError handler add * chore: add button type and remove fragment * [feat] 문의하기 버튼 로직 추가 (#120) * feat: API 추가 및 연결 * chore: placeholder 제거 * [fix] 채팅 스크롤 미갱신 버그 및 멤버 직위 렌더링 수정 (#122) * fix: 채팅 스크롤 미작동 수정 * fix: 한글 출력으로 수정 * feat: 첫 글자 보여주도록 수정 (#124) * hotfix: 동아리 소개 줄바꿈 적용 및 한 줄 소개 글자수 제한 상향 * chore: 리뷰 반영 * fix: disabled 조건 변경 * 126 fix 배포 전 qa 사항 반영 (#127) * fix: 가입 버튼 문구 수정 * fix: 검색창 placeholder 수정 * fix: 불필요해진 UI 비활성화 * fix: 모집공고 없을 때 빈 화면 처리 * fix: 무의미한 회비페이지 수정 * feat: 토글 시 자동 페이지 이동 추가 * fix: 페이지 이동 조건 수정 --------- Co-authored-by: 김혜준 <114041848+hyejun0228@users.noreply.github.com> Co-authored-by: hyejun <hyejunkkim228@gmail.com>
* develop → main 배포 (#125) * feat: 알림설정 구현 (#108) * chore: min-w 추가 * [chore] 코드래빗 설정 파일 추가 (#110) * chore: 코드래빗 설정 파일 추가 * chore: 불필요한 tools 설정 제거 * [feat] preMember 목록 분리 및 삭제 기능 추가 (#115) * feat: preMember 목록 분리 및 삭제 기능 추가 * chore: Pascal case * chore: 변경된 변수명 반영 * feat: 학번 숫자 필터링 추가 * [feat] 채팅 목차 알림 상태 추가 (#113) * chore: svg 추가 * feat: 채팅목록 알림 끄기 설정시 UI 추가 * feat: 목차 열릴시 애니메이션 추가 * [feat] 달력 카테고리 분류 추가 (#118) * feat: 카테고리 추가 * chore: 불필요한 코드 삭제 * [refactor] 관리자 페이지 및 마이페이지 UI 수정 및 리팩토링 (#117) * feat: 정보 카드에서 정보 페이지로 이동하도록 기능 추가 * feat: 토스트 전역상태 추가 * refactor: query 훅 분리 및 onSuccess 콜백 옵션 제거 * refactor: query 훅 사용처 수정 * refactor: 사용처 수정 2 * fix: 채팅창 스크롤 초기화 문제 수정 및 줄바꿈 기준 변경 * feat: 토글 스위치 구현 * refactor: 모집 공고 관련 목록 페이지 디자인 수정 * feat: 컴포넌트 구현 및 icon 추가 * refactor: z-index 값 수정 * refactor: API 필드 변경 사항 반영 * refactor: 모집 공고 페이지 디자인 수정 및 라우트 백 수정 * refactor: 학교 목록에 없을 시 문구 디자인 수정 * fix: lint error * fix: 타입 변경 * feat: 모집 관련 페이지 API 추가사항 반영 * refactor: 토스트 타이머 클린업 추라 * refactor: 전역토스트 사용 변경 * refactor: 관리자 클럽 조회 훅 호출 범위 줄이기 * feat: onError handler add * chore: add button type and remove fragment * [feat] 문의하기 버튼 로직 추가 (#120) * feat: API 추가 및 연결 * chore: placeholder 제거 * [fix] 채팅 스크롤 미갱신 버그 및 멤버 직위 렌더링 수정 (#122) * fix: 채팅 스크롤 미작동 수정 * fix: 한글 출력으로 수정 * feat: 첫 글자 보여주도록 수정 (#124) * hotfix: 동아리 소개 줄바꿈 적용 및 한 줄 소개 글자수 제한 상향 * chore: 리뷰 반영 * fix: disabled 조건 변경 * 126 fix 배포 전 qa 사항 반영 (#127) * fix: 가입 버튼 문구 수정 * fix: 검색창 placeholder 수정 * fix: 불필요해진 UI 비활성화 * fix: 모집공고 없을 때 빈 화면 처리 * fix: 무의미한 회비페이지 수정 * feat: 토글 시 자동 페이지 이동 추가 * fix: 페이지 이동 조건 수정 --------- Co-authored-by: 김혜준 <114041848+hyejun0228@users.noreply.github.com> Co-authored-by: hyejun <hyejunkkim228@gmail.com> * develop -> main 배포 (#132) * chore: 타입 변경 반영 * [feat] 모집 공고에 시간 추가 및 지원서 정렬 추가 (#131) * feat: 모집 공고에 시작, 종료 시간 추가 * feat: 지원자 목록 정렬 추가 및 시간 표시 * feat: 채팅, 모집 공고 링크 파싱 기능 추가 * feat: 인스타그램 파싱 추가 * fix: prettier error * refactor: 유틸 분리 및 타입 변경 * chore: 타입 변경 반영 * chore: 동일 스타일 통합 및 entity 확장 사용 * chore:ios 토큰 테스트를 위한 로직 추가 * Revert "chore:ios 토큰 테스트를 위한 로직 추가" This reverts commit 98570fc. * hotfix: 모집 공고 textarea 길이 자동 재계산 추가 * feat: 페이지네이션 추가 * feat: 수정 * feat: 페이지네이션 수정 * feat: 디자인 수정 * feat: 로직 수정 * fix: key 수정 * develop-> main (#135) * chore: 타입 변경 반영 * [feat] 모집 공고에 시간 추가 및 지원서 정렬 추가 (#131) * feat: 모집 공고에 시작, 종료 시간 추가 * feat: 지원자 목록 정렬 추가 및 시간 표시 * feat: 채팅, 모집 공고 링크 파싱 기능 추가 * feat: 인스타그램 파싱 추가 * fix: prettier error * refactor: 유틸 분리 및 타입 변경 * chore: 타입 변경 반영 * chore: 동일 스타일 통합 및 entity 확장 사용 * chore:ios 토큰 테스트를 위한 로직 추가 * Revert "chore:ios 토큰 테스트를 위한 로직 추가" This reverts commit 98570fc. * hotfix: 모집 공고 textarea 길이 자동 재계산 추가 * Reapply "chore:ios 토큰 테스트를 위한 로직 추가" This reverts commit 3a56f4a. * chore: ios토큰 * feat: 가이드 페이지 이미지 변경 * chore: 푸시알림 로직 임시 변경 * refactor: 푸시 알림 토큰 로직 브릿지 방식으로 수정 (#134) * refactor: 푸시 알림 토큰 로직 브릿지 방식으로 수정 * fix: try catch 적용 * feat: 페이지네이션 추가 * feat: 수정 * feat: 페이지네이션 수정 * feat: 디자인 수정 * feat: 로직 수정 * fix: key 수정 * chore: 스테이지 용 임시 UI 제거 --------- Co-authored-by: hyejun <hyejunkkim228@gmail.com> * [feat] sentry 모니터링 추가 (#141) (#142) * chore: sentry 의존성 추가 * feat: sentry 세팅 * chore: 워크플로우 수정 및 vite 세팅 * chore: 임시 추가 * refactor: 색상 토큰 파일 분리 * refactor: 타이포그래피 스타일 파일 분리 * refactor: 피그마 타이포그래피 네이밍으로 클래스 정렬 * fix: 리뷰 코멘트 기반 접근성 및 토큰 정리 --------- Co-authored-by: 김혜준 <114041848+hyejun0228@users.noreply.github.com> Co-authored-by: hyejun <hyejunkkim228@gmail.com>
Summary by CodeRabbit