Skip to content

feat: 인사이트 페이지 ui 및 코드 정리 (#129)#134

Merged
gyogyo05 merged 10 commits intodevelopfrom
feat/pd-ins-ui-129
Feb 9, 2026
Merged

feat: 인사이트 페이지 ui 및 코드 정리 (#129)#134
gyogyo05 merged 10 commits intodevelopfrom
feat/pd-ins-ui-129

Conversation

@gyogyo05
Copy link
Collaborator

@gyogyo05 gyogyo05 commented Feb 8, 2026

📌 관련 이슈

✨ 변경 내용

  • 가장 많은 피드백을 받은 슬라이드의 박스를 수정한다

💡 참고 사항

추후 InsightPage.tsx의 긴 코드 정리 예정

@github-actions github-actions bot added the page 페이지 관련 변경 label Feb 8, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @gyogyo05, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 PR은 인사이트 페이지의 사용자 인터페이스를 개선하고 코드 구조를 정리하는 초기 단계입니다. 특히, 사용자 피드백이 많았던 슬라이드 섹션의 시각적 정렬을 조정하여 전반적인 사용자 경험을 향상시키는 데 중점을 둡니다.

Highlights

  • UI 개선: 가장 많은 피드백을 받은 슬라이드 섹션의 레이아웃을 조정하여, 항목들이 상단에 정렬되도록 'items-start' Tailwind CSS 클래스를 추가했습니다.
Changelog
  • src/pages/InsightPage.tsx
    • 가장 많은 피드백을 받은 슬라이드 섹션의 컨테이너 div에 'items-start' Tailwind CSS 클래스를 추가하여 내부 항목들의 수직 정렬을 개선했습니다.
Activity
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

이번 PR은 인사이트 페이지의 UI를 개선하는 변경입니다. '가장 많은 피드백을 받은 슬라이드' 섹션의 카드 정렬 방식을 수정하여, 높이가 다른 카드들이 상단에 정렬되도록 하여 일관된 UI를 제공합니다. 코드 변경은 한 줄의 CSS 클래스 추가로 매우 작으며, 다른 부분에 영향을 주지 않습니다. 전반적으로 깔끔한 수정입니다.

@github-actions github-actions bot added component 컴포넌트 관련 변경 hooks 커스텀 훅 변경 labels Feb 8, 2026
@gyogyo05
Copy link
Collaborator Author

gyogyo05 commented Feb 8, 2026

@claude 코드 리뷰 해줘

@claude
Copy link

claude bot commented Feb 8, 2026

Claude finished @gyogyo05's task in 2m 6s —— View job


코드 리뷰 완료 ✅

이 PR은 InsightPage.tsx의 대규모 리팩토링으로, 코드를 더 작은 단위로 분리하여 유지보수성을 크게 향상시켰습니다. 전반적으로 잘 구조화된 변경사항이지만, 몇 가지 개선이 필요한 부분을 발견했습니다.


🎯 주요 변경사항

긍정적인 부분:

  • 관심사 분리: 420줄의 거대한 컴포넌트를 여러 개의 작은 컴포넌트와 커스텀 훅으로 분리
  • 비즈니스 로직 추출: useInsightPageModel 훅으로 데이터 가공 로직을 분리하여 테스트 가능성 향상
  • 타입 정의 분리: components/insight/types.ts로 공유 타입을 중앙화
  • 컴포넌트 재사용성: RetentionChartCard, RecentCommentsSection 등을 독립적인 컴포넌트로 분리

🔴 Critical Issues

1. 파일 위치 불일치 (src/pages/InsightPage.tsx:1-6)

새로 추가된 컴포넌트들이 올바른 디렉토리에 있지 않습니다:

현재:

import { RecentCommentsSection } from '@/components/insight/RecentCommentsSection';
import { RetentionSection } from '@/components/insight/RetentionSection';

문제:

  • 실제 파일 경로가 주석에는 src/pages/insight/sections/, src/pages/insight/charts/로 표시되어 있음
  • 하지만 imports는 @/components/insight/에서 가져오고 있음
  • components/insight/index.ts에 이 컴포넌트들이 export되어 있지 않음

해결 방법:

  1. 파일들을 src/components/insight/ 디렉토리로 이동시키거나
  2. Import 경로를 실제 위치에 맞게 수정 필요

지금 수정하기 →


2. 커스텀 훅 위치 규칙 위반 (src/hooks/useInsightPageModel.ts:1)

문제:

  • CLAUDE.md 컨벤션에 따르면 hooks는 src/hooks/ 디렉토리에 위치
  • 하지만 이 훅은 InsightPage에만 사용되는 페이지 전용 모델 훅
  • 파일 주석에 src/pages/insight/useInsightPageModel.ts로 표시되어 있어 혼란 발생

권장 사항:

옵션 1: src/hooks/ 유지 (현재 상태) - 다른 곳에서도 재사용 가능한 경우
옵션 2: src/pages/insight/ 이동 - InsightPage 전용이라면 페이지와 함께 위치

현재 구현을 보면 InsightPage에 강하게 결합되어 있으므로, 페이지 디렉토리로 이동하는 것이 더 적합해 보입니다.


⚠️ Important Issues

3. 타입 안전성 문제 (src/hooks/useInsightPageModel.ts:33)

const { projectId: projectIdStrRaw } = useParams<{ projectId: string }>();
const projectIdStr = projectIdStrRaw ?? '';
const projectIdNum = projectIdStr ? Number(projectIdStr) : 0;

문제:

  • useParams에서 받은 값이 undefined일 수 있지만, 빈 문자열로 fallback
  • Number('')0이 되어 잘못된 API 요청 발생 가능
  • projectIdNum0일 때 쿼리들이 실행되어 불필요한 네트워크 요청

개선 제안:

const { projectId } = useParams<{ projectId: string }>();
const projectIdNum = projectId ? Number(projectId) : null;

// 쿼리에 enabled 가드 추가
const { data: slideAnalytics } = useSlideAnalytics(projectIdNum ?? 0, {
  enabled: projectIdNum !== null && projectIdNum > 0
});

4. Barrel Export 누락 (src/components/insight/index.ts:1-7)

현재 상태:

export { default as SlideThumb } from './SlideThumb';
// ... 기존 exports만 존재

누락된 exports:

  • RecentCommentsSection
  • RetentionSection
  • Chart 관련 컴포넌트들
  • types.ts의 타입들

CLAUDE.md 컨벤션에 따르면 "Barrel exports: Use centralized exports from components/common/index.ts"를 권장하고 있습니다.

추가 필요:

export { RecentCommentsSection } from './RecentCommentsSection';
export { RetentionSection } from './RetentionSection';
export * from './types';

지금 수정하기 →


5. Magic Number 사용 (src/components/insight/RecentCommentsSection.tsx:19)

className={`flex flex-col gap-2 ${!hasVideo ? 'blur-[3px] pointer-events-none select-none' : ''}`}

문제:

  • blur-[3px]는 임의의 값 (Tailwind v4에서도 design token 사용 권장)
  • CLAUDE.md: "Prefer Tailwind utilities and design tokens over inline styles"

개선 제안:

// Tailwind의 기본 blur 유틸리티 사용
className={`flex flex-col gap-2 ${!hasVideo ? 'blur-sm pointer-events-none select-none' : ''}`}

💡 Suggestions (Minor)

6. 불필요한 래퍼 컴포넌트 (src/components/insight/RetentionSection.tsx:1-15)

export function RetentionSection({ title, data, isVideo }: {...}) {
  return <RetentionChartCard data={data} isVideo={isVideo} />;
}

문제:

  • Props를 그대로 전달하는 것 외에 아무 기능도 하지 않음
  • 불필요한 추상화 레이어 추가

제안:

  1. RetentionSection 제거하고 InsightPage에서 직접 RetentionChartCard 사용
  2. 또는 RetentionSection에 실제 비즈니스 로직 추가 (예: 데이터 변환, 조건부 렌더링 등)

7. useMemo 남용 (src/hooks/useInsightPageModel.ts:69-75)

const summaryStats = useMemo(
  () =>
    hasVideo
      ? computedSummaryStats
      : computedSummaryStats.filter((stat) => stat.label !== summaryStatLabels[3]),
  [computedSummaryStats, hasVideo],
);

문제:

  • 간단한 filter 연산에 useMemo 사용은 오버킬
  • React 공식 문서: "useMemo는 비용이 높은 계산에만 사용"

개선:

// useMemo 없이 직접 계산
const summaryStats = hasVideo
  ? computedSummaryStats
  : computedSummaryStats.filter((stat) => stat.label !== summaryStatLabels[3]);

유사한 케이스: lines 78, 80-90, 98-122, 124, 128-135 등에서도 과도한 useMemo 사용


8. 함수명 불명확 (src/hooks/useInsightPageModel.ts:92-95)

const toPublicUrl = (url?: string) =>
  url?.startsWith('gs://') ? `https://storage.googleapis.com/${url.slice(5)}` : url;

문제:

  • toPublicUrl은 "공개 URL로 변환"을 의미하지만, 실제로는 "GCS URL을 HTTP URL로 변환"
  • Google Cloud Storage 특화된 변환 로직

제안:

const convertGcsToHttpUrl = (gcsUrl?: string) =>
  gcsUrl?.startsWith('gs://') 
    ? `https://storage.googleapis.com/${gcsUrl.slice(5)}` 
    : gcsUrl;

9. 타입 정의 위치 (src/components/insight/types.ts)

현재:

export interface ChartDataPoint { ... }
export type InsightTopSlide = { ... }
export type InsightModel = { ... }

문제:

  • InsightModel은 hook의 반환 타입이므로 src/hooks/ 또는 src/types/가 더 적합
  • ChartDataPoint는 chart 컴포넌트 전용이므로 charts/ 디렉토리에 있는 것이 더 응집도가 높음

제안:

src/components/insight/types.ts        → UI 관련 타입만 (InsightTopSlide)
src/components/insight/charts/types.ts → 차트 타입 (ChartDataPoint)
src/hooks/types.ts or useInsightPageModel.ts → InsightModel

10. 주석 스타일 불일치 (여러 파일)

패턴 1: JSDoc 스타일

// src/pages/insight/InsightPage.tsx

패턴 2: 일반 주석

// 기존 공용 타입 재사용

프로젝트 컨벤션:
CLAUDE.md에는 명시적인 주석 스타일 가이드가 없지만, 기존 코드 (useSlides.ts, usePresentations.ts)를 보면 JSDoc 스타일을 사용 중

권장:
모든 파일 상단에 일관된 형식의 주석 사용


📊 코드 품질 메트릭

항목 변경 전 변경 후 개선도
InsightPage.tsx 라인 수 ~420줄 76줄 82% 감소 ✅
단일 파일 응집도 낮음 높음 개선 ✅
테스트 가능성 어려움 용이함 개선 ✅
타입 안전성 동일 동일 유지
컴포넌트 재사용성 불가 가능 개선 ✅

🎬 다음 단계 권장사항

  1. 즉시 수정 필요 (Critical):

  2. 리팩토링 고려 (Important):

  3. 향후 작업:

    • PR 설명에 언급된 "긴 코드 정리"는 이번 PR로 거의 완료됨
    • 컴포넌트 스토리북 문서화 고려
    • useInsightPageModel 훅에 대한 단위 테스트 추가

✅ 잘된 점

  • 명확한 단일 책임: 각 컴포넌트가 하나의 역할만 수행
  • Props drilling 해소: 비즈니스 로직을 hook으로 추출하여 props 전달 깊이 감소
  • 일관된 네이밍: Section, Card, Item 등 일관된 접미사 사용
  • 타입스크립트 활용: 모든 컴포넌트와 함수에 명확한 타입 정의

총평

이 PR은 대규모 리팩토링의 모범 사례입니다. 코드 가독성과 유지보수성이 크게 향상되었습니다.

Critical issues 몇 가지만 수정하면 머지 준비 완료입니다! 특히 #1 (파일 위치)과 #4 (barrel exports)는 현재 코드가 실행되지 않을 수 있으므로 우선 확인 부탁드립니다.

수고하셨습니다! 🎉


| Branch: feat/pd-ins-ui-129

@gyogyo05 gyogyo05 self-assigned this Feb 8, 2026
@github-actions github-actions bot added the types 타입 정의 변경 label Feb 8, 2026
@gyogyo05 gyogyo05 merged commit 9c9cffa into develop Feb 9, 2026
8 checks passed
@gyogyo05 gyogyo05 deleted the feat/pd-ins-ui-129 branch February 9, 2026 11:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component 컴포넌트 관련 변경 hooks 커스텀 훅 변경 page 페이지 관련 변경 types 타입 정의 변경

Projects

None yet

Development

Successfully merging this pull request may close these issues.

design: 인사이트 내 피드백多 슬라이드 박스 UI 수정

2 participants