'use client'; import { useRef, useState } from 'react'; import { Camera, Loader2 } from 'lucide-react'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { useToast } from '@/components/id/toast-provider'; import { useAvatarUrl } from '@/hooks/use-avatar-url'; import { apiFetch, getApiErrorMessage, uploadMediaObject } from '@/lib/api'; import { VerificationBadge } from '@/components/id/verification-badge'; import { cn } from '@/lib/utils'; interface PresignedUploadResponse { uploadUrl: string; storageKey: string; expiresAt: string; uploadToken?: string; } export function AvatarUpload({ userId, displayName, hasAvatar, token, onUpdated, isVerified, verificationIcon, className = 'h-24 w-24', badgeSize = 'md' }: { userId: string; displayName?: string; hasAvatar?: boolean; token: string | null; onUpdated: () => Promise; isVerified?: boolean; verificationIcon?: string | null; className?: string; badgeSize?: 'xs' | 'sm' | 'md' | 'lg'; }) { const inputRef = useRef(null); const { showToast } = useToast(); const [isUploading, setIsUploading] = useState(false); const { avatarUrl, refreshAvatarUrl } = useAvatarUrl(userId, hasAvatar, token); const initials = (displayName ?? '').slice(0, 2).toUpperCase() || 'ID'; async function handleFileChange(event: React.ChangeEvent) { const file = event.target.files?.[0]; if (!file || !token) return; if (!['image/jpeg', 'image/png', 'image/webp', 'image/gif'].includes(file.type)) { showToast('Допустимы только JPEG, PNG, WEBP или GIF'); return; } setIsUploading(true); try { const presigned = await apiFetch( '/media/avatars/upload-url', { method: 'POST', body: JSON.stringify({ contentType: file.type }) }, token ); await uploadMediaObject(presigned, file, file.type); await apiFetch('/media/avatars/confirm', { method: 'POST', body: JSON.stringify({ storageKey: presigned.storageKey }) }, token); await onUpdated(); await refreshAvatarUrl(); showToast('Аватар обновлён'); } catch (error) { const message = getApiErrorMessage(error, 'Не удалось загрузить аватар'); if (message) showToast(message); } finally { setIsUploading(false); if (inputRef.current) inputRef.current.value = ''; } } function openFilePicker() { if (isUploading || !token) return; inputRef.current?.click(); } return (
{isVerified ? ( ) : null}
); } export function AvatarDisplay({ userId, displayName, hasAvatar, token, className, isVerified, verificationIcon, badgeSize = 'sm' }: { userId: string; displayName?: string; hasAvatar?: boolean; token: string | null; className?: string; isVerified?: boolean; verificationIcon?: string | null; badgeSize?: 'xs' | 'sm' | 'md' | 'lg'; }) { const { avatarUrl } = useAvatarUrl(userId, hasAvatar, token); const initials = (displayName ?? '').slice(0, 2).toUpperCase() || 'ID'; return (
{avatarUrl ? : null} {initials} {isVerified ? ( ) : null}
); }