try fix upload for server

This commit is contained in:
smanylov
2025-12-26 17:56:57 +07:00
parent 164e2568b9
commit 2209bfa48c
9 changed files with 73 additions and 68 deletions
+1 -5
View File
@@ -1,10 +1,6 @@
'use server' 'use server'
import { getSessionData } from '@/app/actions/session'; import { getSessionData } from '@/app/actions/session';
import { localDevelopmentUrl, testUserData } from '@/app/actions/definitions'; import { localDevelopmentUrl, testUserData, API_BASE_URL } from '@/app/actions/definitions';
const API_BASE_URL = process.env.NODE_ENV === 'development'
? localDevelopmentUrl
: 'http://app:8080';
const FRUITS_URL = 'https://www.fruityvice.com/api/fruit/'; const FRUITS_URL = 'https://www.fruityvice.com/api/fruit/';
const ALL = 'all'; const ALL = 'all';
+1 -5
View File
@@ -1,13 +1,9 @@
'use server' 'use server'
import { SignupFormSchema, loginFormSchema, localDevelopmentUrl } from '@/app/actions/definitions'; import { SignupFormSchema, loginFormSchema, API_BASE_URL } from '@/app/actions/definitions';
import { createSession, deleteSession, getSessionData } from '@/app/actions/session'; import { createSession, deleteSession, getSessionData } from '@/app/actions/session';
import { redirect } from 'next/navigation'; import { redirect } from 'next/navigation';
const API_BASE_URL = process.env.NODE_ENV === 'development'
? localDevelopmentUrl
: 'http://app:8080';
export async function logout() { export async function logout() {
const token = await getSessionData('token'); const token = await getSessionData('token');
+4
View File
@@ -78,6 +78,10 @@ export const loginFormSchema = z
export const localDevelopmentUrl = 'http://localhost'; export const localDevelopmentUrl = 'http://localhost';
export const API_BASE_URL = process.env.NODE_ENV === 'development'
? localDevelopmentUrl
: 'http://app:8080';
export const testUserData = { export const testUserData = {
fullName: 'test', fullName: 'test',
email: 'test@mail.com', email: 'test@mail.com',
+1 -4
View File
@@ -1,10 +1,7 @@
'use server' 'use server'
import { getSessionData } from '@/app/actions/session'; import { getSessionData } from '@/app/actions/session';
import { localDevelopmentUrl } from '@/app/actions/definitions'; import { API_BASE_URL } from '@/app/actions/definitions';
const API_BASE_URL = process.env.NODE_ENV === 'development'
? localDevelopmentUrl
: 'http://app:8080';
export async function getUserFilesData() { export async function getUserFilesData() {
+1 -5
View File
@@ -1,12 +1,8 @@
'use server' 'use server'
import { localDevelopmentUrl } from '@/app/actions/definitions'; import { API_BASE_URL } from '@/app/actions/definitions';
import { getSessionData } from '@/app/actions/session'; import { getSessionData } from '@/app/actions/session';
const API_BASE_URL = process.env.NODE_ENV === 'development'
? localDevelopmentUrl
: 'http://app:8080';
interface initMessageBody { interface initMessageBody {
file_name: string, file_name: string,
file_type: string, file_type: string,
-5
View File
@@ -105,11 +105,6 @@ export default function TanstakFilesTable() {
} }
}, [userFilesData]); }, [userFilesData]);
if (typeof window !== 'undefined') {
console.log('typeof window !== undefined');
console.log(userFilesData)
}
// Состояния // Состояния
const [sorting, setSorting] = useState<SortingState>([]); const [sorting, setSorting] = useState<SortingState>([]);
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]); const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
+41 -20
View File
@@ -1,6 +1,6 @@
'use client' 'use client'
import { useRef, useState, useCallback, ChangeEvent, DragEvent, useEffect } from 'react'; import { useRef, useState, useCallback, ChangeEvent, DragEvent, useEffect, useMemo } from 'react';
import { IconShieldAdd } from '@/app/ui/icons/icons'; import { IconShieldAdd } from '@/app/ui/icons/icons';
import { fileUpload, cancelUpload, chunkUpload, checkChunkStatus } from '@/app/actions/fileUpload'; import { fileUpload, cancelUpload, chunkUpload, checkChunkStatus } from '@/app/actions/fileUpload';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
@@ -38,6 +38,7 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile
const [uploadId, setUploadId] = useState<string | null>(null); const [uploadId, setUploadId] = useState<string | null>(null);
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 [isUploading, setIsUploading] = useState(false);
const t = useTranslations('Global'); const t = useTranslations('Global');
let SUPPORTED_FORMATS: string[] = []; let SUPPORTED_FORMATS: string[] = [];
@@ -92,12 +93,17 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile
break; break;
} }
const ALLOWED_EXTENSIONS: string[] = allowedExtensions; const acceptString = useMemo(() => {
if (!allowedExtensions || !Array.isArray(allowedExtensions)) {
return '';
}
return allowedExtensions.map(e => `.${e}`).join(', ');
}, [allowedExtensions]);
const validateFile = (file: File): { isValid: boolean; errorMessage?: string } => { const validateFile = (file: File): { isValid: boolean; errorMessage?: string } => {
if (!SUPPORTED_FORMATS.includes(file.type as string)) { if (!SUPPORTED_FORMATS.includes(file.type as string)) {
const extension = file.name.split('.').pop()?.toLowerCase(); const extension = file.name.split('.').pop()?.toLowerCase();
if (!extension || !ALLOWED_EXTENSIONS.includes(extension as string)) { if (!extension || !allowedExtensions.includes(extension as string)) {
return { return {
isValid: false, isValid: false,
errorMessage: t('unsupported-file-format') errorMessage: t('unsupported-file-format')
@@ -239,7 +245,15 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile
setUploadProgress(0); setUploadProgress(0);
}; };
const handlerFileUpload = async (file: SelectedFile): Promise<void> => { const handlerFileUpload = useCallback(async (file: SelectedFile): Promise<void> => {
// Защита от повторного вызова
if (isUploading) return;
// Сбрасываем состояния
setError(null);
setIsUploading(true);
try {
const extension = file.name.split('.').pop(); const extension = file.name.split('.').pop();
if (!extension) { if (!extension) {
@@ -264,8 +278,11 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile
let start = 0; let start = 0;
let chunkIndex = 0; let chunkIndex = 0;
try { console.log('start upload');
console.log(`total chanks - ${totalChunks}`);
while (start < fileSize) { while (start < fileSize) {
console.log(`chank-${chunkIndex}`);
const end = Math.min(start + CHUNK_SIZE, fileSize); const end = Math.min(start + CHUNK_SIZE, fileSize);
const chunk = file.file.slice(start, end); const chunk = file.file.slice(start, end);
@@ -273,10 +290,11 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile
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);
const chunkResponse = await chunkUpload(formData); const chunkResponse = await chunkUpload(formData);
if (chunkResponse.message_desc !== 'Chunk uploaded successfully') { if (chunkResponse.message_desc !== 'Chunk uploaded successfully') {
throw 'Er1: response error' throw new Error('Er1: response error');
} }
if (chunkIndex === totalChunks - 1) { if (chunkIndex === totalChunks - 1) {
@@ -285,27 +303,32 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile
setUploadId(null); setUploadId(null);
setIsFileUploaded(true); setIsFileUploaded(true);
} else { } else {
throw 'Er2: not all chunks was uploaded' throw new Error('Er2: not all chunks was uploaded');
} }
} }
start = end; start = end;
chunkIndex++; chunkIndex++;
setUploadProgress( setUploadProgress(Math.floor(chunkIndex / totalChunks * 100));
() => {
return Math.floor(chunkIndex / totalChunks * 100);
} }
); } else {
console.error(response);
throw new Error('Failed to get upload_id');
} }
} catch (error) { } catch (error) {
setError(t('error-uploading-file')); setError(t('error-uploading-file'));
console.error('Chunk upload error:', error); console.error('Chunk 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);
} }
} else { } finally {
console.error(response); setIsUploading(false);
setError(t('error-uploading-file'));
}
} }
}, [isUploading, fileType]); // Добавьте зависимости
useEffect(() => { useEffect(() => {
// Обработка закрытия вкладки // Обработка закрытия вкладки
@@ -373,9 +396,7 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile
<input <input
ref={fileInputRef} ref={fileInputRef}
type="file" type="file"
accept={ accept={acceptString}
ALLOWED_EXTENSIONS.map(e => `.${e}`).join(',')
}
style={{ display: 'none' }} style={{ display: 'none' }}
onChange={handleFileInputChange} onChange={handleFileInputChange}
aria-label="Выбор файла для защиты" aria-label="Выбор файла для защиты"
@@ -398,7 +419,7 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile
{t('file-size')}: {t('to')} {(maxFileSize / 1024 / 1024)} {t('mb')} {t('file-size')}: {t('to')} {(maxFileSize / 1024 / 1024)} {t('mb')}
</p> </p>
<p className="description"> <p className="description">
{t('file-format')}: {ALLOWED_EXTENSIONS.join(', ')} {t('file-format')}: {acceptString}
</p> </p>
{error && ( {error && (
@@ -462,7 +483,7 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile
handlerFileUpload(selectedFile); handlerFileUpload(selectedFile);
}} }}
type="button" type="button"
disabled={error || isFileUploaded ? true : false} disabled={error || isFileUploaded || isUploading ? true : false}
> >
{t('upload-file')} {t('upload-file')}
</button> </button>
+1 -1
View File
@@ -89,7 +89,7 @@ export default function NotificationsButton() {
</p> </p>
)} )}
<div className="notification-footer"> <div className="notification-footer">
<Link href="/pages/notifications" className="notification-link"> <Link href="#" className="notification-link">
{t('view-all')} {t('view-all')}
</Link> </Link>
</div> </div>
+1 -1
View File
@@ -80,7 +80,7 @@ export default function UserMenuButton() {
</svg> </svg>
{t('settings')} {t('settings')}
</Link> </Link>
<Link href="/pages/faq" className="user-menu-item"> <Link href="#" className="user-menu-item">
<svg viewBox="0 0 24 24" fill="currentColor"> <svg viewBox="0 0 24 24" fill="currentColor">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"></path> <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"></path>
</svg> </svg>