file upload develop
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
|
||||
import React, { useRef, useState, useCallback, ChangeEvent, DragEvent } from 'react';
|
||||
import { IconShieldAdd } from '@/app/ui/icons/icons';
|
||||
import { fileUpload, cancelUpload, chunkUpload } from '@/app/actions/file-upload';
|
||||
import { fileUpload, cancelUpload, chunkUpload, checkChunkStatus } from '@/app/actions/file-upload';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { FileExtension } from '@/app/actions/definitions';
|
||||
|
||||
interface SelectedFile {
|
||||
file: File;
|
||||
@@ -23,28 +25,40 @@ interface FileUploadInitResponse {
|
||||
status: string
|
||||
}
|
||||
|
||||
type SupportedFormat = 'image/jpeg' | 'image/png' | 'image/gif' | 'image/bmp';
|
||||
type FileExtension = 'jpg' | 'jpeg' | 'png' | 'gif' | 'bmp';
|
||||
interface UploadSectionFile {
|
||||
fileType: string
|
||||
allowedExtensions: FileExtension[]
|
||||
}
|
||||
|
||||
export default function UploadSectionFile({ fileType }: { fileType: string }) {
|
||||
/* type SupportedFormat = 'image/jpeg' | 'image/png' | 'image/gif' | 'image/bmp'; */
|
||||
|
||||
export default function UploadSectionFile({ fileType, allowedExtensions }: UploadSectionFile) {
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const [isDragging, setIsDragging] = useState<boolean>(false);
|
||||
const [selectedFile, setSelectedFile] = useState<SelectedFile | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [uploadId, setUploadId] = useState<any>(null);
|
||||
const [uploadId, setUploadId] = useState<string | null>(null);
|
||||
const [isFileUploaded, setIsFileUploaded] = useState<boolean>(false);
|
||||
|
||||
const SUPPORTED_FORMATS: SupportedFormat[] = [
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/gif',
|
||||
'image/bmp'
|
||||
];
|
||||
const t = useTranslations('Global');
|
||||
console.log('fileType');
|
||||
console.log(allowedExtensions);
|
||||
let SUPPORTED_FORMATS: string[] = []
|
||||
|
||||
const ALLOWED_EXTENSIONS: FileExtension[] = ['jpg', 'jpeg', 'png', 'gif', 'bmp'];
|
||||
if (fileType === "IMAGE") {
|
||||
SUPPORTED_FORMATS = [
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/gif',
|
||||
'image/bmp'
|
||||
];
|
||||
}
|
||||
|
||||
const ALLOWED_EXTENSIONS: FileExtension[] = allowedExtensions;
|
||||
|
||||
|
||||
const validateFile = (file: File): { isValid: boolean; errorMessage?: string } => {
|
||||
if (!SUPPORTED_FORMATS.includes(file.type as SupportedFormat)) {
|
||||
if (!SUPPORTED_FORMATS.includes(file.type as string)) {
|
||||
const extension = file.name.split('.').pop()?.toLowerCase();
|
||||
if (!extension || !ALLOWED_EXTENSIONS.includes(extension as FileExtension)) {
|
||||
return {
|
||||
@@ -171,9 +185,11 @@ export default function UploadSectionFile({ fileType }: { fileType: string }) {
|
||||
URL.revokeObjectURL(selectedFile.preview);
|
||||
}
|
||||
|
||||
const response = await cancelUpload(uploadId);
|
||||
console.log(response);
|
||||
if (uploadId) {
|
||||
await cancelUpload(uploadId);
|
||||
}
|
||||
|
||||
setIsFileUploaded(false);
|
||||
setSelectedFile(null);
|
||||
setError(null);
|
||||
};
|
||||
@@ -185,38 +201,21 @@ export default function UploadSectionFile({ fileType }: { fileType: string }) {
|
||||
extension: file.name.split('.')[1],
|
||||
file_size: file.file.size
|
||||
};
|
||||
console.log("initMessageBody");
|
||||
|
||||
const response = await fileUpload(initMessageBody) as FileUploadInitResponse;
|
||||
|
||||
if (response?.upload_id) {
|
||||
setUploadId(response.upload_id);
|
||||
console.log(response);
|
||||
console.log(file.file);
|
||||
/* {
|
||||
chunk_size: 5242880
|
||||
field_errors: null
|
||||
file_name: "ooop.jpg"
|
||||
status: "INITIATED"
|
||||
total_chunks: 1
|
||||
upload_id: "623261f0-f13b-4d06-8df5-365cb19d7ada"
|
||||
} */
|
||||
/* file.file */
|
||||
const CHUNK_SIZE = response.chunk_size;
|
||||
const totalChunks = response.total_chunks;
|
||||
const fileSize = file.file.size;
|
||||
let start = 0;
|
||||
let chunkIndex = 0;
|
||||
|
||||
console.log('response.upload_id');
|
||||
console.log(response.upload_id);
|
||||
|
||||
try {
|
||||
while (start < fileSize) {
|
||||
const end = Math.min(start + CHUNK_SIZE, fileSize);
|
||||
const chunk = file.file.slice(start, end);
|
||||
console.log(file.file);
|
||||
console.log(chunk);
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('upload_id', response.upload_id);
|
||||
@@ -224,10 +223,18 @@ export default function UploadSectionFile({ fileType }: { fileType: string }) {
|
||||
formData.append('chunk', chunk);
|
||||
const chunkResponse = await chunkUpload(formData);
|
||||
|
||||
console.log(chunkResponse);
|
||||
if (chunkResponse.message_desc !== 'Chunk uploaded successfully') {
|
||||
throw 'Er1'
|
||||
}
|
||||
|
||||
if (chunkIndex === totalChunks - 1) {
|
||||
console.log('upload done');
|
||||
const chunkStatus = await checkChunkStatus(response.upload_id);
|
||||
if (chunkStatus.message_body.missing_chunks === 0) {
|
||||
setUploadId(null);
|
||||
setIsFileUploaded(true);
|
||||
} else {
|
||||
throw 'Er2'
|
||||
}
|
||||
}
|
||||
|
||||
start = end;
|
||||
@@ -236,7 +243,8 @@ export default function UploadSectionFile({ fileType }: { fileType: string }) {
|
||||
|
||||
console.log('File uploaded successfully');
|
||||
} catch (error) {
|
||||
console.error('Upload error:', error);
|
||||
setError('Chunk uploaded error ' + error);
|
||||
console.error('Chunk upload error:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,7 +259,9 @@ export default function UploadSectionFile({ fileType }: { fileType: string }) {
|
||||
|
||||
return (
|
||||
<div className="upload-section">
|
||||
<h3>Загрузить изображение для защиты</h3>
|
||||
<h3>
|
||||
{t('download-for-protection', { fileType: t(fileType.toLocaleLowerCase()) })}
|
||||
</h3>
|
||||
|
||||
<div
|
||||
className={`drag-drop-zone ${isDragging ? 'dragging' : ''}`}
|
||||
@@ -268,12 +278,18 @@ export default function UploadSectionFile({ fileType }: { fileType: string }) {
|
||||
}}
|
||||
>
|
||||
<IconShieldAdd />
|
||||
<h4>Перетащите фаил сюда</h4>
|
||||
<p className="mb-2.5 text-[#6b7280]">или</p>
|
||||
<h4>
|
||||
{t('drag-the-file-here')}
|
||||
</h4>
|
||||
<p className="mb-2.5 text-[#6b7280]">
|
||||
{t('or')}
|
||||
</p>
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
accept=".jpg,.jpeg,.png,.gif,.bmp"
|
||||
accept={
|
||||
ALLOWED_EXTENSIONS.map(e => `.${e}`).join(',')
|
||||
}
|
||||
style={{ display: 'none' }}
|
||||
onChange={handleFileInputChange}
|
||||
aria-label="Выбор файла для защиты"
|
||||
@@ -284,11 +300,11 @@ export default function UploadSectionFile({ fileType }: { fileType: string }) {
|
||||
onClick={handleButtonClick}
|
||||
type="button"
|
||||
>
|
||||
Выбрать файлы для защиты
|
||||
{t('select-files-to-protect')}
|
||||
</button>
|
||||
|
||||
<p className="description">
|
||||
Разрешение изображение: 100x100 - 10000x10000 пикселей
|
||||
Разрешение изображение: 100x100 - 10000x10000
|
||||
</p>
|
||||
<p className="description">
|
||||
Размер файла: до 20 МБ
|
||||
@@ -299,7 +315,7 @@ export default function UploadSectionFile({ fileType }: { fileType: string }) {
|
||||
|
||||
{error && (
|
||||
<div className="mt-4 p-3 bg-red-50 border border-red-200 rounded-lg">
|
||||
<p className="text-red-600 font-medium">❌ {error}</p>
|
||||
<p className="text-red-600 font-medium">{error}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -308,18 +324,31 @@ export default function UploadSectionFile({ fileType }: { fileType: string }) {
|
||||
className="selected-file"
|
||||
>
|
||||
<div className="selected-file-file-info">
|
||||
<p className="text-gray-700">
|
||||
<span className="font-medium">Файл:</span> {selectedFile.name}
|
||||
</p>
|
||||
<p className="text-gray-700">
|
||||
<span className="font-medium">Размер:</span> {selectedFile.size}
|
||||
</p>
|
||||
<p className="text-gray-700">
|
||||
<span className="font-medium">Стоимость защиты:</span> 0
|
||||
</p>
|
||||
<p className="text-gray-700">
|
||||
<span className="font-medium">Текущий баланс:</span> 0
|
||||
</p>
|
||||
<div>
|
||||
<p className="text-gray-700">
|
||||
<span className="font-medium">
|
||||
{t('file')}:
|
||||
</span> {selectedFile.name}
|
||||
</p>
|
||||
<p className="text-gray-700">
|
||||
<span className="font-medium">
|
||||
{t('size')}:
|
||||
</span> {selectedFile.size}
|
||||
</p>
|
||||
<p className="text-gray-700">
|
||||
<span className="font-medium">Стоимость защиты:</span> 0
|
||||
</p>
|
||||
<p className="text-gray-700">
|
||||
<span className="font-medium">Текущий баланс:</span> 0
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
{isFileUploaded && (
|
||||
<div className="font-medium text-green-600 text-2xl">
|
||||
{t('file-successfully-uploaded')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<img
|
||||
@@ -335,7 +364,7 @@ export default function UploadSectionFile({ fileType }: { fileType: string }) {
|
||||
onClick={handleClearFile}
|
||||
type="button"
|
||||
>
|
||||
Отмена
|
||||
{isFileUploaded ? t('close') : t('cancel')}
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-confirm"
|
||||
@@ -344,7 +373,22 @@ export default function UploadSectionFile({ fileType }: { fileType: string }) {
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
Подтвердить защиту
|
||||
{t('upload-file')}
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-cancel"
|
||||
type="button"
|
||||
onClick={
|
||||
async () => {
|
||||
if (uploadId) {
|
||||
console.log('checkChunkStatus')
|
||||
const response = await checkChunkStatus(uploadId);
|
||||
console.log(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
>
|
||||
dev-test-button
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user