add null result for search files

This commit is contained in:
smanylov
2026-01-28 16:30:17 +07:00
parent efae068bac
commit a6a493fe97
5 changed files with 85 additions and 31 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
import SectionSearchFile from '@/app/components/section-search-file'; import SectionSearchFile from '@/app/ui/search/section-search-file';
export default function Page() { export default function Page() {
return ( return (
<> <>
+24 -4
View File
@@ -3125,7 +3125,6 @@
} }
.global-no-result { .global-no-result {
display: none;
text-align: center; text-align: center;
padding: 60px 20px; padding: 60px 20px;
background: #f8fafc; background: #f8fafc;
@@ -3199,6 +3198,20 @@
} }
} }
.empty-results {
text-align: center;
padding: 60px 20px;
color: #64748b;
&-hint {
margin-top: 16px;
padding: 12px;
background: #f0f9ff;
border-radius: 8px;
font-size: 14px;
}
}
.results-list { .results-list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -3307,9 +3320,8 @@
color: #065f46; color: #065f46;
} }
.badge-high-protection { .badge-not-protected {
background: #ddd6fe; background: v.$b-color-2;
color: #5b21b6;
} }
} }
@@ -3387,6 +3399,14 @@
overflow-y: auto; overflow-y: auto;
background: v.$white; background: v.$white;
&-wrapper {
display: grid;
grid-template-columns: 1fr 300px;
gap: 20px;
height: 100%;
max-height: 80vh;
}
.image-section { .image-section {
display: flex; display: flex;
align-items: center; align-items: center;
+39 -7
View File
@@ -5,12 +5,16 @@ import { searchUserFiles, searchGlobalFiles } from '@/app/actions/fileEntity';
export function FileSearchPanel({ fileId, ref }: { fileId: string | null, ref: any }) { export function FileSearchPanel({ fileId, ref }: { fileId: string | null, ref: any }) {
const [searchedUserFiles, setSearchedUserFiles] = useState<string[]>([]); const [searchedUserFiles, setSearchedUserFiles] = useState<string[]>([]);
const [searchedUserFilesShowNull, setSearchedUserFilesShowNull] = useState<boolean>(false);
const [searchedGlobalFiles, setSearchedGlobalFiles] = useState<string[]>([]); const [searchedGlobalFiles, setSearchedGlobalFiles] = useState<string[]>([]);
const [searchedGlobalFilesShowNull, setSearchedGlobalFilesShowNull] = useState<boolean>(false);
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
doSomething: () => { clearList: () => {
setSearchedUserFiles([]); setSearchedUserFiles([]);
setSearchedGlobalFiles([]) setSearchedGlobalFiles([]);
setSearchedUserFilesShowNull(false);
setSearchedGlobalFilesShowNull(false);
} }
})); }));
@@ -22,6 +26,8 @@ export function FileSearchPanel({ fileId, ref }: { fileId: string | null, ref: a
if (result.content.length) { if (result.content.length) {
setSearchedUserFiles(result.content); setSearchedUserFiles(result.content);
} else {
setSearchedUserFilesShowNull(true);
} }
} catch (error) { } catch (error) {
@@ -35,6 +41,8 @@ export function FileSearchPanel({ fileId, ref }: { fileId: string | null, ref: a
let result = await searchGlobalFiles(fileId); let result = await searchGlobalFiles(fileId);
if (result.images.length) { if (result.images.length) {
setSearchedGlobalFiles(result.images); setSearchedGlobalFiles(result.images);
} else {
setSearchedGlobalFilesShowNull(true);
} }
} catch (error) { } catch (error) {
@@ -62,7 +70,29 @@ export function FileSearchPanel({ fileId, ref }: { fileId: string | null, ref: a
{(searchedUserFiles.length !== 0) && ( {(searchedUserFiles.length !== 0) && (
<SearchedUserFilesList list={searchedUserFiles} /> <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>
)} )}
<div <div
@@ -141,11 +171,13 @@ export function FileSearchPanel({ fileId, ref }: { fileId: string | null, ref: a
</div> </div>
</div> </div>
<div className="global-no-result" id="global-no-result"> {searchedGlobalFilesShowNull && (
<div className="global-no-result-icon">&zwj;</div> <div className="global-no-result" id="global-no-result">
<h4>Похожие изображения в интернете не найдены</h4> <div className="global-no-result-icon">&zwj;</div>
<p>Это может означать, что ваше изображение уникально и не используется на других сайтах.</p> <h4>Похожие изображения в интернете не найдены</h4>
</div> <p>Это может означать, что ваше изображение уникально и не используется на других сайтах.</p>
</div>
)}
<div className="global-error" id="global-error"> <div className="global-error" id="global-error">
<strong>Ошибка глобального поиска:</strong> <strong>Ошибка глобального поиска:</strong>
+19 -17
View File
@@ -3,6 +3,7 @@ import { toast } from 'sonner';
import { useState, ReactNode } from 'react'; import { useState, ReactNode } from 'react';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import ModalWindow from '@/app/components/modalWindow'; import ModalWindow from '@/app/components/modalWindow';
import { IconEye, IconDownload } from '@/app/ui/icons/icons';
export function SearchedUserFilesList({ list }: { list: any }) { export function SearchedUserFilesList({ list }: { list: any }) {
const [isFileLoading, setIsFileLoading] = useState(false); const [isFileLoading, setIsFileLoading] = useState(false);
@@ -53,7 +54,7 @@ export function SearchedUserFilesList({ list }: { list: any }) {
<div <div
className="modal-window-view-file-content" className="modal-window-view-file-content"
> >
<div className="flex gap-2"> <div className="modal-window-view-file-content-wrapper">
<div className="image-section"> <div className="image-section">
<div className="image-container"> <div className="image-container">
<img <img
@@ -116,6 +117,7 @@ export function SearchedUserFilesList({ list }: { list: any }) {
className="results-list" className="results-list"
> >
{list.map((e: any, index: number) => { {list.map((e: any, index: number) => {
console.log(e);
return ( return (
<div <div
key={index} key={index}
@@ -124,18 +126,20 @@ export function SearchedUserFilesList({ list }: { list: any }) {
<div className="result-item"> <div className="result-item">
<div className="result-header"> <div className="result-header">
<div className="result-preview"> <div className="result-preview">
<img src="view-image.php?id=431" alt="Preview" /> {e.url ? (
<div className="preview-fallback"> <img src={e.url} alt="Preview" />
<span>📄</span> ) : (
</div> <div className="preview-fallback">
<span>📄</span>
</div>
)}
</div> </div>
<div className="result-info"> <div className="result-info">
<div className="result-filename" title={e.originalFileName}> <div className="result-filename" title={e.originalFileName}>
{e.originalFileName} {e.originalFileName}
</div> </div>
<div className="result-details"> <div className="result-details">
Загружен: - Загружен: {e.uploadDate ? e.uploadDate : '#'}
Размер: {convertBytes(e.fileSize)} Размер: {convertBytes(e.fileSize)}
</div> </div>
</div> </div>
@@ -147,31 +151,29 @@ export function SearchedUserFilesList({ list }: { list: any }) {
</div> </div>
<div className="result-badges"> <div className="result-badges">
<span className="badge badge-protected"> <span className={`badge ${e.status === 'PROTECTED' ? 'badge-protected' : 'badge-not-protected'}`}>
🛡 Защищено {e.status}
</span> </span>
<span className="badge badge-high-protection">
🔒 Высокий уровень защиты
</span>
</div> </div>
<div className="result-actions"> <div className="result-actions">
<button <button
className="btn btn-secondary" className="btn btn-secondary gap-1"
onClick={() => { onClick={() => {
handlerViewfile(e); handlerViewfile(e);
}} }}
> >
👁 Просмотр <IconEye />
Просмотр
</button> </button>
<button <button
className="btn btn-success" className="btn btn-success gap-1"
disabled={isFileLoading} disabled={isFileLoading}
onClick={() => handlerDownload(e.fileId, e.originalFileName)} onClick={() => handlerDownload(e.fileId, e.originalFileName)}
> >
💾 Скачать <IconDownload />
Скачать
</button> </button>
</div> </div>
</div> </div>
@@ -6,7 +6,7 @@ import { fileUpload, cancelUpload, chunkUpload, checkChunkStatus } from '@/app/a
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 { searchUserFiles, removeUserFile, searchGlobalFiles } from '@/app/actions/fileEntity'; import { removeUserFile } from '@/app/actions/fileEntity';
import { FileSearchPanel } from '@/app/ui/search/file-search-panel'; import { FileSearchPanel } from '@/app/ui/search/file-search-panel';
interface SelectedFile { interface SelectedFile {
file: File; file: File;
@@ -91,7 +91,7 @@ export default function SectionSearchFile({ fileType, allowedExtensions, maxFile
if (childRef.current) { if (childRef.current) {
//@ts-ignore //@ts-ignore
childRef.current.doSomething(); childRef.current.clearList();
} }
setUploadProgress(0); setUploadProgress(0);