Skip to content

링크상세패널 흐름별 상세 UI 추가#333

Merged
Seong-Myeong merged 1 commit intomainfrom
feature/#328-add-linkdetailpanel-detailFlow
Jan 7, 2026
Merged

링크상세패널 흐름별 상세 UI 추가#333
Seong-Myeong merged 1 commit intomainfrom
feature/#328-add-linkdetailpanel-detailFlow

Conversation

@Seong-Myeong
Copy link
Copy Markdown
Contributor

관련 이슈

PR 설명

  • 요약 생성 실패
  • 요약 생성 중
  • 위 두가지에 대한 UI 추가 작업완료했습니다.

@Seong-Myeong Seong-Myeong self-assigned this Jan 7, 2026
@Seong-Myeong Seong-Myeong linked an issue Jan 7, 2026 that may be closed by this pull request
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jan 7, 2026

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 7, 2026

Walkthrough

LinkCardDetailPanel 컴포넌트에 요약 관련 상태와 콜백이 추가되었습니다. SummaryState 타입('idle' | 'loading' | 'writing' | 'error' | 'ready') 및 summaryState, summaryErrorMessage, onRegenerateSummary, onRetrySummary props가 공개 API로 도입되었고, 요약 영역이 상태에 따라 로딩/에러/완료 등으로 분기되어 렌더링됩니다. 스타일 변경으로 memoWrapper 클래스가 고정 너비 w-[480px]에서 w-full로 수정되었고, 스토리북에 관련 스토리와 argTypes가 추가·조정되었습니다.

