(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}

`; } // Show loading function showLoading() { articleContainer.innerHTML = `

Loading article...

`; } // Show toast notification function showToast(message, type = 'info') { const existingToast = document.querySelector('.toast-notification'); if (existingToast) { existingToast.remove(); } const toast = document.createElement('div'); toast.className = `toast-notification toast-${type}`; toast.innerHTML = `
${message}
`; document.body.appendChild(toast); setTimeout(() => { toast.classList.add('show'); }, 100); setTimeout(() => { hideToast(toast); }, 4000); toast.querySelector('.toast-close').addEventListener('click', () => { hideToast(toast); }); } // Hide toast function hideToast(toast) { toast.classList.remove('show'); setTimeout(() => { if (toast.parentNode) { toast.parentNode.removeChild(toast); } }, 300); } // Show inline error function showInlineError(element, message) { const existingError = element.parentNode.querySelector('.inline-error'); if (existingError) { existingError.remove(); } const errorElement = document.createElement('div'); errorElement.className = 'inline-error'; errorElement.innerHTML = ` ${message}`; element.parentNode.appendChild(errorElement); element.classList.add('error'); setTimeout(() => { errorElement.remove(); element.classList.remove('error'); }, 3000); } // Render article with counters function renderArticle(post) { const isLiked = userState.likes.includes(Number(post.id)); const isFavorited = userState.favorites.includes(Number(post.id)); articleContainer.innerHTML = `

${escapeHtml(post.title)}

${post.image ? `${escapeHtml(post.title)}` : ''} ${post.content ? `
${post.content}
` : ''}
${post.complete_content || post.content || '

Content coming soon...

'}

Comments

Loading comments... Join the discussion
Loading comments...

Add a Comment

${userState.isSubscribed ? ` ` : ''}
${!userState.isSubscribed ? '
Please subscribe to post comments and interact with others
' : ''}
`; attachEventHandlers(); loadComments(post.id); } // Scroll to comments window.scrollToComments = function() { const commentsSection = document.getElementById('commentsSection'); if (commentsSection) { commentsSection.scrollIntoView({ behavior: 'smooth' }); } }; // Load comments with replies - FIXED COUNTER async function loadComments(postId) { try { const response = await fetch(`${API_BASE}/get_comments.php?post_id=${postId}&visitor_id=${encodeURIComponent(userState.visitor_id)}`); const data = await response.json(); const commentsList = document.querySelector('.comments-list'); const commentsLoading = document.querySelector('.comments-loading'); const commentsCount = document.getElementById('commentsCount'); if (data.success) { commentsLoading.style.display = 'none'; commentsList.style.display = 'block'; if (data.data && data.data.length > 0) { let totalComments = 0; let totalReplies = 0; data.data.forEach(comment => { totalComments++; totalReplies += (comment.replies && comment.replies.length) || 0; }); const totalInteractions = totalComments + totalReplies; commentsCount.textContent = `${totalInteractions} ${totalInteractions === 1 ? 'Comment' : 'Comments'}`; commentsList.innerHTML = data.data.map(comment => { const isCommentLiked = userState.commentLikes.includes(Number(comment.id)); const replies = comment.replies || []; return `
${escapeHtml(comment.name)} ${formatDate(comment.created_at)}
${escapeHtml(comment.content)}
${replies.length > 0 ? `
${replies.length} ${replies.length === 1 ? 'Reply' : 'Replies'}
${replies.map(reply => { const isReplyLiked = userState.commentLikes.includes(Number(reply.id)); return `
${escapeHtml(reply.name)} ${formatDate(reply.created_at)}
${escapeHtml(reply.content)}
`; }).join('')}
` : ''}
`; }).join(''); } else { commentsCount.textContent = '0 Comments'; commentsList.innerHTML = '

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