Files
no-copy-frontend/src/app/ui/search/file-search-panel.tsx
T
2026-02-10 17:29:36 +07:00

226 lines
7.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { SearchedUserFilesList } from '@/app/ui/search/searched-user-files-list';
import { SearchedGlobalFilesList } from '@/app/ui/search/searched-global-files-list';
import { useCallback, useState, useImperativeHandle } from 'react';
import { searchUserFiles, searchGlobalFiles } from '@/app/actions/searchActions';
import { useQueryClient } from '@tanstack/react-query';
import { Pagination } from '@/app/components/Pagination';
export interface SearchItem {
url: string,
pageTitle: string,
height: number,
width: number,
host: string,
pageUrl: string
}
export function FileSearchPanel({ fileId, ref }: { fileId: string | null, ref: any }) {
const [searchedUserFiles, setSearchedUserFiles] = useState<string[]>([]);
const [searchedUserFilesShowNull, setSearchedUserFilesShowNull] = useState<boolean>(false);
const [searchedGlobalFiles, setSearchedGlobalFiles] = useState<SearchItem[]>([]);
const [searchedGlobalFilesShowNull, setSearchedGlobalFilesShowNull] = useState<boolean>(false);
const [loading, setLoading] = useState<boolean>(false);
const [paginationLoading, setPaginationLoading] = useState<boolean>(false);
const [showGlobalSearch, setShowGlobalSearch] = useState<boolean>(false);
const queryClient = useQueryClient();
const [searchTotalPages, setSearchTotalPages] = useState<number>(0);
const [searchCurrentPages, setSearchCurrentPages] = useState<number>(1);
useImperativeHandle(ref, () => ({
clearList: () => {
setSearchedUserFiles([]);
setSearchedGlobalFiles([]);
setSearchedUserFilesShowNull(false);
setSearchedGlobalFilesShowNull(false);
setShowGlobalSearch(false);
setSearchCurrentPages(1);
setSearchTotalPages(0);
}
}));
const handlerSearchUserFile = useCallback(async (fileId: string, page: number): Promise<void> => {
try {
let result = await searchUserFiles(fileId);
if (result.content.length) {
setSearchedUserFiles(result.content);
} else {
setSearchedUserFilesShowNull(true);
}
} catch (error) {
}
setShowGlobalSearch(true);
handlerSearchGlobalFile(fileId, page)
}, [fileId])
const handlerSearchGlobalFile = useCallback(async (fileId: string, page: number, actionFromPagination?: boolean): Promise<void> => {
if (!actionFromPagination) {
setLoading(true);
setSearchedGlobalFilesShowNull(false);
setSearchedGlobalFiles([]);
} else {
setPaginationLoading(true);
}
try {
let result = await searchGlobalFiles(fileId, page);
console.log('searchGlobalFiles');
console.log(result);
if (result.images.length) {
setSearchedGlobalFiles(result.images);
setSearchTotalPages(result.totalPages);
setSearchCurrentPages(page);
} else {
setSearchedGlobalFilesShowNull(true);
}
} catch (error) {
} finally {
await queryClient.invalidateQueries({ queryKey: ['userData'] });
await queryClient.invalidateQueries({ queryKey: ['userSearchData'] });
setLoading(false);
setPaginationLoading(false);
}
}, [fileId])
return (
<>
<div
className="mb-4"
>
<button
className="btn btn-primary btn-search"
disabled={fileId ? false : true}
onClick={() => {
if (fileId) {
handlerSearchUserFile(fileId, 1)
}
}}
>
Начать поиск
</button>
</div>
{(searchedUserFiles.length !== 0) && (
<SearchedUserFilesList list={searchedUserFiles} />
)}
{searchedUserFilesShowNull && (
<div
className="user-file-search-results"
>
<div className="results-header">
<div className="results-title">Результаты поиска</div>
<div className="results-count">
Найдено файлов: {searchedUserFiles.length}
</div>
</div>
<div
className="empty-results"
>
<h3>Похожих файлов не найдено</h3>
<p>В вашей библиотеке нет файлов, похожих на загруженный</p>
<div className="empty-results-hint">
<strong>Совет:</strong> Убедитесь, что вы загружали этот файл ранее через страницу "Маркировка"
</div>
</div>
</div>
)}
{showGlobalSearch && (
<div
className="global-search-section"
>
<div className="global-search-header">
<div className="global-search-title">
Глобальный поиск изображений
</div>
<div className="">
Найти где ещё используется ваше изображение в интернете
</div>
<div className="global-search-badge">
Интернет поиск
</div>
</div>
<div className="global-search-content">
<div className="global-search-info">
<div className="global-search-info-title">
Поиск по всему интернету
</div>
<div className="global-search-info-text">
Используем продвинутые технологии обратного поиска по изображению для поиска копий вашего контента
на сайтах, в социальных сетях и других источниках. Поможет обнаружить несанкционированное использование.
</div>
</div>
<div className="search-counter" id="search-counter">
<div className="counter-info">
<div className="counter-icon" id="counter-icon"></div>
<div className="counter-text">
<div className="counter-label">Глобальных поисков сегодня</div>
<div className="counter-value" id="counter-value">0 из 10</div>
</div>
</div>
<div className="progress-bar">
<div
className="progress-fill"
id="progress-fill"
style={{ width: '0%' }}
>
</div>
</div>
</div>
<div className={`global-loading ${loading ? 'show' : ''}`} id="global-loading">
<div className="global-spinner"></div>
<div className="global-loading-text" id="global-loading-text">
Поиск изображений в интернете...
</div>
</div>
<div className={`global-result ${searchedGlobalFiles.length ? 'show' : ''}`} id="global-result">
<div className="global-result-card">
<div className="global-result-header">
<span>Найдено в интернете</span>
{paginationLoading && (
<div className="loading-animation">
<span className="global-spinner"></span>
</div>
)}
</div>
<div className="global-result-content">
<SearchedGlobalFilesList list={searchedGlobalFiles} />
</div>
</div>
</div>
{searchedGlobalFilesShowNull && (
<div className="global-no-result" id="global-no-result">
<div className="global-no-result-icon">&zwj;</div>
<h4>Похожие изображения в интернете не найдены</h4>
<p>Это может означать, что ваше изображение уникально и не используется на других сайтах.</p>
</div>
)}
<div className="global-error" id="global-error">
<strong>Ошибка глобального поиска:</strong>
<span id="global-error-text"></span>
</div>
<Pagination totalPages={searchTotalPages} currentPage={searchCurrentPages} fileId={fileId} callBack={handlerSearchGlobalFile} />
</div>
</div>
)}
</>
)
}