More stuff
This commit is contained in:
@@ -10,13 +10,26 @@ import {
|
||||
import { Loader2, Pencil, Upload } from 'lucide-react';
|
||||
import type { ComponentProps, ChangeEvent } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
type AvatarUploadProps = {
|
||||
onAvatarUploaded: (path: string) => Promise<void>;
|
||||
cardProps?: ComponentProps<typeof Card>;
|
||||
cardContentProps?: ComponentProps<typeof CardContent>;
|
||||
containerProps?: ComponentProps<'div'>;
|
||||
basedAvatarProps?: ComponentProps<typeof BasedAvatar>;
|
||||
iconProps?: ComponentProps<typeof Upload>;
|
||||
};
|
||||
|
||||
export const AvatarUpload = ({
|
||||
onAvatarUploaded,
|
||||
cardProps,
|
||||
cardContentProps,
|
||||
containerProps,
|
||||
basedAvatarProps,
|
||||
iconProps = {
|
||||
size: 32,
|
||||
},
|
||||
}: AvatarUploadProps) => {
|
||||
const { profile, isAuthenticated } = useAuth();
|
||||
const { isUploading, fileInputRef, uploadAvatarMutation } = useFileUpload();
|
||||
@@ -39,8 +52,8 @@ export const AvatarUpload = ({
|
||||
if (!file.type.startsWith('image/')) throw new Error('File is not an image!');
|
||||
if (file.size > 8 * 1024 * 1024) throw new Error('File is too large!');
|
||||
|
||||
const fileExt = file.name.split('.').pop();
|
||||
const avatarPath = profile?.avatar_url ?? profile?.id;
|
||||
const avatarPath = profile?.avatar_url ??
|
||||
`${profile?.id}.${file.name.split('.').pop()}`;
|
||||
|
||||
const avatarUrl = await uploadAvatarMutation.mutateAsync({
|
||||
client,
|
||||
@@ -61,12 +74,78 @@ export const AvatarUpload = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardContent>
|
||||
<div>
|
||||
<Card
|
||||
{...cardProps}
|
||||
className={cn('', cardProps?.className)}
|
||||
>
|
||||
<CardContent
|
||||
{...cardContentProps}
|
||||
className={cn('flex flex-col items-center', cardContentProps?.className)}
|
||||
>
|
||||
<div
|
||||
{...containerProps}
|
||||
className={cn(
|
||||
'relative group cursor-pointer mb-4',
|
||||
containerProps?.className
|
||||
)}
|
||||
>
|
||||
<BasedAvatar
|
||||
{...basedAvatarProps}
|
||||
src={profile?.avatar_url}
|
||||
fullName={profile?.full_name}
|
||||
className={cn('h-32, w-32', basedAvatarProps?.className)}
|
||||
fallbackProps={{ className: 'text-4xl font-semibold' }}
|
||||
userIconProps={{ size: 100 }}
|
||||
/>
|
||||
<div
|
||||
className={cn(
|
||||
'absoloute inset-0 rounded-full bg-black/0\
|
||||
group-hover:bg-black/50 transition-all flex\
|
||||
items-center justify-center'
|
||||
)}
|
||||
>
|
||||
<Upload
|
||||
{...iconProps}
|
||||
className={cn('text-white opacity-0 group-hover:opacity-100\
|
||||
transition-opacity', iconProps?.className
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
'absolute inset-1 transition-all flex\
|
||||
items-end justify-end',
|
||||
)}
|
||||
>
|
||||
<Pencil
|
||||
{...iconProps}
|
||||
className={cn(
|
||||
'text-white opacity-100 group-hover:opacity-0\
|
||||
transition-opacity', iconProps?.className
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type='file'
|
||||
accept='image/*'
|
||||
className={cn('hidden')}
|
||||
onChange={handleFileChange}
|
||||
disabled={isUploading}
|
||||
/>
|
||||
{isUploading && (
|
||||
<div className={cn('flex items-center text-sm text-gray-500 mt-2')}>
|
||||
<Loader2 className={cn('h-4 w-4 mr-2 animate-spin')} />
|
||||
Uploading...
|
||||
</div>
|
||||
)}
|
||||
{!isAuthenticated && (
|
||||
<p className={cn('text-sm text-muted-foreground mt-2')}>
|
||||
Sign in to upload an avatar.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
|
||||
};
|
||||
|
Reference in New Issue
Block a user