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

200 lines
6.0 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 [authorEmail, setAuthorEmail] = useState("");
const [authorPhone, setAuthorPhone] = useState("");
const [authorAddress, setAuthorAddress] = useState("");
const [authorDate, setAuthorDate] = 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;
}
// Basic email validation if provided
if (authorEmail.trim() && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(authorEmail.trim())) {
setError("Please enter a valid email address.");
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(),
...(authorEmail.trim() ? { authorEmail: authorEmail.trim() } : {}),
...(authorPhone.trim() ? { authorPhone: authorPhone.trim() } : {}),
...(authorAddress.trim() ? { authorAddress: authorAddress.trim() } : {}),
...(authorDate.trim() ? { authorDate: authorDate.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("");
setAuthorEmail("");
setAuthorPhone("");
setAuthorAddress("");
setAuthorDate("");
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-4">
<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}
required
/>
</div>
</div>
<div className="col-lg-4">
<div className="form-clt">
<span>Your Email</span>
<input
type="email"
name="authorEmail"
placeholder="Your email"
value={authorEmail}
onChange={(e) => setAuthorEmail(e.target.value)}
disabled={isPending}
/>
</div>
</div>
<div className="col-lg-4">
<div className="form-clt">
<span>Your Phone</span>
<input
type="text"
name="authorPhone"
placeholder="Phone Number"
value={authorPhone}
onChange={(e) => setAuthorPhone(e.target.value)}
disabled={isPending}
/>
</div>
</div>
<div className="col-lg-6">
<div className="form-clt">
<span>Your Address</span>
<input
type="text"
name="authorAddress"
placeholder="Address Now"
value={authorAddress}
onChange={(e) => setAuthorAddress(e.target.value)}
disabled={isPending}
/>
</div>
</div>
<div className="col-lg-6">
<div className="form-clt">
<span>Your Date</span>
<input
type="text"
name="authorDate"
placeholder="Date"
value={authorDate}
onChange={(e) => setAuthorDate(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}
required
></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>
);
}