Implement image upload functionality

This commit is contained in:
gpt-engineer-app[bot]
2025-10-11 15:19:09 +00:00
parent c7e7bde19e
commit c732180bce
3 changed files with 319 additions and 4 deletions

134
src/hooks/useImageUpload.ts Normal file
View File

@@ -0,0 +1,134 @@
import { useState } from 'react';
import { adminApi, UploadResponse, MultiUploadResponse } from '@/services/adminApi';
import { useToast } from '@/hooks/use-toast';
interface UseImageUploadOptions {
maxSize?: number; // in bytes, default 5MB
allowedTypes?: string[];
category?: string;
}
export const useImageUpload = (options: UseImageUploadOptions = {}) => {
const {
maxSize = 5 * 1024 * 1024, // 5MB default
allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp', 'image/gif'],
category,
} = options;
const { toast } = useToast();
const [uploading, setUploading] = useState(false);
const [progress, setProgress] = useState(0);
const validateFile = (file: File): string | null => {
if (!allowedTypes.includes(file.type)) {
return `Tipo de archivo no permitido. Solo se permiten: ${allowedTypes.join(', ')}`;
}
if (file.size > maxSize) {
return `El archivo es demasiado grande. Tamaño máximo: ${(maxSize / 1024 / 1024).toFixed(2)}MB`;
}
return null;
};
const uploadSingle = async (file: File): Promise<UploadResponse | null> => {
const error = validateFile(file);
if (error) {
toast({
title: 'Error de validación',
description: error,
variant: 'destructive',
});
return null;
}
setUploading(true);
setProgress(0);
try {
// Simulate progress
const progressInterval = setInterval(() => {
setProgress((prev) => Math.min(prev + 10, 90));
}, 200);
const response = await adminApi.uploadImage(file, category);
clearInterval(progressInterval);
setProgress(100);
toast({
title: 'Imagen subida',
description: 'La imagen se ha subido correctamente',
});
return response;
} catch (error) {
console.error('Error uploading image:', error);
toast({
title: 'Error al subir imagen',
description: error instanceof Error ? error.message : 'No se pudo subir la imagen',
variant: 'destructive',
});
return null;
} finally {
setUploading(false);
setTimeout(() => setProgress(0), 1000);
}
};
const uploadMultiple = async (files: File[]): Promise<MultiUploadResponse | null> => {
// Validate all files first
for (const file of files) {
const error = validateFile(file);
if (error) {
toast({
title: 'Error de validación',
description: `${file.name}: ${error}`,
variant: 'destructive',
});
return null;
}
}
setUploading(true);
setProgress(0);
try {
// Simulate progress
const progressInterval = setInterval(() => {
setProgress((prev) => Math.min(prev + 10, 90));
}, 300);
const response = await adminApi.uploadImages(files, category);
clearInterval(progressInterval);
setProgress(100);
toast({
title: 'Imágenes subidas',
description: `${files.length} imagen(es) subida(s) correctamente`,
});
return response;
} catch (error) {
console.error('Error uploading images:', error);
toast({
title: 'Error al subir imágenes',
description: error instanceof Error ? error.message : 'No se pudieron subir las imágenes',
variant: 'destructive',
});
return null;
} finally {
setUploading(false);
setTimeout(() => setProgress(0), 1000);
}
};
return {
uploadSingle,
uploadMultiple,
uploading,
progress,
validateFile,
};
};