diff --git a/src/app/[locale]/pages/marking-photo/page.tsx b/src/app/[locale]/pages/marking-photo/page.tsx
index 677a7ed..502b9a0 100644
--- a/src/app/[locale]/pages/marking-photo/page.tsx
+++ b/src/app/[locale]/pages/marking-photo/page.tsx
@@ -1,21 +1,22 @@
-import ProtectedFilesTable from '@/app/ui/marking-page/protected-files-table';
import ProtectionSummary from '@/app/ui/marking-page/protection-summary';
-import TestSection from '@/app/ui/marking-page/test-section';
+import PageTitle from '@/app/ui/page-title';
import UploadSectionFile from '@/app/components/upload-section-file';
-import { useTranslations } from 'next-intl';
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 FILE_TYPE = "IMAGE"
+
+export default async function Page() {
+ /* const allowedFilesExtensions = await getAllowedFilesExtensions(FILE_TYPE);
+ console.log(allowedFilesExtensions); */
-export default function Page() {
- const t = useTranslations('Global');
return (
-
-
- {t('image-protection')}
-
-
+
-
+
{/*
*/}
{/*
*/}
diff --git a/src/app/actions/definitions.ts b/src/app/actions/definitions.ts
index 6b35521..95672ba 100644
--- a/src/app/actions/definitions.ts
+++ b/src/app/actions/definitions.ts
@@ -24,10 +24,10 @@ export const SignupFormSchema = z
.string()
.min(2, { error: 'register-error-name' })
.regex(/^[^0-9]*$/, { message: 'register-error-no-digits' })
-/* .refine(
- (value) => !/\p{Emoji}/u.test(value),
- { message: 'no-emoji-allowed' }
- ) */
+ /* .refine(
+ (value) => !/\p{Emoji}/u.test(value),
+ { message: 'no-emoji-allowed' }
+ ) */
.trim(),
email: z
.string()
@@ -48,10 +48,10 @@ export const SignupFormSchema = z
.min(8, { error: 'register-error-password-symbols' })
.regex(/[a-zA-Zа-яёА-ЯЁ]/, { error: 'register-error-password-one-letter' })
.regex(/[0-9]/, { error: 'register-error-password-one-digit' })
-/* .refine(
- (value) => !/\p{Emoji}/u.test(value),
- { message: 'no-emoji-allowed' }
- ) */
+ /* .refine(
+ (value) => !/\p{Emoji}/u.test(value),
+ { message: 'no-emoji-allowed' }
+ ) */
.trim(),
confirm_password: z
.string(),
@@ -78,6 +78,8 @@ 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',
diff --git a/src/app/actions/file-upload.ts b/src/app/actions/file-upload.ts
index 1b95387..af336e9 100644
--- a/src/app/actions/file-upload.ts
+++ b/src/app/actions/file-upload.ts
@@ -2,7 +2,6 @@
import { localDevelopmentUrl } from '@/app/actions/definitions';
import { getSessionData, createSession } from '@/app/actions/session';
-import { number } from 'zod';
const API_BASE_URL = process.env.NODE_ENV === 'development'
? localDevelopmentUrl
@@ -51,7 +50,6 @@ export async function fileUpload(messageBody: initMessageBody) {
},
message_code: string
};
- console.log(parsed);
if (parsed.message_desc === 'Operation successful') {
return parsed.message_body;
@@ -69,6 +67,7 @@ export async function fileUpload(messageBody: initMessageBody) {
export async function cancelUpload(udloadId: string) {
console.log('cancelUpload');
+ console.log(udloadId);
try {
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
@@ -114,20 +113,52 @@ export async function cancelUpload(udloadId: string) {
}
export async function chunkUpload(formData: FormData) {
- console.log('chunkUpload');
- console.log(`${API_BASE_URL}/api/v1/files/chunk`);
-
try {
const response = await fetch(`${API_BASE_URL}/api/v1/files/chunk`, {
method: 'POST',
body: formData
});
- console.log(response);
+ if (response.ok) {
+ let parsed = await response.json();
+
+ if (parsed.message_desc === 'Upload cancelled successfully') {
+ console.log('chunkUpload');
+ console.log(parsed.message_body);
+ return parsed.message_body;
+ } else {
+ console.log('error cancel chunkUpload');
+ throw parsed;
+ }
+ } else {
+ throw (`${response.status}`);
+ }
+
+ } catch (error) {
+ return error
+ }
+}
+
+export async function checkChunkStatus(upload_id: string) {
+ try {
+ const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
+ method: 'POST',
+ body: JSON.stringify({
+ version: 1,
+ msg_id: 20004,
+ message_body: {
+ action: 'chunks',
+ upload_id
+ }
+ }),
+ headers: {
+ "Content-Type": "application/json",
+ "Accept": "application/json"
+ }
+ });
if (response.ok) {
let parsed = await response.json();
- console.log('response.ok');
console.log(parsed);
if (parsed.message_desc === 'Upload cancelled successfully') {
@@ -140,6 +171,43 @@ export async function chunkUpload(formData: FormData) {
throw (`${response.status}`);
}
+ } catch (error) {
+ return error
+ }
+}
+
+export async function getAllowedFilesExtensions(type: string) {
+ try {
+ const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
+ method: 'POST',
+ body: JSON.stringify({
+ version: 1,
+ msg_id: 20004,
+ message_body: {
+ action: 'file_extension',
+ file_type: type
+ }
+ }),
+ headers: {
+ "Content-Type": "application/json",
+ "Accept": "application/json"
+ }
+ });
+
+ if (response.ok) {
+ let parsed = await response.json();
+ console.log(parsed);
+
+ if (parsed.message_desc === 'Operation successful') {
+ return parsed.message_body.file_extension;
+ } else {
+ console.log('error cancel getAllowedFilesExtensions');
+ throw parsed;
+ }
+ } else {
+ throw (`${response.status}`);
+ }
+
} catch (error) {
return error
}
diff --git a/src/app/components/upload-section-file.tsx b/src/app/components/upload-section-file.tsx
index 89e1f40..b681511 100644
--- a/src/app/components/upload-section-file.tsx
+++ b/src/app/components/upload-section-file.tsx
@@ -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
(null);
const [isDragging, setIsDragging] = useState(false);
const [selectedFile, setSelectedFile] = useState(null);
const [error, setError] = useState(null);
- const [uploadId, setUploadId] = useState(null);
+ const [uploadId, setUploadId] = useState(null);
+ const [isFileUploaded, setIsFileUploaded] = useState(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 (
-
Загрузить изображение для защиты
+
+ {t('download-for-protection', { fileType: t(fileType.toLocaleLowerCase()) })}
+
-
Перетащите фаил сюда
-
или
+
+ {t('drag-the-file-here')}
+
+
+ {t('or')}
+
`.${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')}
- Разрешение изображение: 100x100 - 10000x10000 пикселей
+ Разрешение изображение: 100x100 - 10000x10000
Размер файла: до 20 МБ
@@ -299,7 +315,7 @@ export default function UploadSectionFile({ fileType }: { fileType: string }) {
{error && (
)}
@@ -308,18 +324,31 @@ export default function UploadSectionFile({ fileType }: { fileType: string }) {
className="selected-file"
>
-
- Файл: {selectedFile.name}
-
-
- Размер: {selectedFile.size}
-
-
- Стоимость защиты: 0
-
-
- Текущий баланс: 0
-
+
+
+
+ {t('file')}:
+ {selectedFile.name}
+
+
+
+ {t('size')}:
+ {selectedFile.size}
+
+
+ Стоимость защиты: 0
+
+
+ Текущий баланс: 0
+
+
+
+ {isFileUploaded && (
+
+ {t('file-successfully-uploaded')}
+
+ )}
+
![]()
- Отмена
+ {isFileUploaded ? t('close') : t('cancel')}
+
diff --git a/src/app/styles/pages-styles.scss b/src/app/styles/pages-styles.scss
index a08fab2..0b138c2 100644
--- a/src/app/styles/pages-styles.scss
+++ b/src/app/styles/pages-styles.scss
@@ -492,6 +492,8 @@
&-file-info {
text-align: left;
+ display: flex;
+ justify-content: space-between;
}
.uploaded-image {
diff --git a/src/app/ui/page-title.tsx b/src/app/ui/page-title.tsx
new file mode 100644
index 0000000..9d2fb91
--- /dev/null
+++ b/src/app/ui/page-title.tsx
@@ -0,0 +1,12 @@
+import { useTranslations } from 'next-intl';
+
+export default function PageTitle({ title }: { title: string }) {
+ const t = useTranslations('Global');
+ return (
+
+
+ {t(title)}
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json
index ef00ba2..ba0fa26 100644
--- a/src/i18n/messages/en.json
+++ b/src/i18n/messages/en.json
@@ -17,7 +17,9 @@
"checks": "Checks",
"check": "Checks",
"videos": "Videos",
+ "video": "vides",
"audios": "Audio",
+ "audio": "audio",
"images": "Images",
"main": "Main",
"marking": "Marking",
@@ -116,7 +118,16 @@
"view-all": "View all",
"days-ago": "days ago",
"there-are-no-files-yet": "There are no files yet",
- "add": "Add"
+ "add": "Add",
+ "file-successfully-uploaded": "File has been successfully uploaded",
+ "cancel": "Cancel",
+ "close": "Close",
+ "upload-file": "Upload file",
+ "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"
},
"Login-register-form": {
"and": "and",
diff --git a/src/i18n/messages/ru.json b/src/i18n/messages/ru.json
index a7fcdfb..458d77a 100644
--- a/src/i18n/messages/ru.json
+++ b/src/i18n/messages/ru.json
@@ -17,7 +17,9 @@
"checks": "Проверки",
"check": "Проверок",
"videos": "Видео",
+ "video": "видео",
"audios": "Аудио",
+ "audio": "аудио",
"images": "Изображения",
"main": "Главная",
"marking": "Маркировка",
@@ -116,7 +118,16 @@
"view-all": "Посмотреть все",
"days-ago": "дней назад",
"there-are-no-files-yet": "Файлов пока нет",
- "add": "Добавить"
+ "add": "Добавить",
+ "file-successfully-uploaded": "Файл успешно загружен",
+ "cancel": "Отмена",
+ "close": "Закрыть",
+ "upload-file": "Загрузить файл",
+ "or": "или",
+ "drag-the-file-here": "Перетащите файл сюда",
+ "select-files-to-protect": "Выбрать файлы для защиты",
+ "download-for-protection": "Загрузить {fileType} для защиты",
+ "image": "изображений"
},
"Login-register-form": {
"and": "и",