"use client" import { useState, useEffect, useCallback } from "react" import { useAuth } from "@/contexts/auth-context" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { Textarea } from "@/components/ui/textarea" import { Badge } from "@/components/ui/badge" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { Alert, AlertDescription } from "@/components/ui/alert" import { Separator } from "@/components/ui/separator" import { Star, MessageSquare, ThumbsUp, ThumbsDown, Edit, Trash2, MoreHorizontal } from "lucide-react" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu" import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog" interface Review { id: string userId: string userName: string userAvatar?: string userDepartment: string rating: number comment: string createdAt: string updatedAt?: string helpful: number notHelpful: number userHelpfulVotes: string[] // user IDs who voted helpful userNotHelpfulVotes: string[] // user IDs who voted not helpful userVote?: boolean // true = 有幫助, false = 沒幫助, undefined = 未投票 } interface ReviewSystemProps { appId: string appName: string currentRating: number onRatingUpdate: (newRating: number, reviewCount: number) => void } export function ReviewSystem({ appId, appName, currentRating, onRatingUpdate }: ReviewSystemProps) { const { user, updateAppRating } = useAuth() // Load reviews from database const [reviews, setReviews] = useState([]) const [isLoadingReviews, setIsLoadingReviews] = useState(true) const [pagination, setPagination] = useState({ page: 1, limit: 5, total: 0, totalPages: 0, hasNext: false, hasPrev: false }) const [showReviewForm, setShowReviewForm] = useState(false) const [newRating, setNewRating] = useState(5) const [newComment, setNewComment] = useState("") const [isSubmitting, setIsSubmitting] = useState(false) const [editingReview, setEditingReview] = useState(null) const [sortBy, setSortBy] = useState<"newest" | "oldest" | "helpful">("newest") // Load reviews from database const loadReviews = useCallback(async (page: number = 1) => { try { setIsLoadingReviews(true) const response = await fetch(`/api/apps/${appId}/reviews?page=${page}&limit=100`) if (response.ok) { const data = await response.json() if (data.success) { // Transform database format to component format const transformedReviews = data.data.reviews.map((review: any) => ({ id: review.id, userId: review.user_id || 'unknown', userName: review.userName || review.user_name || '未知用戶', userAvatar: review.userAvatar || review.user_avatar, userDepartment: review.userDepartment || review.user_department || '未知部門', rating: Number(review.rating) || 0, // 確保 rating 是數字 comment: review.review || review.comment || '', // 使用 review 字段 createdAt: review.ratedAt || review.rated_at || new Date().toISOString(), helpful: 0, notHelpful: 0, userHelpfulVotes: [], userNotHelpfulVotes: [], })) // 載入每個評論的投票統計 for (const review of transformedReviews) { try { const voteUrl = `/api/reviews/${review.id}/votes${user ? `?userId=${user.id}` : ''}` const voteResponse = await fetch(voteUrl) if (voteResponse.ok) { const voteData = await voteResponse.json() if (voteData.success) { review.helpful = voteData.data.helpful review.notHelpful = voteData.data.notHelpful review.userVote = voteData.data.userVote // 用戶的投票狀態 } } else { console.error('投票 API 響應失敗:', voteResponse.status, voteResponse.statusText) } } catch (error) { console.error('載入評論投票錯誤:', error) } } setReviews(transformedReviews) setPagination(data.data.pagination) } } } catch (error) { console.error('載入評論錯誤:', error) } finally { setIsLoadingReviews(false) } }, [appId, user]) // Load reviews on component mount useEffect(() => { loadReviews() }, [loadReviews]) const userReview = reviews.find((review) => review.userId === user?.id) const canReview = user // 允許用戶多次評論,移除 !userReview 限制 // Update rating when reviews change useEffect(() => { if (reviews.length > 0) { const avgRating = reviews.reduce((sum, r) => sum + r.rating, 0) / reviews.length const newAvgRating = Number(avgRating.toFixed(1)) updateAppRating(appId, newAvgRating) onRatingUpdate(newAvgRating, reviews.length) } else { updateAppRating(appId, 0) onRatingUpdate(0, 0) } }, [reviews, appId]) // 移除函數依賴項以避免無限循環 const handleSubmitReview = async () => { if (!user || !newComment.trim()) return setIsSubmitting(true) try { const response = await fetch(`/api/apps/${appId}/reviews`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ userId: user.id, rating: newRating, comment: newComment.trim(), }), }) if (response.ok) { const data = await response.json() if (data.success) { // Reload reviews from database await loadReviews() setNewComment("") setNewRating(5) setShowReviewForm(false) } else { console.error('提交評論失敗:', data.error) alert('提交評論失敗,請稍後再試') } } else { console.error('提交評論失敗:', response.statusText) alert('提交評論失敗,請稍後再試') } } catch (error) { console.error('提交評論錯誤:', error) alert('提交評論時發生錯誤,請稍後再試') } finally { setIsSubmitting(false) } } const handleEditReview = async (reviewId: string) => { if (!user || !newComment.trim()) return setIsSubmitting(true) try { const response = await fetch(`/api/apps/${appId}/reviews`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ userId: user.id, rating: newRating, comment: newComment.trim(), reviewId: reviewId, // 傳遞 reviewId 用於更新 }), }) if (response.ok) { const data = await response.json() if (data.success) { // Reload reviews from database await loadReviews() setEditingReview(null) setNewComment("") setNewRating(5) } else { console.error('更新評論失敗:', data.error) alert('更新評論失敗,請稍後再試') } } else { console.error('更新評論失敗:', response.statusText) alert('更新評論失敗,請稍後再試') } } catch (error) { console.error('更新評論錯誤:', error) alert('更新評論時發生錯誤,請稍後再試') } finally { setIsSubmitting(false) } } const handleDeleteReview = async (reviewId: string) => { // For now, we'll just reload reviews since we don't have a delete API yet // In a real implementation, you would call a DELETE API endpoint await loadReviews() } const handleHelpfulVote = async (reviewId: string, isHelpful: boolean) => { if (!user) return try { const response = await fetch(`/api/reviews/${reviewId}/votes`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ userId: user.id, isHelpful: isHelpful, }), }) if (response.ok) { const data = await response.json() if (data.success) { // 更新本地評論數據 setReviews(prevReviews => prevReviews.map(review => review.id === reviewId ? { ...review, helpful: data.data.helpful, notHelpful: data.data.notHelpful, userVote: data.data.userVote } : review ) ) } } } catch (error) { console.error('投票錯誤:', error) } } const startEdit = (review: Review) => { setEditingReview(review.id) setNewRating(review.rating) setNewComment(review.comment) setShowReviewForm(true) } const cancelEdit = () => { setEditingReview(null) setNewComment("") setNewRating(5) setShowReviewForm(false) } const getInitials = (name: string) => { return name.split("").slice(0, 2).join("").toUpperCase() } const formatDate = (dateString: string) => { return new Date(dateString).toLocaleDateString("zh-TW", { year: "numeric", month: "long", day: "numeric", hour: "2-digit", minute: "2-digit", }) } const renderStars = (rating: number, interactive = false, onRate?: (rating: number) => void) => { return (
{[1, 2, 3, 4, 5].map((star) => ( interactive && onRate && onRate(star)} /> ))}
) } const sortedReviews = [...reviews].sort((a, b) => { switch (sortBy) { case "oldest": return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime() case "helpful": return b.helpful - a.helpful case "newest": default: return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() } }) return (
{/* Review Summary */} 用戶評價 {isLoadingReviews ? ( "載入評價中..." ) : reviews.length > 0 ? (
{renderStars(Math.round(currentRating))} {Number(currentRating).toFixed(1)} ({reviews.length} 則評價)
) : ( "尚無評價,成為第一個評價的用戶!" )}
{/* Rating Distribution */} {reviews.length > 0 && (
{[5, 4, 3, 2, 1].map((rating) => { const count = reviews.filter((r) => r.rating === rating).length const percentage = (count / reviews.length) * 100 console.log(`評分 ${rating}: count=${count}, percentage=${percentage}%`) // 調試信息 return (
{rating}
{count}
) })}
)} {/* Add Review Button */} {canReview && ( )} {/* 移除「已評價過」的警告,允許用戶多次評論 */} {/* Review Form */} {editingReview ? "編輯評價" : "撰寫評價"} 分享您對 {appName} 的使用體驗
{renderStars(newRating, true, setNewRating)}