-
Notifications
You must be signed in to change notification settings - Fork 0
feat: 토스트 팝업을 구현한다 #65
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
Caution Review failedThe pull request is closed. Walkthrough전역 Toaster(sonner)와 next-themes 도입 및 App에 Toaster 배치. 여러 페이지/위젯에 성공/검증 토스트 호출 추가와 레이아웃/스타일 조정, 그리고 Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant App
participant Toaster as Toaster(전역)
participant Page as Page/Widget
participant Sonner as SonnerUI
App->>Toaster: Toaster 렌더링
Note right of Toaster: next-themes로 theme 전달
Page->>Sonner: toast.success("...") 호출
Sonner-->>Page: 토스트 표시
sequenceDiagram
autonumber
participant Page
participant MobileLayout
participant Body
Page->>MobileLayout: bodyVariant="gray"
MobileLayout->>Body: 클래스/스타일 조합 적용 (overflow-auto 포함)
Note right of Body: 배경/스크롤/패딩 변형 적용
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. 📒 Files selected for processing (2)
✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 13
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/pages/subscriptions/SubscriptionEditPage.tsx (1)
61-63: ID 가드 조건 오류: 0도 배제됨
!subscriptionId는0을 잘못된 값으로 취급합니다. 유효성 검사는 NaN 여부로 한정하세요.적용 diff:
- if (!subscriptionId) return; + if (!Number.isFinite(subscriptionId)) return;src/pages/comparison/ComparisonPage.tsx (1)
88-95: 선택 항목이 없을 때 ‘삭제되었습니다’ 노출 방지실제로 삭제된 경우에만 토스트를 띄우세요. 삭제 개수도 함께 알려주면 더 명확합니다.
적용 diff:
const handleDeleteSubs = () => { const filteredIds = addedSubs .filter(s => selectedSubs.includes(s.productId)) .map(s => s.productId); setAddedSubs(prev => prev.filter(s => !filteredIds.includes(s.productId))); setSelectedSubs([]); - toast.success('삭제되었습니다'); + if (filteredIds.length > 0) { + toast.success(`${filteredIds.length}개 삭제되었습니다`); + } };
🧹 Nitpick comments (14)
src/widgets/comparison-section/ui/ComparisonAddedSection.tsx (1)
39-39: 그리드 중앙 정렬이 홀수 개 카드에서 의도한 레이아웃인지 확인place-content-center/justify-items-center로 카드가 홀수일 때도 가운데 정렬됩니다. 좌측 정렬이 더 자연스러워야 한다면 조건부 클래스(아이템 없을 때만 센터) 또는 -mx 보정으로 여백만 조정하는 방식을 고려하세요.
src/widgets/subscription-detail/ui/SubscriptionDetailWidget.tsx (1)
3-3: 토스트를 네비게이션 전에 호출해 표시 안정성 확보navigate 직후 컴포넌트 언마운트 타이밍에 따라 토스트가 놓칠 수 있습니다. 성공 토스트를 먼저 띄우고 이동하는 순서가 안전합니다. 에러 시에도 toast.error 노출을 권장합니다.
- navigate('/subscriptions'); - toast.success('삭제되었습니다'); + toast.success('삭제되었습니다'); + navigate('/subscriptions');에러 처리 예시(참고):
} catch (error) { toast.error('삭제에 실패했어요. 잠시 후 다시 시도해 주세요.'); console.error('구독 삭제 실패:', error); }Also applies to: 47-47
src/widgets/subscription-register/SubscriptionRegisterWidget.tsx (1)
5-5: 등록 성공 토스트를 네비게이션 이전에 호출페이지 이동 후에도 Toaster가 유지되더라도, 선 토스트·후 네비게이션 순서가 사용자 체감상 더 안정적입니다. 실패 케이스에도 toast.error를 추가하면 일관성이 좋아집니다.
- navigate('/subscriptions'); - toast.success('등록되었습니다'); + toast.success('등록되었습니다'); + navigate('/subscriptions');에러 처리 예시(참고):
} catch (error) { toast.error('등록에 실패했어요. 잠시 후 다시 시도해 주세요.'); console.error('구독 등록 실패:', error); }Also applies to: 68-69
src/widgets/payment-summary/ui/PaymentSummaryBlock.tsx (1)
35-35: -m-5는 수직 여백 충돌 소지 있음: 수평만 음수 마진 권장수직(-my-5)까지 포함되는 -m-5는 인접 섹션과 경계가 겹칠 수 있습니다. 의도가 컨테이너 좌우 폭 확장이라면 -mx-5만 사용하세요.
- <div className="py-3 -m-5 px-5 bg-white"> + <div className="py-3 -mx-5 px-5 bg-white">src/pages/my/MyPage.tsx (1)
75-76: 헤더 로고 접근성/탭 이동 개선 및 CLS 감소
- 로고를 홈으로 이동하는 링크로 감싸면 UX가 좋아집니다.
- alt는 의미 있는 텍스트(브랜드명)를 사용하세요.
- width/height/decoding 추가로 CLS를 줄일 수 있습니다.
적용 diff:
- leftSlot: <img src={Logo} alt="Logo" className="h-7" />, + leftSlot: ( + <Link to={ROUTES.HOME} aria-label="홈으로 이동"> + <img + src={Logo} + alt="브랜드 로고" + className="h-7 w-auto" + decoding="async" + width="28" + height="28" + /> + </Link> + ),파일 상단에 Link import도 추가하세요:
import { Link } from 'react-router-dom';src/pages/subscriptions/SubscriptionEditPage.tsx (1)
86-91: 에러/로딩 토스트도 함께 처리 권장실패/진행중 상태에 대한 피드백이 없습니다.
toast.promise를 활용하면 간결하게 처리됩니다.예시:
await toast.promise( updateSubscriptionMutation.mutateAsync({ subscriptionId, ...payload }), { loading: '수정 중…', success: '수정되었습니다', error: '수정에 실패했습니다', }, ); navigate(`/subscriptions/${subscriptionId}`);src/pages/comparison/ComparisonAddPage.tsx (2)
49-49: 토스트 시점 재조정 제안(안정성)라우트 전환 환경에 따라 토스터 마운트 타이밍 이슈가 있을 수 있으니, 토스트를 먼저 띄우고 내비게이션을 권장합니다.
적용 diff:
- navigate(`/comparison?category=${category}`, { - replace: true, - state: { newSubs: selectedSubs, category }, - }); - toast.success('추가되었습니다'); + toast.success('추가되었습니다'); + navigate(`/comparison?category=${category}`, { + replace: true, + state: { newSubs: selectedSubs, category }, + });
51-55: 스크롤 유틸 재사용으로 일관성 확보다른 페이지에서 사용하는
scrollToTop유틸을 재사용하면 일관됩니다.적용 diff:
- // 페이지 로드 시 스크롤을 맨 위로 이동 - useEffect(() => { - window.scrollTo(0, 0); - }, []); + // 페이지 로드 시 스크롤을 맨 위로 이동 + useEffect(() => { + scrollToTop(); + }, []);상단에 import 추가:
import { scrollToTop } from '@/shared/lib/scroll';src/widgets/subscription-list/ui/SubscriptionsSection.tsx (1)
159-163: radiogroup 접근성 속성 보강(선택 사항)명시적으로
aria-orientation="horizontal"을 넣으면 보조기기가 더 잘 해석합니다.적용 diff:
- <div + <div role="radiogroup" aria-label="보기 선택" + aria-orientation="horizontal" className="flex gap-3 py-3 bg-white rounded-b-3xl -mx-5 px-5" >src/pages/comparison/ComparisonPage.tsx (1)
126-126: 주석된 UI 잔재 정리
rightSlot주석은 제거해 코드 노이즈를 줄이세요. 필요 시 Git 히스토리로 충분히 추적 가능합니다.src/widgets/comparison-section/ui/ComparisonResultSection.tsx (1)
174-176: 리스트 key에 index 사용 지양.중복/순서 변경 시 DOM 재사용 이슈가 생깁니다. 값 기반의 안정적인 key를 구성하세요. 값이 중복될 수 있다면
index를 접두/접미로 보조적으로만 사용하세요.예시:
- <li key={index} className="whitespace-pre-wrap"> + <li key={`${p.id}-${key}-${index}`} className="whitespace-pre-wrap">src/pages/my/EmailEditPage.tsx (1)
55-60: Input 제어/접근성 보완(타입, 값 바인딩, 자동완성).
value를 바인딩해 완전 제어 컴포넌트로 유지type="email",autoComplete="email",inputMode="email"지정적용 diff:
- <Input + <Input + type="email" + value={email} placeholder="이메일을 입력해주세요" onChange={handleInputChange} - aria-invalid={isDisabled && email.length > 0} + autoComplete="email" + inputMode="email" + aria-invalid={!validateEmail(email) && email.length > 0} className={`focus:ring-0 transition-colors duration-200 ${isDisabled ? 'focus:border-primary-700' : ''}`} />src/pages/subscriptions/SubscriptionPage.tsx (1)
13-16: 배경색 중복 지정 가능성 —bodyVariant="gray"와 내부bg-gray-50중 하나로 일원화.중복 스타일은 유지보수 부담을 키웁니다.
MobileLayout변수를 신뢰하고 내부 배경은 제거하는 쪽을 권장합니다.적용 diff:
> - <div className="min-h-full bg-gray-50 relative max-w-md "> + <div className="min-h-full relative max-w-md">src/shared/ui/layout/MobileLayout.tsx (1)
46-46: 불필요한 공백 제거
className="col-span-6 "끝의 공백 제거를 권장합니다.- <div className="col-span-6 ">{children ?? <Outlet />}</div> + <div className="col-span-6">{children ?? <Outlet />}</div>
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (17)
package.json(1 hunks)src/app/App.tsx(2 hunks)src/pages/comparison/ComparisonAddPage.tsx(2 hunks)src/pages/comparison/ComparisonPage.tsx(3 hunks)src/pages/my/EmailEditPage.tsx(2 hunks)src/pages/my/MyPage.tsx(2 hunks)src/pages/subscriptions/BenefitDetailPage.tsx(4 hunks)src/pages/subscriptions/SubscriptionEditPage.tsx(2 hunks)src/pages/subscriptions/SubscriptionPage.tsx(1 hunks)src/shared/ui/layout/MobileLayout.tsx(1 hunks)src/shared/ui/toast/Toaster.tsx(1 hunks)src/widgets/comparison-section/ui/ComparisonAddedSection.tsx(2 hunks)src/widgets/comparison-section/ui/ComparisonResultSection.tsx(1 hunks)src/widgets/payment-summary/ui/PaymentSummaryBlock.tsx(1 hunks)src/widgets/subscription-detail/ui/SubscriptionDetailWidget.tsx(2 hunks)src/widgets/subscription-list/ui/SubscriptionsSection.tsx(4 hunks)src/widgets/subscription-register/SubscriptionRegisterWidget.tsx(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
src/app/App.tsx (1)
src/shared/ui/toast/Toaster.tsx (1)
Toaster(28-28)
src/pages/my/MyPage.tsx (1)
src/shared/assets/images/index.ts (1)
Logo(32-32)
src/shared/ui/layout/MobileLayout.tsx (1)
src/shared/lib/utils.ts (1)
cn(8-10)
src/pages/my/EmailEditPage.tsx (1)
src/entities/member/hooks/useMyInfo.ts (2)
useMyInfo(5-12)useUpdateMyInfo(15-29)
src/pages/subscriptions/BenefitDetailPage.tsx (1)
src/shared/lib/utils.ts (1)
cn(8-10)
🔇 Additional comments (5)
src/widgets/comparison-section/ui/ComparisonAddedSection.tsx (1)
54-54: LGTM: 버튼 콘텐츠 수직 정렬 보강items-center 추가로 플러스 버튼 내 정렬이 개선되었습니다.
src/pages/my/MyPage.tsx (1)
11-11: Logo는 named export로 제공됩니다. import 구문이 올바르므로 추가 조치 필요 없습니다.
(src/shared/assets/images/index.ts의export { Logo };확인 완료)src/pages/subscriptions/SubscriptionEditPage.tsx (1)
85-85: 성공 토스트 추가는 적절합니다내비게이션 직후 성공 피드백 제공 흐름이 자연스럽습니다.
src/shared/ui/layout/MobileLayout.tsx (1)
33-34: 클래스 순서 재배치: 기능 변화 없음스타일 의미 변화 없고 안전합니다.
src/pages/subscriptions/BenefitDetailPage.tsx (1)
96-96: bodyVariant 적용 적절회색 배경 바디로 전환 의도대로 보입니다. 다른 섹션들의 배경 대비도 함께 조정되어 일관성 있습니다.
| "next-themes": "^0.4.6", | ||
| "qs": "^6.14.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Vite SPA에서 next-themes 사용 적합성·초기화 확인 필요
이 프로젝트는 Vite + react-router-dom 기반으로 보입니다. next-themes는 주로 Next.js를 타깃으로 하지만 SPA에서도 동작은 합니다. 다만 ThemeProvider 초기화, attribute(class/data-theme) 전략, 시스템 테마 연동(useSystemTheme) 등이 올바르게 설정되어 있어야 sonner Toaster의 theme 연동이 안정적으로 작동합니다. App 루트에 ThemeProvider가 1회만 래핑되어 있는지, Toaster가 단일 인스턴스로 배치되어 있는지 확인 부탁드립니다.
아래 스크립트로 대략적인 통합 상태를 점검할 수 있습니다.
Also applies to: 37-37
🏁 Script executed:
#!/bin/bash
# ThemeProvider/Toaster 통합 확인
set -euo pipefail
echo "== next-themes import 위치 =="
rg -nP "from ['\"]next-themes['\"]" -C2
echo "== ThemeProvider 사용 위치 =="
rg -nP "\bThemeProvider\b" -C3
echo "== Toaster 컴포넌트 및 사용 위치 =="
rg -nP "export.+Toaster|from ['\"]/.*shared/ui/toast/Toaster['\"]" -n -C2
echo "== Toaster 다중 마운트 여부(대략) =="
rg -nP "<Toaster\b" -n -C2Length of output: 437
App 루트에 next-themes ThemeProvider 추가 필요
src/shared/ui/toast/Toaster.tsx에서 useTheme 훅만 import되고 ThemeProvider 사용이 전혀 검출되지 않습니다. App 진입점(e.g. src/App.tsx)에 단일 ThemeProvider를 래핑하고, Toaster가 한 번만 마운트되도록 배치해주세요.
🤖 Prompt for AI Agents
package.json around lines 30-31: The app is using next-themes but no
ThemeProvider is mounted; update the app entry (e.g. src/App.tsx or
src/pages/_app.tsx) to import { ThemeProvider } from 'next-themes' and wrap the
entire application with a single ThemeProvider at the root, moving any
theme-related hook usage (useTheme) inside components but not providing another
provider; also ensure the Toaster component from src/shared/ui/toast/Toaster.tsx
is mounted exactly once at the root (inside the ThemeProvider or directly under
it) rather than in many child components so it renders once for the whole app.
| <QueryClientProvider client={queryClient}> | ||
| <BrowserRouter> | ||
| <AppRouter /> | ||
| <Toaster position="top-center" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
❓ Verification inconclusive
전역 Toaster 위치 적절 — 테마 Provider 존재 여부만 확인해 주세요.
Toaster는 정상 배치되었습니다. 단, next-themes의 ThemeProvider가 최상위에 없으면 테마 전환이 반영되지 않습니다.
앱 루트에 ThemeProvider가 있는지 확인:
🏁 Script executed:
#!/bin/bash
# next-themes ThemeProvider 사용 위치 확인
rg -nP -C2 "(ThemeProvider).*from 'next-themes'|from \"next-themes\"" --type ts --type tsxLength of output: 124
🏁 Script executed:
#!/bin/bash
# next-themes ThemeProvider 사용 위치 재확인 (확장자 필터 없이 .ts/.tsx 전체 검색)
rg -nP "import\s+\{[^}]*ThemeProvider[^}]*\}\s+from\s+['\"]next-themes['\"]" -g "*.ts" -g "*.tsx"Length of output: 103
앱 루트에 next-themes ThemeProvider 추가 필요
코드베이스에서 next-themes의 ThemeProvider import/사용을 찾을 수 없습니다. Toaster가 테마 전환을 반영하려면 최상위 컴포넌트(App)에서 ThemeProvider로 전체를 래핑하세요.
🤖 Prompt for AI Agents
In src/app/App.tsx around line 31, the app root is not wrapped with next-themes'
ThemeProvider so the Toaster won't reflect theme changes; import ThemeProvider
from 'next-themes' and wrap the top-level JSX (the App component return) with
<ThemeProvider> (use attribute="class" and enableSystem as appropriate for the
project) so the entire app including <Toaster /> is inside the provider; ensure
the ThemeProvider import is added at the top of the file and remove any
duplicate providers if present.
#️⃣ 연관된 이슈 (선택)
📝 작업 내용
💬 리뷰 요구사항(선택)
Summary by CodeRabbit