Update files
This commit is contained in:
parent
458c7fadc8
commit
a19c4bca62
|
|
@ -72,7 +72,7 @@ export default function CommentsModal({ post, onClose, onUpdate }) {
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true
|
cancelled = true
|
||||||
}
|
}
|
||||||
}, [post?._id || null]) // Только ID поста в зависимостях, используем null для стабильности
|
}, [post?._id]) // Используем просто post?._id без || null
|
||||||
|
|
||||||
// Проверка на существование поста ПОСЛЕ хуков
|
// Проверка на существование поста ПОСЛЕ хуков
|
||||||
const displayPost = fullPost || post
|
const displayPost = fullPost || post
|
||||||
|
|
@ -104,10 +104,6 @@ export default function CommentsModal({ post, onClose, onUpdate }) {
|
||||||
setComment('')
|
setComment('')
|
||||||
hapticFeedback('success')
|
hapticFeedback('success')
|
||||||
|
|
||||||
// Обновить данные поста для синхронизации (но не блокируем UI)
|
|
||||||
// Перезагружаем через useEffect, который сработает при изменении post._id
|
|
||||||
// Но так как post._id не меняется, просто обновим локально
|
|
||||||
|
|
||||||
if (onUpdate) {
|
if (onUpdate) {
|
||||||
onUpdate()
|
onUpdate()
|
||||||
}
|
}
|
||||||
|
|
@ -124,6 +120,7 @@ export default function CommentsModal({ post, onClose, onUpdate }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const formatDate = (date) => {
|
const formatDate = (date) => {
|
||||||
|
if (!date) return 'только что'
|
||||||
const d = new Date(date)
|
const d = new Date(date)
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const diff = Math.floor((now - d) / 1000) // секунды
|
const diff = Math.floor((now - d) / 1000) // секунды
|
||||||
|
|
@ -142,17 +139,15 @@ export default function CommentsModal({ post, onClose, onUpdate }) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если нет валидного поста, не рендерим модалку вообще
|
// ВСЕГДА рендерим createPortal, даже если пост не валиден
|
||||||
if (!hasValidPost) {
|
// Это критично для соблюдения правил хуков
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return createPortal(
|
return createPortal(
|
||||||
<div
|
<div
|
||||||
className="comments-modal-overlay"
|
className="comments-modal-overlay"
|
||||||
onMouseDown={(e) => e.stopPropagation()}
|
onMouseDown={(e) => e.stopPropagation()}
|
||||||
onTouchStart={(e) => e.stopPropagation()}
|
onTouchStart={(e) => e.stopPropagation()}
|
||||||
onClick={handleOverlayClick}
|
onClick={handleOverlayClick}
|
||||||
|
style={{ display: hasValidPost ? 'flex' : 'none' }}
|
||||||
>
|
>
|
||||||
<div className="comments-modal" onClick={(e) => e.stopPropagation()}>
|
<div className="comments-modal" onClick={(e) => e.stopPropagation()}>
|
||||||
{/* Хедер */}
|
{/* Хедер */}
|
||||||
|
|
@ -165,7 +160,13 @@ export default function CommentsModal({ post, onClose, onUpdate }) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Пост */}
|
{/* Пост */}
|
||||||
{loadingPost ? (
|
{!hasValidPost ? (
|
||||||
|
<div className="post-preview">
|
||||||
|
<div className="loading-state">
|
||||||
|
<p>Загрузка...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : loadingPost ? (
|
||||||
<div className="post-preview">
|
<div className="post-preview">
|
||||||
<div className="loading-state">
|
<div className="loading-state">
|
||||||
<div className="spinner" />
|
<div className="spinner" />
|
||||||
|
|
@ -205,71 +206,75 @@ export default function CommentsModal({ post, onClose, onUpdate }) {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Список комментариев */}
|
{/* Список комментариев */}
|
||||||
<div className="comments-list">
|
{hasValidPost && (
|
||||||
{comments.length === 0 ? (
|
<div className="comments-list">
|
||||||
<div className="empty-comments">
|
{comments.length === 0 ? (
|
||||||
<p>Пока нет комментариев</p>
|
<div className="empty-comments">
|
||||||
<span>Будьте первым!</span>
|
<p>Пока нет комментариев</p>
|
||||||
</div>
|
<span>Будьте первым!</span>
|
||||||
) : (
|
|
||||||
comments
|
|
||||||
.filter(c => {
|
|
||||||
// Фильтруем комментарии без автора или с неполным автором
|
|
||||||
return c && c.author && (typeof c.author === 'object') && c.content
|
|
||||||
})
|
|
||||||
.map((c, index) => {
|
|
||||||
// Используем _id если есть, иначе index
|
|
||||||
const commentId = c._id || c.id || `comment-${index}`
|
|
||||||
// Проверяем, что автор полностью загружен
|
|
||||||
if (!c.author || typeof c.author !== 'object') {
|
|
||||||
console.warn('[CommentsModal] Комментарий без автора:', c)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div key={commentId} className="comment-item fade-in">
|
|
||||||
<img
|
|
||||||
src={c.author?.photoUrl || '/default-avatar.png'}
|
|
||||||
alt={c.author?.username || c.author?.firstName || 'User'}
|
|
||||||
className="comment-avatar"
|
|
||||||
onError={(e) => { e.target.src = '/default-avatar.png' }}
|
|
||||||
/>
|
|
||||||
<div className="comment-content">
|
|
||||||
<div className="comment-header">
|
|
||||||
<span className="comment-author">
|
|
||||||
{c.author?.firstName || ''} {c.author?.lastName || ''}
|
|
||||||
{!c.author?.firstName && !c.author?.lastName && 'Пользователь'}
|
|
||||||
</span>
|
|
||||||
<span className="comment-time">{formatDate(c.createdAt)}</span>
|
|
||||||
</div>
|
|
||||||
<p className="comment-text">{decodeHtmlEntities(c.content)}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
) : (
|
||||||
})
|
comments
|
||||||
.filter(Boolean) // Убираем null значения
|
.filter(c => {
|
||||||
)}
|
// Фильтруем комментарии без автора или с неполным автором
|
||||||
</div>
|
return c && c.author && (typeof c.author === 'object') && c.content
|
||||||
|
})
|
||||||
|
.map((c, index) => {
|
||||||
|
// Используем _id если есть, иначе index
|
||||||
|
const commentId = c._id || c.id || `comment-${index}`
|
||||||
|
// Проверяем, что автор полностью загружен
|
||||||
|
if (!c.author || typeof c.author !== 'object') {
|
||||||
|
console.warn('[CommentsModal] Комментарий без автора:', c)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div key={commentId} className="comment-item fade-in">
|
||||||
|
<img
|
||||||
|
src={c.author?.photoUrl || '/default-avatar.png'}
|
||||||
|
alt={c.author?.username || c.author?.firstName || 'User'}
|
||||||
|
className="comment-avatar"
|
||||||
|
onError={(e) => { e.target.src = '/default-avatar.png' }}
|
||||||
|
/>
|
||||||
|
<div className="comment-content">
|
||||||
|
<div className="comment-header">
|
||||||
|
<span className="comment-author">
|
||||||
|
{c.author?.firstName || ''} {c.author?.lastName || ''}
|
||||||
|
{!c.author?.firstName && !c.author?.lastName && 'Пользователь'}
|
||||||
|
</span>
|
||||||
|
<span className="comment-time">{formatDate(c.createdAt)}</span>
|
||||||
|
</div>
|
||||||
|
<p className="comment-text">{decodeHtmlEntities(c.content)}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.filter(Boolean) // Убираем null значения
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Форма добавления комментария */}
|
{/* Форма добавления комментария */}
|
||||||
<div className="comment-form">
|
{hasValidPost && (
|
||||||
<input
|
<div className="comment-form">
|
||||||
type="text"
|
<input
|
||||||
placeholder="Написать комментарий..."
|
type="text"
|
||||||
value={comment}
|
placeholder="Написать комментарий..."
|
||||||
onChange={e => setComment(e.target.value)}
|
value={comment}
|
||||||
onKeyPress={e => e.key === 'Enter' && handleSubmit()}
|
onChange={e => setComment(e.target.value)}
|
||||||
maxLength={500}
|
onKeyPress={e => e.key === 'Enter' && handleSubmit()}
|
||||||
/>
|
maxLength={500}
|
||||||
<button
|
/>
|
||||||
onClick={handleSubmit}
|
<button
|
||||||
disabled={loading || !comment.trim()}
|
onClick={handleSubmit}
|
||||||
className="send-btn"
|
disabled={loading || !comment.trim()}
|
||||||
>
|
className="send-btn"
|
||||||
<Send size={20} />
|
>
|
||||||
</button>
|
<Send size={20} />
|
||||||
</div>
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>,
|
||||||
|
document.body
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue