148 lines
4.1 KiB
React
148 lines
4.1 KiB
React
|
|
import { useState, useEffect } from 'react'
|
|||
|
|
import { getPosts } from '../utils/api'
|
|||
|
|
import PostCard from '../components/PostCard'
|
|||
|
|
import CreatePostModal from '../components/CreatePostModal'
|
|||
|
|
import { Plus } from 'lucide-react'
|
|||
|
|
import { hapticFeedback } from '../utils/telegram'
|
|||
|
|
import './Feed.css'
|
|||
|
|
|
|||
|
|
export default function Feed({ user }) {
|
|||
|
|
const [posts, setPosts] = useState([])
|
|||
|
|
const [loading, setLoading] = useState(true)
|
|||
|
|
const [showCreateModal, setShowCreateModal] = useState(false)
|
|||
|
|
const [filter, setFilter] = useState('all')
|
|||
|
|
const [page, setPage] = useState(1)
|
|||
|
|
const [hasMore, setHasMore] = useState(true)
|
|||
|
|
|
|||
|
|
useEffect(() => {
|
|||
|
|
loadPosts()
|
|||
|
|
}, [filter])
|
|||
|
|
|
|||
|
|
const loadPosts = async (pageNum = 1) => {
|
|||
|
|
try {
|
|||
|
|
setLoading(true)
|
|||
|
|
const params = {}
|
|||
|
|
if (filter !== 'all') {
|
|||
|
|
params.tag = filter
|
|||
|
|
}
|
|||
|
|
params.page = pageNum
|
|||
|
|
|
|||
|
|
const data = await getPosts(params)
|
|||
|
|
|
|||
|
|
if (pageNum === 1) {
|
|||
|
|
setPosts(data.posts)
|
|||
|
|
} else {
|
|||
|
|
setPosts(prev => [...prev, ...data.posts])
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
setHasMore(pageNum < data.totalPages)
|
|||
|
|
setPage(pageNum)
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('Ошибка загрузки постов:', error)
|
|||
|
|
} finally {
|
|||
|
|
setLoading(false)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const handleCreatePost = () => {
|
|||
|
|
hapticFeedback('light')
|
|||
|
|
setShowCreateModal(true)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const handlePostCreated = (newPost) => {
|
|||
|
|
setPosts(prev => [newPost, ...prev])
|
|||
|
|
setShowCreateModal(false)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const handleLoadMore = () => {
|
|||
|
|
if (!loading && hasMore) {
|
|||
|
|
loadPosts(page + 1)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div className="feed-page">
|
|||
|
|
{/* Хедер */}
|
|||
|
|
<div className="feed-header">
|
|||
|
|
<h1>NakamaSpace</h1>
|
|||
|
|
<button className="create-btn" onClick={handleCreatePost}>
|
|||
|
|
<Plus size={20} />
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Фильтры */}
|
|||
|
|
<div className="feed-filters">
|
|||
|
|
<button
|
|||
|
|
className={`filter-btn ${filter === 'all' ? 'active' : ''}`}
|
|||
|
|
onClick={() => setFilter('all')}
|
|||
|
|
>
|
|||
|
|
Все
|
|||
|
|
</button>
|
|||
|
|
<button
|
|||
|
|
className={`filter-btn ${filter === 'furry' ? 'active' : ''}`}
|
|||
|
|
onClick={() => setFilter('furry')}
|
|||
|
|
style={{ color: filter === 'furry' ? 'var(--tag-furry)' : undefined }}
|
|||
|
|
>
|
|||
|
|
Furry
|
|||
|
|
</button>
|
|||
|
|
<button
|
|||
|
|
className={`filter-btn ${filter === 'anime' ? 'active' : ''}`}
|
|||
|
|
onClick={() => setFilter('anime')}
|
|||
|
|
style={{ color: filter === 'anime' ? 'var(--tag-anime)' : undefined }}
|
|||
|
|
>
|
|||
|
|
Anime
|
|||
|
|
</button>
|
|||
|
|
<button
|
|||
|
|
className={`filter-btn ${filter === 'other' ? 'active' : ''}`}
|
|||
|
|
onClick={() => setFilter('other')}
|
|||
|
|
style={{ color: filter === 'other' ? 'var(--tag-other)' : undefined }}
|
|||
|
|
>
|
|||
|
|
Other
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Посты */}
|
|||
|
|
<div className="feed-content">
|
|||
|
|
{loading && posts.length === 0 ? (
|
|||
|
|
<div className="loading-state">
|
|||
|
|
<div className="spinner" />
|
|||
|
|
</div>
|
|||
|
|
) : posts.length === 0 ? (
|
|||
|
|
<div className="empty-state">
|
|||
|
|
<p>Пока нет постов</p>
|
|||
|
|
<button className="btn-primary" onClick={handleCreatePost}>
|
|||
|
|
Создать первый пост
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
) : (
|
|||
|
|
<>
|
|||
|
|
{posts.map(post => (
|
|||
|
|
<PostCard key={post._id} post={post} currentUser={user} onUpdate={loadPosts} />
|
|||
|
|
))}
|
|||
|
|
|
|||
|
|
{hasMore && (
|
|||
|
|
<button
|
|||
|
|
className="load-more-btn"
|
|||
|
|
onClick={handleLoadMore}
|
|||
|
|
disabled={loading}
|
|||
|
|
>
|
|||
|
|
{loading ? 'Загрузка...' : 'Загрузить ещё'}
|
|||
|
|
</button>
|
|||
|
|
)}
|
|||
|
|
</>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Модальное окно создания поста */}
|
|||
|
|
{showCreateModal && (
|
|||
|
|
<CreatePostModal
|
|||
|
|
user={user}
|
|||
|
|
onClose={() => setShowCreateModal(false)}
|
|||
|
|
onPostCreated={handlePostCreated}
|
|||
|
|
/>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
|