add research button and translate

This commit is contained in:
smanylov
2026-02-23 13:41:07 +07:00
parent 82e27a0ce4
commit 1b9b843f1a
5 changed files with 145 additions and 78 deletions
+16 -1
View File
@@ -67,6 +67,14 @@ export async function searchGlobalFiles(fileId: string, currentPage: number) {
totalResults: 100, totalResults: 100,
} */ } */
/* return {
images: [],
page: 0,
pageSize: 0,
totalPages: 0,
totalResults: 0
} */
try { try {
const response = await fetch(`${API_BASE_URL}/api/v1/data`, { const response = await fetch(`${API_BASE_URL}/api/v1/data`, {
method: 'POST', method: 'POST',
@@ -97,7 +105,14 @@ export async function searchGlobalFiles(fileId: string, currentPage: number) {
} }
} catch (error) { } catch (error) {
return error return {
images: [],
page: 0,
pageSize: 0,
totalPages: 0,
totalResults: 0,
error: 'error'
}
} }
} }
+5 -1
View File
@@ -3255,10 +3255,14 @@
.global-no-result { .global-no-result {
text-align: center; text-align: center;
padding: 60px 20px; padding: 30px 20px;
background: #f8fafc; background: #f8fafc;
border-radius: 16px; border-radius: 16px;
margin: 20px 0; margin: 20px 0;
&-text {
margin-bottom: 40px;
}
} }
.global-error { .global-error {
+48 -40
View File
@@ -4,6 +4,7 @@ import { useCallback, useState, useImperativeHandle } from 'react';
import { searchUserFiles, searchGlobalFiles } from '@/app/actions/searchActions'; import { searchUserFiles, searchGlobalFiles } from '@/app/actions/searchActions';
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import { Pagination } from '@/app/components/Pagination'; import { Pagination } from '@/app/components/Pagination';
import { useTranslations } from 'next-intl';
export interface SearchItem { export interface SearchItem {
url: string, url: string,
@@ -24,6 +25,7 @@ export function FileSearchPanel({ fileId, ref }: { fileId: string | null, ref: a
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 [errorMessage, setErrorMessage] = useState<string | null>(null);
const t = useTranslations('Global');
const [searchTotalPages, setSearchTotalPages] = useState<number>(0); const [searchTotalPages, setSearchTotalPages] = useState<number>(0);
const [searchCurrentPages, setSearchCurrentPages] = useState<number>(1); const [searchCurrentPages, setSearchCurrentPages] = useState<number>(1);
@@ -82,7 +84,7 @@ export function FileSearchPanel({ fileId, ref }: { fileId: string | null, ref: a
setSearchedGlobalFilesShowNull(true); setSearchedGlobalFilesShowNull(true);
} }
} catch (error) { } catch (error) {
setErrorMessage('error');
} finally { } finally {
await queryClient.invalidateQueries({ queryKey: ['userData'] }); await queryClient.invalidateQueries({ queryKey: ['userData'] });
await queryClient.invalidateQueries({ queryKey: ['userSearchData'] }); await queryClient.invalidateQueries({ queryKey: ['userSearchData'] });
@@ -94,24 +96,22 @@ export function FileSearchPanel({ fileId, ref }: { fileId: string | null, ref: a
return ( return (
<> <>
<div <div className="mb-4">
className="mb-4"
>
<button <button
className="btn btn-primary btn-search" className="btn btn-primary btn-search"
disabled={fileId ? false : true} disabled={!fileId}
onClick={() => { onClick={() => {
if (fileId) { if (fileId) {
handlerSearchUserFile(fileId, 1) handlerSearchUserFile(fileId, 1)
} }
}} }}
> >
Начать поиск {t('start-search')}
</button> </button>
{errorMessage && ( {errorMessage && (
<div className='mt-2 text-red-600 text-sm'> <div className='mt-2 text-red-600 text-sm'>
Ошибка поиска {t('search-error')}
</div> </div>
)} )}
</div> </div>
@@ -121,53 +121,44 @@ export function FileSearchPanel({ fileId, ref }: { fileId: string | null, ref: a
)} )}
{searchedUserFilesShowNull && ( {searchedUserFilesShowNull && (
<div <div className="user-file-search-results">
className="user-file-search-results"
>
<div className="results-header"> <div className="results-header">
<div className="results-title">Результаты поиска</div> <div className="results-title">{t('search-results-title')}</div>
<div className="results-count"> <div className="results-count">
Найдено файлов: {searchedUserFiles.length} {t('files-found', { count: searchedUserFiles.length })}
</div> </div>
</div> </div>
<div <div className="empty-results">
className="empty-results" <h3>{t('no-similar-files-title')}</h3>
> <p>{t('no-similar-files-description')}</p>
<h3>Похожих файлов не найдено</h3>
<p>В вашей библиотеке нет файлов, похожих на загруженный</p>
<div className="empty-results-hint"> <div className="empty-results-hint">
<strong>Совет:</strong> Убедитесь, что вы загружали этот файл ранее через страницу "Маркировка" <strong>{t('hint-title')}</strong> {t('hint-text')}
</div> </div>
</div> </div>
</div> </div>
)} )}
{showGlobalSearch && ( {showGlobalSearch && (
<div <div className="global-search-section">
className="global-search-section"
>
<div className="global-search-header"> <div className="global-search-header">
<div className="global-search-title"> <div className="global-search-title">
Глобальный поиск изображений {t('global-search-title')}
</div> </div>
<div className=""> <div className="">
Найти где ещё используется ваше изображение в интернете {t('global-search-description')}
</div> </div>
<div className="global-search-badge"> <div className="global-search-badge">
Интернет поиск {t('global-search-badge')}
</div> </div>
</div> </div>
<div className="global-search-content"> <div className="global-search-content">
<div className="global-search-info"> <div className="global-search-info">
<div className="global-search-info-title"> <div className="global-search-info-title">
Поиск по всему интернету {t('global-search-info-title')}
</div> </div>
<div className="global-search-info-text"> <div className="global-search-info-text">
Используем продвинутые технологии обратного поиска по изображению для поиска копий вашего контента {t('global-search-info-text')}
на сайтах, в социальных сетях и других источниках. Поможет обнаружить несанкционированное использование.
</div> </div>
</div> </div>
@@ -175,8 +166,8 @@ export function FileSearchPanel({ fileId, ref }: { fileId: string | null, ref: a
<div className="counter-info"> <div className="counter-info">
<div className="counter-icon" id="counter-icon"></div> <div className="counter-icon" id="counter-icon"></div>
<div className="counter-text"> <div className="counter-text">
<div className="counter-label">Глобальных поисков сегодня</div> <div className="counter-label">{t('global-searches-today')}</div>
<div className="counter-value" id="counter-value">0 из 10</div> <div className="counter-value" id="counter-value">0 {t('out-of')} 10</div>
</div> </div>
</div> </div>
<div className="progress-bar"> <div className="progress-bar">
@@ -192,14 +183,14 @@ export function FileSearchPanel({ fileId, ref }: { fileId: string | null, ref: a
<div className={`global-loading ${loading ? 'show' : ''}`} id="global-loading"> <div className={`global-loading ${loading ? 'show' : ''}`} id="global-loading">
<div className="global-spinner"></div> <div className="global-spinner"></div>
<div className="global-loading-text" id="global-loading-text"> <div className="global-loading-text" id="global-loading-text">
Поиск изображений в интернете... {t('searching-internet')}
</div> </div>
</div> </div>
<div className={`global-result ${searchedGlobalFiles.length ? 'show' : ''}`} id="global-result"> <div className={`global-result ${searchedGlobalFiles.length ? 'show' : ''}`} id="global-result">
<div className="global-result-card"> <div className="global-result-card">
<div className="global-result-header"> <div className="global-result-header">
<span>Найдено в интернете</span> <span>{t('found-on-internet')}</span>
{paginationLoading && ( {paginationLoading && (
<div className="loading-animation"> <div className="loading-animation">
<span className="global-spinner"></span> <span className="global-spinner"></span>
@@ -212,23 +203,40 @@ export function FileSearchPanel({ fileId, ref }: { fileId: string | null, ref: a
</div> </div>
</div> </div>
{searchedGlobalFilesShowNull && ( {(searchedGlobalFilesShowNull && !loading) && (
<div className="global-no-result" id="global-no-result"> <div className="global-no-result" id="global-no-result">
<div className="global-no-result-icon">&zwj;</div> <div className="global-no-result-icon">&zwj;</div>
<h4>Похожие изображения в интернете не найдены</h4> <h4>{t('no-similar-global-title')}</h4>
<p>Это может означать, что ваше изображение уникально и не используется на других сайтах.</p> <p className="global-no-result-text">
{t('no-similar-global-description')}
</p>
<button
onClick={() => {
if (fileId) {
handlerSearchGlobalFile(fileId, 1);
}
}}
className="btn btn-primary btn-search"
>
{t('search-again')}
</button>
</div> </div>
)} )}
<div className="global-error" id="global-error"> <div className="global-error">
<strong>Ошибка глобального поиска:</strong> <strong>{t('global-error-title')}</strong>
<span id="global-error-text"></span> <span id="global-error-text"></span>
</div> </div>
<Pagination totalPages={searchTotalPages} currentPage={searchCurrentPages} fileId={fileId} callBack={handlerSearchGlobalFile} /> <Pagination
totalPages={searchTotalPages}
currentPage={searchCurrentPages}
fileId={fileId}
callBack={handlerSearchGlobalFile}
/>
</div> </div>
</div> </div>
)} )}
</> </>
) );
} }
+21 -1
View File
@@ -242,7 +242,27 @@
"operation-history": "Operation history", "operation-history": "Operation history",
"tariff-plans": "Tariff plans", "tariff-plans": "Tariff plans",
"add-tokens": "Add tokens", "add-tokens": "Add tokens",
"error-upload-chunk-wav-file-not-have-riff": "Failed to upload file: .wav not have RIFF header." "error-upload-chunk-wav-file-not-have-riff": "Failed to upload file: .wav not have RIFF header.",
"search-again": "Search again",
"start-search": "Start search",
"search-error": "Search error",
"search-results-title": "Search results",
"files-found": "Files found: {count}",
"no-similar-files-title": "No similar files found",
"no-similar-files-description": "Your library has no files similar to the uploaded one",
"hint-title": "Tip:",
"hint-text": "Make sure you have previously uploaded this file through the \"Marking\" page",
"global-search-title": "Global image search",
"global-search-description": "Find where else your image is used on the internet",
"global-search-badge": "Internet search",
"global-search-info-title": "Search across the entire internet",
"global-search-info-text": "We use advanced reverse image search technologies to find copies of your content on websites, social networks, and other sources. Helps detect unauthorized use.",
"global-searches-today": "Global searches today",
"searching-internet": "Searching for images on the internet...",
"found-on-internet": "Found on the internet",
"no-similar-global-title": "No similar images found on the internet",
"no-similar-global-description": "This may mean your image is unique and not used on other websites.",
"global-error-title": "Global search error:"
}, },
"Login-register-form": { "Login-register-form": {
"and": "and", "and": "and",
+21 -1
View File
@@ -242,7 +242,27 @@
"operation-history": "История операций", "operation-history": "История операций",
"tariff-plans": "Тарифные планы", "tariff-plans": "Тарифные планы",
"add-tokens": "Пополнить токены", "add-tokens": "Пополнить токены",
"error-upload-chunk-wav-file-not-have-riff": "Не удалось загрузить файл: .wav не содержит заголовка RIFF." "error-upload-chunk-wav-file-not-have-riff": "Не удалось загрузить файл: .wav не содержит заголовка RIFF.",
"search-again": "Повторный поиск",
"start-search": "Начать поиск",
"search-error": "Ошибка поиска",
"search-results-title": "Результаты поиска",
"files-found": "Найдено файлов: {count}",
"no-similar-files-title": "Похожих файлов не найдено",
"no-similar-files-description": "В вашей библиотеке нет файлов, похожих на загруженный",
"hint-title": "Совет:",
"hint-text": "Убедитесь, что вы загружали этот файл ранее через страницу \"Маркировка\"",
"global-search-title": "Глобальный поиск изображений",
"global-search-description": "Найти где ещё используется ваше изображение в интернете",
"global-search-badge": "Интернет поиск",
"global-search-info-title": "Поиск по всему интернету",
"global-search-info-text": "Используем продвинутые технологии обратного поиска по изображению для поиска копий вашего контента на сайтах, в социальных сетях и других источниках. Поможет обнаружить несанкционированное использование.",
"global-searches-today": "Глобальных поисков сегодня",
"searching-internet": "Поиск изображений в интернете...",
"found-on-internet": "Найдено в интернете",
"no-similar-global-title": "Похожие изображения в интернете не найдены",
"no-similar-global-description": "Это может означать, что ваше изображение уникально и не используется на других сайтах.",
"global-error-title": "Ошибка глобального поиска:"
}, },
"Login-register-form": { "Login-register-form": {
"and": "и", "and": "и",