88 lines
2.1 KiB
TypeScript
88 lines
2.1 KiB
TypeScript
import { useState, useEffect } from 'react'
|
||
import { usersApi } from '@/api'
|
||
|
||
// Глобальный кэш для blob URL аватарок
|
||
const avatarCache = new Map<number, string>()
|
||
|
||
interface UserAvatarProps {
|
||
userId: number
|
||
hasAvatar: boolean // Есть ли у пользователя avatar_url
|
||
nickname: string
|
||
size?: 'sm' | 'md' | 'lg'
|
||
className?: string
|
||
}
|
||
|
||
const sizeClasses = {
|
||
sm: 'w-8 h-8 text-xs',
|
||
md: 'w-12 h-12 text-sm',
|
||
lg: 'w-24 h-24 text-xl',
|
||
}
|
||
|
||
export function UserAvatar({ userId, hasAvatar, nickname, size = 'md', className = '' }: UserAvatarProps) {
|
||
const [blobUrl, setBlobUrl] = useState<string | null>(null)
|
||
const [failed, setFailed] = useState(false)
|
||
|
||
useEffect(() => {
|
||
if (!hasAvatar) {
|
||
setBlobUrl(null)
|
||
return
|
||
}
|
||
|
||
// Проверяем кэш
|
||
const cached = avatarCache.get(userId)
|
||
if (cached) {
|
||
setBlobUrl(cached)
|
||
return
|
||
}
|
||
|
||
// Загружаем аватарку
|
||
let cancelled = false
|
||
usersApi.getAvatarUrl(userId)
|
||
.then(url => {
|
||
if (!cancelled) {
|
||
avatarCache.set(userId, url)
|
||
setBlobUrl(url)
|
||
}
|
||
})
|
||
.catch(() => {
|
||
if (!cancelled) {
|
||
setFailed(true)
|
||
}
|
||
})
|
||
|
||
return () => {
|
||
cancelled = true
|
||
}
|
||
}, [userId, hasAvatar])
|
||
|
||
const sizeClass = sizeClasses[size]
|
||
|
||
if (blobUrl && !failed) {
|
||
return (
|
||
<img
|
||
src={blobUrl}
|
||
alt={nickname}
|
||
className={`rounded-full object-cover ${sizeClass} ${className}`}
|
||
/>
|
||
)
|
||
}
|
||
|
||
// Fallback - первая буква никнейма
|
||
return (
|
||
<div className={`rounded-full bg-gray-700 flex items-center justify-center ${sizeClass} ${className}`}>
|
||
<span className="text-gray-400 font-medium">
|
||
{nickname.charAt(0).toUpperCase()}
|
||
</span>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
// Функция для очистки кэша конкретного пользователя (после загрузки нового аватара)
|
||
export function clearAvatarCache(userId: number) {
|
||
const cached = avatarCache.get(userId)
|
||
if (cached) {
|
||
URL.revokeObjectURL(cached)
|
||
avatarCache.delete(userId)
|
||
}
|
||
}
|