Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions app/record/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,9 @@ export default function RecordScreen() {
{/* 통계 */}
<View style={{ flexDirection: "row", marginHorizontal: 20, marginTop: 16, marginBottom: 16, gap: 4 }}>
{[
{ label: "소요시간", value: "3시간 24분" },
{ label: "고도", value: "642m" },
{ label: "칼로리", value: "1128kcal" },
{ label: "소요시간", value: formatDuration(recordDetail?.durationSeconds ?? durationSec) },
{ label: "고도", value: recordDetail?.ascentMeters != null ? `${Math.round(recordDetail.ascentMeters)}Nm` : "--" },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

고도 단위가 Nm으로 표시되고 있습니다. 원래 하드코딩된 값은 642m이었으며, 고도(ascentMeters)의 표준 단위는 미터(m)입니다. Nm은 뉴턴 미터(Newton-meter) 또는 해리(Nautical Mile)를 의미하므로 오타일 가능성이 높습니다. 사용자에게 올바른 단위를 보여주기 위해 m으로 수정하는 것을 권장합니다.

Suggested change
{ label: "고도", value: recordDetail?.ascentMeters != null ? `${Math.round(recordDetail.ascentMeters)}Nm` : "--" },
{ label: "고도", value: recordDetail?.ascentMeters != null ? `${Math.round(recordDetail.ascentMeters)}m` : "--" },

{ label: "칼로리", value: recordDetail?.calories != null ? `${recordDetail.calories}kcal` : "--" },
].map((stat) => (
<View key={stat.label} style={styles.statItem}>
<Text style={styles.statLabel}>{stat.label}</Text>
Expand Down
18 changes: 15 additions & 3 deletions features/tracking/hooks/use-clive-photos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,27 @@ import { useQuery } from "@tanstack/react-query";
import { api } from "@/lib/api";
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);
},
Comment on lines 3 to 26

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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);
    },
  });
}

});
}
Loading