128 lines
2.9 KiB
JavaScript
128 lines
2.9 KiB
JavaScript
let pageSlug = null;
|
|
|
|
/* -----------------------------
|
|
* DOM builders
|
|
* ----------------------------- */
|
|
|
|
function createComment(comment) {
|
|
const wrapper = document.createElement("div");
|
|
wrapper.className = "comment";
|
|
wrapper.dataset.id = comment.id;
|
|
|
|
const author = document.createElement("strong");
|
|
author.textContent = comment.author || "Anonymous";
|
|
|
|
const body = document.createElement("p");
|
|
body.textContent = comment.content;
|
|
|
|
const time = document.createElement("time");
|
|
time.className = "comment-date";
|
|
time.dateTime = comment.created_at;
|
|
time.textContent = new Date(comment.created_at).toLocaleString();
|
|
|
|
wrapper.appendChild(author);
|
|
wrapper.appendChild(body);
|
|
wrapper.appendChild(time);
|
|
|
|
return wrapper;
|
|
}
|
|
|
|
/* -----------------------------
|
|
* Rendering
|
|
* ----------------------------- */
|
|
|
|
function renderComments(comments) {
|
|
const list = document.getElementById("comments-list");
|
|
list.innerHTML = "";
|
|
|
|
if (!comments.length) {
|
|
const empty = document.createElement("p");
|
|
empty.className = "comments-empty";
|
|
empty.textContent = "No comments yet.";
|
|
list.appendChild(empty);
|
|
return;
|
|
}
|
|
|
|
comments.forEach(c => {
|
|
list.appendChild(createComment(c));
|
|
});
|
|
}
|
|
|
|
/* -----------------------------
|
|
* API
|
|
* ----------------------------- */
|
|
|
|
async function fetchComments() {
|
|
const res = await fetch(`/api/comments/${pageSlug}`);
|
|
if (!res.ok) {
|
|
console.error("Failed to fetch comments");
|
|
return [];
|
|
}
|
|
return await res.json();
|
|
}
|
|
|
|
async function postComment(author, content) {
|
|
const res = await fetch("/api/comments", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
page_slug: pageSlug,
|
|
author: author || null,
|
|
content: content
|
|
})
|
|
});
|
|
|
|
return res.ok;
|
|
}
|
|
|
|
|
|
/* -----------------------------
|
|
* Form handling
|
|
* ----------------------------- */
|
|
|
|
function wireCommentForm() {
|
|
const form = document.getElementById("comment-form");
|
|
|
|
form.addEventListener("submit", async e => {
|
|
e.preventDefault();
|
|
|
|
const authorInput = form.querySelector("input[name='author']");
|
|
const textarea = form.querySelector("textarea[name='content']");
|
|
|
|
const author = authorInput.value.trim();
|
|
const content = textarea.value.trim();
|
|
|
|
if (!content) return;
|
|
|
|
const ok = await postComment(author, content);
|
|
if (ok) {
|
|
textarea.value = "";
|
|
loadComments(); // same pattern as your Kanban board
|
|
} else {
|
|
alert("Failed to post comment");
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
/* -----------------------------
|
|
* Entry point
|
|
* ----------------------------- */
|
|
|
|
async function loadComments() {
|
|
const comments = await fetchComments();
|
|
renderComments(comments);
|
|
}
|
|
|
|
function initComments() {
|
|
const section = document.getElementById("comments");
|
|
if (!section) return;
|
|
|
|
pageSlug = section.dataset.slug;
|
|
|
|
wireCommentForm();
|
|
loadComments();
|
|
}
|
|
|
|
initComments();
|