Files
gg-backend/frontend/src/components/BytescaleUploader/BytescaleUploader.tsx
T

142 lines
3.6 KiB
TypeScript
Raw Normal View History

2026-05-26 15:48:01 +05:30
import { useState, useRef } from 'react';
import { Button } from '@/components/ui/button';
2026-06-16 12:53:41 +05:30
import { User, X, Loader2, Video } from 'lucide-react';
2026-05-26 15:48:01 +05:30
import axios from 'axios';
2026-04-14 17:33:21 +05:30
interface BytescaleUploaderProps {
value: string;
onChange: (url: string) => void;
2026-06-15 09:30:19 +05:30
folderPath:
| '/health-packages'
| '/seo'
| '/doctors'
| '/departments'
| '/news'
| '/blog'
| '/doctor-og'
2026-06-17 14:36:07 +05:30
| '/homepage-banners'
2026-06-23 11:39:09 +05:30
| '/insurance-partners'
| '/accreditations';
2026-04-14 17:33:21 +05:30
}
2026-05-26 15:48:01 +05:30
export function BytescaleUploader({ value, onChange, folderPath }: BytescaleUploaderProps) {
2026-04-16 19:49:06 +05:30
const baseURL = import.meta.env.VITE_API_URL;
2026-04-14 17:33:21 +05:30
const [isUploading, setIsUploading] = useState(false);
const fileInputRef = useRef<HTMLInputElement>(null);
2026-06-16 12:53:41 +05:30
const isVideo = (url: string) => {
return /\.(mp4|webm|ogg)$/i.test(url);
};
2026-04-14 17:33:21 +05:30
const onFileSelected = async (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
2026-06-16 12:53:41 +05:30
2026-04-14 17:33:21 +05:30
if (!file) return;
2026-06-16 12:53:41 +05:30
const maxSize = file.type.startsWith('video/') ? 10 * 1024 * 1024 : 5 * 1024 * 1024;
if (file.size > maxSize) {
alert(file.type.startsWith('video/') ? 'Video is too large (Max 10MB)' : 'Image is too large (Max 5MB)');
return;
}
2026-04-14 17:33:21 +05:30
setIsUploading(true);
const formData = new FormData();
2026-05-26 15:48:01 +05:30
formData.append('file', file);
formData.append('folderPath', folderPath);
2026-04-14 17:33:21 +05:30
try {
2026-04-16 19:49:06 +05:30
const response = await axios.post(`${baseURL}/upload`, formData, {
headers: {
2026-05-26 15:48:01 +05:30
'Content-Type': 'multipart/form-data',
2026-04-14 17:33:21 +05:30
},
2026-04-16 19:49:06 +05:30
});
2026-04-14 17:33:21 +05:30
2026-05-18 11:55:55 +05:30
const { fileUrl } = response.data;
2026-04-14 17:33:21 +05:30
onChange(fileUrl);
} catch (e: any) {
2026-05-26 15:48:01 +05:30
console.error('Upload Error:', e);
const errorMessage = e.response?.data?.error || e.message || 'Upload failed';
alert(`Upload Error: ${errorMessage}`);
2026-04-14 17:33:21 +05:30
} finally {
setIsUploading(false);
2026-06-16 12:53:41 +05:30
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
2026-04-14 17:33:21 +05:30
}
};
return (
<div className="flex flex-col gap-2 p-3 border rounded-md bg-muted/5">
<div className="flex items-center gap-4">
<div className="relative">
{value ? (
<>
2026-06-16 12:53:41 +05:30
{isVideo(value) ? (
<video src={value} className="w-20 h-20 rounded-md object-cover border-2 border-primary/20" controls />
) : (
<img
src={value}
className="w-16 h-16 rounded-full object-cover border-2 border-primary/20"
alt="Preview"
/>
)}
2026-04-14 17:33:21 +05:30
<button
type="button"
2026-05-26 15:48:01 +05:30
onClick={() => onChange('')}
2026-04-14 17:33:21 +05:30
className="absolute -top-1 -right-1 bg-destructive text-white rounded-full p-0.5 shadow-sm hover:scale-110 transition-transform"
>
<X className="w-3 h-3" />
</button>
</>
) : (
<div className="w-16 h-16 rounded-full bg-muted flex items-center justify-center">
{isUploading ? (
<Loader2 className="w-8 h-8 animate-spin text-primary" />
) : (
<User className="w-8 h-8 text-muted-foreground" />
)}
</div>
)}
</div>
<input
type="file"
ref={fileInputRef}
onChange={onFileSelected}
2026-06-16 12:53:41 +05:30
accept="image/jpeg,image/png,image/webp,video/mp4,video/webm,video/ogg"
2026-04-14 17:33:21 +05:30
className="hidden"
/>
<Button
type="button"
variant="outline"
size="sm"
disabled={isUploading}
onClick={() => fileInputRef.current?.click()}
>
{isUploading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Uploading...
</>
) : value ? (
2026-06-16 12:53:41 +05:30
'Change File'
2026-04-14 17:33:21 +05:30
) : (
2026-06-16 12:53:41 +05:30
'Upload Image / Video'
2026-04-14 17:33:21 +05:30
)}
</Button>
</div>
{value && (
<p className="text-xs text-amber-600 pl-[72px]">
2026-05-26 15:48:01 +05:30
Make sure to save the changes by clicking the "Save Changes" button.
2026-04-14 17:33:21 +05:30
</p>
)}
</div>
);
}