file upload update
This commit is contained in:
@@ -1,16 +1,16 @@
|
||||
import ProtectionSummary from '@/app/ui/marking-page/protection-summary';
|
||||
import TestSection from '@/app/ui/marking-page/test-section';
|
||||
import FilesTable from '@/app/ui/dashboard/files-table';
|
||||
import {useTranslations} from 'next-intl';
|
||||
import PageTitle from '@/app/ui/page-title';
|
||||
|
||||
const ALLOWED_EXTENSIONS: string[] = ['jpg', 'jpeg', 'png', 'gif', 'bmp'];
|
||||
const FILE_TYPE = "VIDEO"
|
||||
const MAX_SIZE = 1048576000;
|
||||
|
||||
export default function Page() {
|
||||
const t = useTranslations('Global');
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="page-title">
|
||||
<h1>{t('audio-protection')}</h1>
|
||||
</div>
|
||||
<PageTitle title="audio-protection" />
|
||||
<ProtectionSummary />
|
||||
{/* <TestSection /> */}
|
||||
<FilesTable />
|
||||
|
||||
@@ -2,21 +2,22 @@ import ProtectionSummary from '@/app/ui/marking-page/protection-summary';
|
||||
import PageTitle from '@/app/ui/page-title';
|
||||
import UploadSectionFile from '@/app/components/upload-section-file';
|
||||
import FilesTable from '@/app/ui/dashboard/files-table';
|
||||
import { FileExtension } from '@/app/actions/definitions';
|
||||
import { getAllowedFilesExtensions } from '@/app/actions/file-upload';
|
||||
|
||||
const ALLOWED_EXTENSIONS: FileExtension[] = ['jpg', 'jpeg', 'png', 'gif', 'bmp'];
|
||||
const ALLOWED_EXTENSIONS: string[] = ['jpg', 'jpeg', 'png', 'gif', 'bmp'];
|
||||
const FILE_TYPE = "IMAGE"
|
||||
const MAX_SIZE = 1048576000;
|
||||
|
||||
export default async function Page() {
|
||||
/* const allowedFilesExtensions = await getAllowedFilesExtensions(FILE_TYPE);
|
||||
console.log(allowedFilesExtensions); */
|
||||
/* const allowedFilesExtensions = await getAllowedFilesExtensions(FILE_TYPE);
|
||||
console.log(allowedFilesExtensions);
|
||||
console.log(allowedFilesExtensions); */
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageTitle title="image-protection" />
|
||||
<ProtectionSummary />
|
||||
<UploadSectionFile fileType={FILE_TYPE} allowedExtensions={ALLOWED_EXTENSIONS} />
|
||||
<UploadSectionFile fileType={FILE_TYPE} allowedExtensions={ALLOWED_EXTENSIONS} maxFileSize={MAX_SIZE} />
|
||||
{/* <TestSection /> */}
|
||||
<FilesTable />
|
||||
{/* <ProtectedFilesTable /> */}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import ProtectionSummary from '@/app/ui/marking-page/protection-summary';
|
||||
import TestSection from '@/app/ui/marking-page/test-section';
|
||||
import UploadSectionVideo from '@/app/ui/marking-page/upload-section-video';
|
||||
import FilesTable from '@/app/ui/dashboard/files-table';
|
||||
import {useTranslations} from 'next-intl';
|
||||
import PageTitle from '@/app/ui/page-title';
|
||||
import UploadSectionFile from '@/app/components/upload-section-file';
|
||||
|
||||
const ALLOWED_EXTENSIONS: string[] = ['mp4', 'avi', 'webm', 'mkv', 'flv', 'wmv', 'mov'];
|
||||
const FILE_TYPE = "VIDEO"
|
||||
const MAX_SIZE = 1048576000;
|
||||
|
||||
export default function Page() {
|
||||
const t = useTranslations('Global');
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="page-title">
|
||||
<h1>{t('video-protection')}</h1>
|
||||
</div>
|
||||
<PageTitle title="video-protection" />
|
||||
<ProtectionSummary />
|
||||
<UploadSectionVideo />
|
||||
<UploadSectionFile fileType={FILE_TYPE} allowedExtensions={ALLOWED_EXTENSIONS} maxFileSize={MAX_SIZE} />
|
||||
{/* <TestSection /> */}
|
||||
<FilesTable />
|
||||
</div>
|
||||
|
||||
@@ -78,8 +78,6 @@ export const loginFormSchema = z
|
||||
|
||||
export const localDevelopmentUrl = 'http://localhost';
|
||||
|
||||
export type FileExtension = 'jpg' | 'jpeg' | 'png' | 'gif' | 'bmp';
|
||||
|
||||
export const testUserData = {
|
||||
fullName: 'test',
|
||||
email: 'test@mail.com',
|
||||
|
||||
@@ -4,7 +4,6 @@ import React, { useRef, useState, useCallback, ChangeEvent, DragEvent } from 're
|
||||
import { IconShieldAdd } from '@/app/ui/icons/icons';
|
||||
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;
|
||||
@@ -27,40 +26,79 @@ interface FileUploadInitResponse {
|
||||
|
||||
interface UploadSectionFile {
|
||||
fileType: string
|
||||
allowedExtensions: FileExtension[]
|
||||
allowedExtensions: string[]
|
||||
maxFileSize: number
|
||||
}
|
||||
|
||||
/* type SupportedFormat = 'image/jpeg' | 'image/png' | 'image/gif' | 'image/bmp'; */
|
||||
|
||||
export default function UploadSectionFile({ fileType, allowedExtensions }: UploadSectionFile) {
|
||||
export default function UploadSectionFile({ fileType, allowedExtensions, maxFileSize }: 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<string | null>(null);
|
||||
const [isFileUploaded, setIsFileUploaded] = useState<boolean>(false);
|
||||
const [uploadProgress, setUploadProgress] = useState<number>(0);
|
||||
|
||||
const t = useTranslations('Global');
|
||||
console.log('fileType');
|
||||
console.log(allowedExtensions);
|
||||
let SUPPORTED_FORMATS: string[] = []
|
||||
let SUPPORTED_FORMATS: string[] = [];
|
||||
|
||||
if (fileType === "IMAGE") {
|
||||
SUPPORTED_FORMATS = [
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/gif',
|
||||
'image/bmp'
|
||||
];
|
||||
switch (fileType) {
|
||||
case 'IMAGE':
|
||||
SUPPORTED_FORMATS = [
|
||||
'image/jpeg',
|
||||
'image/jpg',
|
||||
'image/png',
|
||||
'image/gif',
|
||||
'image/bmp',
|
||||
'image/webp',
|
||||
'image/svg+xml',
|
||||
'image/tiff',
|
||||
'image/x-icon'
|
||||
];
|
||||
break;
|
||||
case 'VIDEO':
|
||||
SUPPORTED_FORMATS = [
|
||||
'video/mp4',
|
||||
'video/mpeg',
|
||||
'video/ogg',
|
||||
'video/webm',
|
||||
'video/quicktime',
|
||||
'video/x-msvideo',
|
||||
'video/x-matroska',
|
||||
'video/x-flv',
|
||||
'video/3gpp',
|
||||
'video/3gpp2'
|
||||
];
|
||||
break;
|
||||
case 'AUDIO':
|
||||
SUPPORTED_FORMATS = [
|
||||
'audio/mpeg',
|
||||
'audio/wav',
|
||||
'audio/wave',
|
||||
'audio/x-wav',
|
||||
'audio/x-pn-wav',
|
||||
'audio/ogg',
|
||||
'audio/webm',
|
||||
'audio/aac',
|
||||
'audio/mp4',
|
||||
'audio/x-m4a',
|
||||
'audio/flac',
|
||||
'audio/x-flac',
|
||||
'audio/opus'
|
||||
];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const ALLOWED_EXTENSIONS: FileExtension[] = allowedExtensions;
|
||||
const ALLOWED_EXTENSIONS: string[] = allowedExtensions;
|
||||
|
||||
|
||||
const validateFile = (file: File): { isValid: boolean; errorMessage?: string } => {
|
||||
if (!SUPPORTED_FORMATS.includes(file.type as string)) {
|
||||
const extension = file.name.split('.').pop()?.toLowerCase();
|
||||
if (!extension || !ALLOWED_EXTENSIONS.includes(extension as FileExtension)) {
|
||||
if (!extension || !ALLOWED_EXTENSIONS.includes(extension as string)) {
|
||||
return {
|
||||
isValid: false,
|
||||
errorMessage: 'Неподдерживаемый формат файла.'
|
||||
@@ -68,11 +106,12 @@ export default function UploadSectionFile({ fileType, allowedExtensions }: Uploa
|
||||
}
|
||||
}
|
||||
|
||||
const MAX_SIZE = 100 * 1024 * 1024;
|
||||
const MAX_SIZE = maxFileSize;
|
||||
|
||||
if (file.size > MAX_SIZE) {
|
||||
return {
|
||||
isValid: false,
|
||||
errorMessage: 'Файл слишком большой. Максимальный размер: 100MB'
|
||||
errorMessage: 'Файл слишком большой. Максимальный размер: 1000MB'
|
||||
};
|
||||
}
|
||||
|
||||
@@ -107,23 +146,28 @@ export default function UploadSectionFile({ fileType, allowedExtensions }: Uploa
|
||||
setError(null);
|
||||
return;
|
||||
}
|
||||
|
||||
setUploadProgress(0);
|
||||
setError(null);
|
||||
|
||||
const validation = validateFile(file);
|
||||
|
||||
if (!validation.isValid) {
|
||||
setError(validation.errorMessage || 'Неизвестная ошибка валидации');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const dimensions = await getImageDimensions(file);
|
||||
let dimensions = undefined;
|
||||
|
||||
if (dimensions.width < 150 || dimensions.height < 150 ||
|
||||
dimensions.width > 8000 || dimensions.height > 8000) {
|
||||
setError(`Размер изображения: ${dimensions.width}x${dimensions.height}. Допустимый диапазон: 150x150 - 4000x4000 пикселей.`);
|
||||
return;
|
||||
if (fileType === "IMAGE") {
|
||||
dimensions = await getImageDimensions(file) as { width: number, height: number };
|
||||
if (dimensions.width < 150 || dimensions.height < 150 ||
|
||||
dimensions.width > 10000 || dimensions.height > 10000) {
|
||||
setError(`Размер изображения: ${dimensions.width}x${dimensions.height}. Допустимый диапазон: 150x150 - 10000x10000 пикселей.`);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const objectUrl = URL.createObjectURL(file);
|
||||
@@ -133,14 +177,15 @@ export default function UploadSectionFile({ fileType, allowedExtensions }: Uploa
|
||||
preview: objectUrl,
|
||||
name: file.name,
|
||||
size: `${(file.size / 1024 / 1024).toFixed(2)} MB`,
|
||||
dimensions
|
||||
...(dimensions && { dimensions })
|
||||
});
|
||||
|
||||
console.log('Файл обработан:', {
|
||||
file: file,
|
||||
name: file.name,
|
||||
type: file.type,
|
||||
size: file.size,
|
||||
dimensions
|
||||
...(dimensions && { dimensions })
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
@@ -192,13 +237,21 @@ export default function UploadSectionFile({ fileType, allowedExtensions }: Uploa
|
||||
setIsFileUploaded(false);
|
||||
setSelectedFile(null);
|
||||
setError(null);
|
||||
setUploadProgress(0);
|
||||
};
|
||||
|
||||
const handlerFileUpload = async (file: SelectedFile): Promise<any> => {
|
||||
const handlerFileUpload = async (file: SelectedFile): Promise<void> => {
|
||||
const extension = file.name.split('.').pop();
|
||||
|
||||
if (!extension) {
|
||||
setError(t('file-has-no-extension'));
|
||||
return;
|
||||
}
|
||||
|
||||
const initMessageBody = {
|
||||
file_name: file.name,
|
||||
file_type: fileType,
|
||||
extension: file.name.split('.')[1],
|
||||
extension: extension,
|
||||
file_size: file.file.size
|
||||
};
|
||||
|
||||
@@ -239,26 +292,26 @@ export default function UploadSectionFile({ fileType, allowedExtensions }: Uploa
|
||||
|
||||
start = end;
|
||||
chunkIndex++;
|
||||
setUploadProgress(
|
||||
() => {
|
||||
return Math.floor(chunkIndex / totalChunks * 100);
|
||||
}
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
setError('Chunk uploaded error ' + error);
|
||||
console.error('Chunk upload error:', error);
|
||||
}
|
||||
} else {
|
||||
console.log(response);
|
||||
setError('file uploaded error');
|
||||
}
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
return () => {
|
||||
if (selectedFile) {
|
||||
URL.revokeObjectURL(selectedFile.preview);
|
||||
}
|
||||
};
|
||||
}, [selectedFile]);
|
||||
|
||||
return (
|
||||
<div className="upload-section">
|
||||
<h3>
|
||||
{t('download-for-protection', { fileType: t(fileType.toLocaleLowerCase()) })}
|
||||
{t('upload-for-protection', { fileType: t(fileType.toLocaleLowerCase()) })}
|
||||
</h3>
|
||||
|
||||
<div
|
||||
@@ -349,14 +402,27 @@ export default function UploadSectionFile({ fileType, allowedExtensions }: Uploa
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<img
|
||||
src={selectedFile.preview}
|
||||
alt="Предпросмотр загруженного изображения"
|
||||
className="uploaded-image"
|
||||
onError={() => setError('Не удалось загрузить превью изображения')}
|
||||
/>
|
||||
{fileType === 'IMAGE' && (
|
||||
<img
|
||||
src={selectedFile.preview}
|
||||
alt="Предпросмотр загруженного изображения"
|
||||
className="uploaded-image"
|
||||
onError={() => setError('Не удалось загрузить превью изображения')}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="mt-4 flex gap-3 justify-center">
|
||||
{fileType === 'VIDEO' && (
|
||||
<video
|
||||
src={selectedFile.preview}
|
||||
className="uploaded-image"
|
||||
controls
|
||||
muted
|
||||
onError={() => setError('Не удалось загрузить превью видео')}
|
||||
onLoadedData={() => console.log('Видео загружено')}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="mt-4 flex gap-3 justify-center relative">
|
||||
<button
|
||||
className="btn btn-cancel"
|
||||
onClick={handleClearFile}
|
||||
@@ -365,11 +431,12 @@ export default function UploadSectionFile({ fileType, allowedExtensions }: Uploa
|
||||
{isFileUploaded ? t('close') : t('cancel')}
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-confirm"
|
||||
className={`btn btn-confirm ${error ? 'disabled' : ''}`}
|
||||
onClick={() => {
|
||||
handlerFileUpload(selectedFile);
|
||||
}}
|
||||
type="button"
|
||||
disabled={error ? true : false}
|
||||
>
|
||||
{t('upload-file')}
|
||||
</button>
|
||||
@@ -379,15 +446,20 @@ export default function UploadSectionFile({ fileType, allowedExtensions }: Uploa
|
||||
onClick={
|
||||
async () => {
|
||||
if (uploadId) {
|
||||
console.log('checkChunkStatus')
|
||||
const response = await checkChunkStatus(uploadId);
|
||||
console.log(response);
|
||||
await checkChunkStatus(uploadId);
|
||||
}
|
||||
}
|
||||
}
|
||||
>
|
||||
dev-test-button
|
||||
</button>
|
||||
{uploadProgress !== 0 && (
|
||||
<div
|
||||
className={`absolute top-5 right-5 font-medium ${isFileUploaded ? "text-green-600" : ""}`}
|
||||
>
|
||||
{uploadProgress}%
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -517,6 +517,14 @@
|
||||
min-width: 160px;
|
||||
transform: translateY(0px);
|
||||
box-shadow: none;
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.5;
|
||||
|
||||
&:hover {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-cancel {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
'use client';
|
||||
/* removed */
|
||||
|
||||
import { useState, useRef } from 'react';
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"checks": "Checks",
|
||||
"check": "Checks",
|
||||
"videos": "Videos",
|
||||
"video": "vides",
|
||||
"video": "videos",
|
||||
"audios": "Audio",
|
||||
"audio": "audio",
|
||||
"images": "Images",
|
||||
@@ -126,8 +126,9 @@
|
||||
"or": "or",
|
||||
"drag-the-file-here": "Drag the file here",
|
||||
"select-files-to-protect": "Select files to protect",
|
||||
"download-for-protection": "Download {fileType} for protection",
|
||||
"image": "image"
|
||||
"upload-for-protection": "Upload {fileType} for protection",
|
||||
"image": "image",
|
||||
"file-has-no-extension": "File has no extension"
|
||||
},
|
||||
"Login-register-form": {
|
||||
"and": "and",
|
||||
|
||||
@@ -126,8 +126,9 @@
|
||||
"or": "или",
|
||||
"drag-the-file-here": "Перетащите файл сюда",
|
||||
"select-files-to-protect": "Выбрать файлы для защиты",
|
||||
"download-for-protection": "Загрузить {fileType} для защиты",
|
||||
"image": "изображений"
|
||||
"upload-for-protection": "Загрузить {fileType} для защиты",
|
||||
"image": "изображений",
|
||||
"file-has-no-extension": "Файл не имеет расширения"
|
||||
},
|
||||
"Login-register-form": {
|
||||
"and": "и",
|
||||
|
||||
Reference in New Issue
Block a user