diff --git a/src/app/actions/fileUpload.ts b/src/app/actions/fileUpload.ts index 6a88a89..cc304d0 100644 --- a/src/app/actions/fileUpload.ts +++ b/src/app/actions/fileUpload.ts @@ -102,17 +102,14 @@ export async function cancelUpload(udloadId: string) { } export async function chunkUpload(formData: FormData) { - console.log('chunkUpload'); try { const response = await fetch(`${API_BASE_URL}/api/v1/files/chunk`, { method: 'POST', body: formData }); - console.log('chunkUpload fetch'); + if (response.ok) { let parsed = await response.json(); - console.log('chunkUpload response.ok'); - console.log(parsed); if (parsed.message_desc === 'Upload cancelled successfully') { return parsed.message_body; diff --git a/src/app/components/upload-section-file.tsx b/src/app/components/upload-section-file.tsx index d708db6..8c132b2 100644 --- a/src/app/components/upload-section-file.tsx +++ b/src/app/components/upload-section-file.tsx @@ -7,7 +7,7 @@ import { useTranslations } from 'next-intl'; import { useNavigationBlocker } from '@/app/hooks/useNavigationBlocker'; interface SelectedFile { file: File; - preview: string; + preview: string | undefined; name: string; size: string; dimensions?: { @@ -39,6 +39,8 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile const [isFileUploaded, setIsFileUploaded] = useState(false); const [uploadProgress, setUploadProgress] = useState(0); + const isCancelledRef = useRef(false); + const t = useTranslations('Global'); let SUPPORTED_FORMATS: string[] = []; @@ -150,55 +152,43 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile setError(null); return; } - setUploadProgress(0); - setUploadId(null); setError(null); - setIsFileUploaded(false) + setIsFileUploaded(false); + setUploadProgress(0); const validation = validateFile(file); if (!validation.isValid) { setError(validation.errorMessage || t('unknown-validation-error')); - return; } - try { - let dimensions = undefined; - - if (fileType === "image") { + let dimensions = undefined; + if (fileType === "image") { + try { dimensions = await getImageDimensions(file) as { width: number, height: number }; if (dimensions.width < 150 || dimensions.height < 150 || dimensions.width > 10000 || dimensions.height > 10000) { setError(`${t('image-size')}: ${dimensions.width}x${dimensions.height}. ${t('acceptable-range')}: 150x150 - 10000x10000 ${t('pixels')}.`); - return; } + } catch (err) { + setError(t('error-reading-image')); + return; } - - const objectUrl = URL.createObjectURL(file); - - setSelectedFile({ - file, - preview: objectUrl, - name: file.name, - size: `${(file.size / 1024 / 1024).toFixed(2)} MB`, - ...(dimensions && { dimensions }) - }); - - console.log('Файл обработан:', { - file: file, - name: file.name, - type: file.type, - size: file.size, - ...(dimensions && { dimensions }) - }); - - } catch (err) { - setError(t('error-processing-file')); } - }, []); + + setSelectedFile({ + file, + name: file.name, + size: `${(file.size / 1024 / 1024).toFixed(2)} MB`, + dimensions, + preview: file.size < 10 * 1024 * 1024 ? URL.createObjectURL(file) : undefined + }); + + console.log('Файл выбран:', file.name, file.size); + }, [fileType, t]); const handleFileInputChange = (event: ChangeEvent): void => { const file = event.target.files?.[0] || null; @@ -233,7 +223,7 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile }; const handleClearFile = async (): Promise => { - if (selectedFile) { + if (selectedFile && selectedFile.preview) { URL.revokeObjectURL(selectedFile.preview); } @@ -241,96 +231,80 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile await cancelUpload(uploadId); } + isCancelledRef.current = true; + setIsFileUploaded(false); setSelectedFile(null); setError(null); setUploadProgress(0); }; - const handlerFileUpload = useCallback(async (file: SelectedFile): Promise => { - if (uploadId) { - return; - }; + const handlerFileUpload = useCallback(async (fileInfo: SelectedFile): Promise => { + if (uploadId) return; setError(null); + isCancelledRef.current = false; + const file = fileInfo.file; try { - const extension = file.name.split('.').pop(); - - if (!extension) { - setError(t('file-has-no-extension')); - return; - } - + const extension = file.name.split('.').pop() || ''; const initMessageBody = { file_name: file.name, file_type: fileType, extension: extension, - file_size: file.file.size + file_size: file.size }; const response = await fileUpload(initMessageBody) as FileUploadInitResponse; - if (response?.upload_id) { - setUploadId(response.upload_id); - const CHUNK_SIZE = response.chunk_size; - const totalChunks = response.total_chunks; - const fileSize = file.file.size; - let start = 0; - let chunkIndex = 0; - - console.log('start upload'); - console.log(`total chanks - ${totalChunks}`); - - while (start < fileSize) { - console.log(`chank-${chunkIndex}`); - const end = Math.min(start + CHUNK_SIZE, fileSize); - const chunk = file.file.slice(start, end); - - const formData = new FormData(); - formData.append('upload_id', response.upload_id); - formData.append('chunk_number', chunkIndex.toString()); - formData.append('chunk', chunk); - console.log(`init chunkUpload`); - const chunkResponse = await chunkUpload(formData); - console.log(`chunkResponse - ${chunkResponse}`); - - if (chunkResponse.message_desc !== 'Chunk uploaded successfully') { - throw new Error('Er1: response error'); - } - - if (chunkIndex === totalChunks - 1) { - const chunkStatus = await checkChunkStatus(response.upload_id); - if (chunkStatus.message_body.missing_chunks === 0) { - setUploadId(null); - setIsFileUploaded(true); - } else { - throw new Error('Er2: not all chunks was uploaded'); - } - } - - start = end; - chunkIndex++; - setUploadProgress(Math.floor(chunkIndex / totalChunks * 100)); - } - } else { - console.error(response); + if (!response?.upload_id) { throw new Error('Failed to get upload_id'); } - } catch (error) { - setError(t('error-uploading-file')); - console.error('Chunk upload error:', error); - // Для дебага в production - if (error instanceof Error) { - console.error('Error name:', error.name); - console.error('Error message:', error.message); - if (error.cause) console.error('Error cause:', error.cause); + const CHUNK_SIZE = response.chunk_size; + const totalChunks = response.total_chunks; + + setUploadId(response.upload_id); + + for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) { + if (isCancelledRef.current) { + return; + } + + const start = chunkIndex * CHUNK_SIZE; + const end = Math.min(start + CHUNK_SIZE, file.size); + const chunk = file.slice(start, end); + const formData = new FormData(); + + formData.append('upload_id', response.upload_id); + formData.append('chunk_number', chunkIndex.toString()); + formData.append('chunk', chunk); + + const chunkResponse = await chunkUpload(formData); + + if (chunkResponse.message_desc !== 'Chunk uploaded successfully') { + throw new Error(`Chunk ${chunkIndex} upload failed`); + } + + setUploadProgress(Math.floor((chunkIndex + 1) / totalChunks * 100)); + } + + const chunkStatus = await checkChunkStatus(response.upload_id); + if (chunkStatus.message_body.missing_chunks === 0) { + setIsFileUploaded(true); + } else { + throw new Error('Not all chunks were uploaded'); + } + + } catch (error) { + if (!isCancelledRef.current) { + setError(t('error-uploading-file')); + console.error('Upload error:', error); } } finally { setUploadId(null); } - }, [uploadId, fileType]); + }, [uploadId, fileType, t]); useEffect(() => { // Обработка закрытия вкладки @@ -462,7 +436,7 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile - {fileType === 'image' && ( + {(fileType === 'image' && selectedFile.preview) && (