fix file verification upload

This commit is contained in:
smanylov
2026-04-27 14:58:54 +07:00
parent abc07a5e2f
commit a7c203d7a4
5 changed files with 34 additions and 100 deletions
+4
View File
@@ -230,6 +230,10 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
h3 {
margin-bottom: 10px;
}
.drag-drop-zone { .drag-drop-zone {
border: 2px dashed #6366f1; border: 2px dashed #6366f1;
border-radius: .75rem; border-radius: .75rem;
@@ -5,7 +5,7 @@ import { fileUpload, cancelUpload, chunkUpload, checkChunkStatus, checkOperation
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import { useNavigationBlocker } from '@/app/hooks/useNavigationBlocker'; import { useNavigationBlocker } from '@/app/hooks/useNavigationBlocker';
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import {useUserProfile} from '@/app/hooks/react-query/useUserDataInfo'; import { useUserProfile } from '@/app/hooks/react-query/useUserDataInfo';
export interface SelectedFile { export interface SelectedFile {
file: File; file: File;
@@ -48,9 +48,9 @@ export default function VerificationUploadSection({
const [isDragging, setIsDragging] = useState<boolean>(false); const [isDragging, setIsDragging] = useState<boolean>(false);
const [selectedFiles, setSelectedFiles] = useState<SelectedFile[]>([]); const [selectedFiles, setSelectedFiles] = useState<SelectedFile[]>([]);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [activeUploads, setActiveUploads] = useState<Set<string>>(new Set()); // ID активных загрузок const [activeUploads, setActiveUploads] = useState<Set<string>>(new Set());
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const isCancelledRef = useRef<Map<string, boolean>>(new Map()); // Для отслеживания отмен по файлам const isCancelledRef = useRef<Map<string, boolean>>(new Map());
const selectedFilesRef = useRef<SelectedFile[]>(selectedFiles); const selectedFilesRef = useRef<SelectedFile[]>(selectedFiles);
const t = useTranslations('Global'); const t = useTranslations('Global');
@@ -62,9 +62,9 @@ export default function VerificationUploadSection({
return allowedExtensions.map(e => `.${e}`).join(', '); return allowedExtensions.map(e => `.${e}`).join(', ');
}, [allowedExtensions]); }, [allowedExtensions]);
const validateFile = (file: File): { isValid: boolean; errorMessage?: string } => { const validateFile = (file: File, extension: string | undefined): { isValid: boolean; errorMessage?: string } => {
if (!allowedExtensions.includes(file.type as string)) { if (!allowedExtensions.includes(file.type as string)) {
const extension = file.name.split('.').pop()?.toLowerCase();
if (!extension || !allowedExtensions.includes(extension as string)) { if (!extension || !allowedExtensions.includes(extension as string)) {
return { return {
isValid: false, isValid: false,
@@ -127,8 +127,8 @@ export default function VerificationUploadSection({
duplicateNames.push(file.name); duplicateNames.push(file.name);
continue; continue;
} }
const extension = file.name.split('.').pop()?.toLowerCase();
const validation = validateFile(file); const validation = validateFile(file, extension);
if (!validation.isValid) { if (!validation.isValid) {
setError(prev => prev ? `${prev}, ${validation.errorMessage}` : validation.errorMessage || t('unknown-validation-error')); setError(prev => prev ? `${prev}, ${validation.errorMessage}` : validation.errorMessage || t('unknown-validation-error'));
@@ -139,7 +139,8 @@ export default function VerificationUploadSection({
width: number, width: number,
height: number, height: number,
} | undefined = undefined; } | undefined = undefined;
if (fileType === "image") {
if (fileType === "image" && extension !== 'pdf') {
try { try {
dimensions = await getImageDimensions(file) as { width: number, height: number }; dimensions = await getImageDimensions(file) as { width: number, height: number };
if (dimensions?.width < 100 || dimensions?.height < 100 || if (dimensions?.width < 100 || dimensions?.height < 100 ||
@@ -224,7 +225,6 @@ export default function VerificationUploadSection({
f.uploadId !== fileId && f.name !== fileId f.uploadId !== fileId && f.name !== fileId
)); ));
} else { } else {
console.log('clear all')
selectedFiles.forEach(file => { selectedFiles.forEach(file => {
if (file.preview) { if (file.preview) {
URL.revokeObjectURL(file.preview); URL.revokeObjectURL(file.preview);
@@ -247,17 +247,16 @@ export default function VerificationUploadSection({
const uploadSingleFile = async (fileInfo: SelectedFile, uploadType: 'single' | 'multi', isLastFIle: boolean): Promise<void> => { const uploadSingleFile = async (fileInfo: SelectedFile, uploadType: 'single' | 'multi', isLastFIle: boolean): Promise<void> => {
const fileId = `${fileInfo.name}-${Date.now()}`; const fileId = `${fileInfo.name}-${Date.now()}`;
isCancelledRef.current.set(fileId, false); isCancelledRef.current.set(fileId, false);
setError(null);
if (uploadType === 'single') { /* if (uploadType === 'single') {
setError(null);
const priceCheck = await checkOperationPrice('checkTokensForProtect', 1, fileType); const priceCheck = await checkOperationPrice('checkTokensForProtect', 1, fileType);
if (!priceCheck.success) { if (!priceCheck.success) {
const errorMessage = `${t('there-are-not-enough-funds-to-protect-file', { count: priceCheck?.tokens_count })}`; const errorMessage = `${t('there-are-not-enough-funds-to-protect-file', { count: priceCheck?.tokens_count })}`;
setError(errorMessage); setError(errorMessage);
return; return;
} }
} } */
try { try {
setSelectedFiles(prev => prev.map(f => setSelectedFiles(prev => prev.map(f =>
@@ -267,7 +266,7 @@ export default function VerificationUploadSection({
const extension = fileInfo.file.name.split('.').pop() || ''; const extension = fileInfo.file.name.split('.').pop() || '';
const initMessageBody = { const initMessageBody = {
file_name: fileInfo.file.name, file_name: fileInfo.file.name,
file_type: fileType, file_type: extension === 'pdf' ? 'document' : fileType,
extension: extension, extension: extension,
file_size: fileInfo.file.size file_size: fileInfo.file.size
}; };
@@ -353,21 +352,15 @@ export default function VerificationUploadSection({
if (selectedFilesRef.current.length === 0) { if (selectedFilesRef.current.length === 0) {
return; return;
} }
const priceCheck = await checkOperationPrice('checkTokensForProtect', selectedFilesRef.current.length, fileType);
if (priceCheck.success) { const files = selectedFilesRef.current;
const files = selectedFilesRef.current; const totalFiles = files.length;
const totalFiles = files.length;
for (let i = 0; i < totalFiles; i++) { for (let i = 0; i < totalFiles; i++) {
const file = files[i]; const file = files[i];
const isLastFile = i === totalFiles - 1; const isLastFile = i === totalFiles - 1;
await uploadSingleFile(file, 'multi', isLastFile); await uploadSingleFile(file, 'multi', isLastFile);
}
} else {
const errorMessage = `${t('there-are-not-enough-funds-to-protect-files', { count: priceCheck?.tokens_count })}`;
setError(errorMessage);
} }
}, [maxParallelUploads]); }, [maxParallelUploads]);
@@ -404,7 +397,7 @@ export default function VerificationUploadSection({
return ( return (
<div className="verefication-block" > <div className="verefication-block" >
<h3> <h3>
Загрузка изображений удостоверения личности {t('uploading-id-images')}
</h3> </h3>
< div < div
@@ -413,10 +406,6 @@ export default function VerificationUploadSection({
onDragLeave={handleDragLeave} onDragLeave={handleDragLeave}
onDrop={handleDrop} onDrop={handleDrop}
> >
{/* <h4>
{t('drag-the-file-here')}
</h4> */}
{ {
fileType === "image" && ( fileType === "image" && (
<p className="description" > <p className="description" >
@@ -427,18 +416,15 @@ export default function VerificationUploadSection({
<p className="description" > <p className="description" >
{t('file-format')}: {acceptString} {t('file-format')}: {acceptString}
</p> </p>
{/* < p className="description" >
{t('file-size')}: {t('to')} {(maxFileSize / 1024 / 1024)} {t('mb')}
</p> */}
< input < input
ref={fileInputRef} ref={fileInputRef}
type="file" type="file"
accept={acceptString} accept={`${acceptString}`}
style={{ display: 'none' }} style={{ display: 'none' }}
onChange={handleFileInputChange} onChange={handleFileInputChange}
aria-label="Выбор файла для защиты" aria-label="Выбор файла для защиты"
multiple // Добавляем multiple для выбора нескольких файлов multiple
/> />
{ {
@@ -453,22 +439,6 @@ export default function VerificationUploadSection({
selectedFiles.length > 0 && ( selectedFiles.length > 0 && (
<div className="mt-4" > <div className="mt-4" >
<div className="selected-file-action-panel" > <div className="selected-file-action-panel" >
{/* <div>
<p className="selected-file-action-info" >
<span>{t('total-files')}: {selectedFiles.length}</span>
<span>{t('uploading')}: {uploadingCount}</span>
<span>{t('completed')}: {completedCount}</span>
</p>
<div className="w-full bg-gray-200 rounded-full h-2.5 mt-2">
<div
className="bg-blue-600 h-2.5 rounded-full transition-all duration-300"
style={{ width: `${getTotalProgress}%` }
}
>
</div>
</div>
</div> */}
<button <button
className={`btn btn-primary`} className={`btn btn-primary`}
onClick={handleStartAllUploads} onClick={handleStartAllUploads}
@@ -498,27 +468,6 @@ export default function VerificationUploadSection({
<p className="text-gray-700" > <p className="text-gray-700" >
<span className="font-medium" > {t('file')}: </span> {file.name} <span className="font-medium" > {t('file')}: </span> {file.name}
</p> </p>
{/* < p className="text-gray-700" >
<span className="font-medium" > {t('size')}: </span> {file.size}
</p> */}
{/* < p className="text-gray-700" >
<span className="font-medium" > {t('status')}: </span>
<span className={`ml-2 ${file.status === 'completed' ? 'text-green-600' :
file.status === 'uploading' ? 'text-blue-600' :
file.status === 'error' ? 'text-red-600' :
'text-gray-600'
}`}>
{
file.status === 'completed' ? t('completed') :
file.status === 'uploading' ? t('uploading') :
file.status === 'error' ? t('error') :
t('pending')
}
</span>
</p> */}
{ {
file.error && ( file.error && (
<p className="text-red-600 text-sm mt-1" > {file.error} </p> <p className="text-red-600 text-sm mt-1" > {file.error} </p>
@@ -534,32 +483,9 @@ export default function VerificationUploadSection({
> >
</div> </div>
</div> </div>
{/* <span className={
`upload-progress ${file.status === 'completed' ? 'text-green-600' :
file.status === 'uploading' ? 'text-blue-600' :
'text-gray-600'
}`
}>
{file.progress} %
</span> */}
<div <div
className="selected-file-actions" className="selected-file-actions"
> >
{/* {
file.status === 'pending' && (
<button
className="btn btn-confirm"
onClick={() => uploadSingleFile(file, 'single')
}
type="button"
disabled={uploadingCount >= maxParallelUploads}
>
{t('start-upload')}
</button>
)
} */}
< button < button
className="btn btn-cancel" className="btn btn-cancel"
onClick={() => handleClearFile(file.uploadId || file.name)} onClick={() => handleClearFile(file.uploadId || file.name)}
@@ -582,7 +508,7 @@ export default function VerificationUploadSection({
type="button" type="button"
disabled={uploadingCount > maxParallelUploads} disabled={uploadingCount > maxParallelUploads}
> >
выберете документ(ы) для загрузки {t('select-document-to-upload')}
</button> </button>
</div> </div>
); );
@@ -40,7 +40,7 @@ export default function SettingUserVerification() {
{userData?.verifiedStatus === 'NOT_VERIFIED' || userData?.verifiedStatus === null ? ( {userData?.verifiedStatus === 'NOT_VERIFIED' || userData?.verifiedStatus === null ? (
<VerificationUploadSection <VerificationUploadSection
fileType="image" fileType="image"
allowedExtensions={allFilesExtensions.images} allowedExtensions={[...allFilesExtensions.images, 'pdf']}
maxFileSize={allFilesExtensions.maxFileSize} maxFileSize={allFilesExtensions.maxFileSize}
/> />
) : ( ) : (
+3 -1
View File
@@ -446,7 +446,9 @@
"claims": "Claims", "claims": "Claims",
"complaints": "Complaints", "complaints": "Complaints",
"recent-cases": "Recent cases", "recent-cases": "Recent cases",
"select-at-least-one-filter": "Select at least one filter" "select-at-least-one-filter": "Select at least one filter",
"select-document-to-upload": "Select document(s) to upload",
"uploading-id-images": "Uploading ID images"
}, },
"Login-register-form": { "Login-register-form": {
"and": "and", "and": "and",
+3 -1
View File
@@ -446,7 +446,9 @@
"claims": "Претензии", "claims": "Претензии",
"complaints": "Жалобы", "complaints": "Жалобы",
"recent-cases": "Недавние дела", "recent-cases": "Недавние дела",
"select-at-least-one-filter": "Выберите хотя бы один фильтр" "select-at-least-one-filter": "Выберите хотя бы один фильтр",
"select-document-to-upload": "Выберите документ(ы) для загрузки",
"uploading-id-images": "Загрузка изображений удостоверения личности"
}, },
"Login-register-form": { "Login-register-form": {
"and": "и", "and": "и",