Files
uldp.edu.vn/app/blog/[slug]/components/CommentForm.tsx

124 lines
3.4 KiB
TypeScript

"use client";
import { useRouter } from "next/navigation";
import { useState } from "react";
interface CommentFormProps {
slug: string;
parentId?: string | null;
replyToName?: string | null;
initialContent?: string;
onSubmitted?: () => void;
}
export default function CommentForm({
slug,
parentId = null,
replyToName = null,
initialContent = "",
onSubmitted,
}: CommentFormProps) {
const router = useRouter();
const [isPending, setIsPending] = useState(false);
const [authorName, setAuthorName] = useState("");
const [content, setContent] = useState(initialContent);
const [error, setError] = useState<string | null>(null);
const [success, setSuccess] = useState<string | null>(null);
const apiUrl = process.env.NEXT_PUBLIC_API_URL || "http://localhost:3001";
const onSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError(null);
setSuccess(null);
if (!authorName.trim() || !content.trim()) {
setError("Please enter your name and comment.");
return;
}
try {
setIsPending(true);
const res = await fetch(`${apiUrl}/api/blog/${slug}/comments`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify({
authorName: authorName.trim(),
content: content.trim(),
...(parentId ? { parentId } : {}),
}),
});
const data = await res.json();
if (!res.ok || !data?.success) {
throw new Error(data?.message || "Failed to submit comment");
}
setAuthorName("");
setContent("");
setSuccess("Comment submitted.");
// Re-fetch server data (blog detail is no-store) to show new comment immediately
router.refresh();
onSubmitted?.();
} catch (err) {
setError(err instanceof Error ? err.message : "Failed to submit comment");
} finally {
setIsPending(false);
}
};
return (
<div>
<h3 className="mb-3">
{parentId ? (replyToName ? `Reply to @${replyToName}` : "Reply") : "Leave A Comment"}
</h3>
{error && <p className="text-danger mb-3">{error}</p>}
{success && <p className="text-success mb-3">{success}</p>}
<form onSubmit={onSubmit} className="contact-form-items">
<div className="row g-4">
<div className="col-lg-6">
<div className="form-clt">
<span>Your Name</span>
<input
type="text"
name="authorName"
placeholder="Your name"
value={authorName}
onChange={(e) => setAuthorName(e.target.value)}
disabled={isPending}
/>
</div>
</div>
<div className="col-lg-12">
<div className="form-clt">
<textarea
name="content"
placeholder="Type your comment"
value={content}
onChange={(e) => setContent(e.target.value)}
disabled={isPending}
></textarea>
</div>
</div>
<div className="col-lg-12 wow fadeInUp" data-wow-delay=".3s">
<button type="submit" className="theme-btn" disabled={isPending}>
{isPending ? "Sending..." : "Send Comment"}
<i className="fa-solid fa-arrow-right"></i>
</button>
</div>
</div>
</form>
</div>
);
}