2026-03-18 16:42:18 +05:30

204 lines
8.0 KiB
TypeScript

"use client";
import React, { useState, useEffect, useMemo } from "react";
import Link from "next/link";
import { BlogData } from "@/utils/constant.utils";
interface BlogSidebarProps {
activeCategory?: string;
onCategoryClick?: (category: string) => void;
initialSearchTerm?: string;
onSearch?: (term: string) => void;
excludeSlug?: string;
}
const BlogSidebar = ({
activeCategory,
onCategoryClick,
initialSearchTerm = "",
onSearch,
excludeSlug
}: BlogSidebarProps) => {
const [searchTerm, setSearchTerm] = useState(initialSearchTerm);
// Debounced real-time search
useEffect(() => {
const timer = setTimeout(() => {
if (searchTerm !== initialSearchTerm && onSearch) {
onSearch(searchTerm);
}
}, 500);
return () => clearTimeout(timer);
}, [searchTerm, onSearch, initialSearchTerm]);
// Update search term when initial changes
useEffect(() => {
setSearchTerm(initialSearchTerm);
}, [initialSearchTerm]);
// Recent News (Latest 3 blogs, excluding current one, filtered by category if active)
const recentPosts = useMemo(() => {
let list = [...BlogData];
if (excludeSlug) {
list = list.filter(p => p.slug !== excludeSlug);
}
if (activeCategory) {
// Priority to same category, but if not enough, show others
const sameCat = list.filter(p => p.category === activeCategory);
const others = list.filter(p => p.category !== activeCategory);
list = [...sameCat, ...others];
}
return list
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
.slice(0, 3);
}, [activeCategory, excludeSlug]);
// Categories and Counts (Sorted to show active category at the top, then by most recent post date)
const categories = useMemo(() => {
const catMap = BlogData.reduce((acc: any, item: any) => {
if (!acc[item.category]) {
acc[item.category] = { count: 0, latestDate: new Date(0) };
}
acc[item.category].count += 1;
const itemDate = new Date(item.date);
if (itemDate > acc[item.category].latestDate) {
acc[item.category].latestDate = itemDate;
}
return acc;
}, {});
const allBlogsCat = {
name: "All Blogs",
count: BlogData.length,
latestDate: new Date() // Doesn't matter for sorting as we'll put it first
};
let result = Object.keys(catMap)
.map(cat => ({
name: cat,
count: catMap[cat].count,
latestDate: catMap[cat].latestDate
}))
.sort((a, b) => {
const normalizedActive = (activeCategory || "").trim().toLowerCase();
const normalizedA = (a.name || "").trim().toLowerCase();
const normalizedB = (b.name || "").trim().toLowerCase();
// Active category always first (if not All Blogs)
if (normalizedActive && normalizedA === normalizedActive) return -1;
if (normalizedActive && normalizedB === normalizedActive) return 1;
// Then sort by most recent post date
return b.latestDate.getTime() - a.latestDate.getTime();
});
// Optimize for Detail Page (excludeSlug exists)
if (excludeSlug && result.length > 6) {
return [allBlogsCat, ...result.slice(0, 5)];
}
return [allBlogsCat, ...result];
}, [activeCategory, excludeSlug]);
const handleSearchSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (onSearch) {
onSearch(searchTerm);
}
};
const handleCategoryClick = (e: React.MouseEvent, category: string) => {
if (onCategoryClick) {
e.preventDefault();
onCategoryClick(category);
} else {
// Default behavior if no handler is provided
// Redirect to results page
}
};
return (
<div className="main-sidebar">
{/* Search Widget */}
<div className="single-sidebar-widget search-widget">
<div className="wid-title">
<h3>Search</h3>
</div>
<div className="search_widget">
<form onSubmit={handleSearchSubmit}>
<input
type="text"
placeholder="Search blogs..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<button type="submit"><i className="fa-solid fa-magnifying-glass"></i></button>
</form>
</div>
</div>
{/* Recent News Widget */}
<div className="single-sidebar-widget">
<div className="wid-title">
<h3>Recent Blogs</h3>
</div>
<div className="popular-posts">
{recentPosts.map((post: any) => (
<div key={post.id} className="single-post-item">
<div className="thumb bg-cover">
<Link href={`/${post.slug}`}>
<img loading="lazy" src={post.image} alt={post.title} />
</Link>
</div>
<div className="post-content">
<h5>
<Link href={`/${post.slug}`}>{post.title}</Link>
</h5>
<div className="post-date">
<i className="fa-regular fa-calendar"></i> {post.date}
</div>
</div>
</div>
))}
{recentPosts.length === 0 && <p className="no-posts-found">No recent posts found.</p>}
</div>
</div>
{/* Categories Widget */}
<div className="single-sidebar-widget mb-0">
<div className="wid-title">
<h3>{excludeSlug ? "Blog Related Category" : "Categories"}</h3>
</div>
<div className="widget_categories">
<ul className="list-unstyled">
{categories.map((cat) => {
const isAllBlogs = cat.name === "All Blogs";
// Normalize for comparison to handle case-sensitivity or leading/trailing spaces
const normalizedActive = (activeCategory || "").trim().toLowerCase();
const normalizedCat = (cat.name || "").trim().toLowerCase();
const isActive = isAllBlogs
? (normalizedActive === "")
: (normalizedActive === normalizedCat);
return (
<li key={cat.name} className={isActive ? "active" : ""}>
<Link
href={isAllBlogs ? "/blog" : `/blog/results?category=${encodeURIComponent(cat.name)}`}
onClick={(e) => handleCategoryClick(e, isAllBlogs ? "" : cat.name)}
className="category-item"
>
<span className="category-name">{cat.name}</span>
<span className="category-count">{cat.count < 10 ? `0${cat.count}` : cat.count}</span>
</Link>
</li>
);
})}
</ul>
</div>
</div>
</div>
);
};
export default BlogSidebar;