Skip to content

[Refactor/#450] 타임라인 페이지 훅/UI 분리 - #451

Merged
jjjsun merged 7 commits into
developfrom
refactor/#450
Aug 11, 2026
Merged

[Refactor/#450] 타임라인 페이지 훅/UI 분리#451
jjjsun merged 7 commits into
developfrom
refactor/#450

Conversation

@jjjsun

@jjjsun jjjsun commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

🚨 관련 이슈

Closed #450

✨ 변경사항

  • 🐞 BugFix Something isn't working
  • 💻 CrossBrowsing Browser compatibility
  • 🌏 Deploy Deploy
  • 🎨 Design Markup & styling
  • 📃 Docs Documentation writing and editing (README.md, etc.)
  • ✨ Feature Feature
  • 🔨 Refactor Code refactoring
  • ⚙️ Setting Development environment setup
  • ✅ Test Test related (storybook, jest, etc.)

✏️ 작업 내용

  • Timeline.tsx에서 기간/패널/요약 폴링/수정 모달 로직을 커스텀 훅으로 분리
  • 툴바, 캔버스, 삭제 모달 UI를 컴포넌트로 분리
  • 동작 변경은 없고, 코드 리팩토링만 진행했습니다!

😅 미완성 작업

N/A

📢 논의 사항 및 참고 사항

  • Timeline.tsx 기존 약 450줄에서 대략 260줄로 코드 가독성 높였습니다

💬 리뷰어 가이드 (P-Rules)
P1: 필수 반영 (Critical) - 버그 가능성, 컨벤션 위반. 해결 전 머지 불가.
P2: 적극 권장 (Recommended) - 더 나은 대안 제시. 가급적 반영 권장.
P3: 제안 (Suggestion) - 아이디어 공유. 반영 여부는 드라이버 자율.
P4: 단순 확인/칭찬 (Nit) - 사소한 오타, 칭찬 등 피드백.

Summary by CodeRabbit

  • 새 기능

    • 타임라인을 주간·월간 보기로 전환하고 이전·다음 기간 및 오늘로 이동할 수 있습니다.
    • 상태 필터, 정렬, 타임라인 생성 기능을 제공합니다.
    • 타임라인 바 선택 시 상세 요약 패널과 편집 기능을 이용할 수 있습니다.
    • 타임라인 삭제 전 확인 모달과 진행 상태를 제공합니다.
    • 요약 생성 상태를 자동으로 갱신하고, 완료 또는 오류 시 안내합니다.
  • 사용성 개선

    • 표시할 타임라인이 없을 때 안내 메시지를 표시합니다.
    • 타임라인 화면을 툴바와 캔버스로 구성해 탐색과 조작을 개선했습니다.

@jjjsun
jjjsun requested review from Seojegyeong and YermIm August 11, 2026 10:31
@jjjsun jjjsun self-assigned this Aug 11, 2026
@jjjsun jjjsun added the 🔨 Refactor 코드 리팩토링 label Aug 11, 2026
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jjjsun, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 42 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ce57f95e-6624-40eb-b151-80f16bba184f

📥 Commits

Reviewing files that changed from the base of the PR and between 2617ef5 and a4870d8.

📒 Files selected for processing (2)
  • src/components/timeline/TimelineDeleteModal.tsx
  • src/hooks/timeline/useTimelineSummaryPolling.ts
📝 Walkthrough

Walkthrough

타임라인 페이지의 기간, 패널, 편집 모달, 요약 폴링 상태를 전용 훅으로 분리했습니다. 툴바, 캔버스, 삭제 모달을 새 컴포넌트로 추가하고 Timeline에서 이를 조합합니다.

Changes

타임라인 페이지 리팩터링

Layer / File(s) Summary
기간 상태와 스크롤 동기화
src/hooks/timeline/useTimelinePeriod.ts, src/pages/dashboard/timeline/Timeline.tsx
주간·월간 보기, 기간 이동, 오늘 이동, 기간 라벨과 스크롤 위치 처리를 분리했습니다.
패널·편집·요약 상태 관리
src/hooks/timeline/useTimelinePanel.ts, src/hooks/timeline/useTimelineEditModal.ts, src/hooks/timeline/useTimelineSummaryPolling.ts
바 선택 패널, 편집 초기값, 요약 요청·폴링·시간 초과 상태를 각 훅에서 관리합니다.
타임라인 UI 컴포넌트 추출
src/components/timeline/TimelineToolbar.tsx, src/components/timeline/TimelineCanvas.tsx, src/components/timeline/TimelineDeleteModal.tsx
툴바, 기간·필터·정렬 제어, 타임라인 캔버스, 선택·수정·삭제 이벤트, 삭제 확인 UI를 컴포넌트로 분리했습니다.
페이지 상태와 UI 연결
src/pages/dashboard/timeline/Timeline.tsx
Timeline이 새 훅과 컴포넌트를 사용하도록 변경하고 기존 인라인 UI와 수동 상태 관리를 제거했습니다.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested reviewers: yermim, seojegyeong

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed [450]에 명시된 네 개의 훅과 세 개의 UI 컴포넌트 분리 목표를 모두 반영했습니다.
Out of Scope Changes check ✅ Passed 변경사항이 타임라인 상태 및 UI 로직 분리라는 [450]의 범위에 포함됩니다.
Title check ✅ Passed 제목이 타임라인 페이지의 훅 및 UI 분리 리팩토링이라는 주요 변경 사항을 명확하고 간결하게 설명합니다.
Description check ✅ Passed 관련 이슈, 변경 유형, 작업 내용, 미완성 작업, 참고 사항을 모두 작성해 템플릿 요구 사항을 충족합니다.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/#450

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.

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown

📚 Storybook 배포 완료

항목 링크
📖 Storybook https://69a147b60a56365d9e2185ef-ksxxhjpzqr.chromatic.com/
🔍 Chromatic https://www.chromatic.com/build?appId=69a147b60a56365d9e2185ef&number=626

@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: 2

🧹 Nitpick comments (4)
src/hooks/timeline/useTimelinePeriod.ts (1)

5-8: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

인터페이스 이름 오타를 고쳐주세요.

IUserTimelinePeriodParamsIUseTimelinePeriodParams의 오타로 보입니다. 훅 이름과 파라미터 타입 이름을 일치시키면 검색과 유지보수가 쉬워집니다.

♻️ 제안 수정
-interface IUserTimelinePeriodParams {
+interface IUseTimelinePeriodParams {
   scrollRef: RefObject<HTMLDivElement | null>;
   hasNoTimelines: boolean;
 }
 
 export function useTimelinePeriod({
   scrollRef,
   hasNoTimelines,
-}: IUserTimelinePeriodParams) {
+}: IUseTimelinePeriodParams) {
🤖 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/hooks/timeline/useTimelinePeriod.ts` around lines 5 - 8, Rename the
interface IUserTimelinePeriodParams to IUseTimelinePeriodParams and update all
references to this parameter type so it matches the useTimelinePeriod hook
naming.
src/hooks/timeline/useTimelinePanel.ts (1)

17-26: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

panelData는 파생 값이므로 useMemo로 계산하는 방식을 검토해 주세요.

현재는 detailuseState + useEffect로 복제합니다. 이 패턴은 렌더가 한 번 더 발생하고, 상태 동기화 버그가 생기기 쉽습니다. useTimelineDetail의 쿼리 키에 timelineId가 포함되므로, 선택한 바가 바뀌면 detail은 다시 undefined가 됩니다. 따라서 handleBarClicksetPanelData(null) 없이도 이전 패널 데이터가 남지 않습니다.

♻️ 제안 리팩터
-import { useEffect, useState } from "react";
+import { useMemo, useState } from "react";
@@
   const [isPanelOpen, setIsPanelOpen] = useState(false);
   const [selectedBarId, setSelectedBarId] = useState<number | null>(null);
-  const [panelData, setPanelData] = useState<ITimelineSummaryPanelData | null>(
-    null,
-  );
 
   const { data: detail } = useTimelineDetail(selectedBarId);
 
-  useEffect(() => {
-    if (!detail) return;
-    setPanelData(buildTimelineSummaryPanel(detail));
-  }, [detail]);
+  const panelData: ITimelineSummaryPanelData | null = useMemo(
+    () => (detail ? buildTimelineSummaryPanel(detail) : null),
+    [detail],
+  );

handleBarClick에서 setPanelData(null) 호출도 함께 제거하면 됩니다.

경로 지침의 "Hook 사용: useEffect 의존성 배열 및 불필요한 사용 검토"에 따른 제안입니다.

🤖 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/hooks/timeline/useTimelinePanel.ts` around lines 17 - 26, Replace the
derived panelData useState/useEffect synchronization with a useMemo that
computes buildTimelineSummaryPanel(detail) when detail exists and otherwise
returns null. Update the component to use the memoized value, and remove the
handleBarClick setPanelData(null) call since detail reset from useTimelineDetail
now clears the derived data.

Source: Path instructions

src/components/timeline/TimelineToolbar.tsx (1)

7-13: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

새로 추가한 파일들이 상대 경로 임포트를 사용합니다. 코딩 가이드라인은 모든 임포트에 @/ alias를 요구합니다. 상대 경로는 파일 이동 시 깨지기 쉽고, 기존 코드와 스타일이 어긋납니다.

  • src/components/timeline/TimelineToolbar.tsx#L7-L13: ./TimelineFilterSortMenus, ./TimelinePeriodSelector, ./TimelineStatusLegend, ../common/button/Button@/components/... 경로로 바꾸세요.
  • src/components/timeline/TimelineCanvas.tsx#L9-L11: ./TimelineAxis, ./TimelineBar, ./TimelineGrid@/components/timeline/... 경로로 바꾸세요.
  • src/components/timeline/TimelineDeleteModal.tsx#L1-L2: ../common/modal/Modal, ../common/modal/ModalContent@/components/common/modal/... 경로로 바꾸세요.
  • src/hooks/timeline/useTimelinePanel.ts#L8: ./useTimelineDetail@/hooks/timeline/useTimelineDetail로 바꾸세요.
  • src/hooks/timeline/useTimelineEditModal.ts#L4: ./useTimelineDetail@/hooks/timeline/useTimelineDetail로 바꾸세요.
  • src/hooks/timeline/useTimelineSummaryPolling.ts#L4-L5: ./useRequestTimelineSummary, ./useTimelineDetail@/hooks/timeline/... 경로로 바꾸세요.

코딩 가이드라인의 "Use @/ alias for all imports"에 따른 제안입니다.

🤖 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/timeline/TimelineToolbar.tsx` around lines 7 - 13, Replace all
listed relative imports with the configured `@/` aliases: in
src/components/timeline/TimelineToolbar.tsx lines 7-13, use `@/components/`...
paths for TimelineFilterSortMenus, TimelinePeriodSelector, TimelineStatusLegend,
and Button; in src/components/timeline/TimelineCanvas.tsx lines 9-11, use
`@/components/timeline/`... for TimelineAxis, TimelineBar, and TimelineGrid; in
src/components/timeline/TimelineDeleteModal.tsx lines 1-2, use
`@/components/common/modal/`...; in src/hooks/timeline/useTimelinePanel.ts line 8
and useTimelineEditModal.ts line 4, use `@/hooks/timeline/useTimelineDetail`; and
in src/hooks/timeline/useTimelineSummaryPolling.ts lines 4-5, use
`@/hooks/timeline/`... for both imports.

Source: Coding guidelines

src/hooks/timeline/useTimelineEditModal.ts (1)

36-39: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

로딩 토스트에 고정 ID를 사용하고 로딩 종료 시 닫아 주세요.

toast.loading(message, { id })toast.dismiss(id)를 사용하면 중복 토스트와 잔류 토스트를 방지할 수 있습니다. isEditDetailLoadingfalse가 되거나 editTimelineIdnull이면 고정 ID의 토스트를 닫고, 컴포넌트가 해제될 때도 정리해 주세요.

🤖 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/hooks/timeline/useTimelineEditModal.ts` around lines 36 - 39, Update the
loading toast effect in useTimelineEditModal to use a fixed toast ID with
toast.loading, dismiss that ID when isEditDetailLoading becomes false or
editTimelineId is null, and also dismiss it during effect cleanup on unmount to
prevent duplicate or lingering toasts.
🤖 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/timeline/TimelineDeleteModal.tsx`:
- Around line 13-18: Assign a descriptive function name to the default-exported
component in TimelineDeleteModal, such as TimelineDeleteModal, while preserving
its existing props and behavior. Match the named default export pattern used by
TimelineToolbar and TimelineCanvas.

In `@src/hooks/timeline/useTimelineSummaryPolling.ts`:
- Around line 10-21: Reset summary polling state whenever selectedBarId changes,
including becoming null, by adding the effect in useTimelineSummaryPolling that
clears isAwaitingSummary and summaryPollStartedAt; this is the preferred
root-cause fix. In src/hooks/timeline/useTimelineSummaryPolling.ts lines 10-21,
update the hook accordingly. In src/pages/dashboard/timeline/Timeline.tsx lines
99-117, handlePanelClose requires no direct change because the hook-level reset
covers panel closing and other selection changes.

---

Nitpick comments:
In `@src/components/timeline/TimelineToolbar.tsx`:
- Around line 7-13: Replace all listed relative imports with the configured `@/`
aliases: in src/components/timeline/TimelineToolbar.tsx lines 7-13, use
`@/components/`... paths for TimelineFilterSortMenus, TimelinePeriodSelector,
TimelineStatusLegend, and Button; in src/components/timeline/TimelineCanvas.tsx
lines 9-11, use `@/components/timeline/`... for TimelineAxis, TimelineBar, and
TimelineGrid; in src/components/timeline/TimelineDeleteModal.tsx lines 1-2, use
`@/components/common/modal/`...; in src/hooks/timeline/useTimelinePanel.ts line 8
and useTimelineEditModal.ts line 4, use `@/hooks/timeline/useTimelineDetail`; and
in src/hooks/timeline/useTimelineSummaryPolling.ts lines 4-5, use
`@/hooks/timeline/`... for both imports.

In `@src/hooks/timeline/useTimelineEditModal.ts`:
- Around line 36-39: Update the loading toast effect in useTimelineEditModal to
use a fixed toast ID with toast.loading, dismiss that ID when
isEditDetailLoading becomes false or editTimelineId is null, and also dismiss it
during effect cleanup on unmount to prevent duplicate or lingering toasts.

In `@src/hooks/timeline/useTimelinePanel.ts`:
- Around line 17-26: Replace the derived panelData useState/useEffect
synchronization with a useMemo that computes buildTimelineSummaryPanel(detail)
when detail exists and otherwise returns null. Update the component to use the
memoized value, and remove the handleBarClick setPanelData(null) call since
detail reset from useTimelineDetail now clears the derived data.

In `@src/hooks/timeline/useTimelinePeriod.ts`:
- Around line 5-8: Rename the interface IUserTimelinePeriodParams to
IUseTimelinePeriodParams and update all references to this parameter type so it
matches the useTimelinePeriod hook naming.
🪄 Autofix

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: 0bc33294-43b4-4669-a50d-2da33c540ff3

📥 Commits

Reviewing files that changed from the base of the PR and between 576b539 and 2617ef5.

📒 Files selected for processing (8)
  • src/components/timeline/TimelineCanvas.tsx
  • src/components/timeline/TimelineDeleteModal.tsx
  • src/components/timeline/TimelineToolbar.tsx
  • src/hooks/timeline/useTimelineEditModal.ts
  • src/hooks/timeline/useTimelinePanel.ts
  • src/hooks/timeline/useTimelinePeriod.ts
  • src/hooks/timeline/useTimelineSummaryPolling.ts
  • src/pages/dashboard/timeline/Timeline.tsx

Comment thread src/components/timeline/TimelineDeleteModal.tsx Outdated
Comment thread src/hooks/timeline/useTimelineSummaryPolling.ts
@jjjsun
jjjsun merged commit 48945a6 into develop Aug 11, 2026
3 checks passed
@jjjsun
jjjsun deleted the refactor/#450 branch August 11, 2026 18:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔨 Refactor 코드 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

♻️ [Refactor] 타임라인 페이지 상태와 UI 분리

2 participants