// components/BlogListing.tsx 'use client'; import { useState, useEffect, useCallback } from 'react'; import Image from 'next/image'; import Link from 'next/link'; import { ChevronRight } from 'lucide-react'; import { blogService, Blog } from '../../services/blogService'; // Adjust path as needed const BlogListing: React.FC = () => { const [blogs, setBlogs] = useState([]); const [filteredBlogs, setFilteredBlogs] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [mounted, setMounted] = useState(false); const [selectedCategory, setSelectedCategory] = useState('All Categories'); const [searchQuery, setSearchQuery] = useState(''); const [displayCount, setDisplayCount] = useState(6); const [tagCounts, setTagCounts] = useState<{ [key: string]: number }>({}); // Get unique categories from blogs with their counts const getCategories = () => { const allTags = blogs.flatMap(blog => blog.tags); const uniqueTags = Array.from(new Set(allTags)); return ['All Categories', ...uniqueTags]; }; // Filter blogs based on category and search query const filterBlogs = useCallback(() => { let filtered = blogs; if (selectedCategory !== 'All Categories') { filtered = filtered.filter(blog => blog.tags.some(tag => tag.toLowerCase().includes(selectedCategory.toLowerCase()) ) ); } if (searchQuery.trim()) { const query = searchQuery.toLowerCase().trim(); filtered = filtered.filter(blog => blog.title.toLowerCase().includes(query) || blog.excerpt.toLowerCase().includes(query) || blog.tags.some(tag => tag.toLowerCase().includes(query)) || (blog.professors && blog.professors.some(prof => prof.firstName?.toLowerCase().includes(query) || prof.name?.toLowerCase().includes(query) )) ); } setFilteredBlogs(filtered); }, [blogs, selectedCategory, searchQuery]); // Load blogs from API useEffect(() => { const loadBlogs = async () => { try { setLoading(true); setError(null); // Load both posted blogs and tag counts const [fetchedBlogs, fetchedTagCounts] = await Promise.all([ blogService.getPostedBlogs(), blogService.getTagsWithCount() ]); setBlogs(fetchedBlogs); setFilteredBlogs(fetchedBlogs); setTagCounts(fetchedTagCounts); } catch (err) { setError('Failed to load blogs. Please try again later.'); console.error('Error loading blogs:', err); } finally { setLoading(false); } }; if (mounted) { loadBlogs(); } }, [mounted]); // Filter blogs when category or search changes useEffect(() => { if (mounted && blogs.length > 0) { filterBlogs(); } }, [mounted, filterBlogs]); // Handle mount useEffect(() => { setMounted(true); }, []); const handleCategoryChange = (e: React.ChangeEvent) => { setSelectedCategory(e.target.value); setDisplayCount(6); }; const handleSearchChange = (e: React.ChangeEvent) => { setSearchQuery(e.target.value); setDisplayCount(6); }; const handleLoadMore = () => { setDisplayCount(prev => prev + 6); }; const handleImageError = (event: React.SyntheticEvent) => { // Fallback to default image if the uploaded image fails to load const target = event.target as HTMLImageElement; target.src = '/images/default-blog-image.jpg'; }; if (!mounted) { return null; } if (loading) { return (

Loading blogs...

); } if (error) { return (

⚠️ {error}

); } const categories = getCategories(); const blogsToShow = filteredBlogs.slice(0, displayCount); const hasMoreBlogs = filteredBlogs.length > displayCount; return (
{/* Breadcrumb Section */}
{/* Page Header */}

Trauma Care Resources

Expert insights, healing strategies, and support resources for trauma recovery

{/* Filters Section */}
{/* Category Select */}
{/* Search Input */}
{/* Results Info */} {(selectedCategory !== 'All Categories' || searchQuery.trim()) && (

{filteredBlogs.length === 0 ? 'No blogs found matching your criteria.' : `Showing ${blogsToShow.length} of ${filteredBlogs.length} blog${filteredBlogs.length !== 1 ? 's' : ''}` }

)} {/* Blog Grid Section */}
{blogsToShow.length === 0 ? (

{searchQuery.trim() || selectedCategory !== 'All Categories' ? 'No blogs match your search criteria.' : 'No blogs available at the moment.' }

{(searchQuery.trim() || selectedCategory !== 'All Categories') && ( )}
) : (
{blogsToShow.map((blog) => (
{/* All cards redirect to blog detail page with ID */} {/* Blog Image */}
{blog.title}
{/* Blog Content */}
{/* Tags */}
{blog.tags.slice(0, 3).map((tag, tagIndex) => ( {tag} ))} {blog.tags.length > 3 && ( +{blog.tags.length - 3} )}
{/* Title */}

{blog.title}

{/* Excerpt */}

{blog.excerpt}

{/* Authors (if available) */} {blog.professors && blog.professors.length > 0 && (

By: {blog.professors.map(prof => prof.firstName || prof.name).join(', ')}

)} {/* Meta Information */}
{new Date(blog.publishDate).toLocaleDateString()} {blog.readTime}
))}
)} {/* Load More Button */} {hasMoreBlogs && (
)}
); }; export default BlogListing;