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();