modify search function for all files search
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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) && (
|
||||||
|
|||||||
@@ -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(() => {
|
||||||
// Обработка закрытия вкладки
|
// Обработка закрытия вкладки
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user