From e0420fa6d3dcf77047cca9ff62ab9d1841187e7a Mon Sep 17 00:00:00 2001 From: smanylov Date: Thu, 25 Dec 2025 13:19:32 +0700 Subject: [PATCH] add navagation handler while file upload --- src/app/[locale]/pages/marking-audio/page.tsx | 4 +- src/app/actions/file-upload.ts | 3 + src/app/components/upload-section-file.tsx | 77 ++++++++++-------- src/app/hooks/useNavigationBlocker.ts | 81 +++++++++++++++++++ src/i18n/messages/en.json | 3 +- src/i18n/messages/ru.json | 3 +- 6 files changed, 136 insertions(+), 35 deletions(-) create mode 100644 src/app/hooks/useNavigationBlocker.ts diff --git a/src/app/[locale]/pages/marking-audio/page.tsx b/src/app/[locale]/pages/marking-audio/page.tsx index 34d43ed..3683a77 100644 --- a/src/app/[locale]/pages/marking-audio/page.tsx +++ b/src/app/[locale]/pages/marking-audio/page.tsx @@ -1,9 +1,10 @@ import ProtectionSummary from '@/app/ui/marking-page/protection-summary'; import FilesTable from '@/app/ui/dashboard/files-table'; import PageTitle from '@/app/ui/page-title'; +import UploadSectionFile from '@/app/components/upload-section-file'; const ALLOWED_EXTENSIONS: string[] = ['jpg', 'jpeg', 'png', 'gif', 'bmp']; -const FILE_TYPE = "VIDEO" +const FILE_TYPE = "AUDIO" const MAX_SIZE = 1048576000; export default function Page() { @@ -12,6 +13,7 @@ export default function Page() {
+ {/* */}
diff --git a/src/app/actions/file-upload.ts b/src/app/actions/file-upload.ts index ca08a61..6f4985d 100644 --- a/src/app/actions/file-upload.ts +++ b/src/app/actions/file-upload.ts @@ -66,6 +66,7 @@ export async function fileUpload(messageBody: initMessageBody) { export async function cancelUpload(udloadId: string) { try { + console.log('cancelUpload start'); const response = await fetch(`${API_BASE_URL}/api/v1/data`, { method: 'POST', body: JSON.stringify({ @@ -93,6 +94,7 @@ export async function cancelUpload(udloadId: string) { }; if (parsed.message_desc === 'Upload cancelled successfully') { + console.log('cancelUpload done'); return parsed.message_body; } else { throw parsed; @@ -101,6 +103,7 @@ export async function cancelUpload(udloadId: string) { throw (`${response.status}`); } } catch (error) { + console.log('cancelUpload error'); return error; } } diff --git a/src/app/components/upload-section-file.tsx b/src/app/components/upload-section-file.tsx index feeafe6..2ce6b26 100644 --- a/src/app/components/upload-section-file.tsx +++ b/src/app/components/upload-section-file.tsx @@ -1,10 +1,10 @@ 'use client' -import React, { useRef, useState, useCallback, ChangeEvent, DragEvent } from 'react'; +import { useRef, useState, useCallback, ChangeEvent, DragEvent, useEffect } from 'react'; import { IconShieldAdd } from '@/app/ui/icons/icons'; import { fileUpload, cancelUpload, chunkUpload, checkChunkStatus } from '@/app/actions/file-upload'; import { useTranslations } from 'next-intl'; - +import { useNavigationBlocker } from '@/app/hooks/useNavigationBlocker'; interface SelectedFile { file: File; preview: string; @@ -94,7 +94,6 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile 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(); @@ -308,6 +307,42 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile } } + useEffect(() => { + // Обработка закрытия вкладки + // Тут можно попробовать изучить вопрос с navigator.sendBeacon('', blob) + // он нужен для того что бы послать запрос на бек при закрытии вкладки, + // но у него есть свои особенности и стандартные запросы не работают. + const handleUnload = () => { + if (uploadId) { + //const data = JSON.stringify({ uploadId, reason: 'tab_closed' }); + //const blob = new Blob([data], { type: 'application/json' }); + //navigator.sendBeacon('/api/v1/data/cancel', blob); + console.log('sendBeacon'); + } + }; + if (uploadId) { + window.addEventListener('unload', handleUnload); + } + + return () => { + window.removeEventListener('unload', handleUnload); + }; + }, [uploadId]); + + useNavigationBlocker({ + shouldBlock: !!uploadId, + message: t('have-unsaved-changes'), + onConfirm: async () => { + console.log('User confirmed navigation'); + if (uploadId) { + await cancelUpload(uploadId); + } + }, + onCancel: () => { + console.log('User cancelled navigation'); + } + }); + return (

@@ -354,14 +389,16 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile {t('select-files-to-protect')} + {fileType === "IMAGE" && ( +

+ Разрешение изображение: 100x100 - 10000x10000 +

+ )}

- Разрешение изображение: 100x100 - 10000x10000 + Размер файла: до {(maxFileSize / 1024 / 1024)} МБ

- Размер файла: до 20 МБ -

-

- Формат файла: JPG, PNG, GIF, BMP (WEBP НЕ поддерживается) + Формат файла: {ALLOWED_EXTENSIONS.join(', ')}

{error && ( @@ -411,17 +448,6 @@ export default function UploadSectionFile({ fileType, allowedExtensions, maxFile /> )} - {fileType === 'VIDEO' && ( -