93 lines
2.4 KiB
TypeScript
93 lines
2.4 KiB
TypeScript
import { useState, useCallback } from 'react';
|
|
import { inventoryApi } from '@/lib/api';
|
|
|
|
interface Photo {
|
|
thumbnail_url: string;
|
|
full_url: string;
|
|
uploaded_at: string;
|
|
}
|
|
|
|
interface UsePhotoUploadReturn {
|
|
upload: (file: File, itemId: number) => Promise<Photo>;
|
|
isLoading: boolean;
|
|
error: string | null;
|
|
}
|
|
|
|
const ACCEPTED_MIME_TYPES = ['image/jpeg', 'image/png', 'image/webp', 'image/gif'];
|
|
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
|
|
|
|
export function usePhotoUpload(): UsePhotoUploadReturn {
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const validateFile = useCallback((file: File): { valid: boolean; error?: string } => {
|
|
// Validate file size
|
|
if (file.size > MAX_FILE_SIZE) {
|
|
return {
|
|
valid: false,
|
|
error: 'File too large, max 10MB',
|
|
};
|
|
}
|
|
|
|
// Validate MIME type
|
|
if (!ACCEPTED_MIME_TYPES.includes(file.type)) {
|
|
return {
|
|
valid: false,
|
|
error: 'Invalid image format',
|
|
};
|
|
}
|
|
|
|
return { valid: true };
|
|
}, []);
|
|
|
|
const upload = useCallback(
|
|
async (file: File, itemId: number): Promise<Photo> => {
|
|
setError(null);
|
|
setIsLoading(true);
|
|
|
|
try {
|
|
// Validate file (synchronously)
|
|
const validation = validateFile(file);
|
|
if (!validation.valid) {
|
|
const errorMsg = validation.error || 'File validation failed';
|
|
setError(errorMsg);
|
|
setIsLoading(false);
|
|
throw new Error(errorMsg);
|
|
}
|
|
|
|
// Create FormData for multipart upload
|
|
const formData = new FormData();
|
|
formData.append('file', file);
|
|
|
|
// Upload to backend
|
|
const response = await inventoryApi.uploadItemPhoto(itemId, formData);
|
|
|
|
// Handle response
|
|
if (response.status === 'ok' && response.photo) {
|
|
const photo: Photo = {
|
|
thumbnail_url: response.photo.thumbnail_url,
|
|
full_url: response.photo.full_url,
|
|
uploaded_at: response.photo.uploaded_at,
|
|
};
|
|
setIsLoading(false);
|
|
return photo;
|
|
}
|
|
|
|
throw new Error('Invalid response from server');
|
|
} catch (err: any) {
|
|
const errorMsg = err.message || 'Upload failed';
|
|
setError(errorMsg);
|
|
setIsLoading(false);
|
|
throw new Error(errorMsg);
|
|
}
|
|
},
|
|
[validateFile]
|
|
);
|
|
|
|
return {
|
|
upload,
|
|
isLoading,
|
|
error,
|
|
};
|
|
}
|