Possibly related PRs

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 주요 변경사항을 명확하게 요약하고 있으며, 링크상세패널의 흐름별 상세 UI 추가라는 변경의 핵심을 정확하게 반영합니다.
Description check ✅ Passed PR 설명이 템플릿 구조를 따르고 있으며, 관련 이슈(#328)와 구현된 기능(요약 생성 실패, 요약 생성 중 상태의 UI)을 명확하게 기술하고 있습니다.
Linked Issues check ✅ Passed PR의 코드 변경사항이 이슈 #328의 요구사항을 충족합니다. summaryState 타입 추가, 요약 생성 중/실패 상태에 대한 UI 구현, 그리고 스토리북에 해당 상태별 UI가 모두 추가되었습니다.
Out of Scope Changes check ✅ Passed LinkCardDetailPanel의 스타일 너비 변경(480px → full width)과 전반적인 UI/UX 개선사항들이 모두 요약 흐름별 상세 UI 구현이라는 범위 내에서 적절한 변경입니다.

✏️ Tip: You can configure your own custom Pre-merge Checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @src/components/wrappers/LinkCardDetailPanel/LinkCardDetailPanel.tsx:
- Around line 34-36: The prop summaryBadge is declared on the component
interface and destructured in LinkCardDetailPanel but never used; either render
it in the summary section or remove its declaration/destructuring. Fix options:
(A) If a badge is needed, update the LinkCardDetailPanel JSX where
summary/summaryState is rendered to include summaryBadge (e.g., next to the
summary title or inside the summary card) and ensure SummaryState handling still
works, or (B) if not needed, remove summaryBadge from the props/interface and
from the function parameter list to avoid unused prop warnings; update any
tests/types referring to summaryBadge accordingly.
🧹 Nitpick comments (4)
src/stories/LinkCardDetailPanel.stories.tsx (1)

18-18: summaryState에 대해 select 컨트롤 사용을 권장합니다.

summaryState는 특정 값들('idle' | 'loading' | 'writing' | 'error' | 'ready')만 허용하므로, 'text' 대신 'select' 컨트롤을 사용하면 Storybook에서 더 나은 사용자 경험을 제공할 수 있습니다.

🔎 제안하는 수정
-    summaryState: { control: 'text' },
+    summaryState: {
+      control: 'select',
+      options: ['idle', 'loading', 'writing', 'error', 'ready'],
+    },
src/components/wrappers/LinkCardDetailPanel/LinkCardDetailPanel.tsx (3)

173-177: 클립보드 API 에러 처리가 누락되었습니다.

navigator.clipboard.writeText()는 Promise를 반환하며 권한 거부 등의 이유로 실패할 수 있습니다. 현재 구현에서는 복사 실패 시 사용자에게 피드백이 없습니다. 동일한 패턴이 라인 204-206, 237-239, 428-430에도 반복됩니다.

🔎 에러 처리 예시
  onClick={() => {
    if (typeof navigator !== 'undefined' && navigator.clipboard?.writeText) {
-     navigator.clipboard.writeText(safeUrl || url);
+     navigator.clipboard.writeText(safeUrl || url).catch(() => {
+       // 복사 실패 시 처리 (예: toast 알림)
+     });
    }
  }}

248-253: renderSummaryBox 헬퍼 함수 단순화를 고려해 보세요.

이 헬퍼 함수는 한 번만 사용되고 footer 매개변수도 전달되지 않습니다. 인라인으로 변경하거나 불필요한 매개변수를 제거하면 코드가 더 간결해집니다.


465-465: 중복된 width 클래스가 있습니다.

memoWrapper()가 이미 w-full을 반환하는데, 추가로 w-full max-w-full을 붙이고 있습니다. 기능적으로 문제는 없지만 중복을 제거하면 더 깔끔합니다.

🔎 제안하는 수정
-            <div className={`${memoWrapper()} w-full max-w-full`}>
+            <div className={memoWrapper()}>
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 05b6cae and e0b2273.

📒 Files selected for processing (3)
  • src/components/wrappers/LinkCardDetailPanel/LinkCardDetailPanel.style.ts
  • src/components/wrappers/LinkCardDetailPanel/LinkCardDetailPanel.tsx
  • src/stories/LinkCardDetailPanel.stories.tsx
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: Bangdayeon
Repo: Team-SoFa/linkiving PR: 97
File: src/components/basics/LinkCard/LinkCard.tsx:12-19
Timestamp: 2025-11-23T12:03:33.890Z
Learning: In src/components/basics/LinkCard/LinkCard.tsx, the summary prop should remain required (string type) because the backend always provides it as a string value. The isHaveSummary flag controls whether to display the summary text or show the AddSummaryButton, not whether the data exists.
📚 Learning: 2025-11-23T12:03:33.890Z
Learnt from: Bangdayeon
Repo: Team-SoFa/linkiving PR: 97
File: src/components/basics/LinkCard/LinkCard.tsx:12-19
Timestamp: 2025-11-23T12:03:33.890Z
Learning: In src/components/basics/LinkCard/LinkCard.tsx, the summary prop should remain required (string type) because the backend always provides it as a string value. The isHaveSummary flag controls whether to display the summary text or show the AddSummaryButton, not whether the data exists.

Applied to files:

  • src/components/wrappers/LinkCardDetailPanel/LinkCardDetailPanel.style.ts
  • src/stories/LinkCardDetailPanel.stories.tsx
  • src/components/wrappers/LinkCardDetailPanel/LinkCardDetailPanel.tsx
🧬 Code graph analysis (1)
src/components/wrappers/LinkCardDetailPanel/LinkCardDetailPanel.tsx (1)
src/hooks/util/getSafeUrl.ts (1)
  • getSafeUrl (1-10)
🔇 Additional comments (4)
src/components/wrappers/LinkCardDetailPanel/LinkCardDetailPanel.style.ts (1)

18-18: LGTM!

memoWrapper를 전체 너비로 변경한 것은 새로운 레이아웃과 잘 맞습니다. 컴포넌트의 메모 섹션 업데이트와 일관성이 있습니다.

src/stories/LinkCardDetailPanel.stories.tsx (1)

43-81: LGTM!

스토리 구조가 잘 작성되었습니다. baseArgs를 활용한 재사용 패턴과 각 요약 상태별 스토리 분리가 적절합니다.

src/components/wrappers/LinkCardDetailPanel/LinkCardDetailPanel.tsx (2)

255-330: LGTM!

renderSummaryContent 함수가 각 요약 상태를 명확하게 처리합니다. 로딩, 에러, 완료 상태에 대한 UI가 잘 구현되어 있고, 접기/펼치기 기능도 적절합니다.


337-349: LGTM!

URL 표시 로직이 잘 구현되었습니다. getSafeUrl을 활용한 유효성 검증과 유효하지 않은 URL에 대한 fallback 처리가 적절합니다.

Comment thread src/components/wrappers/LinkCardDetailPanel/LinkCardDetailPanel.tsx
@Seong-Myeong Seong-Myeong changed the title 링크상세패널 흐름 별 상세 UI 추가 링크상세패널 흐름별 상세 UI 추가 Jan 7, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jan 7, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/wrappers/LinkCardDetailPanel/LinkCardDetailPanel.tsx (1)

425-429: 클립보드 복사 시 빈 문자열 처리가 필요합니다.

safeUrl이 빈 문자열일 경우에도 클립보드에 빈 값이 복사됩니다. 헤더의 복사 버튼(line 173)처럼 safeUrl || url 폴백을 사용하거나, 빈 값일 때는 복사를 수행하지 않도록 처리하는 것이 좋습니다.

🔧 제안된 수정
              onClick={() => {
                if (typeof navigator !== 'undefined' && navigator.clipboard?.writeText) {
-                  navigator.clipboard.writeText(safeUrl);
+                  navigator.clipboard.writeText(safeUrl || url);
                }
              }}
🧹 Nitpick comments (2)
src/stories/LinkCardDetailPanel.stories.tsx (1)

18-18: summaryStateselect 컨트롤 사용을 권장합니다.

summaryState'idle' | 'loading' | 'writing' | 'error' | 'ready' 유니온 타입이므로, 스토리북에서 유효한 값만 선택할 수 있도록 select 컨트롤이 더 적합합니다.

🔧 제안된 수정
-    summaryState: { control: 'text' },
+    summaryState: {
+      control: 'select',
+      options: ['idle', 'loading', 'writing', 'error', 'ready'],
+    },
src/components/wrappers/LinkCardDetailPanel/LinkCardDetailPanel.tsx (1)

21-21: SummaryState 타입을 export하는 것을 고려해 주세요.

외부 컴포넌트에서 summaryState prop을 전달할 때 타입 안전성을 위해 SummaryState 타입을 export하면 유용합니다.

🔧 제안된 수정
-type SummaryState = 'idle' | 'loading' | 'writing' | 'error' | 'ready';
+export type SummaryState = 'idle' | 'loading' | 'writing' | 'error' | 'ready';
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e0b2273 and 705346d.

📒 Files selected for processing (3)
  • src/components/wrappers/LinkCardDetailPanel/LinkCardDetailPanel.style.ts
  • src/components/wrappers/LinkCardDetailPanel/LinkCardDetailPanel.tsx
  • src/stories/LinkCardDetailPanel.stories.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/wrappers/LinkCardDetailPanel/LinkCardDetailPanel.style.ts
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: Bangdayeon
Repo: Team-SoFa/linkiving PR: 97
File: src/components/basics/LinkCard/LinkCard.tsx:12-19
Timestamp: 2025-11-23T12:03:33.890Z
Learning: In src/components/basics/LinkCard/LinkCard.tsx, the summary prop should remain required (string type) because the backend always provides it as a string value. The isHaveSummary flag controls whether to display the summary text or show the AddSummaryButton, not whether the data exists.
📚 Learning: 2025-11-23T12:03:33.890Z
Learnt from: Bangdayeon
Repo: Team-SoFa/linkiving PR: 97
File: src/components/basics/LinkCard/LinkCard.tsx:12-19
Timestamp: 2025-11-23T12:03:33.890Z
Learning: In src/components/basics/LinkCard/LinkCard.tsx, the summary prop should remain required (string type) because the backend always provides it as a string value. The isHaveSummary flag controls whether to display the summary text or show the AddSummaryButton, not whether the data exists.

Applied to files:

  • src/stories/LinkCardDetailPanel.stories.tsx
  • src/components/wrappers/LinkCardDetailPanel/LinkCardDetailPanel.tsx
🧬 Code graph analysis (2)
src/stories/LinkCardDetailPanel.stories.tsx (2)
src/components/basics/LinkCard/components/AddSummaryButton.tsx (2)
  • onSummaryGenerate (3-18)
  • console (4-6)
src/stories/ReSummaryModal.stories.tsx (1)
  • useModalStore (17-26)
src/components/wrappers/LinkCardDetailPanel/LinkCardDetailPanel.tsx (1)
src/hooks/util/getSafeUrl.ts (1)
  • getSafeUrl (1-10)
🔇 Additional comments (6)
src/stories/LinkCardDetailPanel.stories.tsx (1)

43-79: LGTM!

baseArgs를 활용한 스토리 구성이 깔끔하고, 각 상태별(loading, error, ready) 스토리가 잘 정의되어 있습니다. SummaryError에서 summaryErrorMessage도 적절히 포함되어 있습니다.

src/components/wrappers/LinkCardDetailPanel/LinkCardDetailPanel.tsx (5)

210-242: 조건부 렌더링 로직이 올바르게 구현되어 있습니다.

loadingerror 상태에서는 액션을 숨기고, 그 외 상태에서만 "요약 다시 생성" 및 "복사" 버튼을 표시하는 로직이 적절합니다.


253-328: renderSummaryContent 함수가 잘 구현되어 있습니다.

각 상태(loading, error, ready, writing, idle)에 따른 UI 분기가 명확하고, writing 상태에서 추가 안내 문구를 표시하는 UX가 좋습니다. isSummaryOverflowing을 활용한 아코디언 펼침/접기 기능도 적절합니다.


44-45: 상수 정의가 적절합니다.

TITLE_MAX_LENGTHMEMO_MAX_LENGTH 상수가 매직 넘버 대신 명명된 상수로 정의되어 가독성과 유지보수성이 향상되었습니다.


462-486: 메모 섹션의 편집 가능 여부 처리가 올바릅니다.

memoEditable prop을 통해 읽기 전용 모드와 편집 모드를 적절히 구분하고 있으며, 이벤트 핸들러들도 memoEditable 조건을 일관되게 검사하고 있습니다.


333-348: 헤더 섹션 구조가 개선되었습니다.

URL 표시 영역과 액션 버튼이 잘 구성되어 있고, safeUrl 유효성 검사를 통해 유효하지 않은 URL에 대한 폴백 UI도 제공됩니다.

@Seong-Myeong Seong-Myeong merged commit cefdfcf into main Jan 7, 2026
5 checks passed
@Seong-Myeong Seong-Myeong deleted the feature/#328-add-linkdetailpanel-detailFlow branch February 9, 2026 13:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LinkDetailPanel 흐름별 상세 UI 구현

2 participants