Conversation
There was a problem hiding this comment.
Code Review
This pull request replaces hardcoded record statistics with dynamic data in the record screen and updates the useClivePhotos hook to fetch data from the production endpoint. Feedback highlights a typo in the altitude unit (using Nm instead of m) and suggests using the auto-generated TrackingPhotoResponse type instead of a duplicate local definition, along with filtering out undefined image URLs to prevent runtime errors.
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.
| { label: "고도", value: "642m" }, | ||
| { label: "칼로리", value: "1128kcal" }, | ||
| { label: "소요시간", value: formatDuration(recordDetail?.durationSeconds ?? durationSec) }, | ||
| { label: "고도", value: recordDetail?.ascentMeters != null ? `${Math.round(recordDetail.ascentMeters)}Nm` : "--" }, |
There was a problem hiding this comment.
고도 단위가 Nm으로 표시되고 있습니다. 원래 하드코딩된 값은 642m이었으며, 고도(ascentMeters)의 표준 단위는 미터(m)입니다. Nm은 뉴턴 미터(Newton-meter) 또는 해리(Nautical Mile)를 의미하므로 오타일 가능성이 높습니다. 사용자에게 올바른 단위를 보여주기 위해 m으로 수정하는 것을 권장합니다.
| { label: "고도", value: recordDetail?.ascentMeters != null ? `${Math.round(recordDetail.ascentMeters)}Nm` : "--" }, | |
| { label: "고도", value: recordDetail?.ascentMeters != null ? `${Math.round(recordDetail.ascentMeters)}m` : "--" }, |
| import { ENDPOINTS } from "@/types/api.generated"; | ||
|
|
||
| type ClivePhoto = { | ||
| photoId: number; | ||
| trackingSessionId: number; | ||
| milestoneIndex: number; | ||
| milestoneDistanceM: number; | ||
| imageUrl: string; | ||
| capturedAt: string; | ||
| lat: number; | ||
| lng: number; | ||
| altitude: number; | ||
| }; | ||
|
|
||
| export function useClivePhotos(sessionId: number | null) { | ||
| return useQuery({ | ||
| queryKey: ["clivePhotos", sessionId], | ||
| enabled: sessionId != null, | ||
| queryFn: async () => { | ||
| const res = await api.get<string[]>({ | ||
| path: `${ENDPOINTS.DEMO_TRACKING_SESSIONS_BY_SESSIONID_PHOTOS(sessionId!)}?count=2`, | ||
| const res = await api.get<ClivePhoto[]>({ | ||
| path: ENDPOINTS.TRACKING_SESSIONS_BY_SESSIONID_PHOTOS(sessionId!), | ||
| }); | ||
| return res.data ?? []; | ||
| return (res.data ?? []).map((p) => p.imageUrl); | ||
| }, |
There was a problem hiding this comment.
types/api.generated.ts에 이미 자동 생성된 TrackingPhotoResponse 타입이 존재하므로, 중복된 ClivePhoto 타입을 직접 정의하기보다 자동 생성된 타입을 사용하는 것이 유지보수 관점에서 좋습니다.
또한, TrackingPhotoResponse에서 imageUrl은 선택적 필드(?)이므로 undefined일 가능성이 있습니다. clivePhotos를 사용하는 곳에서 발생할 수 있는 런타임 에러(예: Image.prefetch 실패 등)를 방지하기 위해 filter를 통해 유효한 이미지 URL만 필터링하여 반환하는 것이 안전합니다.
import { ENDPOINTS, TrackingPhotoResponse } from "@/types/api.generated";
export function useClivePhotos(sessionId: number | null) {
return useQuery({
queryKey: ["clivePhotos", sessionId],
enabled: sessionId != null,
queryFn: async () => {
const res = await api.get<TrackingPhotoResponse[]>({
path: ENDPOINTS.TRACKING_SESSIONS_BY_SESSIONID_PHOTOS(sessionId!),
});
return (res.data ?? [])
.map((p) => p.imageUrl)
.filter((url): url is string => !!url);
},
});
}
Summary
useClivePhotosdemo API → 실제 API(TRACKING_SESSIONS_BY_SESSIONID_PHOTOS)로 복원ClivePhoto타입 복원 및imageUrl매핑 복원recordDetailAPI 연동으로 복원Nm유지Test plan