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