67 lines
1.8 KiB
TypeScript
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 };
|