Files
app-admin/app/apps/[id]/store/ReviewCard.tsx
2026-03-24 15:46:27 +03:00

144 lines
5.2 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useState, useTransition } from "react";
import { Star, MessageSquare, Loader2, CheckCircle2, ChevronDown, ChevronUp } from "lucide-react";
function StarRating({ rating }: { rating: number }) {
return (
<div className="flex items-center gap-0.5">
{[1, 2, 3, 4, 5].map((s) => (
<Star
key={s}
size={10}
className={s <= rating ? "fill-yellow-400 text-yellow-400" : "text-slate-700"}
/>
))}
</div>
);
}
const TERRITORY_NAMES: Record<string, string> = {
USA: "🇺🇸", TUR: "🇹🇷", GBR: "🇬🇧", DEU: "🇩🇪", FRA: "🇫🇷",
JPN: "🇯🇵", KOR: "🇰🇷", CHN: "🇨🇳", AUS: "🇦🇺", CAN: "🇨🇦",
BRA: "🇧🇷", IND: "🇮🇳", RUS: "🇷🇺", ESP: "🇪🇸", ITA: "🇮🇹",
};
export default function ReviewCard({ review }: { review: any }) {
const attr = review.attributes ?? {};
const [expanded, setExpanded] = useState(false);
const [showReply, setShowReply] = useState(false);
const [replyText, setReplyText] = useState("");
const [submitting, startTransition] = useTransition();
const [submitted, setSubmitted] = useState(false);
const [error, setError] = useState<string | null>(null);
const bodyPreview = attr.body?.length > 140 ? attr.body.slice(0, 140) + "…" : attr.body;
function handleReply() {
setError(null);
startTransition(async () => {
const res = await fetch("/api/asc/review-response", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ reviewId: review.id, responseBody: replyText }),
});
if (res.ok) {
setSubmitted(true);
setShowReply(false);
setTimeout(() => setSubmitted(false), 3000);
} else {
const d = await res.json();
setError(d.error ?? "Gönderilemedi");
}
});
}
return (
<div className="px-5 py-4 hover:bg-white/[0.02] transition-colors">
{/* Header */}
<div className="flex items-start justify-between gap-3">
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-1">
<StarRating rating={attr.rating ?? 0} />
<span className="text-[10px] text-slate-500">
{TERRITORY_NAMES[attr.territory] ?? ""} {attr.territory}
</span>
</div>
{attr.title && (
<p className="text-xs font-semibold text-white truncate">{attr.title}</p>
)}
</div>
<div className="text-[10px] text-slate-600 shrink-0">
{attr.createdDate
? new Date(attr.createdDate).toLocaleDateString("tr-TR", {
month: "short", day: "numeric", year: "numeric",
})
: ""}
</div>
</div>
{/* Body */}
<div className="mt-2">
<p className="text-[11px] text-slate-400 leading-relaxed">
{expanded ? attr.body : bodyPreview}
</p>
{attr.body?.length > 140 && (
<button
onClick={() => setExpanded(!expanded)}
className="mt-1 flex items-center gap-0.5 text-[10px] text-slate-500 hover:text-slate-300 transition-colors"
>
{expanded ? <><ChevronUp size={10} /> Daralt</> : <><ChevronDown size={10} /> Devamını gör</>}
</button>
)}
</div>
{/* Reviewer */}
{attr.reviewerNickname && (
<p className="mt-1.5 text-[10px] text-slate-600 italic"> {attr.reviewerNickname}</p>
)}
{/* Reply section */}
<div className="mt-3 flex items-center gap-3">
{submitted ? (
<span className="flex items-center gap-1 text-[10px] text-emerald-400">
<CheckCircle2 size={10} /> Yanıt gönderildi
</span>
) : (
<button
onClick={() => setShowReply(!showReply)}
className="flex items-center gap-1 text-[10px] font-semibold text-violet-400 hover:text-violet-300 transition-colors"
>
<MessageSquare size={10} />
{showReply ? "İptal" : "Yanıtla"}
</button>
)}
</div>
{showReply && (
<div className="mt-3 space-y-2">
<textarea
value={replyText}
onChange={(e) => setReplyText(e.target.value)}
placeholder="Kullanıcıya yanıtınızı yazın…"
rows={3}
maxLength={5900}
className="w-full bg-black/30 border border-white/8 rounded-xl px-3 py-2 text-xs text-white placeholder-slate-600 focus:outline-none focus:border-violet-500/50 resize-none"
/>
<div className="flex items-center justify-between">
{error && <p className="text-[10px] text-red-400">{error}</p>}
<span className="text-[10px] text-slate-600 ml-auto">{replyText.length}/5900</span>
</div>
<button
onClick={handleReply}
disabled={submitting || !replyText.trim()}
className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-violet-600 hover:bg-violet-500 disabled:opacity-40 text-[11px] font-bold transition-colors"
>
{submitting ? <Loader2 size={10} className="animate-spin" /> : <MessageSquare size={10} />}
Gönder
</button>
</div>
)}
</div>
);
}