"use client"; import { useCallback, useEffect, useState } from "react"; import { api } from "@/lib/api"; import type { Memo } from "@/lib/api"; import { useAuth } from "@/lib/auth-context"; import Icon from "@/components/Icon"; import Stars from "@/components/Stars"; interface MemoSectionProps { restaurantId: string; } // #281 — ReviewSection의 StarSelector와 동일 UX (0.5 단위 + 44px 터치 + ARIA radiogroup) function StarSelector({ value, onChange, }: { value: number; onChange: (v: number) => void; }) { return (
별점: {[1, 2, 3, 4, 5].map((v) => { const nextVal = value === v ? v - 0.5 : v; return ( ); })} {value > 0 && {value}}
); } export default function MemoSection({ restaurantId }: MemoSectionProps) { const { user } = useAuth(); const [memo, setMemo] = useState(null); const [loading, setLoading] = useState(true); const [showForm, setShowForm] = useState(false); const [editing, setEditing] = useState(false); // Form state const [rating, setRating] = useState(3); const [text, setText] = useState(""); const [visitedAt, setVisitedAt] = useState(new Date().toISOString().slice(0, 10)); const [submitting, setSubmitting] = useState(false); const loadMemo = useCallback(() => { if (!user) { setLoading(false); return; } setLoading(true); api.getMemo(restaurantId) .then(setMemo) .catch(() => setMemo(null)) .finally(() => setLoading(false)); }, [restaurantId, user]); useEffect(() => { loadMemo(); }, [loadMemo]); if (!user) return null; const startEdit = () => { if (memo) { setRating(memo.rating || 3); setText(memo.memo_text || ""); setVisitedAt(memo.visited_at || new Date().toISOString().slice(0, 10)); } else { setRating(3); setText(""); setVisitedAt(new Date().toISOString().slice(0, 10)); } setEditing(true); setShowForm(true); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setSubmitting(true); try { const saved = await api.upsertMemo(restaurantId, { rating, memo_text: text || undefined, visited_at: visitedAt || undefined, }); setMemo(saved); setShowForm(false); setEditing(false); } catch (err) { // #281 — 사용자 피드백 alert(`메모 저장 실패: ${err instanceof Error ? err.message : String(err)}`); } finally { setSubmitting(false); } }; const handleDelete = async () => { if (!confirm("메모를 삭제하시겠습니까?")) return; try { await api.deleteMemo(restaurantId); setMemo(null); } catch (err) { alert(`메모 삭제 실패: ${err instanceof Error ? err.message : String(err)}`); } }; return (

내 메모

비공개
{loading ? (
) : showForm ? (