Feat(extension): 익스텐션 ui 반영 및 바운더리 최적화 작업#213
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Walkthrough익스텐션 팝업에 신규 Header 컴포넌트 추가, 토큰 기반 렌더링 도입(토큰 없으면 LogOutPop 표시), 여러 위치의 자동 창 닫기( Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
🔇 Additional comments (1)
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 |
|
✅ Storybook chromatic 배포 확인: |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
apps/extension/src/hooks/useSaveBookmarks.ts (1)
21-31:chrome.storage.local.get/set에서chrome.runtime.lastError미처리
bookmarks로컬 저장이 실패해도 조용히 진행될 수 있습니다(특히 확장 스토리지/권한/쿼터 이슈). 최소한 reject 처리해 catch로 떨어지게 만드는 게 안전합니다.- const result = await new Promise<{ bookmarks?: any[] }>((resolve) => { - chrome.storage.local.get(['bookmarks'], (items) => resolve(items)); - }); + const result = await new Promise<{ bookmarks?: unknown[] }>((resolve, reject) => { + chrome.storage.local.get(['bookmarks'], (items) => { + if (chrome.runtime.lastError) return reject(chrome.runtime.lastError); + resolve(items); + }); + }); ... - await new Promise<void>((resolve) => { - chrome.storage.local.set({ bookmarks }, resolve); - }); + await new Promise<void>((resolve, reject) => { + chrome.storage.local.set({ bookmarks }, () => { + if (chrome.runtime.lastError) return reject(chrome.runtime.lastError); + resolve(); + }); + });apps/extension/src/hooks/usePageMeta.ts (1)
31-57: 예외 처리 누락으로loading이 영구 true가 될 수 있음
chrome.tabs.query콜백이async인데getOgMeta(내부적으로 fetch)에서 throw되면setLoading(false)가 실행되지 않을 수 있습니다. try/catch로 최소한 로딩 종료와 fallback meta를 보장하세요.useEffect(() => { chrome.tabs.query({ active: true, currentWindow: true }, async (tabs) => { - const activeTab = tabs[0]; - if (!activeTab?.url) { - setLoading(false); - return; - } - - const currentUrl = activeTab.url; - - chrome.storage.local.set({ bookmarkedUrl: currentUrl }); - const newMeta = await getOgMeta(currentUrl); + try { + const activeTab = tabs[0]; + if (!activeTab?.url) { + setLoading(false); + return; + } + + const currentUrl = activeTab.url; + chrome.storage.local.set({ bookmarkedUrl: currentUrl }); + const newMeta = await getOgMeta(currentUrl); + + setMeta(newMeta); + chrome.storage.local.set({ titleSave: newMeta.title }); + } catch (e) { + setMeta({ url: '', title: '', description: '', imgUrl: '' }); + } finally { + setLoading(false); + } - setMeta(newMeta); - setLoading(false); - - chrome.storage.local.set({ titleSave: newMeta.title }); }); }, []);apps/extension/src/pages/MainPop.tsx (1)
173-178:getKSTISOString()타임존 계산이 잘못됨(지역에 따라 더 틀어질 수 있음)
현재 구현은 “KST”를 보장하지 않습니다. 의도가 “항상 KST 기준 문자열”이라면 UTC 기준으로 +9시간을 더하는 방식이 안전합니다.- function getKSTISOString() { - const now = new Date(); - const offset = now.getTimezoneOffset() * 60000; // UTC 기준 오프셋 (분 단위) - const kst = new Date(now.getTime() - offset); // UTC → KST 보정 - return kst.toISOString().slice(0, 19); // 밀리초, Z 제거 - } + function getKSTISOString() { + const KST_OFFSET_MS = 9 * 60 * 60 * 1000; + return new Date(Date.now() + KST_OFFSET_MS).toISOString().slice(0, 19); + }
🧹 Nitpick comments (5)
apps/extension/src/hooks/useSaveBookmarks.ts (2)
83-85:window.close()주석 유지 대신 “동작 플래그화” 또는 제거 권장
지금처럼 “주석으로 남긴 동작 코드”는 의도/정책이 바뀔 때 중복 주석이 쌓이기 쉽습니다.shouldAutoClose같은 옵션(기본 false)으로 분기하거나, 정말 개발 중 임시라면 TODO와 함께 이슈 트래킹이 더 안전해요.- // window 닫기 - // window.close(); + // TODO(#212): 자동 닫기 정책 확정 시 플래그로 제어 + // if (shouldAutoClose) window.close();
50-52: 북마크 폴더parentId: '2'상수 의존은 최소 주석/근거 보강 권장
Chrome에선 보통 “기타 북마크”가 id2이긴 한데, 환경/브라우저에 따라 달라질 여지가 있어요. 그대로 갈 거면 “Chrome root mapping 전제”를 주석으로 명확히 남기거나, 가능하면 트리에서 “Other bookmarks”를 찾아 id를 얻는 방식이 더 안전합니다.apps/extension/src/pages/MainPop.tsx (3)
287-298: 홈 아이콘: hover는 좋지만 클릭/키보드 접근성 보완 권장
cursor-pointer만으로는 접근성/명확한 인터랙션이 부족할 수 있어요. 가능하면<button aria-label="홈으로">로 감싸고onClick,onKeyDown(Enter/Space)를 지원하세요.
50-50: hover 상태는 CSS로도 대체 가능(선택 사항)
단순 hover 스왑이면 상태(isHover) 대신group-hover/hover:로 처리하면 리렌더를 줄일 수 있습니다(Icon 컴포넌트가 두 상태 렌더를 지원한다는 전제).
245-248:window.close()주석 방치 대신 정책을 한 곳에서 관리 권장
edit 성공 시 close를 막는 의도는 이해되지만, 이 패턴이 여러 군데 퍼지면 나중에 정책 변경이 어렵습니다(설정/상수/훅으로 일원화 추천).
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
apps/extension/src/assets/home.svgis excluded by!**/*.svgpackages/design-system/src/icons/source/chippi_profile.svgis excluded by!**/*.svgpackages/design-system/src/icons/source/ext_home1.svgis excluded by!**/*.svgpackages/design-system/src/icons/source/ext_home2.svgis excluded by!**/*.svg
📒 Files selected for processing (4)
apps/extension/src/hooks/usePageMeta.ts(1 hunks)apps/extension/src/hooks/useSaveBookmarks.ts(1 hunks)apps/extension/src/pages/MainPop.tsx(4 hunks)packages/design-system/src/icons/iconNames.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: jjangminii
Repo: Pinback-Team/pinback-client PR: 52
File: apps/client/src/shared/components/sidebar/SideItem.tsx:57-60
Timestamp: 2025-09-03T08:57:48.626Z
Learning: SideItem 컴포넌트에서 아이콘 디자인이 일반적인 기대와 반대여서, 회전 로직도 반대로 구현되었습니다. 이를 명확히 하기 위해 prop 이름을 open에서 close로 변경하여 실제 동작과 일치시켰습니다.
📚 Learning: 2025-07-08T11:47:10.642Z
Learnt from: constantly-dev
Repo: Pinback-Team/pinback-client PR: 30
File: apps/extension/src/App.tsx:10-21
Timestamp: 2025-07-08T11:47:10.642Z
Learning: In apps/extension/src/App.tsx, the InfoBox component currently uses a hardcoded external URL for the icon prop as a temporary static placeholder. The plan is to replace this with dynamic favicon extraction from bookmarked websites in future iterations.
Applied to files:
packages/design-system/src/icons/iconNames.tsapps/extension/src/pages/MainPop.tsx
📚 Learning: 2025-07-15T20:00:13.756Z
Learnt from: constantly-dev
Repo: Pinback-Team/pinback-client PR: 80
File: apps/client/src/shared/components/ui/modalPop/ModalPop.tsx:36-41
Timestamp: 2025-07-15T20:00:13.756Z
Learning: In apps/client/src/shared/components/ui/modalPop/ModalPop.tsx, the InfoBox component uses hardcoded values for title, location, and icon URL as temporary test data. These should be replaced with dynamic data from props when implementing actual functionality and should be marked with TODO comments for future changes.
Applied to files:
apps/extension/src/pages/MainPop.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: storybook
🔇 Additional comments (2)
apps/extension/src/hooks/usePageMeta.ts (1)
42-53: 내부 페이지/타이틀 가드가 사실상 제거됨(의도 확인 필요)
현재는 내부 페이지(chrome://,edge://,about:등)에서도 OG fetch를 시도하게 됩니다. 자동 닫기를 없애더라도 “저장 불가 UI 상태로 전환” 같은 형태의 가드는 남기는 게 안전해요.packages/design-system/src/icons/iconNames.ts (1)
2-7: 아이콘 네이밍 추가는 OK — 실제 에셋/빌드 파이프라인 동기화만 확인
자동 생성 파일인 만큼ext_home1,ext_home2에 대응하는 에셋이 디자인 시스템 아이콘 번들에 포함되는지(Storybook/빌드)만 확인하면 됩니다.
| useEffect(() => { | ||
| if (!loading && !title) { | ||
| alert('이 페이지는 저장할 수 없어요 🐿️'); | ||
| window.close(); | ||
| // window.close(); | ||
| } | ||
| }, [loading, title]); |
There was a problem hiding this comment.
“저장 불가 페이지”에서 이제 닫지 않으니, 후속 UX(버튼 비활성/에러 UI)가 필요
현재는 alert만 띄우고 화면이 계속 남아서 사용자가 저장을 시도할 수 있습니다(타이틀 공백 등). isInvalidPage 상태를 두고 저장 버튼 disable + 안내 문구 렌더링 같은 처리가 있어야 흐름이 끊기지 않습니다.
🤖 Prompt for AI Agents
In apps/extension/src/pages/MainPop.tsx around lines 71-76, the effect currently
only alerts when the page is not savable but leaves the UI interactive;
introduce an isInvalidPage boolean state (derived from !loading && !title) and
set it in the useEffect (or compute it from dependencies), then use that state
to disable the Save button(s) and render a visible inline notice explaining why
saving is disabled (e.g., "타이틀이 필요합니다" or similar) in the main render; ensure
the Save handler also early-returns when isInvalidPage to guard against direct
calls.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
apps/extension/src/shared/components/Header.tsx (2)
7-17:chrome.tabs.create는 실행 환경 가드(+ 에러 처리) 추가를 권장합니다.
Storybook/테스트/웹 런타임에서chrome이 없으면 런타임 에러가 날 수 있어if (globalThis.chrome?.tabs?.create) ... else window.open(...)같은 방어 코드(또는 호출부에서 extension-only 보장)를 확인해 주세요.
7-14: hover 토글은onPointerEnter/Leave+ focus 상태까지 포함하는 편이 안전합니다.
터치/펜 입력이나 키보드 포커스에서는onMouseEnter/Leave만으로 상태 전환이 안 될 수 있어onPointerEnter/Leave또는onFocus/onBlur도 함께 고려해 주세요.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/extension/src/pages/MainPop.tsx(2 hunks)apps/extension/src/shared/components/Header.tsx(1 hunks)apps/extension/tsconfig.json(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/extension/src/pages/MainPop.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-08T11:47:10.642Z
Learnt from: constantly-dev
Repo: Pinback-Team/pinback-client PR: 30
File: apps/extension/src/App.tsx:10-21
Timestamp: 2025-07-08T11:47:10.642Z
Learning: In apps/extension/src/App.tsx, the InfoBox component currently uses a hardcoded external URL for the icon prop as a temporary static placeholder. The plan is to replace this with dynamic favicon extraction from bookmarked websites in future iterations.
Applied to files:
apps/extension/src/shared/components/Header.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: storybook
🔇 Additional comments (1)
apps/extension/tsconfig.json (1)
23-33:@shared/*경로 별칭 추가는 좋고, 빌드/린트/테스트 쪽 별칭 동기화만 확인해 주세요.
tsconfig.paths만 추가하면 일부 도구(Vite resolve.alias, eslint import resolver, 테스트 러너)가@shared/*를 못 찾는 케이스가 있어서, 해당 설정들도 동일 별칭을 쓰는지 점검하면 안전합니다.
| const Header = () => { | ||
| const [isHover, setIsHover] = useState(false); | ||
| return ( | ||
| <div className="flex items-center justify-between"> | ||
| <Icon | ||
| name={isHover ? 'ext_home2' : 'ext_home1'} | ||
| width={28} | ||
| height={28} | ||
| className="cursor-pointer" | ||
| onMouseEnter={() => setIsHover(true)} | ||
| onMouseLeave={() => setIsHover(false)} | ||
| onClick={() => { | ||
| chrome.tabs.create({ url: 'https://www.pinback.today/' }); | ||
| }} | ||
| /> | ||
| <Icon name="main_logo" width={72} height={20} /> | ||
| </div> |
There was a problem hiding this comment.
클릭 가능한 아이콘에 키보드 접근성(버튼/aria/포커스) 추가가 필요합니다.
현재는 마우스 이벤트 기반이라 키보드/스크린리더 사용자에게 동작이 막힙니다. button으로 감싸고 aria-label, type="button", onKeyDown(Enter/Space) 또는 기본 버튼 클릭만으로 동작하게 하는 쪽을 권장합니다.
constantly-dev
left a comment
There was a problem hiding this comment.
수고하셨습니다 간단한 코멘트만 확인해주세요~~
| 지금 로그인하고 북마크한 정보의 | ||
| <br /> 리마인드 알람을 받아보세요 | ||
| </p> | ||
| <button |
There was a problem hiding this comment.
button은 type 명시적으로 지정해주세요!
| const Header = () => { | ||
| const [isHover, setIsHover] = useState(false); | ||
| return ( | ||
| <div className="flex items-center justify-between"> |
There was a problem hiding this comment.
sematic태그를 이용하는 것은 어떨까요? header태그!
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
apps/extension/src/pages/LogOutPop.tsx (1)
19-26: 버튼에type="button"속성 명시 필요의도하지 않은 폼 제출을 방지하기 위해 버튼에
type속성을 명시적으로 지정해야 합니다.🔎 수정 제안
<button + type="button" className="sub4-sb mt-[1.6rem] flex h-[4.4rem] w-[25.15rem] items-center justify-between rounded-full border border-gray-100 bg-white px-[2rem]" onClick={() => {
🧹 Nitpick comments (2)
packages/design-system/src/icons/iconNames.ts (1)
23-23: 아이콘 이름에 점(.) 문자 포함 검증 필요
logout_chippi.2512에 점(.)과 숫자가 포함되어 있습니다. 점 문자는 파일 확장자로 오인될 수 있고, 일부 시스템에서 예기치 않은 동작을 유발할 수 있습니다. 다른 아이콘들은 언더스코어(_)만 사용하는 컨벤션을 따르고 있습니다.
logout_chippi_2512형태로 변경하는 것을 권장합니다.apps/extension/src/App.tsx (1)
38-38: 주석 처리된 코드 제거디버깅 또는 테스트용으로 보이는 주석 처리된
<LogOutPop />을 제거해 주세요.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (7)
packages/design-system/src/icons/source/google.svgis excluded by!**/*.svgpackages/design-system/src/icons/source/logout_chippi.2512.svgis excluded by!**/*.svgpackages/design-system/src/icons/source/tooltip_1.svgis excluded by!**/*.svgpackages/design-system/src/icons/source/tooltip_2.svgis excluded by!**/*.svgpackages/design-system/src/icons/source/tooltip_3.svgis excluded by!**/*.svgpackages/design-system/src/icons/source/tooltip_4.svgis excluded by!**/*.svgpackages/design-system/src/icons/source/tooltip_5.svgis excluded by!**/*.svg
📒 Files selected for processing (3)
apps/extension/src/App.tsx(2 hunks)apps/extension/src/pages/LogOutPop.tsx(1 hunks)packages/design-system/src/icons/iconNames.ts(2 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-07-11T20:47:15.055Z
Learnt from: constantly-dev
Repo: Pinback-Team/pinback-client PR: 43
File: apps/client/src/shared/components/ui/cards/BookmarkCard.tsx:0-0
Timestamp: 2025-07-11T20:47:15.055Z
Learning: React 컴포넌트에서 button 요소를 사용할 때는 항상 type 속성을 명시적으로 지정해야 합니다. 일반적인 클릭 버튼의 경우 type="button"을, 폼 제출 버튼의 경우 type="submit"을 명시해야 합니다. 이렇게 해야 의도하지 않은 폼 제출 동작을 방지할 수 있습니다.
Applied to files:
apps/extension/src/pages/LogOutPop.tsx
📚 Learning: 2025-07-13T09:18:25.323Z
Learnt from: constantly-dev
Repo: Pinback-Team/pinback-client PR: 63
File: packages/design-system/src/components/commonBtn/CommonBtn.tsx:37-42
Timestamp: 2025-07-13T09:18:25.323Z
Learning: React 버튼 컴포넌트에서 submit, button 등 다양한 버튼 타입을 사용해야 하는 경우, buttonType prop을 추가하여 HTML button 요소의 type 속성을 설정할 수 있도록 해야 합니다. 기본값은 'button'으로 설정하여 의도하지 않은 폼 제출을 방지해야 합니다.
Applied to files:
apps/extension/src/pages/LogOutPop.tsx
📚 Learning: 2025-07-15T20:00:13.756Z
Learnt from: constantly-dev
Repo: Pinback-Team/pinback-client PR: 80
File: apps/client/src/shared/components/ui/modalPop/ModalPop.tsx:36-41
Timestamp: 2025-07-15T20:00:13.756Z
Learning: In apps/client/src/shared/components/ui/modalPop/ModalPop.tsx, the InfoBox component uses hardcoded values for title, location, and icon URL as temporary test data. These should be replaced with dynamic data from props when implementing actual functionality and should be marked with TODO comments for future changes.
Applied to files:
apps/extension/src/App.tsx
📚 Learning: 2025-07-08T11:47:10.642Z
Learnt from: constantly-dev
Repo: Pinback-Team/pinback-client PR: 30
File: apps/extension/src/App.tsx:10-21
Timestamp: 2025-07-08T11:47:10.642Z
Learning: In apps/extension/src/App.tsx, the InfoBox component currently uses a hardcoded external URL for the icon prop as a temporary static placeholder. The plan is to replace this with dynamic favicon extraction from bookmarked websites in future iterations.
Applied to files:
packages/design-system/src/icons/iconNames.ts
🧬 Code graph analysis (1)
apps/extension/src/App.tsx (2)
apps/extension/src/hooks/usePageMeta.ts (1)
usePageMeta(21-61)apps/extension/src/apis/query/queries.ts (1)
useGetArticleSaved(53-59)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: storybook
🔇 Additional comments (3)
packages/design-system/src/icons/iconNames.ts (1)
1-32: 자동 생성 파일 수동 수정 확인파일 주석에 "자동 생성 파일입니다. (직접 수정 금지)"라고 명시되어 있습니다. 이 변경이 아이콘 생성 스크립트를 통해 추가된 것인지, 아니면 수동으로 편집된 것인지 확인해 주세요. 수동 수정의 경우 다음 빌드 시 덮어써질 수 있습니다.
apps/extension/src/pages/LogOutPop.tsx (1)
3-31: 컴포넌트 구현 LGTM로그아웃 상태 UI가 잘 구현되어 있습니다. Chrome extension API를 사용한 탭 생성 로직도 적절합니다.
apps/extension/src/App.tsx (1)
9-10: 토큰 없을 때 불필요한 API 호출 검토
useGetArticleSaved가 토큰 존재 여부와 관계없이 호출됩니다. 인증이 필요한 API라면 토큰이 없을 때 불필요한 에러나 네트워크 요청이 발생할 수 있습니다. 해당 훅에서 토큰 기반enabled조건이 이미 처리되어 있는지 확인해 주세요.
| const [isToken, setIsToken] = useState<boolean | null>(null); | ||
|
|
||
| useEffect(() => { | ||
| chrome.storage.local.get('token', (result) => { | ||
| setIsToken(!!result.token); | ||
| }); | ||
| }, []); |
There was a problem hiding this comment.
토큰 확인 전 로딩 상태 처리 필요
isToken이 null(초기값)일 때 falsy로 평가되어 LogOutPop이 렌더링됩니다. 이로 인해 로그인된 사용자도 토큰 확인이 완료되기 전까지 잠깐 로그아웃 화면을 보게 됩니다.
로딩 상태를 명시적으로 처리하는 것을 권장합니다:
🔎 수정 제안
const [isToken, setIsToken] = useState<boolean | null>(null);
+ // 토큰 확인 중일 때 로딩 표시
+ if (isToken === null) {
+ return null; // 또는 로딩 스피너
+ }
return (
<>
- {/* <LogOutPop /> */}
{isToken ? (Also applies to: 39-50
🤖 Prompt for AI Agents
In apps/extension/src/App.tsx around lines 14 to 20 (and similarly at 39-50),
the component treats isToken null as falsy and immediately renders the LogOutPop
before chrome.storage check completes; change the logic to explicitly represent
loading (keep isToken initial value null) and avoid rendering auth-dependent UI
while isToken === null: add a loading branch (or return null / a spinner) until
chrome.storage callback sets isToken to true/false, and ensure all conditional
renders that currently check falsy values use explicit comparisons (isToken ===
true / isToken === false) so users don't see the logout screen briefly.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/extension/src/pages/LogOutPop.tsx (1)
19-30: 버튼 구현이 올바르지만, 에러 처리와 URL 관리 개선이 필요합니다.
type="button"이 올바르게 명시되어 있어 좋습니다 (이전 리뷰 코멘트 반영됨).다음 개선사항을 권장합니다:
chrome.tabs.create호출에 에러 핸들링을 추가하여 실패 시 사용자에게 피드백을 제공하세요.- 하드코딩된 URL을 상수로 추출하여 유지보수성을 높이세요.
🔎 개선된 구현 예시
파일 상단에 상수 추가:
+const ONBOARDING_URL = 'https://www.pinback.today/onboarding?step=SOCIAL_LOGIN'; + const LogOutPop = () => {버튼 핸들러에 에러 처리 추가:
<button className="sub4-sb mt-[1.6rem] flex h-[4.4rem] w-[25.15rem] items-center justify-between rounded-full border border-gray-100 bg-white px-[2rem]" type="button" onClick={() => { - chrome.tabs.create({ - url: 'https://www.pinback.today/onboarding?step=SOCIAL_LOGIN', - }); + try { + chrome.tabs.create({ + url: ONBOARDING_URL, + }); + } catch (error) { + console.error('Failed to open onboarding tab:', error); + // 선택사항: 사용자에게 에러 토스트 표시 + } }} >
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/extension/src/pages/LogOutPop.tsx(1 hunks)apps/extension/src/shared/components/Header.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/extension/src/shared/components/Header.tsx
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: jjangminii
Repo: Pinback-Team/pinback-client PR: 52
File: apps/client/src/shared/components/sidebar/SideItem.tsx:57-60
Timestamp: 2025-09-03T08:57:48.626Z
Learning: SideItem 컴포넌트에서 아이콘 디자인이 일반적인 기대와 반대여서, 회전 로직도 반대로 구현되었습니다. 이를 명확히 하기 위해 prop 이름을 open에서 close로 변경하여 실제 동작과 일치시켰습니다.
📚 Learning: 2025-07-11T20:47:15.055Z
Learnt from: constantly-dev
Repo: Pinback-Team/pinback-client PR: 43
File: apps/client/src/shared/components/ui/cards/BookmarkCard.tsx:0-0
Timestamp: 2025-07-11T20:47:15.055Z
Learning: React 컴포넌트에서 button 요소를 사용할 때는 항상 type 속성을 명시적으로 지정해야 합니다. 일반적인 클릭 버튼의 경우 type="button"을, 폼 제출 버튼의 경우 type="submit"을 명시해야 합니다. 이렇게 해야 의도하지 않은 폼 제출 동작을 방지할 수 있습니다.
Applied to files:
apps/extension/src/pages/LogOutPop.tsx
📚 Learning: 2025-07-13T09:18:25.323Z
Learnt from: constantly-dev
Repo: Pinback-Team/pinback-client PR: 63
File: packages/design-system/src/components/commonBtn/CommonBtn.tsx:37-42
Timestamp: 2025-07-13T09:18:25.323Z
Learning: React 버튼 컴포넌트에서 submit, button 등 다양한 버튼 타입을 사용해야 하는 경우, buttonType prop을 추가하여 HTML button 요소의 type 속성을 설정할 수 있도록 해야 합니다. 기본값은 'button'으로 설정하여 의도하지 않은 폼 제출을 방지해야 합니다.
Applied to files:
apps/extension/src/pages/LogOutPop.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: storybook
🔇 Additional comments (2)
apps/extension/src/pages/LogOutPop.tsx (2)
1-2: 임포트 구조가 올바릅니다.디자인 시스템의 Icon 컴포넌트를 올바르게 임포트하고 있습니다.
3-18: 컴포넌트 구조와 UI가 깔끔합니다.로고, 일러스트레이션, 안내 문구가 잘 구성되어 있으며, 사용자 친화적인 메시지를 제공합니다.
jjangminii
left a comment
There was a problem hiding this comment.
익스텐션에서 서스펜스 적용은 까다롭네요....... 확실히공부가 많이 필요한 부분 같아요 수고하셨습니다-!
There was a problem hiding this comment.
툴팁 이미지 변경된거같은데 이부분은 파일 뺴고 올려주실 수 있나요?
📌 Related Issues
📄 Tasks
⭐ PR Point (To Reviewer)
1. Suspense가 동작하는 조건
React Suspense는 렌더링 과정 중에 Promise가 발생(throw)될 때 동작합니다.
즉, "컴포넌트가 렌더링되는 도중" 데이터가 아직 준비되지 않았음을 React가 인지해야 하며, 이 떄만 가 로딩 UI를 대신 렌더링
2. 현재 데이터 로딩 구조
[usePageMeta 훅]
이 구조에서는 렌더링 도중에 Promise가 발생하지 않음 + 비동기 로직은 모두 렌더 이후(useEffect)에 실행
"렌더 중간에 감지하는" Suspense 입장에선.. 개입할 수 있는 시점이 없음
3. 그럼 [진혁] 왈 : useEffect를 제거하고 useQuery로 변경하면 되지않냐??
=> 찾아보니..
라고 함...
강제로 Promise 감싸면,
이렇게 Promise로 감싸면 useQuery 자체는 사용할 수 있다함, 근데?
Suspense는 React 렌더링 단계에서 발생한 Promise만 감지할 수 있기 때문에,
useQuery를 사용하더라도 기본 구조에서는 Suspense의 개입이 불가능하다함!
제일 최종적으로는,, 크롬 익스텐션 상
(1) suspense: true 옵션이 존재하긴 하나, Chrome Extension 팝업 환경에서는 전체 UI가 fallback으로 대체되거나 에러 시 팝업 전체가 중단되는 문제가 있어 적용하지 않는다 함
(2) chrome.tabs.query 및 chrome.storage API
얘네는 side-effect이며
React 규칙상 렌더링 단계에서 호출할 수 없고, 반드시 effect 이후에 실행되어야 합니다.
이로 인해 “렌더 중 데이터 로딩”이라는 Suspense의 전제 조건을 만족 불가
📷 Screenshot (UI 적인 변화 기록)
[ 토큰 비어있을 시 (로그인 안되어있을 시 UI케이스 추가) ]

[ 헤더 수정 ]

Summary by CodeRabbit
New Features
UI/UX
버그 수정
아이콘
✏️ Tip: You can customize this high-level summary in your review settings.