add null result for search files
This commit is contained in:
@@ -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 (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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">‍</div>
|
<div className="global-no-result" id="global-no-result">
|
||||||
<h4>Похожие изображения в интернете не найдены</h4>
|
<div className="global-no-result-icon">‍</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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
+2
-2
@@ -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);
|
||||||
Reference in New Issue
Block a user