nakama/frontend/src/components/FollowListModal.jsx

134 lines
4.3 KiB
React
Raw Normal View History

2025-12-04 20:00:39 +00:00
import { X, UserPlus, UserMinus } from 'lucide-react'
import { useNavigate } from 'react-router-dom'
import { useState } from 'react'
2025-12-04 20:27:45 +00:00
import { createPortal } from 'react-dom'
2025-12-04 20:00:39 +00:00
import { followUser, unfollowUser } from '../utils/api'
import { hapticFeedback } from '../utils/telegram'
import './FollowListModal.css'
export default function FollowListModal({ users, title, onClose, currentUser }) {
const navigate = useNavigate()
const [userStates, setUserStates] = useState(
users.reduce((acc, user) => {
acc[user._id] = {
isFollowing: currentUser?.following?.some(f => f._id === user._id || f === user._id) || false
}
return acc
}, {})
)
const handleOverlayClick = (e) => {
if (e.target === e.currentTarget) {
onClose()
}
}
const handleUserClick = (userId) => {
hapticFeedback('light')
onClose()
navigate(`/user/${userId}`)
}
const handleFollowToggle = async (userId, e) => {
e.stopPropagation()
try {
hapticFeedback('light')
const isCurrentlyFollowing = userStates[userId]?.isFollowing || false
if (isCurrentlyFollowing) {
await unfollowUser(userId)
setUserStates(prev => ({
...prev,
[userId]: { isFollowing: false }
}))
} else {
await followUser(userId)
setUserStates(prev => ({
...prev,
[userId]: { isFollowing: true }
}))
}
hapticFeedback('success')
} catch (error) {
console.error('Ошибка подписки:', error)
hapticFeedback('error')
}
}
2025-12-04 20:27:45 +00:00
return createPortal(
2025-12-04 20:11:28 +00:00
<div
className="follow-list-modal-overlay"
onMouseDown={(e) => e.stopPropagation()}
onTouchStart={(e) => e.stopPropagation()}
onClick={handleOverlayClick}
>
2025-12-04 20:00:39 +00:00
<div className="follow-list-modal" onClick={(e) => e.stopPropagation()}>
{/* Хедер */}
<div className="follow-list-header">
<button className="close-btn" onClick={onClose}>
<X size={24} />
</button>
<h2>{title}</h2>
<div style={{ width: 40 }} />
</div>
{/* Список пользователей */}
<div className="follow-list-content">
{users.length === 0 ? (
<div className="empty-state">
<p>Пока никого нет</p>
</div>
) : (
<div className="users-list">
{users.map((user) => {
const isOwnProfile = user._id === currentUser?.id
const isFollowing = userStates[user._id]?.isFollowing || false
return (
2025-12-04 20:47:07 +00:00
<div key={user._id} className="user-item-wrapper">
<div
className="user-item"
onClick={() => handleUserClick(user._id)}
>
<img
src={user.photoUrl || '/default-avatar.png'}
alt={user.username || user.firstName || 'User'}
className="user-avatar"
onError={(e) => { e.target.src = '/default-avatar.png' }}
/>
<div className="user-info">
<div className="user-name">
{user.firstName || ''} {user.lastName || ''}
{!user.firstName && !user.lastName && 'Пользователь'}
</div>
<div className="user-username">@{user.username || user.firstName || 'user'}</div>
2025-12-04 20:00:39 +00:00
</div>
</div>
2025-12-04 22:00:18 +00:00
{!isOwnProfile && (
<button
className={`follow-btn-icon ${isFollowing ? 'following' : ''}`}
onClick={(e) => handleFollowToggle(user._id, e)}
>
{isFollowing ? (
<UserMinus size={12} />
) : (
<UserPlus size={12} />
)}
</button>
)}
</div>
2025-12-04 20:00:39 +00:00
</div>
)
})}
</div>
)}
</div>
</div>
2025-12-04 20:27:45 +00:00
</div>,
document.body
2025-12-04 20:00:39 +00:00
)
}