auto-claude: subtask-1-4 - Add URL state management using searchParams and router.push
This commit is contained in:
@@ -7,6 +7,7 @@ import { BlogList } from '@/components/blog/BlogList';
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
params: Promise<{ locale: string }>;
|
params: Promise<{ locale: string }>;
|
||||||
|
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Legacy blog posts with translations (these have manual translations)
|
// Legacy blog posts with translations (these have manual translations)
|
||||||
@@ -304,8 +305,9 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default async function BlogPage({ params }: Props) {
|
export default async function BlogPage({ params, searchParams }: Props) {
|
||||||
const { locale } = await params;
|
const { locale } = await params;
|
||||||
|
const resolvedSearchParams = await searchParams;
|
||||||
setRequestLocale(locale);
|
setRequestLocale(locale);
|
||||||
|
|
||||||
const t = await getTranslations('blog');
|
const t = await getTranslations('blog');
|
||||||
@@ -323,6 +325,10 @@ export default async function BlogPage({ params }: Props) {
|
|||||||
...legacyPosts,
|
...legacyPosts,
|
||||||
].sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
|
].sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
|
||||||
|
|
||||||
|
// Extract search and category from URL params
|
||||||
|
const initialSearch = typeof resolvedSearchParams.search === 'string' ? resolvedSearchParams.search : '';
|
||||||
|
const initialCategory = typeof resolvedSearchParams.category === 'string' ? resolvedSearchParams.category : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="min-h-screen">
|
<main className="min-h-screen">
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16 sm:py-20 lg:py-24">
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16 sm:py-20 lg:py-24">
|
||||||
@@ -344,6 +350,8 @@ export default async function BlogPage({ params }: Props) {
|
|||||||
<BlogList
|
<BlogList
|
||||||
posts={allPosts}
|
posts={allPosts}
|
||||||
locale={locale}
|
locale={locale}
|
||||||
|
initialSearch={initialSearch}
|
||||||
|
initialCategory={initialCategory}
|
||||||
translations={{
|
translations={{
|
||||||
searchPlaceholder: t('ui.search.placeholder'),
|
searchPlaceholder: t('ui.search.placeholder'),
|
||||||
showingText: (start: number, end: number, total: number) =>
|
showingText: (start: number, end: number, total: number) =>
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState, useMemo } from 'react';
|
import { useState, useMemo, useEffect } from 'react';
|
||||||
import { Calendar, Tag, ExternalLink, ChevronLeft, ChevronRight } from 'lucide-react';
|
import { Calendar, Tag, ExternalLink, ChevronLeft, ChevronRight } from 'lucide-react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
|
import { useRouter, usePathname } from 'next/navigation';
|
||||||
import { BlogPost } from '@/lib/blog';
|
import { BlogPost } from '@/lib/blog';
|
||||||
import { SearchBar } from './SearchBar';
|
import { SearchBar } from './SearchBar';
|
||||||
import { CategoryFilter } from './CategoryFilter';
|
import { CategoryFilter } from './CategoryFilter';
|
||||||
@@ -281,6 +282,8 @@ function Pagination({
|
|||||||
interface BlogListProps {
|
interface BlogListProps {
|
||||||
posts: BlogPost[];
|
posts: BlogPost[];
|
||||||
locale: string;
|
locale: string;
|
||||||
|
initialSearch?: string;
|
||||||
|
initialCategory?: string | null;
|
||||||
translations: {
|
translations: {
|
||||||
searchPlaceholder: string;
|
searchPlaceholder: string;
|
||||||
showingText: (start: number, end: number, total: number) => string;
|
showingText: (start: number, end: number, total: number) => string;
|
||||||
@@ -290,11 +293,32 @@ interface BlogListProps {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function BlogList({ posts, locale, translations }: BlogListProps) {
|
export function BlogList({ posts, locale, initialSearch = '', initialCategory = null, translations }: BlogListProps) {
|
||||||
const [searchQuery, setSearchQuery] = useState('');
|
const router = useRouter();
|
||||||
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
const [searchQuery, setSearchQuery] = useState(initialSearch);
|
||||||
|
const [selectedCategory, setSelectedCategory] = useState<string | null>(initialCategory);
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
|
|
||||||
|
// Update URL when filters change
|
||||||
|
useEffect(() => {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
|
||||||
|
if (searchQuery.trim()) {
|
||||||
|
params.set('search', searchQuery.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedCategory) {
|
||||||
|
params.set('category', selectedCategory);
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryString = params.toString();
|
||||||
|
const newUrl = queryString ? `${pathname}?${queryString}` : pathname;
|
||||||
|
|
||||||
|
router.push(newUrl, { scroll: false });
|
||||||
|
}, [searchQuery, selectedCategory, pathname, router]);
|
||||||
|
|
||||||
// Extract unique categories from all posts
|
// Extract unique categories from all posts
|
||||||
const allCategories = useMemo(() => {
|
const allCategories = useMemo(() => {
|
||||||
const categories = new Set(posts.map(post => post.category).filter(Boolean));
|
const categories = new Set(posts.map(post => post.category).filter(Boolean));
|
||||||
|
|||||||
Reference in New Issue
Block a user