fix: fixed category filtering problem

This commit is contained in:
poyrazavsever
2026-03-11 13:29:52 +03:00
parent 875ea7f70e
commit b3e2b42de5
10 changed files with 82 additions and 31 deletions
+7 -3
View File
@@ -2,14 +2,18 @@ import { BlogContent } from "@/components/blog-content";
import { getBlogPageData } from "@/data/blog";
type BlogPageProps = {
searchParams?: Promise<{ page?: string }>;
searchParams?: Promise<{ page?: string | string[]; category?: string | string[] }>;
};
export default async function BlogPage({ searchParams }: BlogPageProps) {
const resolved = searchParams ? await searchParams : undefined;
const page = Number(resolved?.page ?? "1");
const pageParam = Array.isArray(resolved?.page) ? resolved?.page[0] : resolved?.page;
const categoryParam = Array.isArray(resolved?.category)
? resolved?.category[0]
: resolved?.category;
const page = Number(pageParam ?? "1");
const currentPage = Number.isFinite(page) && page > 0 ? Math.floor(page) : 1;
const data = await getBlogPageData(currentPage, 12);
const data = await getBlogPageData(currentPage, 12, categoryParam);
return <BlogContent data={data} />;
}
+38 -10
View File
@@ -16,8 +16,30 @@ type BlogContentProps = {
data: BlogPageData;
};
function pageHref(page: number) {
return page <= 1 ? "/blog" : `/blog?page=${page}`;
function pageHref(page: number, category: string) {
const params = new URLSearchParams();
if (page > 1) {
params.set("page", String(page));
}
if (category !== "All") {
params.set("category", category);
}
const query = params.toString();
return query ? `/blog?${query}` : "/blog";
}
function categoryHref(category: string) {
if (category === "All") {
return "/blog";
}
const params = new URLSearchParams();
params.set("category", category);
return `/blog?${params.toString()}`;
}
export function BlogContent({ data }: BlogContentProps) {
@@ -45,14 +67,15 @@ export function BlogContent({ data }: BlogContentProps) {
<Card className="rounded-sm border-border p-4">
<Typography variant="large">Kategoriler</Typography>
<div className="mt-3 flex flex-wrap gap-2">
{data.categories.map((category, index) => (
{data.categories.map((category) => (
<Link key={category} href={categoryHref(category)}>
<Badge
key={category}
variant={index === 0 ? "default" : "outline"}
className="rounded-sm"
variant={category === data.selectedCategory ? "default" : "outline"}
className="cursor-pointer rounded-sm"
>
{category}
</Badge>
</Link>
))}
</div>
</Card>
@@ -114,7 +137,9 @@ export function BlogContent({ data }: BlogContentProps) {
) : (
<Card className="rounded-sm border-border p-5">
<Typography variant="p" className="text-muted-foreground">
Henüz blog yazısı bulunmuyor.
{data.selectedCategory === "All"
? "Henüz blog yazısı bulunmuyor."
: `"${data.selectedCategory}" kategorisinde henüz blog yazısı bulunmuyor.`}
</Typography>
</Card>
)}
@@ -123,14 +148,17 @@ export function BlogContent({ data }: BlogContentProps) {
<PaginationContent className="justify-start">
<PaginationItem>
<PaginationPrevious
href={pageHref(Math.max(1, data.currentPage - 1))}
href={pageHref(Math.max(1, data.currentPage - 1), data.selectedCategory)}
aria-disabled={data.currentPage <= 1}
/>
</PaginationItem>
{pageNumbers.map((page) => (
<PaginationItem key={page}>
<PaginationLink href={pageHref(page)} isActive={page === data.currentPage}>
<PaginationLink
href={pageHref(page, data.selectedCategory)}
isActive={page === data.currentPage}
>
{page}
</PaginationLink>
</PaginationItem>
@@ -138,7 +166,7 @@ export function BlogContent({ data }: BlogContentProps) {
<PaginationItem>
<PaginationNext
href={pageHref(Math.min(data.totalPages, data.currentPage + 1))}
href={pageHref(Math.min(data.totalPages, data.currentPage + 1), data.selectedCategory)}
aria-disabled={data.currentPage >= data.totalPages}
/>
</PaginationItem>
+1 -1
View File
@@ -4,7 +4,7 @@ category: "Yazilim"
date: "2026-02-01"
readTime: "8 min read"
author: "Poyraz Avsever"
excerpt: "Bu yazida temel kavramlari, pratik ornekleri ve uygulayabileceginiz ipuclarini sade bir dille bulabilirsiniz."
excerpt: "Yazılım geliştirme sürecinde yalnızca kod yazmıyoruz; aynı zamanda takım iletişimini ve proje geçmişini...."
coverImage: "https://miro.medium.com/v2/resize:fit:1400/format:webp/1*WQOgajPE2m4aYuVC3SZoFQ.jpeg"
---
@@ -4,7 +4,7 @@ category: "Testing"
date: "2026-02-22"
readTime: "9 min read"
author: "Poyraz Avsever"
excerpt: "Bu yazida temel kavramlari, pratik ornekleri ve uygulayabileceginiz ipuclarini sade bir dille bulabilirsiniz."
excerpt: "Frontend tarafında kaliteyi korumanın en sağlam yolu testtir. Bu yazıda, farklı amaçlara hizmet eden..."
coverImage: "https://miro.medium.com/v2/resize:fit:1400/format:webp/0*uNpkjRqVlaB2WbDl.png"
---
+1 -1
View File
@@ -4,7 +4,7 @@ category: "TypeScript"
date: "2026-02-18"
readTime: "8 min read"
author: "Poyraz Avsever"
excerpt: "Bu yazida temel kavramlari, pratik ornekleri ve uygulayabileceginiz ipuclarini sade bir dille bulabilirsiniz."
excerpt: "JavaScript'ten TypeScript'e geçiş, özellikle React projelerinde kod kalitesini gözle görülür şekilde artırıyor..."
coverImage: "https://miro.medium.com/v2/resize:fit:1400/format:webp/0*yRK5eL_pqabAhrn7"
---
@@ -4,7 +4,7 @@ category: "UX"
date: "2026-02-05"
readTime: "6 min read"
author: "Poyraz Avsever"
excerpt: "Bu yazida temel kavramlari, pratik ornekleri ve uygulayabileceginiz ipuclarini sade bir dille bulabilirsiniz."
excerpt: "Tasarım dünyasında, ürünlerimizin kullanıcılarımızın ihtiyaçlarını en iyi şekilde karşılamasını istemek..."
coverImage: "https://miro.medium.com/v2/resize:fit:1400/format:webp/0*BEVhh2Et54wytkaA.jpg"
---
@@ -4,7 +4,7 @@ category: "Frontend"
date: "2026-02-14"
readTime: "11 min read"
author: "Poyraz Avsever"
excerpt: "Bu yazida temel kavramlari, pratik ornekleri ve uygulayabileceginiz ipuclarini sade bir dille bulabilirsiniz."
excerpt: "Frontend dünyasında React, Vue ve Angular gibi güçlü seçenekler var. Son yıllarda bu listeye güçlü bir alternatif..."
coverImage: "https://miro.medium.com/v2/resize:fit:1400/format:webp/0*Dx04pr9plejiCcWI.png"
---
@@ -4,7 +4,7 @@ category: "Frontend"
date: "2026-02-10"
readTime: "10 min read"
author: "Poyraz Avsever"
excerpt: "Bu yazida temel kavramlari, pratik ornekleri ve uygulayabileceginiz ipuclarini sade bir dille bulabilirsiniz."
excerpt: "Tailwind CSS, son dönemde front-end geliştiriciler arasında çok popüler hale geldi. Klasik CSS..."
coverImage: "/news/performance.svg"
---
@@ -4,7 +4,7 @@ category: "UX"
date: "2026-02-26"
readTime: "12 min read"
author: "Poyraz Avsever"
excerpt: "Bu yazida temel kavramlari, pratik ornekleri ve uygulayabileceginiz ipuclarini sade bir dille bulabilirsiniz."
excerpt: "UX (Kullanıcı Deneyimi) tasarımı, teknolojiyle etkileşime geçen herkesin deneyimini iyileştirmeye..."
coverImage: "https://miro.medium.com/v2/resize:fit:1400/format:webp/0*5OUFz00g3w5ee2lV.jpg"
---
+26 -7
View File
@@ -44,6 +44,7 @@ export type BlogPageData = {
news: BlogNewsItem[];
articles: BlogArticleItem[];
categories: string[];
selectedCategory: string;
podcastGroups: BlogPodcastGroup[];
totalPages: number;
currentPage: number;
@@ -74,6 +75,10 @@ function sortByDateDesc<T extends { date: string; id: string }>(items: T[]) {
});
}
function normalizeCategory(value: string) {
return value.trim().toLocaleLowerCase();
}
function mapEpisodeToPodcastItem(episode: PodcastEpisode): BlogPodcastItem {
return {
id: `${episode.podcast}-${episode.slug}`,
@@ -115,13 +120,12 @@ export async function getHomeBlogNews(limit = 3): Promise<BlogNewsItem[]> {
}));
}
export async function getBlogPageData(page = 1, pageSize = 12): Promise<BlogPageData> {
export async function getBlogPageData(
page = 1,
pageSize = 12,
selectedCategoryParam?: string,
): Promise<BlogPageData> {
const articles = await getAllBlogArticles();
const totalPages = Math.max(1, Math.ceil(Math.max(articles.length, 1) / pageSize));
const currentPage = Math.min(Math.max(1, page), totalPages);
const start = (currentPage - 1) * pageSize;
const paginated = articles.slice(start, start + pageSize);
const categories = [
"All",
...new Set(
@@ -130,11 +134,25 @@ export async function getBlogPageData(page = 1, pageSize = 12): Promise<BlogPage
.filter(Boolean),
),
];
const categoryByNormalized = new Map(
categories.map((category) => [normalizeCategory(category), category]),
);
const requestedCategory = selectedCategoryParam?.trim();
const selectedCategory =
(requestedCategory && categoryByNormalized.get(normalizeCategory(requestedCategory))) || "All";
const filteredArticles =
selectedCategory === "All"
? articles
: articles.filter((item) => normalizeCategory(item.category) === normalizeCategory(selectedCategory));
const totalPages = Math.max(1, Math.ceil(Math.max(filteredArticles.length, 1) / pageSize));
const currentPage = Math.min(Math.max(1, page), totalPages);
const start = (currentPage - 1) * pageSize;
const paginated = filteredArticles.slice(start, start + pageSize);
const podcastCollections = await getPodcastCollections();
return {
news: articles.slice(0, 4).map((item) => ({
news: filteredArticles.slice(0, 4).map((item) => ({
id: `blog-news-${item.slug}`,
title: item.title,
category: item.category,
@@ -144,6 +162,7 @@ export async function getBlogPageData(page = 1, pageSize = 12): Promise<BlogPage
})),
articles: paginated,
categories,
selectedCategory,
totalPages,
currentPage,
podcastGroups: [