- Admin: video management with Google Maps match status, manual restaurant mapping, restaurant remap on name change - Admin: user management tab with favorites/reviews detail - Admin: channel deletion fix for IDs with slashes - Frontend: responsive mobile layout (map top, list bottom, 2-row header) - Frontend: channel-colored map markers with legend - Frontend: my reviews list, favorites toggle, visit counter overlay - Frontend: force light mode for dark theme devices - Backend: visit tracking (site_visits table), user reviews endpoint - Backend: bulk transcript/extract streaming, geocode key fixes - Nginx config for production deployment Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
70 lines
2.1 KiB
TypeScript
70 lines
2.1 KiB
TypeScript
"use client";
|
|
|
|
import type { Review } from "@/lib/api";
|
|
|
|
interface MyReview extends Review {
|
|
restaurant_id: string;
|
|
restaurant_name: string | null;
|
|
}
|
|
|
|
interface MyReviewsListProps {
|
|
reviews: MyReview[];
|
|
onClose: () => void;
|
|
onSelectRestaurant: (restaurantId: string) => void;
|
|
}
|
|
|
|
export default function MyReviewsList({
|
|
reviews,
|
|
onClose,
|
|
onSelectRestaurant,
|
|
}: MyReviewsListProps) {
|
|
return (
|
|
<div className="p-4 space-y-3">
|
|
<div className="flex justify-between items-center">
|
|
<h2 className="font-bold text-lg">내 리뷰 ({reviews.length})</h2>
|
|
<button
|
|
onClick={onClose}
|
|
className="text-gray-400 hover:text-gray-600 text-xl leading-none"
|
|
>
|
|
x
|
|
</button>
|
|
</div>
|
|
|
|
{reviews.length === 0 ? (
|
|
<p className="text-sm text-gray-500 py-8 text-center">
|
|
아직 작성한 리뷰가 없습니다.
|
|
</p>
|
|
) : (
|
|
<div className="space-y-2">
|
|
{reviews.map((r) => (
|
|
<button
|
|
key={r.id}
|
|
onClick={() => onSelectRestaurant(r.restaurant_id)}
|
|
className="w-full text-left border rounded-lg p-3 hover:bg-gray-50 transition-colors"
|
|
>
|
|
<div className="flex items-center justify-between mb-1">
|
|
<span className="font-semibold text-sm truncate">
|
|
{r.restaurant_name || "알 수 없는 식당"}
|
|
</span>
|
|
<span className="text-yellow-500 text-sm shrink-0 ml-2">
|
|
{"★".repeat(Math.round(r.rating))}
|
|
<span className="text-gray-500 ml-1">{r.rating}</span>
|
|
</span>
|
|
</div>
|
|
{r.review_text && (
|
|
<p className="text-xs text-gray-600 line-clamp-2">
|
|
{r.review_text}
|
|
</p>
|
|
)}
|
|
<div className="flex items-center gap-2 mt-1.5 text-[10px] text-gray-400">
|
|
{r.visited_at && <span>방문: {r.visited_at}</span>}
|
|
{r.created_at && <span>{r.created_at.slice(0, 10)}</span>}
|
|
</div>
|
|
</button>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|