veza/apps/web/src/components/ui/avatar-upload/AvatarUpload.tsx
senke c4111ac059 refactor(ui): extract AvatarUpload into avatar-upload module
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-05 22:21:02 +01:00

67 lines
1.8 KiB
TypeScript

/**
* FE-COMP-009: Avatar upload with drag-and-drop and preview
*/
import { cn } from '@/lib/utils';
import { useAvatarUpload } from './useAvatarUpload';
import { AvatarUploadDropzone } from './AvatarUploadDropzone';
import { AvatarUploadActions } from './AvatarUploadActions';
import { AvatarUploadSkeleton } from './AvatarUploadSkeleton';
import type { AvatarUploadProps } from './types';
import { MAX_FILE_SIZE_DEFAULT } from './types';
export function AvatarUpload({
userId,
currentAvatarUrl,
onAvatarUpdated,
onAvatarDeleted,
size = 'lg',
className,
disabled = false,
maxSize = MAX_FILE_SIZE_DEFAULT,
accept = 'image/*',
}: AvatarUploadProps) {
const state = useAvatarUpload({
userId,
currentAvatarUrl,
onAvatarUpdated,
onAvatarDeleted,
maxSize,
disabled,
});
return (
<div className={cn('flex flex-col items-center gap-4', className)}>
<AvatarUploadDropzone
preview={state.preview}
dragActive={state.dragActive}
isUploading={state.isUploading}
disabled={disabled}
size={size}
onDragEnter={state.handleDrag}
onDragLeave={state.handleDrag}
onDragOver={state.handleDrag}
onDrop={state.handleDrop}
onClick={state.handleClick}
/>
<input
ref={state.fileInputRef}
type="file"
accept={accept}
onChange={state.handleFileInput}
disabled={disabled || state.isUploading}
className="hidden"
/>
<AvatarUploadActions
hasAvatar={state.hasAvatar}
disabled={disabled}
isUploading={state.isUploading}
isDeleting={state.isDeleting}
maxSize={maxSize}
onUploadClick={state.handleClick}
onDelete={state.handleDelete}
/>
</div>
);
}
export { AvatarUploadSkeleton };