2025-11-03 21:43:00 +00:00
|
|
|
import { useState, useEffect, useRef } from 'react'
|
2025-11-03 20:35:01 +00:00
|
|
|
import { X, Send } from 'lucide-react'
|
|
|
|
|
import { commentPost } from '../utils/api'
|
2025-11-03 21:43:00 +00:00
|
|
|
import { hapticFeedback, getTelegramApp } from '../utils/telegram'
|
2025-11-03 20:35:01 +00:00
|
|
|
import './CommentsModal.css'
|
|
|
|
|
|
|
|
|
|
export default function CommentsModal({ post, onClose, onUpdate }) {
|
|
|
|
|
const [comment, setComment] = useState('')
|
|
|
|
|
const [loading, setLoading] = useState(false)
|
|
|
|
|
const [comments, setComments] = useState(post.comments || [])
|
2025-11-03 21:43:00 +00:00
|
|
|
const modalRef = useRef(null)
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const tg = getTelegramApp()
|
|
|
|
|
|
|
|
|
|
if (tg) {
|
|
|
|
|
// Фиксировать высоту при изменении viewport (клавиатура)
|
|
|
|
|
const handleViewportChange = () => {
|
|
|
|
|
if (modalRef.current) {
|
|
|
|
|
const currentHeight = modalRef.current.offsetHeight
|
|
|
|
|
modalRef.current.style.height = `${currentHeight}px`
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tg.onEvent('viewportChanged', handleViewportChange)
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
if (tg.offEvent) {
|
|
|
|
|
tg.offEvent('viewportChanged', handleViewportChange)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}, [])
|
2025-11-03 20:35:01 +00:00
|
|
|
|
|
|
|
|
const handleSubmit = async () => {
|
|
|
|
|
if (!comment.trim()) return
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
setLoading(true)
|
|
|
|
|
hapticFeedback('light')
|
|
|
|
|
|
|
|
|
|
const result = await commentPost(post._id, comment)
|
|
|
|
|
setComments(result.comments)
|
|
|
|
|
setComment('')
|
|
|
|
|
hapticFeedback('success')
|
|
|
|
|
onUpdate()
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Ошибка добавления комментария:', error)
|
|
|
|
|
hapticFeedback('error')
|
|
|
|
|
} finally {
|
|
|
|
|
setLoading(false)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const formatDate = (date) => {
|
|
|
|
|
const d = new Date(date)
|
|
|
|
|
const now = new Date()
|
|
|
|
|
const diff = Math.floor((now - d) / 1000) // секунды
|
|
|
|
|
|
|
|
|
|
if (diff < 60) return 'только что'
|
|
|
|
|
if (diff < 3600) return `${Math.floor(diff / 60)} мин`
|
|
|
|
|
if (diff < 86400) return `${Math.floor(diff / 3600)} ч`
|
|
|
|
|
|
|
|
|
|
return d.toLocaleDateString('ru-RU', { day: 'numeric', month: 'short' })
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-03 21:29:00 +00:00
|
|
|
const handleOverlayClick = (e) => {
|
|
|
|
|
// Закрывать только при клике на overlay, не на содержимое
|
|
|
|
|
if (e.target === e.currentTarget) {
|
|
|
|
|
onClose()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-03 20:35:01 +00:00
|
|
|
return (
|
2025-11-03 21:29:00 +00:00
|
|
|
<div className="comments-modal-overlay" onClick={handleOverlayClick}>
|
2025-11-03 21:43:00 +00:00
|
|
|
<div className="comments-modal" ref={modalRef}>
|
2025-11-03 20:35:01 +00:00
|
|
|
{/* Хедер */}
|
|
|
|
|
<div className="modal-header">
|
|
|
|
|
<button className="close-btn" onClick={onClose}>
|
|
|
|
|
<X size={24} />
|
|
|
|
|
</button>
|
|
|
|
|
<h2>Комментарии ({comments.length})</h2>
|
|
|
|
|
<div style={{ width: 32 }} />
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Список комментариев */}
|
|
|
|
|
<div className="comments-list">
|
|
|
|
|
{comments.length === 0 ? (
|
|
|
|
|
<div className="empty-comments">
|
|
|
|
|
<p>Пока нет комментариев</p>
|
|
|
|
|
<span>Будьте первым!</span>
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
comments.map((c, index) => (
|
|
|
|
|
<div key={index} className="comment-item fade-in">
|
|
|
|
|
<img
|
|
|
|
|
src={c.author.photoUrl || '/default-avatar.png'}
|
|
|
|
|
alt={c.author.username}
|
|
|
|
|
className="comment-avatar"
|
|
|
|
|
/>
|
|
|
|
|
<div className="comment-content">
|
|
|
|
|
<div className="comment-header">
|
|
|
|
|
<span className="comment-author">
|
|
|
|
|
{c.author.firstName} {c.author.lastName}
|
|
|
|
|
</span>
|
|
|
|
|
<span className="comment-time">{formatDate(c.createdAt)}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<p className="comment-text">{c.content}</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
))
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Форма добавления комментария */}
|
|
|
|
|
<div className="comment-form">
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
placeholder="Написать комментарий..."
|
|
|
|
|
value={comment}
|
|
|
|
|
onChange={e => setComment(e.target.value)}
|
|
|
|
|
onKeyPress={e => e.key === 'Enter' && handleSubmit()}
|
|
|
|
|
maxLength={500}
|
|
|
|
|
/>
|
|
|
|
|
<button
|
|
|
|
|
onClick={handleSubmit}
|
|
|
|
|
disabled={loading || !comment.trim()}
|
|
|
|
|
className="send-btn"
|
|
|
|
|
>
|
|
|
|
|
<Send size={20} />
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|