Public Access
1
0

feat: enhance blog post view counter with individual tracking and display

This commit is contained in:
2025-08-24 23:36:11 -04:00
parent 9b2f5d5840
commit 3416ee171c
3 changed files with 78 additions and 40 deletions

View File

@@ -1,37 +1,70 @@
document.addEventListener('DOMContentLoaded', () => {
const viewCountElement = document.querySelector('[data-view-count]');
// Select all elements that are designated to display view counts.
const viewCountElements = document.querySelectorAll('[data-view-count]');
if (viewCountElement) {
const slug = viewCountElement.dataset.slug;
// Function to fetch and display the view count
const getViews = async () => {
try {
const response = await fetch(`/api/views/${slug}`);
if (!response.ok) throw new Error('Failed to fetch views');
const data = await response.json();
viewCountElement.textContent = `${data.count} views`;
} catch (error) {
console.error('Error getting views:', error);
viewCountElement.textContent = 'Could not load views';
}
};
// Function to increment the view count
const incrementView = async () => {
try {
// Use a flag in localStorage to prevent incrementing on every refresh
const viewed = localStorage.getItem(`viewed-${slug}`);
if (!viewed) {
await fetch(`/api/views/${slug}`, { method: 'POST' });
localStorage.setItem(`viewed-${slug}`, 'true');
}
} catch (error) {
console.error('Error incrementing view:', error);
}
};
// Run the functions
incrementView().then(getViews);
// If no such elements are found, do nothing.
if (viewCountElements.length === 0) {
return;
}
});
// Process each view count element found on the page.
viewCountElements.forEach(element => {
const slug = element.dataset.slug;
if (!slug) {
// Skip if the element is missing the data-slug attribute.
return;
}
// Check if the element is on a single post page by looking for a `.post-meta` parent.
// This distinguishes a single post view (which should be counted) from a list view.
const isSinglePost = element.closest('.post-meta');
if (isSinglePost) {
// On a single post page, increment the view count.
const viewed = localStorage.getItem(`viewed-${slug}`);
// Only increment if the user hasn't viewed this post in the current session.
if (!viewed) {
fetch(`/api/views/${slug}`, { method: 'POST' })
.then(response => {
if (!response.ok) throw new Error('Network response was not ok');
return response.json();
})
.then(data => {
element.textContent = data.count ?? 'Error';
// Mark as viewed to prevent re-counting on refresh.
localStorage.setItem(`viewed-${slug}`, 'true');
})
.catch(error => {
console.error(`Error incrementing view count for slug ${slug}:`, error);
element.textContent = 'N/A';
});
} else {
// If already viewed in this session, just fetch the count without incrementing.
fetch(`/api/views/${slug}`)
.then(response => {
if (!response.ok) throw new Error('Network response was not ok');
return response.json();
})
.then(data => {
element.textContent = data.count ?? 0;
})
.catch(error => {
console.error(`Error fetching view count for slug ${slug}:`, error);
element.textContent = 'N/A';
});
}
} else {
// On a list page (like the main blog page), just fetch and display the count.
fetch(`/api/views/${slug}`)
.then(response => response.json())
.then(data => {
element.textContent = data.count ?? 0;
})
.catch(error => {
console.error(`Error fetching view count for slug ${slug}:`, error);
element.textContent = 'N/A';
});
}
});
});