russ_react/src/pages/ArticlePage.tsx

163 lines
5.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState, useEffect } from 'react';
import { useParams, Link } from 'react-router-dom';
import { ArrowLeft, Clock, Share2, Bookmark } from 'lucide-react';
import { Header } from '../components/Header';
import { ReactionButtons } from '../components/ReactionButtons';
import { PhotoGallery } from '../components/PhotoGallery';
//import { articles } from '../data/mock';
import {Article, CategoryTitles} from '../types';
import { ArticleContent } from '../components/ArticleContent';
import MinutesWord from '../components/MinutesWord';
import axios from "axios";
export function ArticlePage() {
const { id } = useParams();
const [articleData, setArticleData] = useState<Article | null>(null);
// const [error, setError] = useState<string | null>(null);
/*
const [articleData, setArticleData] = useState<Article | undefined>(
articles.find(a => a.id === id)
);
*/
useEffect(() => {
const fetchArticle = async () => {
try {
const response = await axios.get(`/api/articles/${id}`);
setArticleData(response.data);
} catch (error) {
//setError('Не удалось загрузить статью');
console.error(error);
}
};
fetchArticle();
}, [id]);
useEffect(() => {
window.scrollTo(0, 0);
}, [id]);
if (!articleData) {
return (
<div className="min-h-screen flex items-center justify-center">
<div className="text-center">
<h2 className="text-2xl font-bold text-gray-900 mb-4">Article not found</h2>
<Link to="/" className="text-blue-600 hover:text-blue-800">
Назад на главную
</Link>
</div>
</div>
);
}
const handleReaction = (reaction: 'like' | 'dislike') => {
setArticleData(prev => {
if (!prev) return prev;
const newArticle = { ...prev };
if (prev.userReaction === 'like') newArticle.likes--;
if (prev.userReaction === 'dislike') newArticle.dislikes--;
if (prev.userReaction !== reaction) {
if (reaction === 'like') newArticle.likes++;
if (reaction === 'dislike') newArticle.dislikes++;
newArticle.userReaction = reaction;
} else {
newArticle.userReaction = null;
}
return newArticle;
});
};
return (
<div className="min-h-screen bg-white">
<Header />
<main className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
<Link
to="/"
className="inline-flex items-center text-gray-600 hover:text-gray-900 mb-8"
>
<ArrowLeft size={20} className="mr-2" />
К списку статей
</Link>
<article>
{/* Article Header */}
<div className="mb-8">
<div className="flex items-center gap-4 mb-6">
<img
src={articleData.author.avatarUrl}
alt={articleData.author.displayName}
className="w-12 h-12 rounded-full"
/>
<div>
<p className="font-medium text-gray-900">{articleData.author.displayName}</p>
<div className="flex items-center text-sm text-gray-500">
<Clock size={14} className="mr-1" />
{articleData.readTime} <MinutesWord minutes={articleData.readTime}/> на чтение ·{' '}
{new Date(articleData.publishedAt).toLocaleDateString('ru-RU', {
month: 'long',
day: 'numeric',
year: 'numeric',
})}
</div>
</div>
</div>
<h1 className="text-4xl font-bold text-gray-900 mb-4">{articleData.title}</h1>
<p className="text-xl text-gray-600 mb-6">{articleData.excerpt}</p>
<div className="flex items-center gap-4 mb-8">
<span className="bg-blue-100 text-blue-800 px-3 py-1 rounded-full text-sm font-medium">
{CategoryTitles[articleData.categoryId]}
</span>
<div className="flex-1" />
<button className="p-2 text-gray-500 hover:text-gray-700 rounded-full hover:bg-gray-100">
<Share2 size={20} />
</button>
<button className="p-2 text-gray-500 hover:text-gray-700 rounded-full hover:bg-gray-100">
<Bookmark size={20} />
</button>
</div>
</div>
{/* Cover Image */}
<img
src={articleData.coverImage}
alt={articleData.title}
className="w-full h-[28rem] object-cover rounded-xl mb-8"
/>
{/* Article Content */}
<div className="prose prose-lg max-w-none mb-8">
<div className="text-gray-800 leading-relaxed">
<ArticleContent content={articleData.content} />
</div>
</div>
{/* Photo Gallery */}
{articleData.gallery && articleData.gallery.length > 0 && (
<div className="mb-8">
<h2 className="text-2xl font-bold text-gray-900 mb-4">Фото галерея</h2>
<PhotoGallery images={articleData.gallery} />
</div>
)}
{/* Article Footer */}
<div className="border-t pt-8">
<ReactionButtons
likes={articleData.likes}
dislikes={articleData.dislikes}
userReaction={articleData.userReaction}
onReact={handleReaction}
/>
</div>
</article>
</main>
</div>
);
}