From 2209bfa48cebde59e580ccdca05ee3c2d1bdd41a Mon Sep 17 00:00:00 2001 From: smanylov Date: Fri, 26 Dec 2025 17:56:57 +0700 Subject: [PATCH] try fix upload for server --- src/app/actions/action.ts | 6 +- src/app/actions/auth.ts | 6 +- src/app/actions/definitions.ts | 4 + src/app/actions/fileEntity.ts | 5 +- src/app/actions/fileUpload.ts | 6 +- src/app/components/tanstakTable.tsx | 5 - src/app/components/upload-section-file.tsx | 105 ++++++++++++--------- src/app/ui/header/notificationsButton.tsx | 2 +- src/app/ui/header/userMenuButton.tsx | 2 +- 9 files changed, 73 insertions(+), 68 deletions(-) diff --git a/src/app/actions/action.ts b/src/app/actions/action.ts index cbeafc2..14694f2 100644 --- a/src/app/actions/action.ts +++ b/src/app/actions/action.ts @@ -1,10 +1,6 @@ 'use server' import { getSessionData } from '@/app/actions/session'; -import { localDevelopmentUrl, testUserData } from '@/app/actions/definitions'; - -const API_BASE_URL = process.env.NODE_ENV === 'development' - ? localDevelopmentUrl - : 'http://app:8080'; +import { localDevelopmentUrl, testUserData, API_BASE_URL } from '@/app/actions/definitions'; const FRUITS_URL = 'https://www.fruityvice.com/api/fruit/'; const ALL = 'all'; diff --git a/src/app/actions/auth.ts b/src/app/actions/auth.ts index 8088167..5a2bd43 100644 --- a/src/app/actions/auth.ts +++ b/src/app/actions/auth.ts @@ -1,13 +1,9 @@ '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 { redirect } from 'next/navigation'; -const API_BASE_URL = process.env.NODE_ENV === 'development' - ? localDevelopmentUrl - : 'http://app:8080'; - export async function logout() { const token = await getSessionData('token'); diff --git a/src/app/actions/definitions.ts b/src/app/actions/definitions.ts index 454a4e7..fb719c8 100644 --- a/src/app/actions/definitions.ts +++ b/src/app/actions/definitions.ts @@ -78,6 +78,10 @@ export const loginFormSchema = z export const localDevelopmentUrl = 'http://localhost'; +export const API_BASE_URL = process.env.NODE_ENV === 'development' + ? localDevelopmentUrl + : 'http://app:8080'; + export const testUserData = { fullName: 'test', email: 'test@mail.com', diff --git a/src/app/actions/fileEntity.ts b/src/app/actions/fileEntity.ts index ae8b6b0..92ea466 100644 --- a/src/app/actions/fileEntity.ts +++ b/src/app/actions/fileEntity.ts @@ -1,10 +1,7 @@ 'use server' import { getSessionData } from '@/app/actions/session'; -import { localDevelopmentUrl } from '@/app/actions/definitions'; -const API_BASE_URL = process.env.NODE_ENV === 'development' - ? localDevelopmentUrl - : 'http://app:8080'; +import { API_BASE_URL } from '@/app/actions/definitions'; export async function getUserFilesData() { diff --git a/src/app/actions/fileUpload.ts b/src/app/actions/fileUpload.ts index 43d7124..cc304d0 100644 --- a/src/app/actions/fileUpload.ts +++ b/src/app/actions/fileUpload.ts @@ -1,12 +1,8 @@ 'use server' -import { localDevelopmentUrl } from '@/app/actions/definitions'; +import { API_BASE_URL } from '@/app/actions/definitions'; import { getSessionData } from '@/app/actions/session'; -const API_BASE_URL = process.env.NODE_ENV === 'development' - ? localDevelopmentUrl - : 'http://app:8080'; - interface initMessageBody { file_name: string, file_type: string, diff --git a/src/app/components/tanstakTable.tsx b/src/app/components/tanstakTable.tsx index 07584fc..e483206 100644 --- a/src/app/components/tanstakTable.tsx +++ b/src/app/components/tanstakTable.tsx @@ -105,11 +105,6 @@ export default function TanstakFilesTable() { } }, [userFilesData]); - if (typeof window !== 'undefined') { - console.log('typeof window !== undefined'); - console.log(userFilesData) - } - // Состояния const [sorting, setSorting] = useState([]); const [columnFilters, setColumnFilters] = useState([]); diff --git a/src/app/components/upload-section-file.tsx b/src/app/components/upload-section-file.tsx index 36c4ea2..b79764d 100644 --- a/src/app/components/upload-section-file.tsx +++ b/src/app/components/upload-section-file.tsx @@ -1,6 +1,6 @@ '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 { fileUpload, cancelUpload, chunkUpload, checkChunkStatus } from '@/app/actions/fileUpload'; import { useTranslations } from 'next-intl'; @@ -38,6 +38,7 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile const [uploadId, setUploadId] = useState(null); const [isFileUploaded, setIsFileUploaded] = useState(false); const [uploadProgress, setUploadProgress] = useState(0); + const [isUploading, setIsUploading] = useState(false); const t = useTranslations('Global'); let SUPPORTED_FORMATS: string[] = []; @@ -92,12 +93,17 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile 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 } => { if (!SUPPORTED_FORMATS.includes(file.type as string)) { const extension = file.name.split('.').pop()?.toLowerCase(); - if (!extension || !ALLOWED_EXTENSIONS.includes(extension as string)) { + if (!extension || !allowedExtensions.includes(extension as string)) { return { isValid: false, errorMessage: t('unsupported-file-format') @@ -239,33 +245,44 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile setUploadProgress(0); }; - const handlerFileUpload = async (file: SelectedFile): Promise => { - const extension = file.name.split('.').pop(); + const handlerFileUpload = useCallback(async (file: SelectedFile): Promise => { + // Защита от повторного вызова + if (isUploading) return; - if (!extension) { - setError(t('file-has-no-extension')); - return; - } + // Сбрасываем состояния + setError(null); + setIsUploading(true); - const initMessageBody = { - file_name: file.name, - file_type: fileType, - extension: extension, - file_size: file.file.size - }; + try { + const extension = file.name.split('.').pop(); - const response = await fileUpload(initMessageBody) as FileUploadInitResponse; + if (!extension) { + setError(t('file-has-no-extension')); + return; + } - if (response?.upload_id) { - setUploadId(response.upload_id); - const CHUNK_SIZE = response.chunk_size; - const totalChunks = response.total_chunks; - const fileSize = file.file.size; - let start = 0; - let chunkIndex = 0; + const initMessageBody = { + file_name: file.name, + file_type: fileType, + extension: extension, + file_size: file.file.size + }; + + const response = await fileUpload(initMessageBody) as FileUploadInitResponse; + + if (response?.upload_id) { + setUploadId(response.upload_id); + const CHUNK_SIZE = response.chunk_size; + const totalChunks = response.total_chunks; + const fileSize = file.file.size; + let start = 0; + let chunkIndex = 0; + + console.log('start upload'); + console.log(`total chanks - ${totalChunks}`); - try { while (start < fileSize) { + console.log(`chank-${chunkIndex}`); const end = Math.min(start + CHUNK_SIZE, fileSize); 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('chunk_number', chunkIndex.toString()); formData.append('chunk', chunk); + const chunkResponse = await chunkUpload(formData); if (chunkResponse.message_desc !== 'Chunk uploaded successfully') { - throw 'Er1: response error' + throw new Error('Er1: response error'); } if (chunkIndex === totalChunks - 1) { @@ -285,27 +303,32 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile setUploadId(null); setIsFileUploaded(true); } else { - throw 'Er2: not all chunks was uploaded' + throw new Error('Er2: not all chunks was uploaded'); } } start = end; chunkIndex++; - setUploadProgress( - () => { - return Math.floor(chunkIndex / totalChunks * 100); - } - ); + setUploadProgress(Math.floor(chunkIndex / totalChunks * 100)); } - } catch (error) { - setError(t('error-uploading-file')); - console.error('Chunk upload error:', error); + } else { + console.error(response); + throw new Error('Failed to get upload_id'); } - } else { - console.error(response); + } catch (error) { setError(t('error-uploading-file')); + 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); + } + } finally { + setIsUploading(false); } - } + }, [isUploading, fileType]); // Добавьте зависимости useEffect(() => { // Обработка закрытия вкладки @@ -373,9 +396,7 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile `.${e}`).join(',') - } + accept={acceptString} style={{ display: 'none' }} onChange={handleFileInputChange} 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-format')}: {ALLOWED_EXTENSIONS.join(', ')} + {t('file-format')}: {acceptString}

{error && ( @@ -462,7 +483,7 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile handlerFileUpload(selectedFile); }} type="button" - disabled={error || isFileUploaded ? true : false} + disabled={error || isFileUploaded || isUploading ? true : false} > {t('upload-file')} diff --git a/src/app/ui/header/notificationsButton.tsx b/src/app/ui/header/notificationsButton.tsx index 4ae1292..3e883e5 100644 --- a/src/app/ui/header/notificationsButton.tsx +++ b/src/app/ui/header/notificationsButton.tsx @@ -89,7 +89,7 @@ export default function NotificationsButton() {

)}
- + {t('view-all')}
diff --git a/src/app/ui/header/userMenuButton.tsx b/src/app/ui/header/userMenuButton.tsx index 077748d..dfd2d84 100644 --- a/src/app/ui/header/userMenuButton.tsx +++ b/src/app/ui/header/userMenuButton.tsx @@ -80,7 +80,7 @@ export default function UserMenuButton() { {t('settings')} - +