${escapeHtml(post.title)}
${post.image ? `Content coming soon...
'}(function() { const progressBar = document.querySelector('.progress-bar'); if (!progressBar) return; window.addEventListener('scroll', () => { const windowHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight; const scrolled = (window.scrollY / windowHeight) * 100; progressBar.style.width = scrolled + '%'; }); })(); // article.js - Complete Fixed Version with Comment Counters (function() { const API_BASE = "/backend"; const articleContainer = document.getElementById('articleContainer'); const newsletterModal = document.getElementById('newsletterModal'); let currentPost = null; let userState = { visitor_id: null, likes: [], favorites: [], isSubscribed: false, commentLikes: [], // Track liked comments and replies user_name: 'Anonymous', // Store user name user_email: null // Store user email }; // Get URL parameters function getUrlParams() { const params = new URLSearchParams(window.location.search); return { slug: params.get('slug'), id: params.get('id') }; } // Enhanced subscription check that also gets user data async function checkSubscription() { try { const response = await fetch(`${API_BASE}/check_newsletter_session.php`); const data = await response.json(); userState.isSubscribed = data.subscribed === true; // Store user data if available if (data.user_data) { userState.user_name = data.user_data.name || 'Subscriber'; userState.user_email = data.user_data.email || userState.visitor_id; } return userState.isSubscribed; } catch (error) { console.error('❌ Subscription check failed:', error); return false; } } // Fetch user state (likes, favorites, comment likes) async function fetchUserState() { userState.visitor_id = getVisitorId(); try { const res = await fetch(`${API_BASE}/get_user_stats.php?visitor_id=${encodeURIComponent(userState.visitor_id)}`); const json = await res.json(); if (json && json.success && json.data) { userState.likes = (json.data.likes || []).map(Number); userState.favorites = (json.data.favorites || []).map(Number); userState.commentLikes = (json.data.comment_likes || []).map(Number); } } catch (err) { console.warn("fetchUserState error:", err); } } // Get visitor ID function getVisitorId() { let id = localStorage.getItem("visitor_id"); if (!id) { id = "v_" + Date.now().toString(36) + "_" + Math.random().toString(36).slice(2, 9); localStorage.setItem("visitor_id", id); } return id; } // Fetch article content async function fetchArticle() { const params = getUrlParams(); if (!params.slug && !params.id) { showError('Article not found'); return; } try { let url = `${API_BASE}/get_post.php?`; if (params.slug) { url += `slug=${encodeURIComponent(params.slug)}`; } else { url += `id=${encodeURIComponent(params.id)}`; } const response = await fetch(url); const data = await response.json(); if (data.success && data.data) { currentPost = data.data; renderArticle(currentPost); } else { showError('Article not found'); } } catch (error) { console.error('Error fetching article:', error); showError('Error loading article'); } } // Show error function showError(message) { articleContainer.innerHTML = `
${message}
Loading article...
Content coming soon...
'}No comments yet. Be the first to comment!
'; } attachCommentEventHandlers(); } else { commentsLoading.innerHTML = 'Error loading comments
'; } } catch (error) { document.querySelector('.comments-loading').innerHTML = 'Error loading comments
'; } } // Update action counters function updateActionCounters(postId, likes, favorites, comments) { document.querySelectorAll(`.like-btn[data-post="${postId}"] .like-count`).forEach(count => { if (likes !== undefined) count.textContent = likes; }); document.querySelectorAll(`.favorite-btn[data-post="${postId}"] .favorite-count`).forEach(count => { if (favorites !== undefined) count.textContent = favorites; }); document.querySelectorAll(`.comment-btn .comment-count`).forEach(count => { if (comments !== undefined) count.textContent = comments; }); } // Attach comment event handlers function attachCommentEventHandlers() { document.querySelectorAll('.like-comment-btn').forEach(btn => { btn.addEventListener('click', handleCommentLikeClick); }); document.querySelectorAll('.like-reply-btn').forEach(btn => { btn.addEventListener('click', handleReplyLikeClick); }); document.querySelectorAll('.reply-btn').forEach(btn => { btn.addEventListener('click', handleReplyClick); }); document.querySelectorAll('.cancel-reply').forEach(btn => { btn.addEventListener('click', handleCancelReply); }); document.querySelectorAll('.submit-reply').forEach(btn => { btn.addEventListener('click', handleReplySubmit); }); } // Handle comment like async function handleCommentLikeClick(e) { if (!userState.isSubscribed) { showNewsletterModal(); return; } const btn = e.currentTarget; const commentId = Number(btn.getAttribute('data-comment')); btn.disabled = true; try { const res = await fetch(`${API_BASE}/toggle_comment_like.php`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ comment_id: commentId, visitor_id: userState.visitor_id }), }); const data = await res.json(); if (data.success) { const isLiked = btn.classList.contains('active'); btn.classList.toggle('active'); const icon = btn.querySelector('i'); icon.classList.toggle('far'); icon.classList.toggle('fas'); const countSpan = btn.querySelector('.comment-like-count'); if (countSpan && data.likes !== undefined) { countSpan.textContent = data.likes; } if (isLiked) { userState.commentLikes = userState.commentLikes.filter(id => id !== commentId); } else { userState.commentLikes.push(commentId); } showToast(`Comment ${isLiked ? 'unliked' : 'liked'}`, 'success'); } else { showToast('Failed to like comment', 'error'); } } catch (error) { showToast('Failed to like comment. Please try again.', 'error'); } finally { btn.disabled = false; } } // Handle reply like async function handleReplyLikeClick(e) { if (!userState.isSubscribed) { showNewsletterModal(); return; } const btn = e.currentTarget; const replyId = Number(btn.getAttribute('data-reply')); btn.disabled = true; try { const res = await fetch(`${API_BASE}/toggle_reply_like.php`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ reply_id: replyId, visitor_id: userState.visitor_id }), }); const data = await res.json(); if (data.success) { const isLiked = btn.classList.contains('active'); btn.classList.toggle('active'); const icon = btn.querySelector('i'); icon.classList.toggle('far'); icon.classList.toggle('fas'); const countSpan = btn.querySelector('.reply-like-count'); if (countSpan && data.likes !== undefined) { countSpan.textContent = data.likes; } if (isLiked) { userState.commentLikes = userState.commentLikes.filter(id => id !== replyId); } else { userState.commentLikes.push(replyId); } showToast(`Reply ${isLiked ? 'unliked' : 'liked'}`, 'success'); } else { showToast('Failed to like reply', 'error'); } } catch (error) { showToast('Failed to like reply. Please try again.', 'error'); } finally { btn.disabled = false; } } // Handle reply click function handleReplyClick(e) { if (!userState.isSubscribed) { showNewsletterModal(); return; } const btn = e.currentTarget; const commentId = btn.getAttribute('data-comment'); const replyForm = document.getElementById(`replyForm-${commentId}`); document.querySelectorAll('.reply-form').forEach(form => { form.style.display = 'none'; }); replyForm.style.display = 'block'; const textarea = replyForm.querySelector('.reply-input'); setTimeout(() => textarea.focus(), 100); } // Handle cancel reply function handleCancelReply(e) { const btn = e.currentTarget; const commentId = btn.getAttribute('data-comment'); const replyForm = document.getElementById(`replyForm-${commentId}`); replyForm.style.display = 'none'; const textarea = replyForm.querySelector('.reply-input'); textarea.value = ''; } // Handle reply submission - FIXED COUNTER async function handleReplySubmit(e) { if (!userState.isSubscribed) { showNewsletterModal(); return; } const btn = e.currentTarget; const commentId = Number(btn.getAttribute('data-comment')); const replyForm = document.getElementById(`replyForm-${commentId}`); const textarea = replyForm.querySelector('.reply-input'); const content = textarea.value.trim(); if (!content) { showInlineError(textarea, 'Please write a reply before submitting.'); return; } const originalText = btn.innerHTML; btn.disabled = true; btn.innerHTML = ' Posting...'; try { const response = await fetch(`${API_BASE}/add_reply.php`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ comment_id: commentId, content: content, visitor_id: userState.visitor_id }), }); const data = await response.json(); if (data.success) { textarea.value = ''; replyForm.style.display = 'none'; // Update main comments counter const commentsCount = document.getElementById('commentsCount'); const currentText = commentsCount.textContent; const currentCount = parseInt(currentText) || 0; commentsCount.textContent = `${currentCount + 1} ${currentCount + 1 === 1 ? 'Comment' : 'Comments'}`; // Update comment button counter const commentBtnCount = document.querySelector('.comment-btn .comment-count'); if (commentBtnCount) { const btnCurrentCount = parseInt(commentBtnCount.textContent) || 0; commentBtnCount.textContent = btnCurrentCount + 1; } // Update reply count for this comment const replyBtn = document.querySelector(`.reply-btn[data-comment="${commentId}"] .reply-count`); if (replyBtn) { const currentReplyCount = parseInt(replyBtn.textContent) || 0; replyBtn.textContent = currentReplyCount + 1; } loadComments(currentPost.id); showToast('Reply posted successfully!', 'success'); } else { showToast('Failed to post reply. Please try again.', 'error'); } } catch (error) { showToast('Failed to post reply. Please try again.', 'error'); } finally { btn.disabled = false; btn.innerHTML = originalText; } } // Attach event handlers function attachEventHandlers() { document.querySelectorAll('.like-btn').forEach(btn => { btn.addEventListener('click', handleLikeClick); }); document.querySelectorAll('.favorite-btn').forEach(btn => { btn.addEventListener('click', handleFavoriteClick); }); const commentForm = document.getElementById('commentForm'); if (commentForm) { commentForm.addEventListener('submit', handleCommentSubmit); } document.getElementById('modalClose')?.addEventListener('click', closeModal); document.getElementById('closeModal')?.addEventListener('click', closeModal); newsletterModal?.addEventListener('click', (e) => { if (e.target === newsletterModal) { closeModal(); } }); document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { closeModal(); } }); } // Handle like click async function handleLikeClick(e) { if (!userState.isSubscribed) { showNewsletterModal(); return; } const btn = e.currentTarget; const postId = Number(btn.getAttribute('data-post')); btn.disabled = true; try { const res = await fetch(`${API_BASE}/toggle_like.php`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ post_id: postId, visitor_id: userState.visitor_id }), }); const data = await res.json(); if (data.success) { const isLiked = btn.classList.contains('active'); document.querySelectorAll(`.like-btn[data-post="${postId}"]`).forEach(likeBtn => { likeBtn.classList.toggle('active'); const icon = likeBtn.querySelector('i'); icon.classList.toggle('far'); icon.classList.toggle('fas'); }); updateActionCounters(postId, data.likes, undefined, undefined); if (isLiked) { userState.likes = userState.likes.filter(id => id !== postId); } else { userState.likes.push(postId); } showToast(`Article ${isLiked ? 'unliked' : 'liked'}`, 'success'); } else { showToast('Failed to like article', 'error'); } } catch (error) { showToast('Failed to like article. Please try again.', 'error'); } finally { btn.disabled = false; } } // Handle favorite click async function handleFavoriteClick(e) { if (!userState.isSubscribed) { showNewsletterModal(); return; } const btn = e.currentTarget; const postId = Number(btn.getAttribute('data-post')); btn.disabled = true; try { const res = await fetch(`${API_BASE}/toggle_favorite.php`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ post_id: postId, visitor_id: userState.visitor_id }), }); const data = await res.json(); if (data.success) { document.querySelectorAll(`.favorite-btn[data-post="${postId}"]`).forEach(favBtn => { favBtn.classList.toggle('active'); const icon = favBtn.querySelector('i'); icon.classList.toggle('far'); icon.classList.toggle('fas'); }); updateActionCounters(postId, undefined, data.favorites_count, undefined); if (btn.classList.contains('active')) { userState.favorites = userState.favorites.filter(id => id !== postId); } else { userState.favorites.push(postId); } showToast(`Article ${data.action === 'added' ? 'added to' : 'removed from'} favorites`, 'success'); } else { showToast('Failed to favorite article', 'error'); } } catch (error) { showToast('Failed to favorite article. Please try again.', 'error'); } finally { btn.disabled = false; } } // Handle comment submission - FIXED COUNTER async function handleCommentSubmit(e) { e.preventDefault(); if (!userState.isSubscribed) { showNewsletterModal(); return; } const form = e.target; const contentInput = document.getElementById('commentContent'); const content = contentInput.value.trim(); const postId = currentPost.id; if (!content) { showInlineError(contentInput, 'Please write a comment before submitting.'); return; } const submitBtn = form.querySelector('button[type="submit"]'); const originalText = submitBtn.innerHTML; submitBtn.disabled = true; submitBtn.innerHTML = ' Posting...'; try { const response = await fetch(`${API_BASE}/add_comment.php`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ post_id: postId, content: content, visitor_id: userState.visitor_id }), }); const data = await response.json(); if (data.success) { contentInput.value = ''; // Update comments section counter const commentsCount = document.getElementById('commentsCount'); const currentText = commentsCount.textContent; const currentCount = parseInt(currentText) || 0; commentsCount.textContent = `${currentCount + 1} ${currentCount + 1 === 1 ? 'Comment' : 'Comments'}`; // Update comment button counter const commentBtnCount = document.querySelector('.comment-btn .comment-count'); if (commentBtnCount) { const btnCurrentCount = parseInt(commentBtnCount.textContent) || 0; commentBtnCount.textContent = btnCurrentCount + 1; } loadComments(postId); showToast('Comment posted successfully!', 'success'); } else { showToast('Failed to post comment. Please try again.', 'error'); } } catch (error) { showToast('Failed to post comment. Please try again.', 'error'); } finally { submitBtn.disabled = false; submitBtn.innerHTML = originalText; } } // Show newsletter modal function showNewsletterModal() { if (newsletterModal) { newsletterModal.classList.add('active'); document.body.style.overflow = 'hidden'; } } // Close modal function closeModal() { if (newsletterModal) { newsletterModal.classList.remove('active'); document.body.style.overflow = ''; } } // Helper functions function escapeHtml(str) { if (!str) return ""; const div = document.createElement('div'); div.textContent = str; return div.innerHTML; } function formatDate(dateString) { try { if (!dateString) return ""; const date = new Date(dateString); const now = new Date(); const diffTime = Math.abs(now - date); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); if (diffDays === 1) { return 'Yesterday'; } else if (diffDays < 7) { return `${diffDays} days ago`; } else if (diffDays < 30) { const weeks = Math.floor(diffDays / 7); return `${weeks} week${weeks > 1 ? 's' : ''} ago`; } else { return date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' }); } } catch (e) { return dateString || ""; } } // Initialize async function init() { showLoading(); await Promise.all([ checkSubscription(), fetchUserState() ]); await fetchArticle(); setInterval(async () => { await checkSubscription(); }, 30000); } // Start the application document.addEventListener('DOMContentLoaded', init); })();
Comments
Add a Comment
${userState.isSubscribed ? `