'use client'; import { useRef, useState } from 'react'; import { Camera, Loader2 } from 'lucide-react'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { Button } from '@/components/ui/button'; import { useToast } from '@/components/id/toast-provider'; import { useAvatarUrl } from '@/hooks/use-avatar-url'; import { apiFetch, getApiErrorMessage, uploadMediaObject } from '@/lib/api'; interface PresignedUploadResponse { uploadUrl: string; storageKey: string; expiresAt: string; uploadToken?: string; } export function AvatarUpload({ userId, displayName, hasAvatar, token, onUpdated }: { userId: string; displayName?: string; hasAvatar?: boolean; token: string | null; onUpdated: () => Promise; }) { 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 = ''; } } return (
{avatarUrl ? : null} {initials}
); } export function AvatarDisplay({ userId, displayName, hasAvatar, token, className }: { userId: string; displayName?: string; hasAvatar?: boolean; token: string | null; className?: string; }) { const { avatarUrl } = useAvatarUrl(userId, hasAvatar, token); const initials = (displayName ?? '').slice(0, 2).toUpperCase() || 'ID'; return ( {avatarUrl ? : null} {initials} ); }