modify search function for all files search

This commit is contained in:
smanylov
2026-02-12 18:02:25 +07:00
parent f3e8ef3f65
commit a3da6b8530
5 changed files with 97 additions and 26 deletions
+22 -5
View File
@@ -2,7 +2,14 @@ import SectionSearchFile from '@/app/ui/search/section-search-file';
import { SupportedFormats } from '@/app/ui/search/supported-formats'; import { SupportedFormats } from '@/app/ui/search/supported-formats';
import { SearchStats } from '@/app/ui/search/search-stats'; import { SearchStats } from '@/app/ui/search/search-stats';
import { RecentSearches } from '@/app/ui/search/recent-searches'; import { RecentSearches } from '@/app/ui/search/recent-searches';
export default function Page() { import { getAllowedFilesExtensions } from '@/app/actions/fileUpload';
export default async function Page() {
const { file_extension: extensionVideo, max_file_size } = await getAllowedFilesExtensions('video');
const { file_extension: extensionAudio } = await getAllowedFilesExtensions('audio');
const { file_extension: extensionImage } = await getAllowedFilesExtensions('image');
const { file_extension: extensionDocument } = await getAllowedFilesExtensions('document');
return ( return (
<> <>
<div className="block-wrapper"> <div className="block-wrapper">
@@ -15,12 +22,22 @@ export default function Page() {
</div> </div>
<div className="search-grid"> <div className="search-grid">
<SectionSearchFile <SectionSearchFile
maxFileSize={1024000000} maxFileSize={max_file_size}
allowedExtensions={['jpg', 'jpeg', 'png', 'gif', 'bmp']} /* allowedExtensions={allExtensions} */
fileType="image" allowedExtensions={{
images: extensionImage,
videos: extensionVideo,
audios: extensionAudio,
documents: extensionDocument
}}
/> />
<div className="search-sidebar"> <div className="search-sidebar">
<SupportedFormats /> <SupportedFormats
extensionVideo={extensionVideo}
extensionAudio={extensionAudio}
extensionImage={extensionImage}
extensionDocument={extensionDocument}
/>
<SearchStats /> <SearchStats />
<RecentSearches /> <RecentSearches />
</div> </div>
+1
View File
@@ -3819,6 +3819,7 @@
color: v.$text-s; color: v.$text-s;
font-size: 14px; font-size: 14px;
line-height: 1.5; line-height: 1.5;
text-transform: uppercase;
} }
.stat-item { .stat-item {
+11 -3
View File
@@ -23,6 +23,7 @@ export function FileSearchPanel({ fileId, ref }: { fileId: string | null, ref: a
const [paginationLoading, setPaginationLoading] = useState<boolean>(false); const [paginationLoading, setPaginationLoading] = useState<boolean>(false);
const [showGlobalSearch, setShowGlobalSearch] = useState<boolean>(false); const [showGlobalSearch, setShowGlobalSearch] = useState<boolean>(false);
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const [searchTotalPages, setSearchTotalPages] = useState<number>(0); const [searchTotalPages, setSearchTotalPages] = useState<number>(0);
const [searchCurrentPages, setSearchCurrentPages] = useState<number>(1); const [searchCurrentPages, setSearchCurrentPages] = useState<number>(1);
@@ -41,20 +42,21 @@ export function FileSearchPanel({ fileId, ref }: { fileId: string | null, ref: a
const handlerSearchUserFile = useCallback(async (fileId: string, page: number): Promise<void> => { const handlerSearchUserFile = useCallback(async (fileId: string, page: number): Promise<void> => {
setErrorMessage(null);
try { try {
let result = await searchUserFiles(fileId); let result = await searchUserFiles(fileId);
if (result.content.length) { if (result.content.length) {
setSearchedUserFiles(result.content); setSearchedUserFiles(result.content);
setShowGlobalSearch(true);
handlerSearchGlobalFile(fileId, page)
} else { } else {
setSearchedUserFilesShowNull(true); setSearchedUserFilesShowNull(true);
} }
} catch (error) { } catch (error) {
setErrorMessage('error');
} }
setShowGlobalSearch(true);
handlerSearchGlobalFile(fileId, page)
}, [fileId]) }, [fileId])
@@ -106,6 +108,12 @@ export function FileSearchPanel({ fileId, ref }: { fileId: string | null, ref: a
> >
Начать поиск Начать поиск
</button> </button>
{errorMessage && (
<div className='mt-2 text-red-600 text-sm'>
Ошибка поиска
</div>
)}
</div> </div>
{(searchedUserFiles.length !== 0) && ( {(searchedUserFiles.length !== 0) && (
+47 -10
View File
@@ -24,12 +24,16 @@ interface FileUploadInitResponse {
} }
interface SectionSearchFile { interface SectionSearchFile {
fileType: string allowedExtensions: {
allowedExtensions: string[] images: string[],
videos: string[],
audios: string[],
documents: string[]
}
maxFileSize: number maxFileSize: number
} }
export default function SectionSearchFile({ fileType, allowedExtensions, maxFileSize }: SectionSearchFile) { export default function SectionSearchFile({ allowedExtensions, maxFileSize }: SectionSearchFile) {
const fileInputRef = useRef<HTMLInputElement>(null); const fileInputRef = useRef<HTMLInputElement>(null);
const [isDragging, setIsDragging] = useState<boolean>(false); const [isDragging, setIsDragging] = useState<boolean>(false);
const [selectedFile, setSelectedFile] = useState<SelectedFile | null>(null); const [selectedFile, setSelectedFile] = useState<SelectedFile | null>(null);
@@ -45,17 +49,49 @@ export default function SectionSearchFile({ fileType, allowedExtensions, maxFile
const t = useTranslations('Global'); const t = useTranslations('Global');
const allExtensions = useMemo(() => { return [...allowedExtensions.images, ...allowedExtensions.videos, ...allowedExtensions.audios, ...allowedExtensions.documents] }, []);
const acceptString = useMemo(() => { const acceptString = useMemo(() => {
if (!allowedExtensions || !Array.isArray(allowedExtensions)) { if (!allExtensions || !Array.isArray(allExtensions)) {
return ''; return '';
} }
return allowedExtensions.map(e => `.${e}`).join(', '); return allExtensions.map(e => `.${e}`).join(', ');
}, [allowedExtensions]); }, [allExtensions]);
const getFileType = (fileName: string, allowedExtensions: {
images: string[],
videos: string[],
audios: string[],
documents: string[]
}): 'image' | 'video' | 'audio' | 'document' | 'unknown' => {
const lastDotIndex = fileName.lastIndexOf('.');
const extension = fileName.substring(lastDotIndex + 1).toLowerCase();
if (allowedExtensions.images.includes(extension)) {
return 'image';
}
if (allowedExtensions.videos.includes(extension)) {
return 'video';
}
if (allowedExtensions.audios.includes(extension)) {
return 'audio';
}
if (allowedExtensions.documents.includes(extension)) {
return 'document';
}
return 'unknown';
}
const validateFile = (file: File): { isValid: boolean; errorMessage?: string } => { const validateFile = (file: File): { isValid: boolean; errorMessage?: string } => {
if (!allowedExtensions.includes(file.type as string)) { if (!allExtensions.includes(file.type as string)) {
const extension = file.name.split('.').pop()?.toLowerCase(); const extension = file.name.split('.').pop()?.toLowerCase();
if (!extension || !allowedExtensions.includes(extension as string)) { if (!extension || !allExtensions.includes(extension as string)) {
return { return {
isValid: false, isValid: false,
errorMessage: t('unsupported-file-format') errorMessage: t('unsupported-file-format')
@@ -117,7 +153,7 @@ export default function SectionSearchFile({ fileType, allowedExtensions, maxFile
preview: file.size < 10 * 1024 * 1024 ? URL.createObjectURL(file) : undefined preview: file.size < 10 * 1024 * 1024 ? URL.createObjectURL(file) : undefined
}); });
}, [fileType, t]); }, [t]);
const handleFileInputChange = (event: ChangeEvent<HTMLInputElement>): void => { const handleFileInputChange = (event: ChangeEvent<HTMLInputElement>): void => {
const file = event.target.files?.[0] || null; const file = event.target.files?.[0] || null;
@@ -157,6 +193,7 @@ export default function SectionSearchFile({ fileType, allowedExtensions, maxFile
setError(null); setError(null);
isCancelledRef.current = false; isCancelledRef.current = false;
const file = fileInfo.file; const file = fileInfo.file;
const fileType = getFileType(fileInfo.file.name, allowedExtensions);
try { try {
const extension = file.name.split('.').pop() || ''; const extension = file.name.split('.').pop() || '';
@@ -225,7 +262,7 @@ export default function SectionSearchFile({ fileType, allowedExtensions, maxFile
} finally { } finally {
setUploadId(null); setUploadId(null);
} }
}, [uploadId, fileType]); }, [uploadId, allowedExtensions]);
useEffect(() => { useEffect(() => {
// Обработка закрытия вкладки // Обработка закрытия вкладки
+16 -8
View File
@@ -1,5 +1,13 @@
import { IconImageFile, IconVideoFile, IconAudioFile, IconDocument } from '@/app/ui/icons/icons'; import { IconImageFile, IconVideoFile, IconAudioFile, IconDocument } from '@/app/ui/icons/icons';
export function SupportedFormats() {
interface supportedFormats {
extensionVideo: string[]
extensionAudio: string[]
extensionImage: string[]
extensionDocument: string[]
}
export function SupportedFormats({ extensionVideo, extensionAudio, extensionImage, extensionDocument }: supportedFormats) {
return ( return (
<div className="supported-formats"> <div className="supported-formats">
<div className="formats-title"> <div className="formats-title">
@@ -11,34 +19,34 @@ export function SupportedFormats() {
<IconImageFile /> Изображения <IconImageFile /> Изображения
</div> </div>
<div className="format-list"> <div className="format-list">
JPEG, PNG, GIF, BMP {extensionImage.join(', ')}
</div> </div>
</div> </div>
<div className="format-group hidden"> <div className="format-group">
<div className="format-type video"> <div className="format-type video">
<IconVideoFile /> Видео <IconVideoFile /> Видео
</div> </div>
<div className="format-list"> <div className="format-list">
MP4, AVI, MOV, WMV {extensionVideo.join(', ')}
</div> </div>
</div> </div>
<div className="format-group hidden"> <div className="format-group">
<div className="format-type audio"> <div className="format-type audio">
<IconAudioFile /> Аудио <IconAudioFile /> Аудио
</div> </div>
<div className="format-list"> <div className="format-list">
MP3, WAV, FLAC, AAC {extensionAudio.join(', ')}
</div> </div>
</div> </div>
<div className="format-group hidden"> <div className="format-group">
<div className="format-type document"> <div className="format-type document">
<IconDocument /> Документы <IconDocument /> Документы
</div> </div>
<div className="format-list"> <div className="format-list">
PDF, DOC, DOCX {extensionDocument.join(', ')}
</div> </div>
</div> </div>
</div> </div>