[Feature/#233] 플랫폼 연동 페이지 UI 구현#234
Conversation
📝 WalkthroughWalkthrough플랫폼 연동 화면을 추가했습니다: 타입·매핑 유틸·훅·목, 카드·스켈레톤·예정 카드 UI, 사이드바 배지, 라우트 및 레이아웃 연동을 통해 연결 현황을 조회·표시하고 상태별 액션을 제공합니다. Changes플랫폼 연동 기능 전체 흐름
Sequence DiagramsequenceDiagram
participant Page as PlatformIntegrationsPage
participant Hook as usePlatformConnections
participant MockAPI as platformAccountsApiMock
participant Mapper as mapPlatformAccountsToConnections
participant Card as PlatformIntegrationCard
Page->>Hook: usePlatformConnections(orgId)
Hook->>MockAPI: fetch mock data (800ms delay)
MockAPI-->>Hook: IPlatformAccountApi[]
Hook->>Mapper: mapPlatformAccountsToConnections(accounts)
Mapper-->>Hook: IPlatformConnectionItem[]
Hook-->>Page: platformConnections
Page->>Card: render each connection with callbacks
Card-->>Page: onConnect/onReconnect/onDisconnect events (toast)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
📋 리뷰 포인트
요약: 전체 흐름은 명확히 구성되어 있으며, 안정성(날짜 파싱·폴백), 접근성(aria-live/label), 방어 코드와 테스트 보강에 집중하면 좋습니다. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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 배포 완료
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/pages/integration/PlatformIntegrationsPage.tsx (1)
9-14: ⚡ Quick win에러 상태에서 즉시 재시도 액션을 추가해 주세요.
현재는 실패 메시지만 보여서 사용자가 복구를 위해 페이지를 벗어나야 합니다.
refetch를 노출해서 에러 영역에다시 시도버튼을 두면 UX가 좋아집니다.제안 diff
export default function PlatformIntegrationsPage() { const { data: platformConnections = [], isLoading, isError, error, + refetch, } = usePlatformConnections(); @@ ) : isError ? ( <div className="flex min-h-40 items-center justify-center rounded-3xl bg-surface-100 p-8 shadow-Soft"> - <p className="text-center font-body2 text-text-muted"> - {error?.message ?? - "플랫폼 연동 정보를 불러오지 못했습니다. 잠시 후 다시 시도해 주세요."} - </p> + <div className="flex flex-col items-center gap-3"> + <p className="text-center font-body2 text-text-muted"> + {error?.message ?? + "플랫폼 연동 정보를 불러오지 못했습니다. 잠시 후 다시 시도해 주세요."} + </p> + <button + type="button" + onClick={() => void refetch()} + className="rounded-xl border border-surface-300 px-4 py-2 font-body2 text-text-title hover:bg-surface-200" + > + 다시 시도 + </button> + </div> </div>As per coding guidelines
src/**:6. 에러 처리: API 실패 대응 및 사용자 피드백 적절성 검토.Also applies to: 20-26
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/integration/PlatformIntegrationsPage.tsx` around lines 9 - 14, The error UI in PlatformIntegrationsPage doesn't offer a retry; update the component to use the refetch function from usePlatformConnections (add refetch to the destructuring alongside data/isLoading/isError/error) and render a "다시 시도" button in the error branch that calls refetch when clicked; ensure the error block still displays a helpful message (using error) and disables the button while isLoading to prevent duplicate calls.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/sidebar/SidebarItem.tsx`:
- Around line 33-45: The collapsed-state rendering in SidebarItem currently
shows only the Icon with aria-hidden, which leaves the NavLink/button (rendered
elsewhere) without an accessible name; update the collapsed branch in the
content JSX so that when isCollapsed is true you add an accessible label (e.g.,
aria-label and optionally title) derived from item.label to the interactive
element that uses content (ensure the same label is applied when Icon exists or
is null), and keep aria-hidden on the decorative Icon; check NavLink/button
usages that consume content to ensure they forward the aria-label when
collapsed.
---
Nitpick comments:
In `@src/pages/integration/PlatformIntegrationsPage.tsx`:
- Around line 9-14: The error UI in PlatformIntegrationsPage doesn't offer a
retry; update the component to use the refetch function from
usePlatformConnections (add refetch to the destructuring alongside
data/isLoading/isError/error) and render a "다시 시도" button in the error branch
that calls refetch when clicked; ensure the error block still displays a helpful
message (using error) and disables the button while isLoading to prevent
duplicate calls.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 30ec8865-4f6e-4c5f-9b42-4ced4d53adee
⛔ Files ignored due to path filters (1)
src/assets/icon/sidebar/connect.svgis excluded by!**/*.svgand included bysrc/**
📒 Files selected for processing (11)
src/components/integration/PlatformIntegrationCard.tsxsrc/components/integration/skeleton/PlatformIntegrationsSkeleton.tsxsrc/components/sidebar/Sidebar.tsxsrc/components/sidebar/SidebarItem.tsxsrc/constants/sidebarNav.tssrc/hooks/integration/usePlatformConnections.tssrc/layout/main/MainLayout.tsxsrc/pages/integration/PlatformIntegrationsPage.tsxsrc/pages/integration/platformIntegrations.mock.tssrc/routes/MainRoutes.tsxsrc/types/integration/platformConnection.ts
|
P3: 혹시 지금 페이지 아래에는 비어있는듯한 느낌이 들어서, 플랫폼을 세로로 flex로 배치하고, 재연동/연결해제/연동하기 버튼들을 우측에 맞춰서 flex로 넣으면 어떨까요? |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/integration/UpcomingPlatformCard.tsx`:
- Around line 26-27: The UpcomingPlatformCard component currently sets the prop
default disabled = true which causes the interactive control (the button
rendered in the component—see the Button / <button> usage around the block that
starts at Line 61) to always be disabled; update UpcomingPlatformCard to honor
the incoming disabled prop by removing or changing the hard-coded true and
passing the component's disabled prop down to the rendered button (or using
disabled={disabled} on the Button element) so the prop contract matches runtime
behavior.
In `@src/types/integration/platformConnection.ts`:
- Line 6: TPlatformAccountApiStatus is missing a syncing variant so the UI badge
never appears; add the corresponding API status (e.g., "SYNCING" or the exact
casing your backend emits) to the TPlatformAccountApiStatus union and update the
mapApiStatusToUi function to handle that new API value by returning "syncing"
(or the appropriate TPlatformConnectionStatus) so the UI branch is covered;
adjust any code that constructs API status strings to use the same casing to
keep types and runtime values consistent.
In `@src/utils/integration/mapPlatformAccounts.ts`:
- Around line 16-19: The parseDate function currently uses new Date(value),
which parses YYYY-MM-DD as UTC and can shift the date across timezones; update
parseDate to detect date-only strings (e.g., /^\d{4}-\d{2}-\d{2}$/) and
construct the Date via new Date(year, monthIndex, day) (using
Number(parsedYear), Number(parsedMonth)-1, Number(parsedDay)) to create a
local-midnight Date, preserving the intended calendar day; then ensure
isTokenExpired and isTokenExpiringSoon call the updated parseDate and perform
comparisons using getTime() (or Date objects) so mapApiStatusToUi uses correct
expiry decisions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 74383a45-a30e-4cec-9897-e2f123a131dd
📒 Files selected for processing (12)
src/components/integration/PlatformIntegrationCard.tsxsrc/components/integration/UpcomingPlatformCard.tsxsrc/components/integration/skeleton/PlatformIntegrationsSkeleton.tsxsrc/components/sidebar/Sidebar.tsxsrc/constants/sidebarNav.tssrc/hooks/integration/usePlatformConnections.tssrc/layout/main/MainLayout.tsxsrc/pages/integration/PlatformIntegrationsPage.tsxsrc/pages/integration/platformIntegrations.mock.tssrc/routes/MainRoutes.tsxsrc/types/integration/platformConnection.tssrc/utils/integration/mapPlatformAccounts.ts
🚧 Files skipped from review as they are similar to previous changes (6)
- src/layout/main/MainLayout.tsx
- src/components/sidebar/Sidebar.tsx
- src/routes/MainRoutes.tsx
- src/constants/sidebarNav.ts
- src/components/integration/skeleton/PlatformIntegrationsSkeleton.tsx
- src/pages/integration/PlatformIntegrationsPage.tsx
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/utils/integration/mapPlatformAccounts.ts (2)
69-98: ⚡ Quick winparseDate 실패 시 원본 문자열을 반환하면 invalid 값이 UI에 노출될 수 있습니다.
Lines 72, 92에서
parseDate실패 시 원본value를 그대로 반환하고 있습니다. 서버가 잘못된 날짜 형식을 보내는 경우, raw string이 UI에 표시될 수 있습니다. null을 반환하면PlatformConnectionMeta에서 해당 필드를 렌더링하지 않아 더 안전합니다.♻️ 제안 수정안
export function formatConnectionDateTime(value?: string): string | null { if (!value) return null; const date = parseDate(value); - if (!date) return value; + if (!date) return null; if (value.includes("T")) { return date.toLocaleString("ko-KR", { year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", }); } return date.toLocaleDateString("ko-KR", { year: "numeric", month: "2-digit", day: "2-digit", }); } export function formatConnectionDate(value?: string): string | null { if (!value) return null; const date = parseDate(value); - if (!date) return value; + if (!date) return null; return date.toLocaleDateString("ko-KR", { year: "numeric", month: "2-digit", day: "2-digit", }); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/utils/integration/mapPlatformAccounts.ts` around lines 69 - 98, formatConnectionDateTime and formatConnectionDate currently return the original raw value when parseDate(value) fails, which can expose invalid strings in the UI; change both functions so that if parseDate(value) returns a falsy value you return null instead of value, keeping the functions' return type (string | null) and preventing invalid raw dates from being rendered; update the logic in formatConnectionDateTime (the branch after const date = parseDate(value)) and in formatConnectionDate to return null on parseDate failure.
125-129: 💤 Low value에러 메시지를 상수로 분리하면 유지보수성이 향상됩니다.
Line 128의 에러 메시지가 하드코딩되어 있습니다. 향후 메시지 변경이나 다국어 지원 시 관리가 어려울 수 있으므로, 파일 상단에 상수로 분리하는 것을 권장합니다.
♻️ 제안 수정안
const INTEGRATION_PROVIDERS: TIntegrationProvider[] = [ "META", "GOOGLE", "NAVER", ]; const TOKEN_EXPIRE_WARNING_DAYS = 7; +const TOKEN_EXPIRED_ERROR_MESSAGE = "토큰이 만료되었습니다. 다시 연동해 주세요."; const DATE_ONLY_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/;if (status === "error") { return { ...base, - errorMessage: "토큰이 만료되었습니다. 다시 연동해 주세요.", + errorMessage: TOKEN_EXPIRED_ERROR_MESSAGE, }; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/utils/integration/mapPlatformAccounts.ts` around lines 125 - 129, The hard-coded Korean error string returned in the status === "error" branch should be moved to a top-level constant for maintainability and i18n; add a constant (e.g., TOKEN_EXPIRED_MSG or MAP_PLATFORM_TOKEN_EXPIRED) at the top of the file and replace the inline "토큰이 만료되었습니다. 다시 연동해 주세요." in the return object inside the if (status === "error") block (within mapPlatformAccounts) with that constant.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/utils/integration/mapPlatformAccounts.ts`:
- Around line 69-98: formatConnectionDateTime and formatConnectionDate currently
return the original raw value when parseDate(value) fails, which can expose
invalid strings in the UI; change both functions so that if parseDate(value)
returns a falsy value you return null instead of value, keeping the functions'
return type (string | null) and preventing invalid raw dates from being
rendered; update the logic in formatConnectionDateTime (the branch after const
date = parseDate(value)) and in formatConnectionDate to return null on parseDate
failure.
- Around line 125-129: The hard-coded Korean error string returned in the status
=== "error" branch should be moved to a top-level constant for maintainability
and i18n; add a constant (e.g., TOKEN_EXPIRED_MSG or MAP_PLATFORM_TOKEN_EXPIRED)
at the top of the file and replace the inline "토큰이 만료되었습니다. 다시 연동해 주세요." in the
return object inside the if (status === "error") block (within
mapPlatformAccounts) with that constant.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 2ed54318-bfe5-4241-81de-b891c9ac3bfc
📒 Files selected for processing (4)
src/components/integration/PlatformIntegrationCard.tsxsrc/components/integration/UpcomingPlatformCard.tsxsrc/types/integration/platformConnection.tssrc/utils/integration/mapPlatformAccounts.ts
💤 Files with no reviewable changes (1)
- src/components/integration/PlatformIntegrationCard.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- src/components/integration/UpcomingPlatformCard.tsx




🚨 관련 이슈
close #233
✨ 변경사항
✏️ 작업 내용
플랫폼 연동 페이지 (
/integrations)사이드바
error상태가 있으면 펼침 시 연동 필요 뱃지😅 미완성 작업
N/A
📢 논의 사항 및 참고 사항
API 연동하면서 필요한 UI 추가 예정입니다!
Summary by CodeRabbit