feat: 마이페이지 UI 개선 - #22
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 45794d5. Configure here.
| ? Math.min(100, Math.round((currentDistanceKm / monthlyGoalKm) * 100)) | ||
| : 0; | ||
| const averagePaceLabel = stats.averagePaceLabel | ||
| || getAveragePaceLabel(previewActivities, `6'20"`); |
There was a problem hiding this comment.
Monthly pace uses preview only
Medium Severity
When stats.averagePaceLabel is missing, 평균 페이스 in 이번 달 러닝 is derived via getAveragePaceLabel(previewActivities, …), so only the first three recent activities are included. That value can disagree with the month’s total distance and run count shown in the same card.
Reviewed by Cursor Bugbot for commit 45794d5. Configure here.
| } | ||
| }; | ||
|
|
||
| const handleViewMoreActivities = () => {}; |
There was a problem hiding this comment.
View all button does nothing
Medium Severity
The 최근 활동 header wires 전체보기 to handleViewMoreActivities, which is an empty function, so the control never navigates or opens a full activity list despite looking like an active link.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 45794d5. Configure here.
There was a problem hiding this comment.
Code Review
This pull request introduces the Mypage component and its associated CSS module, which displays user profile information, monthly running goals, statistics, and recent activities. The feedback highlights two key improvement opportunities: first, implementing defensive programming (such as optional chaining and default values) when destructuring data from useMypageData to prevent potential runtime errors during loading states; second, implementing the routing logic within the currently empty handleViewMoreActivities handler to make the 'View More' button functional.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| const { | ||
| user, | ||
| stats, | ||
| activities, | ||
| isLoading, | ||
| isUsingMockData, | ||
| } = useMypageData(); | ||
|
|
||
| const dotClass = getDotClassName(user.status); | ||
| const previewActivities = activities.slice(0, PREVIEW_ACTIVITY_COUNT); | ||
| const monthlyGoalKm = Number(stats.monthlyGoalKm) || MONTHLY_GOAL_KM; | ||
| const currentDistanceKm = Number(stats.totalDistanceKm) || 0; | ||
| const goalProgress = monthlyGoalKm > 0 | ||
| ? Math.min(100, Math.round((currentDistanceKm / monthlyGoalKm) * 100)) | ||
| : 0; | ||
| const averagePaceLabel = stats.averagePaceLabel | ||
| || getAveragePaceLabel(previewActivities, `6'20"`); |
There was a problem hiding this comment.
데이터를 불러오는 중(isLoading이 true인 경우)이나 API 응답이 지연될 때, useMypageData()에서 반환하는 user, stats, activities 객체가 undefined 또는 null일 가능성이 있습니다. 이 경우 user.status, activities.slice, stats.monthlyGoalKm 등을 직접 참조하면 런타임 에러(TypeError)가 발생하여 화면이 정상적으로 렌더링되지 않고 화이트스크린이 발생할 수 있습니다.
안전한 렌더링을 위해 구조 분해 할당 시 기본값을 지정하거나, 옵셔널 체이닝(?.) 및 널 병합 연산자(??)를 사용하여 방어적 코드(Defensive Programming)를 작성하는 것이 좋습니다.
| const { | |
| user, | |
| stats, | |
| activities, | |
| isLoading, | |
| isUsingMockData, | |
| } = useMypageData(); | |
| const dotClass = getDotClassName(user.status); | |
| const previewActivities = activities.slice(0, PREVIEW_ACTIVITY_COUNT); | |
| const monthlyGoalKm = Number(stats.monthlyGoalKm) || MONTHLY_GOAL_KM; | |
| const currentDistanceKm = Number(stats.totalDistanceKm) || 0; | |
| const goalProgress = monthlyGoalKm > 0 | |
| ? Math.min(100, Math.round((currentDistanceKm / monthlyGoalKm) * 100)) | |
| : 0; | |
| const averagePaceLabel = stats.averagePaceLabel | |
| || getAveragePaceLabel(previewActivities, `6'20"`); | |
| const { | |
| user = {}, | |
| stats = {}, | |
| activities = [], | |
| isLoading, | |
| isUsingMockData, | |
| } = useMypageData(); | |
| const dotClass = getDotClassName(user?.status); | |
| const previewActivities = (activities || []).slice(0, PREVIEW_ACTIVITY_COUNT); | |
| const monthlyGoalKm = Number(stats?.monthlyGoalKm) || MONTHLY_GOAL_KM; | |
| const currentDistanceKm = Number(stats?.totalDistanceKm) || 0; | |
| const goalProgress = monthlyGoalKm > 0 | |
| ? Math.min(100, Math.round((currentDistanceKm / monthlyGoalKm) * 100)) | |
| : 0; | |
| const averagePaceLabel = stats?.averagePaceLabel | |
| || getAveragePaceLabel(previewActivities, "6'20\""); |
| } | ||
| }; | ||
|
|
||
| const handleViewMoreActivities = () => {}; |
There was a problem hiding this comment.


작업 내용
확인 사항
Note
Low Risk
Mostly presentational React/CSS; the only behavioral change is logout via existing
clearAuthSession, with no API or auth logic changes described in the diff.Overview
Redesigns the
/mypagescreen as a mobile-first profile view: sticky header with back navigation and a 더보기 overflow menu (profile edit, notifications, privacy placeholders; 로그아웃 clears the session and routes home).The page still loads data via
useMypageDataand adds presentation-only pieces: a hero profile block (avatar with fallback image, run-status dot, monthly run count), an 이번 달 목표 card with km progress and a progress bar, an 이번 달 러닝 stats grid (distance, average pace with derived fallback, run count), and 최근 활동 limited to three items with optional deep links to/running-record/:idand an empty state when there is no real activity data.Companion
mypage.module.cssdefines the card layout, gradients, and max-width shell styling. 전체보기 is wired in the UI but its handler is still a no-op.Reviewed by Cursor Bugbot for commit 45794d5. Bugbot is set up for automated code reviews on this repo. Configure here.