102 lines
3.4 KiB
TypeScript
102 lines
3.4 KiB
TypeScript
import { useEffect, useState } from 'react';
|
||
import { useSearchParams } from 'react-router-dom';
|
||
import { Header } from '../components/Header';
|
||
import { ArticleCard } from '../components/ArticleCard';
|
||
import { Pagination } from '../components/Pagination';
|
||
import { Article } from '../types';
|
||
import api from '../utils/api';
|
||
|
||
const ARTICLES_PER_PAGE = 9;
|
||
|
||
|
||
export function SearchPage() {
|
||
const [searchParams, setSearchParams] = useSearchParams();
|
||
const query = searchParams.get('q') || '';
|
||
const authorId = searchParams.get('author');
|
||
const page = parseInt(searchParams.get('page') || '1', 10);
|
||
|
||
const [articles, setArticles] = useState<Article[]>([]);
|
||
const [totalPages, setTotalPages] = useState(1);
|
||
const [loading, setLoading] = useState(false);
|
||
|
||
useEffect(() => {
|
||
const fetchResults = async () => {
|
||
if (!query && !authorId) return;
|
||
|
||
setLoading(true);
|
||
try {
|
||
const response = await api.get('/articles/search', {
|
||
params: {
|
||
q: query,
|
||
author: authorId,
|
||
page,
|
||
limit: ARTICLES_PER_PAGE
|
||
}
|
||
});
|
||
setArticles(response.data.articles);
|
||
setTotalPages(response.data.totalPages);
|
||
} catch (error) {
|
||
console.error('Ошибка поиска:', error);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||
|
||
fetchResults();
|
||
}, [query, authorId, page]);
|
||
|
||
const handlePageChange = (newPage: number) => {
|
||
setSearchParams({ q: query, page: newPage.toString() });
|
||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||
};
|
||
|
||
return (
|
||
<div className="min-h-screen bg-gray-50">
|
||
<Header />
|
||
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
||
<div className="mb-8">
|
||
<h1 className="text-3xl font-bold text-gray-900">
|
||
{query ? `Результаты поиска "${query}"` : 'Статьи автора'}
|
||
</h1>
|
||
{articles.length > 0 && (
|
||
<p className="mt-2 text-gray-600">
|
||
Найдено {articles.length} статей
|
||
</p>
|
||
)}
|
||
</div>
|
||
|
||
{loading ? (
|
||
<div className="flex justify-center items-center h-64">
|
||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
|
||
</div>
|
||
) : articles.length > 0 ? (
|
||
<>
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||
{articles.map((article) => (
|
||
<ArticleCard key={article.id} article={article} />
|
||
))}
|
||
</div>
|
||
{totalPages > 1 && (
|
||
<Pagination
|
||
currentPage={page}
|
||
totalPages={totalPages}
|
||
onPageChange={handlePageChange}
|
||
/>
|
||
)}
|
||
</>
|
||
) : (query || authorId) ? (
|
||
<div className="text-center py-12">
|
||
<h2 className="text-xl font-medium text-gray-900 mb-2">
|
||
Не найдено ни одной статьи
|
||
</h2>
|
||
<p className="text-gray-500">
|
||
{authorId ? "Этот автор не опубликовал пока ни одной статьи" : "Ничего не найдено. Попытайтесь изменить сроку поиска"}
|
||
</p>
|
||
</div>
|
||
) : null}
|
||
</main>
|
||
</div>
|
||
);
|
||
} |