Skip to content

[Refactor/#104] 통합 대시보드 렌더링 성능 최적화 및 태블릿 UX 개선 - #105

Merged
Seojegyeong merged 13 commits into
developfrom
refactor/#104
Mar 18, 2026
Merged

[Refactor/#104] 통합 대시보드 렌더링 성능 최적화 및 태블릿 UX 개선#105
Seojegyeong merged 13 commits into
developfrom
refactor/#104

Conversation

@Seojegyeong

@Seojegyeong Seojegyeong commented Mar 18, 2026

Copy link
Copy Markdown
Collaborator

🚨 관련 이슈

#104

✨ 변경사항

  • 🐞 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.)

✏️ 작업 내용

  1. 성능 최적화(렌더링)
  • React.memo 적용
  • OverviewAiReportPanel lazy load 적용
  • 날짜 계산 useMemo 적용
  1. 성능 최적화(CSS/애니메이션)
  • transition-all은 브라우저가 모든 CSS 속성을 매 프레임 감시해서 불필요한 레이아웃/페인트 유발. 따라서 transition-all 제거하고 실제 변하는 속성만 명시하도록 수정
  • AI 패널 요약 버튼 shimmer 애니메이션을 hover 시에만 재생하도록 수정
  1. 차트 개선
  • 이상 징후 마커 ripple 애니메이션 적용
  1. 태블릿(iPad) UX
  • 데스크톱: 우측 슬라이드인 유지
  • 태블릿: bottom sheet 형태로 전환
  • 태블릿의 경우 드래그 핸들 추가하여 스와이프 해 닫을 수 있도록 수정

😅 미완성 작업

N/A

📢 논의 사항 및 참고 사항

N/A

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

Summary by CodeRabbit

개선 사항

  • 새로운 기능

    • 태블릿에서 드로어를 손가락으로 스와이프해 닫기 지원
    • AI 리포트 패널 레이지 로딩 도입
  • 성능 개선

    • 여러 UI 컴포넌트 렌더링 최적화로 반응성 향상
    • 차트 로딩·렌더링 최적화 및 툴팁 표시 개선
  • 시각/사용성 개선

    • 카드·통계 카드·플랫폼 표 등 호버·전환 효과 미세 조정
    • 대시보드 이상치 툴팁 및 포커스 인터랙션 개선

@Seojegyeong
Seojegyeong requested review from YermIm and jjjsun March 18, 2026 10:16
@Seojegyeong Seojegyeong self-assigned this Mar 18, 2026
@Seojegyeong Seojegyeong added ✨ Feature 기능 개발 🔨 Refactor 코드 리팩토링 labels Mar 18, 2026
@Seojegyeong Seojegyeong linked an issue Mar 18, 2026 that may be closed by this pull request
6 tasks
@coderabbitai

coderabbitai Bot commented Mar 18, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

여러 UI 컴포넌트에 React.memo를 적용해 선언 형태를 변경하고, Drawer에 태블릿용 터치 기반 swipe-to-close 제스처를 추가했으며, 차트 컴포넌트들에 lazy 로딩·Suspense와 리팩토링(성능/상태 관리 개선)을 도입했습니다.

Changes

Cohort / File(s) 요약
메모이제이션 적용
src/components/common/PageHeader.tsx, src/components/common/card/Card.tsx, src/components/common/card/StatCard.tsx, src/components/common/chart/ChartLegend.tsx, src/components/dashboard/charts/BudgetGaugeChart.tsx, src/components/dashboard/platform/PlatformRoasTable.tsx
여러 컴포넌트를 React.memo로 래핑하고 default export 패턴을 함수 선언 → memo화된 const + export default 형태로 변경. public props 타입은 유지됨.
Drawer 터치 제스처
src/components/common/drawer/Drawer.tsx
태블릿 전용 swipe-to-close 추가: panelRef, touchStartY, isDragging 등 useRef/터치 핸들러 도입, 패널 translate 애니메이션 및 태블릿 드래그 핸들 UI 추가.
TrafficChart 리팩토링
src/components/dashboard/charts/TrafficChart.tsx, src/components/dashboard/charts/trafficChart.config.ts, src/components/dashboard/charts/useAnomalyMarkerPos.ts
차트에 lazy 로드 및 Suspense 적용, tooltip/AnomalyBubble 재구성, 차트 config(애니메이션/곡선/채움) 변경, ResizeObserver → 디바운스 업데이트 등 리팩터링 및 성능 조정.
BudgetGaugeChart 최적화
src/components/dashboard/charts/BudgetGaugeChart.tsx
기간 계산 로직을 useMemo로 캐싱하고 컴포넌트를 memo로 래핑.
훅 단순화
src/hooks/common/useIsMounted.ts
requestAnimationFrame 기반 지연 제거, 마운트 시 즉시 setIsMounted(true) 호출로 단순화.
대시보드 페이지 변경
src/pages/dashboard/overview/OverviewDashboard.tsx
OverviewAiReportPanel을 lazy 로드하고 Suspense로 감싸서 조건부 렌더링; 예산 상태 배지 로직 단순화 및 UI 클래스 조정.

Sequence Diagram(s)

sequenceDiagram
  participant User as 사용자
  participant Drawer as DrawerPanel
  participant Parent as 상위컴포넌트
  participant Portal as Portal

  User->>Drawer: touchstart (패널 드래그 시작)
  Drawer->>Drawer: 기록 touchStartY, isDragging = true
  User->>Drawer: touchmove (translate 패널)
  Drawer->>Drawer: apply transform (translateY)
  User->>Drawer: touchend
  alt drag distance >= threshold
    Drawer->>Parent: call onClose()
    Parent->>Portal: close Drawer (isOpen = false)
    Drawer->>Drawer: reset transform/transition
  else
    Drawer->>Drawer: animate back to open position
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • jjjsun
  • YermIm
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% 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 제목이 변경사항의 주요 내용(렌더링 성능 최적화 및 태블릿 UX 개선)을 명확하게 요약하고 있습니다.
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 refactor/#104
📝 Coding Plan
  • Generate coding plan for human review comments

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 generate a title for your PR based on the changes.

Add @coderabbitai placeholder anywhere in the title of your PR and CodeRabbit will replace it with a title based on the changes in the PR. You can change the placeholder by changing the reviews.auto_title_placeholder setting.

@github-actions

github-actions Bot commented Mar 18, 2026

Copy link
Copy Markdown

📚 Storybook 배포 완료

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

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

🧹 Nitpick comments (4)
src/pages/dashboard/overview/OverviewDashboard.tsx (1)

188-192: Lazy loading 적용 LGTM, 로딩 표시 고려 권장

isAiPanelOpen && <Suspense>로 패널 열릴 때만 컴포넌트를 로드하는 패턴이 적절합니다. 다만, fallback={null}로 인해 네트워크 지연 시 빈 화면이 잠시 보일 수 있습니다. 사용자 경험을 위해 로딩 스피너나 스켈레톤을 고려해 보세요.

💡 선택적 개선 제안
         {isAiPanelOpen && (
-          <Suspense fallback={null}>
+          <Suspense fallback={<div className="flex items-center justify-center h-40"><span>로딩 중...</span></div>}>
             <OverviewAiReportPanel />
           </Suspense>
         )}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/dashboard/overview/OverviewDashboard.tsx` around lines 188 - 192,
The Suspense fallback currently uses null which can show a blank screen during
network delay; update the Suspense that wraps OverviewAiReportPanel (the block
gated by isAiPanelOpen) to render a visible loading state (e.g., a Spinner or
Skeleton component) instead of null, by providing a meaningful fallback prop
(for example <Suspense fallback={<Spinner/>}> or a Skeleton) and ensure any
Spinner/Skeleton component is imported and matches your design system so users
see feedback while OverviewAiReportPanel loads.
src/components/dashboard/charts/useAnomalyMarkerPos.ts (1)

45-45: 의존성 배열에 대한 확인이 필요합니다.

containerRefuseRef로 생성된 RefObject이므로 컴포넌트 생명주기 동안 동일한 참조를 유지합니다. 따라서 이 의존성 배열은 실질적으로 []와 동일하게 동작합니다. 의도한 동작이라면 괜찮지만, 명시적으로 빈 배열 []을 사용하는 것이 의도를 더 명확히 전달할 수 있습니다.

♻️ 선택적 개선 제안
-  }, [containerRef]);
+  }, []); // containerRef는 useRef로 생성되어 안정적인 참조
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/dashboard/charts/useAnomalyMarkerPos.ts` at line 45, The
dependency array for the useEffect inside useAnomalyMarkerPos currently lists
containerRef, but since containerRef is a RefObject that stays stable across
renders the effect behaves like one with an empty dependency array; update the
dependency array to [] to make this intent explicit (or, if you actually want
the effect to re-run when the ref.current changes, change the logic to track the
value you care about instead), and ensure you modify the effect in
useAnomalyMarkerPos that references containerRef so the hook’s behavior is
clear.
src/components/dashboard/platform/PlatformRoasTable.tsx (2)

85-85: will-change 트리거를 group-hover와 맞춰주세요.

지금은 transform이 group-hover:scale-105로 행 전체 hover에서 실행되는데, will-change는 로고 자체 hover일 때만 적용됩니다. 그래서 행의 다른 영역에 hover된 경우엔 실제 transform과 최적화 힌트가 서로 다른 조건으로 동작합니다. 같은 트리거로 맞추는 편이 이번 최적화 의도와 더 일관돼요.

제안 코드
-                <div className="shrink-0 p-1.5 hover:will-change-transform group-hover:scale-105">
+                <div className="shrink-0 p-1.5 group-hover:will-change-transform group-hover:scale-105">

As per coding guidelines, src/**: 5. 성능: 불필요한 리렌더링 체크. React.memo, useCallback 사용 검토.

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

In `@src/components/dashboard/platform/PlatformRoasTable.tsx` at line 85, The
will-change optimization is currently tied to the element's own hover
(hover:will-change-transform) while the transform is triggered by the row's
hover (group-hover:scale-105); change the will-change class to use the same
trigger (group-hover:will-change-transform) so the optimization hint and the
actual transform share the same condition—for example update the div with
className containing "shrink-0 p-1.5 hover:will-change-transform
group-hover:scale-105" to use "group-hover:will-change-transform" instead,
ensuring the row hover (group) drives both the will-change hint and the scale
transform.

42-50: Deltamemo는 현재 구조에선 이득이 거의 없어요.

상위 PlatformRoasTable가 이미 prop 없는 memo 컴포넌트라서 부모 리렌더가 여기까지 내려오지 않습니다. 지금 기준으로는 Delta에 비교 비용과 복잡도만 추가돼서, 이 파일이 나중에 prop/state 기반으로 바뀌기 전까지는 일반 컴포넌트로 두는 편이 더 단순합니다.

제안 코드
-const Delta = memo(function Delta({ value }: { value: number }) {
+function Delta({ value }: { value: number }) {
   const isPos = value >= 0;
   return (
     <TrendBadge
       direction={isPos ? "up" : "down"}
       value={`${Math.abs(value).toFixed(1)}%`}
     />
   );
-});
+}

As per coding guidelines, src/**: 5. 성능: 불필요한 리렌더링 체크. React.memo, useCallback 사용 검토.

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

In `@src/components/dashboard/platform/PlatformRoasTable.tsx` around lines 42 -
50, Delta is wrapped with React.memo but since its parent PlatformRoasTable is
already a memoized component with no changing props, the memo adds overhead
without benefit; remove the memo wrapper and convert Delta back to a plain
functional component (export/local const Delta = function Delta({ value }: {
value: number }) { ... } or equivalent) so it renders normally, keeping the
inner logic that computes isPos and returns the TrendBadge with
value={`${Math.abs(value).toFixed(1)}%`} unchanged; this simplifies code and
avoids unnecessary memoization overhead.
🤖 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/common/drawer/Drawer.tsx`:
- Around line 126-129: The tablet drag-handle div (the element with classes
"hidden tablet:flex justify-center pt-3 pb-1 shrink-0 cursor-grab
active:cursor-grabbing") is currently visual-only and not keyboard/screen-reader
accessible; make it focusable (tabIndex=0), give it an accessible role and label
(e.g., role="button" and aria-label="Drag to close or open drawer"), and add
keyboard handlers (onKeyDown handling Enter/Space to start/trigger close or open
and Escape to close) that call the existing drawer control methods (e.g., the
same onClose/onToggle handlers used elsewhere). Also ensure the drawer's close
control remains available on tablet (keep or render the CloseButton component on
tablet breakpoint or duplicate its accessible button into the tablet header), so
users who cannot swipe still have a visible, keyboard- and
screen-reader-accessible way to close the drawer.

---

Nitpick comments:
In `@src/components/dashboard/charts/useAnomalyMarkerPos.ts`:
- Line 45: The dependency array for the useEffect inside useAnomalyMarkerPos
currently lists containerRef, but since containerRef is a RefObject that stays
stable across renders the effect behaves like one with an empty dependency
array; update the dependency array to [] to make this intent explicit (or, if
you actually want the effect to re-run when the ref.current changes, change the
logic to track the value you care about instead), and ensure you modify the
effect in useAnomalyMarkerPos that references containerRef so the hook’s
behavior is clear.

In `@src/components/dashboard/platform/PlatformRoasTable.tsx`:
- Line 85: The will-change optimization is currently tied to the element's own
hover (hover:will-change-transform) while the transform is triggered by the
row's hover (group-hover:scale-105); change the will-change class to use the
same trigger (group-hover:will-change-transform) so the optimization hint and
the actual transform share the same condition—for example update the div with
className containing "shrink-0 p-1.5 hover:will-change-transform
group-hover:scale-105" to use "group-hover:will-change-transform" instead,
ensuring the row hover (group) drives both the will-change hint and the scale
transform.
- Around line 42-50: Delta is wrapped with React.memo but since its parent
PlatformRoasTable is already a memoized component with no changing props, the
memo adds overhead without benefit; remove the memo wrapper and convert Delta
back to a plain functional component (export/local const Delta = function
Delta({ value }: { value: number }) { ... } or equivalent) so it renders
normally, keeping the inner logic that computes isPos and returns the TrendBadge
with value={`${Math.abs(value).toFixed(1)}%`} unchanged; this simplifies code
and avoids unnecessary memoization overhead.

In `@src/pages/dashboard/overview/OverviewDashboard.tsx`:
- Around line 188-192: The Suspense fallback currently uses null which can show
a blank screen during network delay; update the Suspense that wraps
OverviewAiReportPanel (the block gated by isAiPanelOpen) to render a visible
loading state (e.g., a Spinner or Skeleton component) instead of null, by
providing a meaningful fallback prop (for example <Suspense
fallback={<Spinner/>}> or a Skeleton) and ensure any Spinner/Skeleton component
is imported and matches your design system so users see feedback while
OverviewAiReportPanel loads.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 530eaa7d-fd37-464c-99be-547075f4e2cf

📥 Commits

Reviewing files that changed from the base of the PR and between 06af9c2 and 03eae1a.

📒 Files selected for processing (12)
  • src/components/common/PageHeader.tsx
  • src/components/common/card/Card.tsx
  • src/components/common/card/StatCard.tsx
  • src/components/common/chart/ChartLegend.tsx
  • src/components/common/drawer/Drawer.tsx
  • src/components/dashboard/charts/BudgetGaugeChart.tsx
  • src/components/dashboard/charts/TrafficChart.tsx
  • src/components/dashboard/charts/trafficChart.config.ts
  • src/components/dashboard/charts/useAnomalyMarkerPos.ts
  • src/components/dashboard/platform/PlatformRoasTable.tsx
  • src/hooks/common/useIsMounted.ts
  • src/pages/dashboard/overview/OverviewDashboard.tsx

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

♻️ Duplicate comments (1)
src/components/common/drawer/Drawer.tsx (1)

159-165: ⚠️ Potential issue | 🟡 Minor

태블릿에서 닫기 버튼이 숨겨져 있습니다

스와이프 제스처를 사용할 수 없는 사용자(운동 장애, 키보드 전용 사용자 등)가 태블릿에서 drawer를 닫을 방법이 없어요. 드래그 핸들에 키보드 지원을 추가하거나, 닫기 버튼을 태블릿에서도 유지하는 것을 권장합니다.

♿ 닫기 버튼 유지 제안
                   <button
                     onClick={onClose}
-                    className="tablet:hidden h-10 w-10 cursor-pointer rounded-component-sm hover:bg-gray-100 transition-colors flex items-center justify-center outline-none"
+                    className="h-10 w-10 cursor-pointer rounded-component-sm hover:bg-gray-100 transition-colors flex items-center justify-center outline-none"
                     aria-label="닫기"
                   >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/common/drawer/Drawer.tsx` around lines 159 - 165, The close
button in Drawer.tsx is hidden on tablets via the "tablet:hidden" class which
prevents keyboard-only or non-gesture users from closing the drawer; update the
component so the close control remains available on tablet (remove or adjust the
"tablet:hidden" rule) or add keyboard support to the drag handle (ensure the
element handling onClose exposes keyboard events like Enter/Escape and has
proper aria-label/role). Specifically, modify the button containing onClose and
CloseIcon to be visible on tablet (remove "tablet:hidden") or implement keyboard
handlers on the drag handle component (listen for keydown and call onClose) and
ensure accessible attributes (aria-label, tabindex/role) are present.
🧹 Nitpick comments (1)
src/components/common/drawer/Drawer.tsx (1)

78-90: 중복 코드 정리 제안

delta > SWIPE_CLOSE_THRESHOLD 조건의 if/else 양쪽 분기에서 panelRef.current.style.transform = ""가 동일하게 설정되고 있어요. 조건문 밖으로 빼면 코드가 더 간결해집니다.

♻️ 리팩토링 제안
   const handleTouchEnd = (e: TouchEvent) => {
     if (!isDragging.current || !panelRef.current) return;
     isDragging.current = false;
     const delta = e.changedTouches[0].clientY - touchStartY.current;
     panelRef.current.style.transition = "";
+    panelRef.current.style.transform = "";

     if (delta > SWIPE_CLOSE_THRESHOLD) {
-      panelRef.current.style.transform = "";
       onClose();
-    } else {
-      panelRef.current.style.transform = "";
     }
   };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/common/drawer/Drawer.tsx` around lines 78 - 90, handleTouchEnd
contains duplicate assignment panelRef.current.style.transform = "" in both
branches; move that assignment out of the if/else so it always runs after
computing delta and before calling onClose. Concretely, inside handleTouchEnd
(which uses isDragging.current, touchStartY, panelRef, SWIPE_CLOSE_THRESHOLD and
calls onClose) set isDragging.current = false, compute delta, clear transition,
then set panelRef.current.style.transform = "" once, and finally if delta >
SWIPE_CLOSE_THRESHOLD call onClose().
🤖 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/common/drawer/Drawer.tsx`:
- Around line 126-135: The drag handle currently uses role="slider" which is
semantically incorrect and missing required slider attributes; change the
element in the Drawer component to role="button" (or role="button" +
aria-pressed if applicable), keep the existing aria-label, ensure it remains
focusable (tabIndex={0}), and wire both onClick and keyboard handlers to invoke
the Drawer close routine (call the component's close handler such as onClose or
handleClose) when Enter or Space is pressed; remove any slider-only ARIA
attributes (aria-valuemin/aria-valuemax/aria-valuenow) so the control is
accessible and behaves like a button.

---

Duplicate comments:
In `@src/components/common/drawer/Drawer.tsx`:
- Around line 159-165: The close button in Drawer.tsx is hidden on tablets via
the "tablet:hidden" class which prevents keyboard-only or non-gesture users from
closing the drawer; update the component so the close control remains available
on tablet (remove or adjust the "tablet:hidden" rule) or add keyboard support to
the drag handle (ensure the element handling onClose exposes keyboard events
like Enter/Escape and has proper aria-label/role). Specifically, modify the
button containing onClose and CloseIcon to be visible on tablet (remove
"tablet:hidden") or implement keyboard handlers on the drag handle component
(listen for keydown and call onClose) and ensure accessible attributes
(aria-label, tabindex/role) are present.

---

Nitpick comments:
In `@src/components/common/drawer/Drawer.tsx`:
- Around line 78-90: handleTouchEnd contains duplicate assignment
panelRef.current.style.transform = "" in both branches; move that assignment out
of the if/else so it always runs after computing delta and before calling
onClose. Concretely, inside handleTouchEnd (which uses isDragging.current,
touchStartY, panelRef, SWIPE_CLOSE_THRESHOLD and calls onClose) set
isDragging.current = false, compute delta, clear transition, then set
panelRef.current.style.transform = "" once, and finally if delta >
SWIPE_CLOSE_THRESHOLD call onClose().

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b68650f4-a267-48db-99f5-e014d572c1ed

📥 Commits

Reviewing files that changed from the base of the PR and between 03eae1a and cfb2fae.

📒 Files selected for processing (1)
  • src/components/common/drawer/Drawer.tsx

Comment thread src/components/common/drawer/Drawer.tsx
@YermIm

YermIm commented Mar 18, 2026

Copy link
Copy Markdown
Collaborator

P4: 확인했습니다. 수고하셨어요!!

@jjjsun jjjsun left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

P4: 확인했습니다! 고생하셨어요!

@Seojegyeong
Seojegyeong merged commit b8e853a into develop Mar 18, 2026
3 checks passed
@Seojegyeong
Seojegyeong deleted the refactor/#104 branch March 18, 2026 13:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 기능 개발 🔨 Refactor 코드 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

♻️ [Refactor] ApexCharts/react-apexcharts 최적화

3 participants