♻️ [Refactor] 캘린더 화면 구조 및 반응형 UI 개선 (#97)#98
Conversation
|
Warning Review limit reached
Next review available in: 45 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthrough캘린더의 자녀 데이터 로딩과 주간·월간 스크롤 구조를 재구성하고 상단 이동 버튼을 추가했습니다. 자녀 필터를 공통 컴포넌트로 통합했으며, 캘린더·문서·프로필·알림 화면의 텍스트 및 반응형 레이아웃을 조정했습니다. Changes캘린더 스크롤 및 렌더링
문서 필터 통합
반응형 화면 스타일
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant CalendarScreen
participant fetchChildrenApi
participant useChildrenStore
participant CalendarScrollView
CalendarScreen->>fetchChildrenApi: 자녀 데이터 요청
fetchChildrenApi-->>CalendarScreen: 자녀 데이터 반환
CalendarScreen->>useChildrenStore: setChildren 호출
CalendarScreen->>CalendarScrollView: 선택 변경 시 scrollTo
CalendarScrollView-->>CalendarScreen: 스크롤 위치 전달
CalendarScreen->>CalendarScrollView: 임계값 초과 시 상단 버튼 표시
Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
app/(tabs)/calendar.tsx (2)
116-121: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win렌더링 중 ref 값 변경(no-ref-current-in-render).
weekOffsetRef.current = weekOffset;가 컴포넌트 렌더 본문에서 조건 없이 직접 실행됩니다. React Doctor가 지적한 대로 렌더는 순수해야 하며, React가 커밋 없이 렌더를 재실행/폐기하는 경로(Concurrent 기능, React 19.2의<Activity>등)에서 예기치 않은 부작용의 원인이 될 수 있습니다.이 "최신 값을 ref로 유지" 패턴은 React 19.2에 새로 추가된
useEffectEvent()로 대체하는 것이 권장됩니다.useEffect로 옮기면 한 렌더 지연이 생기지만useEffectEvent는 그 지연 없이 항상 최신 값을 안전하게 참조할 수 있습니다.♻️ 제안: useEffectEvent로 대체
- const weekOffsetRef = useRef(weekOffset); - const shouldAutoScrollRef = useRef(weekOffset === 0); - weekOffsetRef.current = weekOffset; + const shouldAutoScrollRef = useRef(weekOffset === 0); + const getWeekOffset = useEffectEvent(() => weekOffset);그리고
onContentSizeChange콜백 내부의weekOffsetRef.current를getWeekOffset()호출로 교체합니다.🤖 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 `@app/`(tabs)/calendar.tsx around lines 116 - 121, Replace the render-time assignment to weekOffsetRef.current in the calendar component with React 19.2’s useEffectEvent-based latest-value accessor. Define the accessor near weekOffsetRef and update the onContentSizeChange callback to call getWeekOffset() instead of reading weekOffsetRef.current, while preserving the existing auto-scroll behavior.Source: Linters/SAST tools
95-109: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win자녀 목록 fetch에 다른 호출과 동일한 race-guard 패턴이 빠져 있습니다.
주간/월간/일간/학사일정 fetch는 모두
reqIdref로 오래된 응답이 최신 상태를 덮어쓰지 않도록 보호하지만,fetchChildrenApi().then(setStoreChildren)는 이 보호가 없습니다. 포커스 이벤트가 짧은 간격으로 연속 발생하면 응답 순서가 뒤바뀌어 오래된 자녀 목록이 최신 목록을 덮어쓸 수 있습니다.🛡️ 제안: 다른 fetch와 동일한 reqId 가드 적용
+ const childrenReqIdRef = useRef(0); + useFocusEffect( useCallback(() => { if (!hasFocusedOnceRef.current) { hasFocusedOnceRef.current = true; - fetchChildrenApi() - .then(setStoreChildren) - .catch(() => {}); + childrenReqIdRef.current += 1; + const reqId = childrenReqIdRef.current; + fetchChildrenApi() + .then((data) => { if (reqId === childrenReqIdRef.current) setStoreChildren(data); }) + .catch(() => {}); return; } - fetchChildrenApi() - .then(setStoreChildren) - .catch(() => {}); + childrenReqIdRef.current += 1; + const reqId = childrenReqIdRef.current; + fetchChildrenApi() + .then((data) => { if (reqId === childrenReqIdRef.current) setStoreChildren(data); }) + .catch(() => {}); setFocusKey((k) => k + 1); }, [setStoreChildren]) );🤖 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 `@app/`(tabs)/calendar.tsx around lines 95 - 109, Apply the existing reqId race-guard pattern to the child-list fetch flow in useFocusEffect: track each fetchChildrenApi request with a request-id ref and call setStoreChildren only when its response matches the latest request. Preserve the current focus handling and dependency structure while preventing stale responses from updating the store.
🤖 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 `@src/components/calendar/MonthCalendar.tsx`:
- Around line 35-40: Update the dayNames construction so each weekday header
uses a stable, domain-unique key derived from its fixed date or weekday identity
rather than the array index i. Adjust the corresponding day.key usage in the
header rendering while preserving the existing labels and ordering.
---
Nitpick comments:
In `@app/`(tabs)/calendar.tsx:
- Around line 116-121: Replace the render-time assignment to
weekOffsetRef.current in the calendar component with React 19.2’s
useEffectEvent-based latest-value accessor. Define the accessor near
weekOffsetRef and update the onContentSizeChange callback to call
getWeekOffset() instead of reading weekOffsetRef.current, while preserving the
existing auto-scroll behavior.
- Around line 95-109: Apply the existing reqId race-guard pattern to the
child-list fetch flow in useFocusEffect: track each fetchChildrenApi request
with a request-id ref and call setStoreChildren only when its response matches
the latest request. Preserve the current focus handling and dependency structure
while preventing stale responses from updating the store.
🪄 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: CHILL
Plan: Pro Plus
Run ID: 1a5250d1-dce0-47ac-bafb-baa6e239fb1f
📒 Files selected for processing (13)
app/(tabs)/calendar.tsxapp/(tabs)/document.tsxsrc/components/calendar/MonthCalendar.tsxsrc/components/calendar/WeekCalendar.tsxsrc/components/common/ChildFilterBar.tsxsrc/components/common/SelectionCard.tsxsrc/styles/calendar/calendar.tssrc/styles/notifications/notifications.tssrc/styles/profile/profile.tssrc/styles/profile/profileEdit.tssrc/styles/profile/profileNotification.tssrc/styles/register/language.tssrc/styles/register/notification.ts
📜 Review details
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-06-08T16:56:51.296Z
Learnt from: chae1125
Repo: GACHI-Project/GACHI-FE PR: 83
File: src/components/home/MealTimetableWidget.tsx:108-109
Timestamp: 2026-06-08T16:56:51.296Z
Learning: In the GACHI-FE React Native/Expo codebase, the `react/no-array-index-key` ESLint rule is enforced—do not use an array index (e.g., `key={i}`) as a React `key`. Use a stable, domain-unique identifier instead (e.g., an entity id, or a field guaranteed unique by the domain). If uniqueness depends on additional context, compose a key from multiple stable attributes (e.g., `${date}-${name}` for items repeated across multiple days).
Applied to files:
src/components/common/ChildFilterBar.tsxsrc/components/common/SelectionCard.tsxsrc/components/calendar/MonthCalendar.tsxapp/(tabs)/document.tsxapp/(tabs)/calendar.tsxsrc/components/calendar/WeekCalendar.tsx
🪛 React Doctor (0.7.6)
app/(tabs)/calendar.tsx
[error] 119-119: This ref is mutated during render. React can replay or discard render work, so the mutation can leak from UI that never commits.
Move ref writes into an event handler or effect. Render must stay pure because React can replay or discard it. The predictable null-guarded lazy initialization pattern remains supported.
(no-ref-current-in-render)
🔇 Additional comments (15)
src/components/calendar/MonthCalendar.tsx (1)
104-105: LGTM!Also applies to: 138-139, 175-176
src/components/calendar/WeekCalendar.tsx (1)
21-21: LGTM!Also applies to: 65-75, 107-108
src/components/common/ChildFilterBar.tsx (1)
39-39: LGTM!Also applies to: 54-57, 72-73, 85-87
app/(tabs)/document.tsx (1)
2-2: LGTM!Also applies to: 14-14, 148-152, 212-214
src/components/common/SelectionCard.tsx (1)
38-38: LGTM!Also applies to: 70-70, 95-95, 110-110, 124-124
src/styles/notifications/notifications.ts (1)
15-16: LGTM!Also applies to: 57-65, 74-74, 91-94
src/styles/profile/profile.ts (1)
35-35: LGTM!Also applies to: 53-54, 73-73, 84-84, 102-113, 130-142
src/styles/profile/profileEdit.ts (1)
51-53: LGTM!src/styles/profile/profileNotification.ts (2)
36-37: LGTM!Also applies to: 154-160
129-140: 🎯 Functional Correctness알림 화면 제목과 뱃지를 함께 흐르는 flex 제어는 실제 렌더가 확인되지 않았습니다.
flexWrap만 추가해 제목 텍스트가 줄바꿈되더라도, 제목을 감싸는 row가 실제 flex item으로 사용되지 않으면 이 스타일이 적용되지 않습니다. 렌더 JSX에서itemTitleRow/cardTitleRow가 뱃지와 같은 flex row 아이템인지 먼저 확인한 뒤, 필요하면itemTitle/cardTitle/row에flex: 1 minWidth: 0및badge flexShrink: 0을 적용하세요.src/styles/register/language.ts (1)
47-47: LGTM!src/styles/register/notification.ts (1)
51-53: LGTM!Also applies to: 90-94, 107-112, 129-136
app/(tabs)/calendar.tsx (2)
452-467: 🎯 Functional Correctness
todayGroupY가 갱신되지 않을 수 있는 경로 확인 필요.
todayGroupY.current는 오늘 날짜 그룹이 렌더링될 때만onLayout으로 갱신됩니다(라인 490-494). 만약 특정 시점에 오늘 일정이 없어weekDisplayGroups에 "오늘" 그룹이 아예 포함되지 않으면, 이전에 설정된todayGroupY값이 그대로 남아있게 됩니다. 이후 주(0주차)로 복귀했을 때shouldAutoScrollRef가 다시 true가 되면서, 이 오래된 오프셋으로 스크롤을 시도할 가능성이 있는지 확인이 필요합니다.발생 빈도는 낮아 보이지만(동일 세션 내에서 오늘 일정 유무가 바뀌는 경우), 방어적으로
weekDisplayGroups가 바뀔 때 오늘 그룹이 없으면todayGroupY.current를 초기화하는 편이 안전합니다.
479-482: 🎯 Functional Correctness문제 없음.
styles.loadingContainer참조가 남아 있지 않습니다.src/styles/calendar/calendar.ts (1)
30-51: LGTM!Also applies to: 101-122, 182-182
📌 작업 내용
document.tsx자녀 필터를 공용ChildFilterBar컴포넌트로 통합📷 스크린 샷
🔗 관련 이슈
Closes #97
Summary by CodeRabbit
새로운 기능
개선 사항