add pice check for file upload
This commit is contained in:
@@ -12,7 +12,7 @@ interface initMessageBody {
|
||||
file_size: number | string,
|
||||
action?: string,
|
||||
token?: string,
|
||||
convertTo? : string | undefined | null
|
||||
convertTo?: string | undefined | null
|
||||
}
|
||||
|
||||
export async function fileUpload(messageBody: initMessageBody, convertTo?: string | null | undefined) {
|
||||
@@ -229,3 +229,48 @@ export async function getAllowedFilesExtensions(type: string) {
|
||||
return error
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkOperationPrice(action: string, filesCount: number, fileType: string) {
|
||||
const token = await getSessionData('token');
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
version: 1,
|
||||
msg_id: 30008,
|
||||
message_body: {
|
||||
auth_token: token,
|
||||
action: action,
|
||||
file_type: fileType,
|
||||
count_files: filesCount
|
||||
}
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
let parsed = await response.json();
|
||||
console.log(parsed);
|
||||
|
||||
if (parsed.message_code === 0) {
|
||||
return parsed.message_body;
|
||||
} else {
|
||||
throw parsed;
|
||||
}
|
||||
} else {
|
||||
throw (`${response.status}`);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
return {
|
||||
cost: 0,
|
||||
success: false,
|
||||
tokens_count: 0,
|
||||
error: 'error'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useRef, useState, useCallback, ChangeEvent, DragEvent, useEffect, useMemo } from 'react';
|
||||
import { IconShieldAdd } from '@/app/ui/icons/icons';
|
||||
import { fileUpload, cancelUpload, chunkUpload, checkChunkStatus } from '@/app/actions/fileUpload';
|
||||
import { fileUpload, cancelUpload, chunkUpload, checkChunkStatus, checkOperationPrice } from '@/app/actions/fileUpload';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useNavigationBlocker } from '@/app/hooks/useNavigationBlocker';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
@@ -113,8 +113,16 @@ export default function UploadSectionFile({
|
||||
setError(null);
|
||||
|
||||
const newFiles: SelectedFile[] = [];
|
||||
const selectedFileNames = new Set(selectedFiles.map(f => f.name));
|
||||
const currentFileNames = new Set<string>();
|
||||
const duplicateNames: string[] = [];
|
||||
|
||||
for (const file of files) {
|
||||
if (selectedFileNames.has(file.name)) {
|
||||
duplicateNames.push(file.name);
|
||||
continue;
|
||||
}
|
||||
|
||||
const validation = validateFile(file);
|
||||
|
||||
if (!validation.isValid) {
|
||||
@@ -141,6 +149,8 @@ export default function UploadSectionFile({
|
||||
}
|
||||
}
|
||||
|
||||
currentFileNames.add(file.name);
|
||||
|
||||
newFiles.push({
|
||||
file,
|
||||
name: file.name,
|
||||
@@ -152,8 +162,13 @@ export default function UploadSectionFile({
|
||||
});
|
||||
}
|
||||
|
||||
if (duplicateNames.length > 0) {
|
||||
const uniqueDuplicates = [...new Set(duplicateNames)];
|
||||
setError(`${t('duplicate-files')}: ${uniqueDuplicates.join(', ')}`);
|
||||
}
|
||||
|
||||
setSelectedFiles(prev => [...prev, ...newFiles]);
|
||||
}, [fileType, t]);
|
||||
}, [fileType, selectedFiles]);
|
||||
|
||||
const handleFileInputChange = (event: ChangeEvent<HTMLInputElement>): void => {
|
||||
const files = Array.from(event.target.files || []);
|
||||
@@ -204,6 +219,7 @@ export default function UploadSectionFile({
|
||||
f.uploadId !== fileId && f.name !== fileId
|
||||
));
|
||||
} else {
|
||||
console.log('clear all')
|
||||
selectedFiles.forEach(file => {
|
||||
if (file.preview) {
|
||||
URL.revokeObjectURL(file.preview);
|
||||
@@ -223,10 +239,21 @@ export default function UploadSectionFile({
|
||||
setError(null);
|
||||
};
|
||||
|
||||
const uploadSingleFile = async (fileInfo: SelectedFile): Promise<void> => {
|
||||
const uploadSingleFile = async (fileInfo: SelectedFile, uploadType: 'single' | 'multi'): Promise<void> => {
|
||||
const fileId = `${fileInfo.name}-${Date.now()}`;
|
||||
isCancelledRef.current.set(fileId, false);
|
||||
|
||||
if (uploadType === 'single') {
|
||||
setError(null);
|
||||
const priceCheck = await checkOperationPrice('checkTokensForProtect', 1, fileType);
|
||||
|
||||
if (!priceCheck.success) {
|
||||
const errorMessage = `${t('there-are-not-enough-funds-to-protect-file', { count: priceCheck?.tokens_count })}`;
|
||||
setError(errorMessage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
setSelectedFiles(prev => prev.map(f =>
|
||||
f.name === fileInfo.name ? { ...f, status: 'uploading' } : f
|
||||
@@ -315,13 +342,20 @@ export default function UploadSectionFile({
|
||||
}, [selectedFiles]);
|
||||
|
||||
const handleStartAllUploads = useCallback(async (): Promise<void> => {
|
||||
setError(null);
|
||||
if (selectedFilesRef.current.length === 0) {
|
||||
return;
|
||||
}
|
||||
const priceCheck = await checkOperationPrice('checkTokensForProtect', selectedFilesRef.current.length, fileType);
|
||||
|
||||
if (priceCheck.success) {
|
||||
const uploadNextBatch = async () => {
|
||||
const currentPending = selectedFilesRef.current.filter(f => f.status === 'pending');
|
||||
const batch = currentPending.slice(0, maxParallelUploads);
|
||||
|
||||
if (batch.length === 0) return;
|
||||
|
||||
await Promise.all(batch.map(file => uploadSingleFile(file)));
|
||||
await Promise.all(batch.map(file => uploadSingleFile(file, 'multi')));
|
||||
|
||||
if (selectedFilesRef.current.some(f => f.status === 'pending')) {
|
||||
await uploadNextBatch();
|
||||
@@ -329,6 +363,10 @@ export default function UploadSectionFile({
|
||||
};
|
||||
|
||||
await uploadNextBatch();
|
||||
} else {
|
||||
const errorMessage = `${t('there-are-not-enough-funds-to-protect-files', { count: priceCheck?.tokens_count })}`;
|
||||
setError(errorMessage);
|
||||
}
|
||||
}, [maxParallelUploads]);
|
||||
|
||||
const getTotalProgress = useMemo(() => {
|
||||
@@ -399,7 +437,6 @@ export default function UploadSectionFile({
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className="upload-section" >
|
||||
<h3>
|
||||
@@ -607,7 +644,7 @@ export default function UploadSectionFile({
|
||||
<div className="mt-2 text-center" >
|
||||
<button
|
||||
className="btn btn-confirm"
|
||||
onClick={() => uploadSingleFile(file)
|
||||
onClick={() => uploadSingleFile(file, 'single')
|
||||
}
|
||||
type="button"
|
||||
disabled={uploadingCount >= maxParallelUploads}
|
||||
|
||||
@@ -293,7 +293,10 @@
|
||||
"security-details": "Security details",
|
||||
"number-of-checks": "Number of checks",
|
||||
"format": "Format",
|
||||
"file-name": "File name"
|
||||
"file-name": "File name",
|
||||
"there-are-not-enough-funds-to-protect-files": "There are not enough funds to protect files. {count} tokens required",
|
||||
"there-are-not-enough-funds-to-protect-file": "There are not enough funds to protect file. {count} tokens required",
|
||||
"duplicate-files": "Duplicate files"
|
||||
},
|
||||
"Login-register-form": {
|
||||
"and": "and",
|
||||
|
||||
@@ -293,7 +293,10 @@
|
||||
"security-details": "Детали защиты",
|
||||
"number-of-checks": "Количество проверок",
|
||||
"format": "Формат",
|
||||
"file-name": "Имя файла"
|
||||
"file-name": "Имя файла",
|
||||
"there-are-not-enough-funds-to-protect-files": "Для защиты файлов недостаточно средств. Необходимо {count} токен(ов/а)",
|
||||
"there-are-not-enough-funds-to-protect-file": "Для защиты файла недостаточно средств. Необходимо {count} токен(ов/а)",
|
||||
"duplicate-files": "Дубликаты файлов"
|
||||
},
|
||||
"Login-register-form": {
|
||||
"and": "и",
|
||||
|
||||
Reference in New Issue
Block a user