// blog.js - fixed version with proper filtered view handling (function () { const API_BASE = "/backend"; const blogGrid = document.getElementById("blogGrid"); if (!blogGrid) return; const filterBtns = document.querySelectorAll(".blog-filter .filter-btn"); const loadMoreBtn = document.getElementById("loadMore"); let posts = []; let filteredPosts = []; // Store filtered posts let userState = { visitor_id: null, likes: [], favorites: [], isSubscribed: false }; let isShowingAll = false; // Track if showing all posts let currentFilter = "all"; // Track current filter const POSTS_PER_PAGE = 4; // Changed from 3 to 4 /* ---------------- 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; } /* ---------------- enhanced subscription check ---------------- */ async function checkSubscription() { try { const response = await fetch(`${API_BASE}/check_newsletter_session.php`); const data = await response.json(); console.log('📊 Subscription check result:', data); userState.isSubscribed = data.subscribed === true; return userState.isSubscribed; } catch (error) { console.error('❌ Subscription check failed:', error); return false; } } /* ---------------- subscription prompt ---------------- */ function showSubscriptionPrompt(action = 'perform this action') { const message = `Please subscribe to our newsletter to ${action}.`; // Create a custom modal instead of alert const modal = document.createElement('div'); modal.style.cssText = ` position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); display: flex; align-items: center; justify-content: center; z-index: 10000; backdrop-filter: blur(5px); `; modal.innerHTML = `
${message}
No articles available
`; } } catch (err) { console.error("fetchPosts error:", err); blogGrid.innerHTML = `Error loading articles
`; } } /* ---------------- create card ---------------- */ function createBlogCard(post = {}, index = 0) { const id = post.id ?? ""; const title = post.title ?? "Untitled"; const slug = post.slug ?? id; const category = post.category ?? "general"; const image = post.image || "/uploads/blog/default.jpg"; const author = post.author || "Admin"; const excerpt = post.excerpt || ""; const read_time = post.read_time || ""; const published_date = post.published_date || ""; const card = document.createElement("article"); card.className = "blog-card"; card.setAttribute("data-id", id); card.setAttribute("data-category", category); card.innerHTML = `${escapeHtml(excerpt)}
No articles found
`; updateLoadMoreButton(); return; } postsToRender.forEach((p, i) => { const card = createBlogCard(p, i); blogGrid.appendChild(card); setTimeout(() => card.classList.add("visible"), i * 80); }); attachCardEventHandlers(); updateLoadMoreButton(); } /* ---------------- update load more button ---------------- */ function updateLoadMoreButton() { if (!loadMoreBtn) return; let totalPosts; if (currentFilter === "favorites" || currentFilter === "liked") { totalPosts = filteredPosts.length; } else { totalPosts = posts.length; } if (totalPosts <= POSTS_PER_PAGE) { loadMoreBtn.style.display = "none"; } else { loadMoreBtn.style.display = "block"; loadMoreBtn.innerHTML = isShowingAll ? ' View Less' : ' View All Articles'; } } /* ---------------- render filtered posts ---------------- */ function renderFilteredPosts(list, filterType) { filteredPosts = list; currentFilter = filterType; isShowingAll = false; // Reset to show limited posts first // Clear the grid blogGrid.innerHTML = ""; if (!Array.isArray(filteredPosts) || filteredPosts.length === 0) { blogGrid.innerHTML = `No articles found
`; updateLoadMoreButton(); return; } // Show limited posts initially const postsToShow = isShowingAll ? filteredPosts : filteredPosts.slice(0, POSTS_PER_PAGE); postsToShow.forEach((p, i) => { const card = createBlogCard(p, i); blogGrid.appendChild(card); setTimeout(() => card.classList.add("visible"), i * 80); }); attachCardEventHandlers(); updateLoadMoreButton(); } /* ---------------- events for cards ---------------- */ function attachCardEventHandlers() { // bookmarks (favorites) document.querySelectorAll(".bookmark-btn").forEach((btn) => { btn.removeEventListener("click", handleBookmarkClick); btn.addEventListener("click", handleBookmarkClick); }); // likes document.querySelectorAll(".like-stat").forEach((stat) => { stat.removeEventListener("click", handleLikeClick); stat.addEventListener("click", handleLikeClick); }); // read more anchors document.querySelectorAll(".read-more").forEach((a) => { a.removeEventListener("click", handleReadMoreClick); a.addEventListener("click", handleReadMoreClick); }); } async function handleBookmarkClick(e) { e.preventDefault(); e.stopPropagation(); // Check subscription first if (!userState.isSubscribed) { showSubscriptionPrompt('bookmark articles'); return; } const btn = e.currentTarget; const postId = Number(btn.getAttribute("data-post")); if (!postId) return; 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 j = await res.json(); if (j && j.success) { const icon = btn.querySelector("i"); icon.classList.toggle("far"); icon.classList.toggle("fas"); // Update user state if (icon.classList.contains("fas")) { userState.favorites.push(postId); } else { userState.favorites = userState.favorites.filter(id => id !== postId); } // If we're on the favorites filter, update the view if (currentFilter === "favorites") { const favPosts = posts.filter((p) => userState.favorites.includes(Number(p.id))); renderFilteredPosts(favPosts, "favorites"); } } } catch (err) { console.error("toggle_favorite error:", err); } } async function handleLikeClick(e) { e.preventDefault(); e.stopPropagation(); // Check subscription first if (!userState.isSubscribed) { showSubscriptionPrompt('like articles'); return; } const stat = e.currentTarget; const postId = Number(stat.getAttribute("data-post")); if (!postId) return; 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 j = await res.json(); if (j && j.success) { const icon = stat.querySelector("i"); const cnt = stat.querySelector("span"); if (typeof j.likes !== "undefined") cnt.textContent = j.likes; icon.classList.toggle("far"); icon.classList.toggle("fas"); // Update user state if (icon.classList.contains("fas")) { userState.likes.push(postId); } else { userState.likes = userState.likes.filter(id => id !== postId); } // If we're on the liked filter, update the view if (currentFilter === "liked") { const likedPosts = posts.filter((p) => userState.likes.includes(Number(p.id))); renderFilteredPosts(likedPosts, "liked"); } } } catch (err) { console.error("toggle_like error:", err); } } function handleReadMoreClick(e) { e.preventDefault(); const slug = e.currentTarget.getAttribute("href").split('=')[1]; if (!slug) return; window.location.href = `article.html?slug=${slug}`; } /* ---------------- filters ---------------- */ if (filterBtns && filterBtns.length) { filterBtns.forEach((btn) => { btn.addEventListener("click", async function () { filterBtns.forEach((b) => b.classList.remove("active")); this.classList.add("active"); const filter = this.dataset.filter; // Reset view state when changing filters isShowingAll = false; if (filter === "favorites") { if (!userState.isSubscribed) { showSubscriptionPrompt('view your favorite articles'); return; } const favPosts = posts.filter((p) => userState.favorites.includes(Number(p.id))); renderFilteredPosts(favPosts, "favorites"); return; } if (filter === "liked") { if (!userState.isSubscribed) { showSubscriptionPrompt('view your liked articles'); return; } const likedPosts = posts.filter((p) => userState.likes.includes(Number(p.id))); renderFilteredPosts(likedPosts, "liked"); return; } // For category filters, fetch new posts currentFilter = filter; await fetchPosts(filter); }); }); } /* ---------------- load more / view all ---------------- */ if (loadMoreBtn) { loadMoreBtn.addEventListener("click", (e) => { e.preventDefault(); // Toggle between showing all and showing limited posts isShowingAll = !isShowingAll; renderPosts(); // Smooth scroll to top when showing less if (!isShowingAll) { blogGrid.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); } /* ---------------- helpers ---------------- */ function escapeHtml(str) { if (!str) return ""; return String(str).replace(/[&<>"']/g, (m) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[m])); } function capitalize(s) { if (!s) return ""; return s.charAt(0).toUpperCase() + s.slice(1); } function formatDate(d) { try { if (!d) return ""; const dt = new Date(d); return dt.toLocaleDateString(); } catch (e) { return d || ""; } } /* ---------------- enhanced init ---------------- */ (async function init() { console.log('🚀 Initializing blog system...'); await fetchUserState(); await checkSubscription(); // Check subscription status console.log('✅ Subscription status:', userState.isSubscribed); await fetchPosts("all"); // Periodically check subscription status (every 30 seconds) setInterval(async () => { await checkSubscription(); }, 30000); })(); })();