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
41 changes: 21 additions & 20 deletions features/mountains-detail/components/restaurant-tab.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { LoadingSpinner } from "@/components/loading-spinner";
import { useMountainDetail } from "@/features/mountains/hooks/use-mountain-detail";
import { useLocalSearchParams } from "expo-router";
import { Image, ScrollView, Text, View } from "react-native";
import {
Image,
Linking,
Pressable,
ScrollView,
Text,
View,
} from "react-native";

export function RestaurantTab() {
const { id } = useLocalSearchParams<{ id: string }>();
Expand All @@ -24,7 +31,18 @@ export function RestaurantTab() {
contentContainerStyle={{ paddingHorizontal: 20, gap: 12 }}
>
{section.restaurants?.map((item) => (
<View key={item.restaurantId} className="gap-2">
<Pressable
key={item.restaurantId}
className="gap-2"
disabled={!item.mapUrl}
Comment on lines +34 to +37

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

optional한 restaurantId를 그대로 key로 사용하지 마세요.

types/api.generated.ts:554-560에서 restaurantId가 optional이므로, ID가 없는 항목들은 모두 동일한 undefined key를 갖게 될 수 있습니다. API에서 ID가 항상 보장된다면 계약을 required로 변경하고, 그렇지 않다면 불변의 고유 필드를 사용하는 fallback key를 추가하세요.

🤖 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 `@features/mountains-detail/components/restaurant-tab.tsx` around lines 34 -
37, Update the restaurant list rendering around the Pressable keyed by
item.restaurantId so it never uses an optional or undefined restaurantId
directly as the React key. If the API guarantees an ID, make restaurantId
required in the generated type contract; otherwise, use a stable unique fallback
field for items without an ID, preserving unique keys across all rendered
restaurants.

onPress={() => {
// 맛집 탭 시 네이버 지도(mapUrl)로 이동
if (!item.mapUrl) return;
Linking.openURL(item.mapUrl).catch((err) =>
console.warn("[Restaurant] 지도 열기 실패:", err),
);
}}
>
{item.imageUrl ? (
<Image
source={{ uri: item.imageUrl }}
Expand All @@ -41,25 +59,8 @@ export function RestaurantTab() {
{item.category}
</Text>
</View>
</View>
))}
{/* TODO : 화면 개발되면 추가 */}
{/* 더보기 버튼은 앞에 아이템 3개 이상일때 부터 추가 */}
{/* {(section.restaurants?.length ?? 0) >= 3 && (
<Pressable
className="h-[116px] w-[188px] items-center justify-center gap-1 rounded-[10px] bg-fill-stronger"
onPress={() => {
// TODO: 맛집 더보기 화면으로 이동
}}
>
<Text className="text-center text-label-subtle typo-body-2-normal-semi-bold">
{section.title}
</Text>
<Text className="text-label-subtler typo-body-2-normal-regular">
{"더보기 >"}
</Text>
</Pressable>
)} */}
))}
</ScrollView>
</View>
))}
Expand Down
1 change: 1 addition & 0 deletions types/api.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,7 @@ export type RestaurantInfo = {
name?: string;
category?: string;
imageUrl?: string;
mapUrl?: string;
};
export type RestaurantSectionInfo = {
title?: string;
Expand Down
Loading