diff --git a/src/app/[locale]/pages/search/page.tsx b/src/app/[locale]/pages/search/page.tsx index b0c9414..2e5b525 100644 --- a/src/app/[locale]/pages/search/page.tsx +++ b/src/app/[locale]/pages/search/page.tsx @@ -1,36 +1,18 @@ import SectionSearchFile from '@/app/ui/search/section-search-file'; import { SupportedFormats } from '@/app/ui/search/supported-formats'; import { SearchStats } from '@/app/ui/search/search-stats'; -import { RecentSearches } from '@/app/ui/search/recent-searches'; -import { getAllowedFilesExtensions } from '@/app/actions/fileUpload'; +import SearchTitle from '@/app/ui/search/search-title'; 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 ( <> -
-

- Поиск защищенного контента -

-

- Загрузите файл для поиска похожего защищенного контента в вашей библиотеке и в интернете -

-
+
- + - {/* */}
diff --git a/src/app/actions/SearchSetting.ts b/src/app/actions/SearchSetting.ts new file mode 100644 index 0000000..2c73593 --- /dev/null +++ b/src/app/actions/SearchSetting.ts @@ -0,0 +1,63 @@ +'use server' + +import { getSessionData } from '@/app/actions/session'; +import { API_BASE_URL } from '@/app/actions/definitions'; + +export async function getSearchSettings() { + const token = await getSessionData('token'); + + try { + const response = await fetch(`${API_BASE_URL}/api/search/settings`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Authorization': `Bearer ${token}`, + } + }); + + if (response.ok) { + let parsed = await response.json(); + if (parsed.message_body) { + return parsed.message_body; + } + } else { + return null; + } + } catch (error) { + return null; + } +} + +export async function putSearchSettings(proxy: boolean, yandex: boolean, google: boolean) { + const token = await getSessionData('token'); + + try { + const response = await fetch(`${API_BASE_URL}/api/search/settings`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Authorization': `Bearer ${token}`, + }, + body: JSON.stringify({ + engines: { + yandex: yandex, + google: google + }, + proxyEnabled: proxy + }) + }); + + if (response.ok) { + let parsed = await response.json(); + if (parsed.message_desc === 'Settings updated') { + return true; + } + } else { + return false; + } + } catch (error) { + return false; + } +} \ No newline at end of file diff --git a/src/app/hooks/react-query/useViolationStatistic.ts b/src/app/hooks/react-query/useViolationStatistic.ts index 2f9d66f..4f5a35b 100644 --- a/src/app/hooks/react-query/useViolationStatistic.ts +++ b/src/app/hooks/react-query/useViolationStatistic.ts @@ -2,10 +2,10 @@ import { useQuery } from '@tanstack/react-query'; import { fetchViolationStatistic } from '@/app/actions/violationActions'; export interface UseViolationStatistic { - total_violations: 2565, - new_violations: 2565, - in_progress_violations: 0, - resolved_violations: 0 + total_violations: number, + new_violations: number, + in_progress_violations: number, + resolved_violations: number } export const useViolationStatistic = () => { diff --git a/src/app/styles/global-styles.scss b/src/app/styles/global-styles.scss index 3aa4a83..d994340 100644 --- a/src/app/styles/global-styles.scss +++ b/src/app/styles/global-styles.scss @@ -736,4 +736,49 @@ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25); /* transform: translateY(-2px); */ } +} + +.search-settings { + &-wrapper { + margin-bottom: 20px; + background: #f0f9ff; + border: 1px solid #bfdbfe; + border-radius: 12px; + margin-bottom: 20px; + padding: 16px; + color: #1e40af; + } + + &-header { + display: flex; + gap: 10px; + font-weight: 600; + + &.loading { + opacity: 0.5; + } + } + + &-item { + cursor: pointer; + + span { + margin-left: 4px; + color: v.$red; + + &.active { + color: v.$green; + } + } + + + &:hover { + text-decoration: underline; + } + } + + /* &-action-panel { + display: flex; + gap: 10px; + } */ } \ No newline at end of file diff --git a/src/app/ui/header/headerPanel.tsx b/src/app/ui/header/headerPanel.tsx index 83b97be..aeb2cf4 100644 --- a/src/app/ui/header/headerPanel.tsx +++ b/src/app/ui/header/headerPanel.tsx @@ -15,7 +15,7 @@ export default function HeaderPanel() { return (
- + {/* */}
{/* */} {typeof userData?.tariffInfo?.tokens === 'number' && ( diff --git a/src/app/ui/search/search-settings-block.tsx b/src/app/ui/search/search-settings-block.tsx new file mode 100644 index 0000000..36fa9bf --- /dev/null +++ b/src/app/ui/search/search-settings-block.tsx @@ -0,0 +1,132 @@ +'use client' + +import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { useEffect, useState } from 'react'; +import { getSearchSettings, putSearchSettings } from '@/app/actions/SearchSetting'; +import { useTranslations } from 'next-intl'; +import { toast } from 'sonner'; + +interface SearchSettings { + engines: { + yandex: boolean; + google: boolean; + }; + proxyEnabled: boolean; +} + +export default function SearchSettingsBlock() { + + const { data: searchStats } = useQuery({ + queryKey: ['searchStats'], + queryFn: getSearchSettings, + retry: false + }); + + const queryClient = useQueryClient(); + const t = useTranslations('Global'); + const [isLoading, setIsLoading] = useState(false); + + async function changeHandler(changetItem: 'proxy' | 'yandex' | 'google') { + if (!searchStats) { + toast.error(t('error')); + return; + } + + if (isLoading) { + return; + } + + setIsLoading(true); + + let proxy = searchStats.proxyEnabled; + let yandex = searchStats.engines.yandex; + let google = searchStats.engines.google; + + switch (changetItem) { + case 'yandex': + yandex = !yandex; + break + + case 'google': + google = !google; + break + + case 'proxy': + proxy = !proxy; + break + } + + try { + const response = await putSearchSettings(proxy, yandex, google); + + if (response) { + toast.success('Succes'); + await queryClient.invalidateQueries({ queryKey: ['searchStats'] }); + } else { + toast.warning('Not succes'); + } + } catch (error) { + toast.error(t('error')); + } finally { + setIsLoading(false); + } + + } + + return ( +
+
+
{ + changeHandler('proxy'); + }} + > + {t('proxy-enabled')}: + + {searchStats?.proxyEnabled ? t('yes') : t('no')} + +
+
{ + changeHandler('yandex'); + }} + > + yandex: + + {searchStats?.engines?.yandex ? t('yes') : t('no')} + +
+
{ + changeHandler('google'); + }} + > + google: + + {searchStats?.engines?.google ? t('yes') : t('no')} + +
+ {isLoading && ( +
+
+
+
+
+ )} +
+
+ ) +} \ No newline at end of file diff --git a/src/app/ui/search/search-stats.tsx b/src/app/ui/search/search-stats.tsx index e0a6729..4d7989a 100644 --- a/src/app/ui/search/search-stats.tsx +++ b/src/app/ui/search/search-stats.tsx @@ -9,14 +9,10 @@ export function SearchStats() { const { data: userSearchData, isLoading, isError, error } = useUserSearchData(); const t = useTranslations('Global'); - useEffect(() => { - console.log(userSearchData); - }, [userSearchData]) - return (
- Статистика поиска + {t('search-stats')}
diff --git a/src/app/ui/search/search-title.tsx b/src/app/ui/search/search-title.tsx new file mode 100644 index 0000000..50ef0cc --- /dev/null +++ b/src/app/ui/search/search-title.tsx @@ -0,0 +1,18 @@ +'use client' + +import { useTranslations } from 'next-intl' + +export default function SearchTitle() { + const t = useTranslations('Global'); + + return ( +
+

+ {t('search-protected-content')} +

+

+ {t('search-title-description')} +

+
+ ) +} \ No newline at end of file diff --git a/src/app/ui/search/section-search-file.tsx b/src/app/ui/search/section-search-file.tsx index d4fe806..e1010d7 100644 --- a/src/app/ui/search/section-search-file.tsx +++ b/src/app/ui/search/section-search-file.tsx @@ -10,6 +10,7 @@ import { removeUserFile } from '@/app/actions/fileEntity'; import { FileSearchPanel } from '@/app/ui/search/file-search-panel'; import { getFileType } from '@/app/lib/getFileType'; import { useAllFilesExtensions } from '@/app/hooks/react-query/useAllFilesExtensions'; +import SearchSettingsBlock from '@/app/ui/search/search-settings-block'; interface SelectedFile { file: File; preview: string | undefined; @@ -287,13 +288,16 @@ export default function SectionSearchFile() { return (
-
Как работает поиск?
+
+ {t('how-does-search-work')} +
- Наша система анализирует загруженный файл и сравнивает его с вашими защищенными файлами, - используя алгоритмы компьютерного зрения и цифровых отпечатков. + {t('search-info-description-text')}
+ +
- Поддерживаемые форматы + {t('supported-formats')}
@@ -22,7 +20,7 @@ export function SupportedFormats({ extensionVideo, extensionAudio, extensionImag {t('images')}
- {extensionImage.join(', ')} + {allFilesExtensions?.images?.join(', ')}
@@ -31,7 +29,7 @@ export function SupportedFormats({ extensionVideo, extensionAudio, extensionImag {t('videos')}
- {extensionVideo.join(', ')} + {allFilesExtensions?.videos?.join(', ')}
@@ -40,7 +38,7 @@ export function SupportedFormats({ extensionVideo, extensionAudio, extensionImag {t('audios')}
- {extensionAudio.join(', ')} + {allFilesExtensions?.audios?.join(', ')}
@@ -49,7 +47,7 @@ export function SupportedFormats({ extensionVideo, extensionAudio, extensionImag {t('documents')}
- {extensionDocument.join(', ')} + {allFilesExtensions?.documents?.join(', ')}
diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index 305bb81..8779844 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -358,7 +358,14 @@ "payment-history": "Payment history", "file-verification": "File verification", "file-is-protected": "The file is protected.", - "read-more": "Read more" + "read-more": "Read more", + "proxy-enabled": "Proxy enabled", + "supported-formats": "Supported formats", + "search-stats": "Search stats", + "search-protected-content": "Search for protected content", + "search-title-description": "Upload a file to search for similar protected content in your library and on the web", + "how-does-search-work": "How does search work?", + "search-info-description-text": "Our system analyzes the uploaded file and compares it with your protected files, using computer vision and digital fingerprinting algorithms." }, "Login-register-form": { "and": "and", diff --git a/src/i18n/messages/ru.json b/src/i18n/messages/ru.json index ca36b48..42b1b67 100644 --- a/src/i18n/messages/ru.json +++ b/src/i18n/messages/ru.json @@ -358,7 +358,14 @@ "payment-history": "История выплат", "file-verification": "Проверка файла", "file-is-protected": "Файл защищен.", - "read-more": "Подробнее" + "read-more": "Подробнее", + "proxy-enabled": "Прокси включен", + "supported-formats": "Поддерживаемые форматы", + "search-stats": "Статистика поиска", + "search-protected-content": "Поиск защищенного контента", + "search-title-description": "Загрузите файл для поиска похожего защищенного контента в вашей библиотеке и в интернете", + "how-does-search-work": "Как работает поиск?", + "search-info-description-text": "Наша система анализирует загруженный файл и сравнивает его с вашими защищенными файлами, используя алгоритмы компьютерного зрения и цифровых отпечатков." }, "Login-register-form": { "and": "и",