Feat: 개발 QA 1차(재림 | 온보딩 기능 및 익스텐션 UI 쪽 수정) #107
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded@jllee000 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 3 minutes and 38 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (2)
Walkthrough온보딩 텍스트 일부를 변경하고(두 곳), 알림/타임피커 관련 스타일·포지셔닝·토글 동작을 조정했으며, 확장프로그램 설치 시 열리는 온보딩 URL을 프로덕션 도메인으로 변경하고 Layout에서 온보딩 경로일 때 사이드바를 숨기도록 조건부 렌더링을 추가했습니다. 디자인 시스템 BaseCard에 고정 높이( Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User as 사용자
participant Ext as 확장 background
participant LS as 로컬스토리지
participant Web as 웹 온보딩
note right of Ext #E6F4EA: onInstalled (URL 변경)
User->>Ext: 확장 설치
Ext->>Ext: onInstalled 핸들러 실행
Ext->>Ext: chrome.identity.getProfileUserInfo 등으로 이메일 조회
Ext->>LS: 이메일 저장
Ext->>Ext: 1초 대기
Ext->>Web: Open https://www.pinback.today/onboarding?email={email}
Web-->>User: 온보딩 페이지 렌더링
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
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: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/extension/src/background.ts (2)
5-7: 개인정보 콘솔 노출 제거
info.email을 콘솔에 출력하면 사용자 PII가 개발자 도구에 남습니다. 삭제 권장합니다.- chrome.storage.local.set({ 'userEmail': info.email }, () => { - console.log(info.email); - }); + chrome.storage.local.set({ userEmail: info.email });
20-22: 토큰 콘솔 로깅 금지액세스 토큰을 콘솔에 기록하면 유출 위험이 큽니다. 즉시 제거하세요.
- chrome.storage.local.set({ 'token': message.token }, () => { - console.log('Token saved!', message.token); - }); + chrome.storage.local.set({ token: message.token });
🧹 Nitpick comments (4)
apps/client/src/pages/onBoarding/components/funnel/step/FinalStep.tsx (1)
5-8: 장식 이미지 대체텍스트와 헤딩 시맨틱 보완 제안-dotori 아이콘은 장식용으로 보이며, 스크린리더 낭독을 피하려면 빈 alt가 적절합니다.
-시각적 헤딩(head2)을 실제 헤딩 요소(<h2>)로 바꾸면 접근성 트리 구조가 개선됩니다.아래와 같이 수정을 제안합니다:
- <img src={dotori} className="mb-[1.2rem]" alt="dotori" /> - <p className="head2 text-font-black-1"> - Pinback에 오신 걸 환영해요 - </p> + <img src={dotori} className="mb-[1.2rem]" alt="" aria-hidden="true" /> + <h2 className="head2 text-font-black-1"> + Pinback에 오신 걸 환영해요 + </h2>추가로, 문구가 하드코딩되어 있어 i18n 적용 범위를 점검해 주세요(예: 번역 키 사용).
apps/client/src/pages/onBoarding/components/funnel/step/MacStep.tsx (1)
6-9: 헤딩 시맨틱 적용 및 장식 이미지 alt 정리-시각적 헤딩을
<h2>로 변경해 접근성 향상.
-dotori 아이콘은 장식이라면 빈 alt 권장.- <img src={dotori} className="mb-[1.2rem]" alt="dotori" /> - <p className="head2 text-font-black-1"> - 치삐를 만나려면 알림 설정이 필요해요 - </p> + <img src={dotori} className="mb-[1.2rem]" alt="" aria-hidden="true" /> + <h2 className="head2 text-font-black-1"> + 치삐를 만나려면 알림 설정이 필요해요 + </h2>문구 하드코딩 여부(i18n)도 함께 확인 부탁드립니다.
apps/extension/src/background.ts (2)
8-12: 지연 오픈 로직 점검(필요 시 제거 또는 안정화)1초 지연의 근거가 없다면 제거하거나, 탭 중복 생성 방지(동일 URL 기존 탭 포커싱) 로직을 고려해 주세요.
10-10: 이메일 쿼리 인코딩 및 베이스 URL 환경변수화
- apps/extension/src/background.ts (라인 10): info.email을 직접 URL에 넣지 말고 encodeURIComponent(info.email) 사용.
- 하드코딩된 https://www.pinback.today 대신 import.meta.env.VITE_WEB_BASE_URL(또는 프로젝트 콘벤션의 VITE_* 변수)로 분리.
- 서버 라우트가 소문자 '/onboarding'인지 확인.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/client/src/pages/onBoarding/components/funnel/step/FinalStep.tsx(1 hunks)apps/client/src/pages/onBoarding/components/funnel/step/MacStep.tsx(1 hunks)apps/extension/src/background.ts(1 hunks)
⏰ 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
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/design-system/src/components/card/BaseCard.tsx (1)
8-12: onClick이 있는 카드의 접근성(a11y) 속성 보강 제안키보드 접근성 확보를 위해 role/tabIndex/키보드 핸들링 및 포인터 커서 부여를 권장합니다. 기존 동작에는 영향 없고, 클릭 가능한 경우에만 활성화됩니다.
<div - onClick={onClick} - className="border-gray200 w-[24.8rem] overflow-hidden rounded-[1.2rem] border bg-white h-[12rem]" + onClick={onClick} + role={onClick ? 'button' : undefined} + tabIndex={onClick ? 0 : undefined} + onKeyDown={ + onClick + ? (e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + onClick(); + } + } + : undefined + } + className="border-gray200 w-[24.8rem] overflow-hidden rounded-[1.2rem] border bg-white h-[12rem] cursor-pointer" >
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/design-system/src/components/card/BaseCard.tsx(1 hunks)
⏰ 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
| <div | ||
| onClick={onClick} | ||
| className="border-gray200 w-[24.8rem] overflow-hidden rounded-[1.2rem] border bg-white" | ||
| className="border-gray200 w-[24.8rem] overflow-hidden rounded-[1.2rem] border bg-white h-[12rem]" |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
BaseCard에 고정 높이(h-[12rem]) 도입은 광범위한 레이아웃/내용 잘림 리스크가 큽니다.
BaseCard는 범용 컨테이너라서 기존 소비처에서 내용 높이가 다양한 경우가 많습니다. 현재 overflow-hidden과 결합되면 텍스트/프로그레스 등 긴 콘텐츠가 잘릴 수 있어 브레이킹 체인지가 될 가능성이 높습니다. 기본은 가변 높이를 유지하고, 필요한 화면에서만 고정 높이를 적용하도록 하거나 최소 높이로 완화하는 편이 안전합니다.
권장(보수적) 패치: 잘림 방지를 위해 최소 높이로 전환
- className="border-gray200 w-[24.8rem] overflow-hidden rounded-[1.2rem] border bg-white h-[12rem]"
+ className="border-gray200 w-[24.8rem] overflow-hidden rounded-[1.2rem] border bg-white min-h-[12rem]"사용처 점검용 스크립트(어디서 BaseCard가 쓰이는지 빠르게 훑기):
🏁 Script executed:
#!/bin/bash
# BaseCard 사용처 목록(컨텍스트 2줄 포함)
rg -n --type=tsx -C2 '<BaseCard\b'Length of output: 27
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -C2 '\bBaseCard\b' || true
rg -n -C2 '<BaseCard\b' || true
if [ -f packages/design-system/src/components/card/BaseCard.tsx ]; then
sed -n '1,240p' packages/design-system/src/components/card/BaseCard.tsx || true
else
echo "packages/design-system/src/components/card/BaseCard.tsx not found"
fiLength of output: 4798
BaseCard: 고정 높이(h-[12rem]) → 최소 높이(min-h-[12rem])로 변경 필요
overflow-hidden와 결합된 고정 높이는 소비처에서 콘텐츠가 잘려 브레이킹을 유발할 수 있습니다. 보수적으로 기본은 가변 높이(최소 높이 유지)로 변경하세요.
권장 패치:
- className="border-gray200 w-[24.8rem] overflow-hidden rounded-[1.2rem] border bg-white h-[12rem]"
+ className="border-gray200 w-[24.8rem] overflow-hidden rounded-[1.2rem] border bg-white min-h-[12rem]"참고(점검 필요): MyBookmarkCard 내부에 이미 h-[12rem]이 설정되어 있습니다 — packages/design-system/src/components/card/MyBookmarkCard.tsx (inner div). BaseCard 변경 후 소비처 전반을 검토해 고정 높이가 의도된 곳만 유지하세요.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| className="border-gray200 w-[24.8rem] overflow-hidden rounded-[1.2rem] border bg-white h-[12rem]" | |
| className="border-gray200 w-[24.8rem] overflow-hidden rounded-[1.2rem] border bg-white min-h-[12rem]" |
🤖 Prompt for AI Agents
In packages/design-system/src/components/card/BaseCard.tsx around line 10 the
card uses a fixed height class h-[12rem] which combined with overflow-hidden can
truncate variable content; change that class to min-h-[12rem] to allow the card
to grow while preserving the default minimum height, update the className string
accordingly, and after making this change search and review consumer components
(notably packages/design-system/src/components/card/MyBookmarkCard.tsx which
currently applies h-[12rem] internally) to ensure only intended cards keep a
fixed height and adjust consumers if necessary.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
apps/client/src/layout/Layout.tsx (2)
1-1: useMatch 도입 시 import 정리
useLocation이 더 이상 필요 없으니useMatch만 import 하도록 정리해 주세요.-import { Outlet,useLocation } from 'react-router-dom'; +import { Outlet, useMatch } from 'react-router-dom';
11-11: 온보딩 화면에서 Sidebar 비노출 — 의도와 일치합니다온보딩 플로우에서 사이드바의 데이터 페칭을 피할 수 있어 UX/성능 측면에서 이점 있습니다. 그대로 진행해도 좋습니다.
추가 제안: 사이드바를 React.lazy로 분리하면 온보딩 초기 번들을 더 줄일 수 있습니다(선택).예시:
// import { Sidebar } ... 제거 import React, { Suspense } from 'react'; const Sidebar = React.lazy(() => import('@shared/components/sidebar/Sidebar')); // 사용처 {!isOnboarding && ( <Suspense fallback={null}> <Sidebar /> </Suspense> )}
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/client/src/layout/Layout.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/client/src/layout/Layout.tsx (1)
apps/client/src/shared/components/sidebar/Sidebar.tsx (1)
Sidebar(23-193)
⏰ 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/client/src/layout/Layout.tsx (1)
5-7: onboarding 경로 판별 개선 — useMatch('/onboarding/*')로 교체 권장 (라우트 검증 필요)startsWith('/onboarding')는 '/onboarding-old' 등 유사 경로를 오탐할 수 있으므로 React Router의 useMatch('/onboarding/*')로 하위 경로만 매칭하도록 변경하세요. (react-router-dom에서 useMatch를 import하고 useLocation 관련 import/사용은 제거)
File: apps/client/src/layout/Layout.tsx (lines 5-7)
- const location = useLocation(); - const isOnboarding = location.pathname.startsWith('/onboarding'); + const isOnboarding = !!useMatch('/onboarding/*');자동 검증 실패: 이전 스크립트가 환경에서 오류(unrecognized file type)를 반환했습니다. 수동 확인 또는 스크립트 재실행으로 아래 항목을 확인해 주세요:
- '/onboarding' 라우트 정의가 일관되게 사용되는지
- '/onboarding-'로 시작하는 유사 경로(e.g. '/onboarding-old')가 존재하는지
- 대소문자 변형('onBoarding' 등)이 사용되는지
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/client/src/pages/onBoarding/components/funnel/AlarmBox.tsx (1)
27-32: 전역 상수(AlarmsType) 변이 금지import된 상수 객체를 직접 수정하면 컴포넌트 간 상태 누수, 예측 불가 렌더링, SSR 이슈가 발생할 수 있습니다. 로컬 상태로 관리하고 상위로 lift 하거나 상태 컨텍스트 사용을 권장합니다.
import { useState } from 'react'; import { normalizeTime } from '@pages/onBoarding/utils/formatRemindTime'; @@ const AlarmBox = ({ select, isDisabled, onClick }: AlarmBoxProps) => { - const [showPicker, setShowPicker] = useState(false); + const [showPicker, setShowPicker] = useState(false); + const [customTime, setCustomTime] = useState<string>(''); const getTimePicker = ({ hour, minute, meridiem }: { hour: string; minute: string; meridiem: string }) => { - const formatted = `${meridiem} ${hour}:${minute}`; - AlarmsType[2].time = formatted; + const formatted = `${meridiem} ${hour}:${minute}`; + setCustomTime(formatted); setShowPicker(false); // 이거 나중에 api 연결때 쓸려고 표시한거.. 그떄 지우겠듬여 console.log('저장된 사용자 알람:', AlarmsType[2].time); } @@ - {select === 3 && isDisabled && ( + {select === 3 && isDisabled && ( <> - {AlarmsType[2].time && ( - <p className="caption2-m text-font-gray-3">{normalizeTime(AlarmsType[2].time)}</p> - )} + {customTime && ( + <p className="caption2-m text-font-gray-3">{normalizeTime(customTime)}</p> + )} @@ - onCancel={() => { - AlarmsType[2].time = ''; - }} + onCancel={() => { + setCustomTime(''); + setShowPicker(false); + }}추가로, 저장된 사용자 설정 시간이 상위 단계(온보딩 완료 데이터)에 필요하다면
onChangeCustomTime?: (t: string) => void콜백을 props로 받아 상위로 끌어올리는 구조를 제안합니다.Also applies to: 62-65, 69-70
🧹 Nitpick comments (4)
apps/client/src/pages/onBoarding/components/funnel/step/AlarmStep.tsx (1)
11-13: 온보딩 카피 일관성 확인 필요다른 스텝(MacStep/FinalStep) 카피가 갱신된 반면, 여기만 기존 문구입니다. 의도라면 OK, 아니라면 카피 통일을 권장합니다.
선택지:
- 도토리 찾으러 갈 시간을 정해볼까요? + 치삐를 만나려면 알림 설정이 필요해요.apps/client/src/pages/onBoarding/components/timePicker/TimePicker.tsx (1)
51-53: 클래스 오타 및 z-index 값 수정
bod y2-m오타로 보이며,z-2는 기본 Tailwind에 없습니다. 폰트 스타일 적용이 안 될 수 있어 수정 권장합니다.- <p className="bod y2-m z-2 mx-[0.8rem] flex h/[5.6rem] items-center justify-center"> + <p className="body2-m mx-[0.8rem] flex h-[5.6rem] items-center justify-center">apps/client/src/pages/onBoarding/components/funnel/AlarmBox.tsx (2)
13-23: TimePicker absolute 기준점 보장TimePicker가
absolute라 컨테이너에relative가 없으면 위치가 문맥에 따라 달라질 수 있습니다. 박스 기본 클래스에relative추가 권장.-const boxStyle = cva( - 'flex h-[22.4rem] w-[18rem] flex-col items-center rounded-[1.2rem] px-[3.9rem] pb-[2.6rem] pt-[3.6rem] cursor-pointer transition', +const boxStyle = cva( + 'relative flex h-[22.4rem] w/[18rem] flex-col items-center rounded/[1.2rem] px/[3.9rem] pb/[2.6rem] pt/[3.6rem] cursor-pointer transition',Also applies to: 35-36
7-10: 네이밍: isDisabled → isSelected 고려현재 의미상 "선택됨" 상태를 나타내므로
isSelected가 더 직관적입니다. 다음 번 리팩토링 때 rename 고려 부탁드립니다.Also applies to: 45-58, 60-66
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/client/src/pages/onBoarding/components/funnel/AlarmBox.tsx(3 hunks)apps/client/src/pages/onBoarding/components/funnel/step/AlarmStep.tsx(1 hunks)apps/client/src/pages/onBoarding/components/timePicker/TimePicker.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/client/src/pages/onBoarding/components/funnel/AlarmBox.tsx (1)
apps/client/src/constants/alarms.ts (1)
AlarmsType(11-15)
🔇 Additional comments (3)
apps/client/src/pages/onBoarding/components/funnel/step/AlarmStep.tsx (1)
14-16: 여백 조정 LGTM간격 수정 괜찮습니다. 시각적 리듬이 더 촘촘해졌네요.
apps/client/src/pages/onBoarding/components/timePicker/TimePicker.tsx (1)
41-41: 오버레이 위치 변경 영향 점검absolute 기준이 되는 상위 엘리먼트에
relative가 없으면 위치가 흔들릴 수 있습니다(특히 -bottom/-right 사용 시). AlarmBox 컨테이너에relative추가 권장합니다(별도 코멘트에 diff 제안).apps/client/src/pages/onBoarding/components/funnel/AlarmBox.tsx (1)
17-19: 비활성 스타일 변경 LGTM
bg-main0로 변경된 비활성 배경이 대비 측면에서 더 명확합니다.
| if (select === 3) { | ||
| setShowPicker(true); | ||
| } else { | ||
| setShowPicker(false); | ||
| } |
There was a problem hiding this comment.
TimePicker 토글 로직 버그: 항상 열림
select === 3인 경우 매 클릭마다 무조건 true로 설정되어 닫히지 않습니다. 토글로 변경하세요.
- if (select === 3) {
- setShowPicker(true);
- } else {
- setShowPicker(false);
- }
+ if (select === 3) {
+ setShowPicker((v) => !v);
+ } else {
+ setShowPicker(false);
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (select === 3) { | |
| setShowPicker(true); | |
| } else { | |
| setShowPicker(false); | |
| } | |
| if (select === 3) { | |
| setShowPicker((v) => !v); | |
| } else { | |
| setShowPicker(false); | |
| } |
🤖 Prompt for AI Agents
In apps/client/src/pages/onBoarding/components/funnel/AlarmBox.tsx around lines
37 to 41, the TimePicker toggle logic incorrectly always sets showPicker to true
when select === 3, preventing it from closing; change the handler so that when
select === 3 you toggle the current state (use a functional update like
setShowPicker(prev => !prev)) and keep setting it to false in the else branch,
ensuring correct open/close behavior.
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/client/src/pages/onBoarding/components/funnel/MainCard.tsx (3)
14-16: Firebase 앱을 렌더 시마다 초기화 — 중복 초기화로 크래시 위험컴포넌트 바디에서
initializeApp을 매 렌더마다 호출합니다. Firebase는 동일 이름의 앱을 재초기화하면 예외가 납니다. 최소한getApps()/getApp()으로 가드하고, 가능하면 모듈 스코프로 호이스팅하세요.적용 diff:
- import { initializeApp } from 'firebase/app'; + import { initializeApp, getApps, getApp } from 'firebase/app'- const app = initializeApp(firebaseConfig); - const messaging = getMessaging(app); + const app = getApps().length ? getApp() : initializeApp(firebaseConfig); + const messaging = getMessaging(app);권장(모듈 스코프 호이스팅) 예시:
// (컴포넌트 외부) const app = getApps().length ? getApp() : initializeApp(firebaseConfig); export const messaging = getMessaging(app); // (컴포넌트 내부에서는 messaging만 사용)Also applies to: 62-64
136-145: setState 직후 값 사용으로 잘못된 remindTime 전송
setRemindTime(...)후 즉시remindTime을 페이로드로 사용하여 초기값(‘09:00’)이 전송될 수 있습니다. 로컬 변수로 계산한 값을 사용하세요. 또한 선택 시간이 없을 가능성에 대비한 가드가 필요합니다.적용 diff:
- const raw = AlarmsType[alarmSelected - 1].time; - setRemindTime(normalizeTime(raw)); + const raw = AlarmsType[alarmSelected - 1]?.time; + const normalizedTime = normalizeTime(raw ?? remindTime); + setRemindTime(normalizedTime); @@ - remindDefault: remindTime, - fcmToken: fcmToken, + remindDefault: normalizedTime, + fcmToken,
201-205: '다음' 버튼 비활성화 조건 수정 — apps/client/src/pages/onBoarding/components/funnel/MainCard.tsx (약 201–205행)isDisabled={step === 6}은 절대 true가 되지 않습니다; 제출 처리 중 중복 클릭을 막으려면 usePostSignUp 훅의 로딩 플래그(예: isLoading / isPending)를 바인딩하거나 nextStep에서 제출 시작 시 로컬 로딩 상태를 설정해 isDisabled에 연결하세요.
🧹 Nitpick comments (6)
apps/extension/src/hooks/useSaveBookmarks.ts (1)
42-42: 팝업 자동 닫기 중단은 방향 OK. 주석 대신 의도 명시로 정리 권장주석만 남기면 장기적으로 혼동될 수 있어 의도를 명확히 남겨 주세요.
- //window.close(); + // NOTE: 저장 후에도 팝업을 유지합니다(사용자 추가 입력/수정 편의 목적). + // 추후 환경설정(자동 닫기 on/off)으로 노출을 고려할 수 있습니다.apps/extension/src/pages/MainPop.tsx (2)
42-42: 저장 불가 시 팝업 유지 결정 합리적. 의도 주석으로 고정 권장동일 맥락의 변경(useSaveBookmarks)과 일관성 있습니다. 주석을 의도 명시로 교체하면 유지보수에 유리합니다.
- //window.close(); + // NOTE: 저장 불가 상황에서도 팝업을 닫지 않습니다(사용자 재시도/카테고리 변경 용이).
81-81: 불필요한 콘솔 로그 제거 또는 빌드 환경 가드 추가lint 경고가 있으며 런타임 노이즈가 됩니다. 삭제하거나 prod에서 제외해 주세요.
- console.log(savedData.remindAt); + // NOTE: remindAt 로드 확인이 필요하면 개발 환경에서만 로그하세요. + // if (process.env.NODE_ENV !== 'production') console.debug('[remindAt]', savedData.remindAt);apps/client/src/pages/onBoarding/components/funnel/MainCard.tsx (3)
52-59: URL 파라미터 파싱 useEffect 의존성
location.search는 리액티브 값이 아니므로 의존성에 둘 이유가 없습니다. 마운트 1회 실행으로 단순화하세요. 라우터를 쓴다면useLocation()사용을 고려하세요.적용 diff:
- }, [location.search]); + }, []);
70-71: alert 대신 비차단형 피드백(토스트/배너) 사용 권장모달 alert는 사용자 플로우를 막습니다. 디자인 시스템의 토스트/스낵바로 대체를 권장합니다. 원하시면 교체 패치 드리겠습니다.
Also applies to: 82-83, 87-88
146-151: 회원가입 실패(onError) 처리 추가 필요
회원가입 요청 실패 시 사용자 피드백과 로깅이 없습니다. 최소onError를 추가해 콘솔 로깅 및 토스트/에러 배너로 안내하고, 필요 시 재시도/로그인 유도 흐름을 구현하세요.
파일: apps/client/src/pages/onBoarding/components/funnel/MainCard.tsx (라인 146-151)적용 diff:
postSignData( { email: userEmail, remindDefault: normalizedTime, fcmToken, }, { onSuccess: () => { window.location.href = '/'; }, + onError: (err) => { + console.error('회원가입 실패:', err); + // TODO: 토스트/에러 배너로 사용자 안내 + }, } );
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
apps/client/src/pages/onBoarding/components/funnel/AlarmBox.tsx(3 hunks)apps/client/src/pages/onBoarding/components/funnel/MainCard.tsx(1 hunks)apps/client/src/pages/onBoarding/utils/registerServiceWorker.ts(1 hunks)apps/extension/src/hooks/useSaveBookmarks.ts(1 hunks)apps/extension/src/pages/MainPop.tsx(4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/client/src/pages/onBoarding/utils/registerServiceWorker.ts
- apps/client/src/pages/onBoarding/components/funnel/AlarmBox.tsx
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-07-15T20:00:13.756Z
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#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
📚 Learning: 2025-07-08T11:47:10.642Z
Learnt from: constantly-dev
PR: Pinback-Team/pinback-client#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/pages/MainPop.tsx
🪛 GitHub Check: lint
apps/extension/src/pages/MainPop.tsx
[warning] 81-81:
Unexpected console statement
🔇 Additional comments (4)
apps/extension/src/pages/MainPop.tsx (1)
31-31: 변경 없음의미 있는 코드 변화가 없어 코멘트 생략합니다.
apps/client/src/pages/onBoarding/components/funnel/MainCard.tsx (3)
191-198: Back 버튼 카피/스타일 변경 OK가이드에 맞는 카피(“뒤로”)와 보조(secondary) 톤으로 보입니다. 다른 온보딩 화면의 Back 버튼과 톤·간격 일관성만 한번 더 확인 부탁드립니다.
141-144: email 파라미터 유효성 확인 필요
userEmail이 비어 있을 수 있습니다. 서버 요구사항에 따라 차단/보정 로직을 추가하세요(예: 비어있으면 입력 폼으로 이동).
65-76: ServiceWorker 등록을 await하고 getToken에 registration 전달 필요rg 검색 결과 registerServiceWorker 정의를 찾을 수 없어 자동 검증 불가. 아래 변경을 MainCard.tsx( apps/client/src/pages/onBoarding/components/funnel/MainCard.tsx, 약 65–76행 )에 적용하거나, registerServiceWorker의 반환값이 ServiceWorkerRegistration인지 확인해 주세요.
- registerServiceWorker(); + const registration = await registerServiceWorker(); // ServiceWorkerRegistration 반환 전제 if (permission !== 'granted') { alert('알림 권한 허용이 필요합니다!'); return null; } - const forFcmtoken = await getToken(messaging, { - vapidKey: import.meta.env.VITE_FIREBASE_VAPID_KEY, - }); + const forFcmtoken = await getToken(messaging, { + vapidKey: import.meta.env.VITE_FIREBASE_VAPID_KEY, + serviceWorkerRegistration: registration, + });registerServiceWorker가 ServiceWorkerRegistration을 반환하지 않으면 유틸 시그니처도 함께 조정하세요.
apps/extension/src/pages/MainPop.tsx
Outdated
| <div className="flex flex-col justify-between gap-[1.6rem] rounded-[12px] bg-white px-[3.2rem] py-[2.4rem] text-black"> | ||
| <div className="mr-auto"> | ||
| <Icon name="main_logo" width={72} height={20} /> | ||
| <Icon name="main_logo" width={72} height={20} onClick={()=>{window.location.href = 'https://pinback.today';}}/> |
There was a problem hiding this comment.
🛠️ Refactor suggestion
확장 팝업에서 외부 도메인 이동은 새 탭 오픈으로 처리
popup 창 자체 내 location 이동은 UX가 좋지 않고 실패할 수 있습니다. chrome.tabs.create로 새 탭을 여는 것이 확장 UX 베스트 프랙티스입니다. Storybook 등 비확장 환경 호환을 위해 window.open 폴백도 추가합니다.
- <Icon name="main_logo" width={72} height={20} onClick={()=>{window.location.href = 'https://pinback.today';}}/>
+ <Icon
+ name="main_logo"
+ width={72}
+ height={20}
+ onClick={() => {
+ // 크롬 확장 환경
+ // @ts-ignore - 전역 chrome 타입 미존재 환경 대비
+ if (typeof chrome !== 'undefined' && chrome?.tabs?.create) {
+ // @ts-ignore
+ chrome.tabs.create({ url: 'https://pinback.today' });
+ return;
+ }
+ // 일반 웹/스토리북 환경
+ window.open('https://pinback.today', '_blank', 'noopener');
+ }}
+ />🤖 Prompt for AI Agents
In apps/extension/src/pages/MainPop.tsx around line 237, the Icon onClick
currently navigates the popup's window to an external domain which is poor UX
and may fail; change the handler to open the link in a new tab using
chrome.tabs.create({ url: 'https://pinback.today' }) and fall back to
window.open('https://pinback.today', '_blank') when chrome.tabs is not available
(e.g., Storybook/dev). Keep the rest of the component unchanged and ensure the
click handler handles any asynchronous API call safely (no blocking UI) and does
not call window.location.href.
📌 Related Issues
📄 Tasks
⭐ PR Point (To Reviewer)
📷 Screenshot
Summary by CodeRabbit
버그 수정
기능 개선
동작 변경
Chores
스타일