import { Suspense } from 'react' import { Metadata } from 'next' import { Header } from '@/components/header' import { Footer } from '@/components/footer' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Badge } from '@/components/ui/badge' import { Card, CardContent } from '@/components/ui/card' import { Skeleton } from '@/components/ui/skeleton' import { Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, } from '@/components/ui/pagination' import { Search, BookOpen, Eye } from 'lucide-react' import Link from 'next/link' import Image from 'next/image' import { ITopic } from '@/models/topic' // Force dynamic rendering for real-time topic updates export const dynamic = 'force-dynamic' // SEO metadata for the topics page export async function generateMetadata(): Promise { return { title: 'Topic - SiliconPin | Web Development Insights & Tutorials', description: 'Discover the latest insights, tutorials, and stories from the SiliconPin community. Learn about web development, cloud computing, and cutting-edge technology trends.', keywords: [ 'web development', 'cloud computing', 'programming tutorials', 'tech insights', 'software engineering', 'SiliconPin topic', 'development tutorials', ], authors: [{ name: 'SiliconPin Team' }], openGraph: { title: 'SiliconPin Topic - Web Development Insights', description: 'Discover the latest insights, tutorials, and stories from the SiliconPin community.', type: 'website', siteName: 'SiliconPin', }, twitter: { card: 'summary_large_image', title: 'SiliconPin Topic - Web Development Insights', description: 'Discover the latest insights, tutorials, and stories from the SiliconPin community.', }, alternates: { canonical: '/topics', }, robots: { index: true, follow: true, googleBot: { index: true, follow: true, }, }, } } // Server-side data fetching async function parseSearchParams( searchParams: Promise<{ [key: string]: string | string[] | undefined }> ) { const params = await searchParams return { page: params.page ? parseInt(params.page as string) : 1, tag: params.tag ? (params.tag as string) : undefined, search: params.q ? (params.q as string) : undefined, } } async function getTopics(searchParams: Promise<{ [key: string]: string | string[] | undefined }>) { const { page, tag, search } = await parseSearchParams(searchParams) try { // Build API URL with parameters const baseUrl = process.env.NODE_ENV === 'production' ? `${process.env.NEXTAUTH_URL || 'https://siliconpin.com'}` : 'http://localhost:4023' const searchQuery = new URLSearchParams({ page: page.toString(), limit: '6', ...(tag && { tag }), ...(search && { q: search }), }) const response = await fetch(`${baseUrl}/api/topics?${searchQuery}`, { headers: { 'Content-Type': 'application/json', }, // Disable cache for dynamic data cache: 'no-store', }) if (!response.ok) { throw new Error(`Failed to fetch topics: ${response.status}`) } const result = await response.json() if (!result.success) { throw new Error(result.error?.message || 'Failed to fetch topics') } return { topics: result.data || [], pagination: result.pagination || { total: 0, page, limit: 6, totalPages: 0, }, } } catch (error) { console.error('Error fetching topics:', error) // Fallback to empty state return { topics: [], pagination: { total: 0, page, limit: 6, totalPages: 0, }, } } } // Get unique tags from topics for filtering async function getTags(): Promise> { try { const baseUrl = process.env.NODE_ENV === 'production' ? `${process.env.NEXTAUTH_URL || 'https://siliconpin.com'}` : 'http://localhost:4023' const response = await fetch(`${baseUrl}/api/topics/tags`, { headers: { 'Content-Type': 'application/json', }, cache: 'no-store', }) if (!response.ok) { throw new Error(`Failed to fetch tags: ${response.status}`) } const result = await response.json() if (!result.success) { throw new Error(result.error?.message || 'Failed to fetch tags') } return result.data || [] } catch (error) { console.error('Error fetching tags:', error) // Fallback to empty array return [] } } // Topic grid skeleton loader function TopicGridSkeleton() { return (
{Array.from({ length: 6 }).map((_, i) => (
))}
) } export default async function TopicsPage({ searchParams, }: { searchParams: Promise<{ [key: string]: string | string[] | undefined }> }) { const { page: currentPage, tag: selectedTag, search: searchQuery, } = await parseSearchParams(searchParams) const { topics, pagination } = await getTopics(searchParams) const tags = await getTags() return (

Topic Posts

{/* Search and filter section */}
{searchQuery && ( )}
{tags.map((tag) => ( {tag.name} ))}
{/* Filter info */} {(selectedTag || searchQuery) && (

{pagination.total} post(s) found {selectedTag && ` with tag: ${selectedTag}`} {searchQuery && ` containing: "${searchQuery}"`}

)} {/* Topic posts grid */} }> {topics.length > 0 ? (
{topics.map((topic) => (
{topic.title}
{new Date(topic.publishedAt).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric', })} {(topic.views || 0) > 0 && ( {topic.views?.toLocaleString()} )}

{topic.title}

{topic.excerpt}

{topic.tags.map((tag) => ( {tag.name} ))}
))}
) : (

No posts found matching your criteria.

)} {/* Pagination */} {topics.length > 0 && pagination.totalPages > 1 && ( {currentPage > 1 && ( )} {Array.from({ length: Math.min(pagination.totalPages, 5) }, (_, i) => { const page = i + 1 return ( {page} ) })} {currentPage < pagination.totalPages && ( )} )}
) }