add translate and make refactor

This commit is contained in:
smanylov
2025-12-17 16:41:07 +07:00
parent fd59fb3e5e
commit 9b8cb3b583
13 changed files with 261 additions and 83 deletions
+23 -8
View File
@@ -3,7 +3,9 @@
import { useState, useRef } from 'react';
import { fetchFruits } from '@/app/actions/action';
import { useClickOutside } from '@/app/hooks/useClickOutside';
import { useTranslations } from 'next-intl';
import Link from 'next/link';
import {IconNotification} from '@/app/ui/icons/icons';
export default function NotificationsButton() {
const [isOpen, setIsOpen] = useState(false);
@@ -11,6 +13,7 @@ export default function NotificationsButton() {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const menuRef = useRef<HTMLDivElement | null>(null);
const t = useTranslations('Global');
useClickOutside(menuRef, () => {
setIsOpen(false);
@@ -57,26 +60,38 @@ export default function NotificationsButton() {
) : (
<>
<div className='notification-header'>
<h4>Уведомления</h4>
<span className="notification-count">Нет новых</span>
<h4>
{t('notifications')}
</h4>
<span className="notification-count">
{t('no-new')}
</span>
</div>
{data ? (
<div className="notification-list">
<div className="notification-item">
<div className="notification-icon"></div>
<div className="notification-icon">
<IconNotification/>
</div>
<div className="notification-content">
<div className="notification-title">Токены добавлены</div>
<div className="notification-text">На ваш баланс добавлено 100 токенов. Теперь вы можете защитить ещё больше файлов!</div>
<div className="notification-time">4 дн назад</div>
<div className="notification-title">
{t('tokens-added')}
</div>
<div className="notification-text">{t('added')} 100 {t('tokens')}.</div>
<div className="notification-time">4 {t('days-ago')}</div>
</div>
</div>
{JSON.stringify(data)}
</div>
) : (
<p>Нет данных</p>
<p>
{t('no-data')}
</p>
)}
<div className="notification-footer">
<Link href="/pages/notifications" className="notification-link">Посмотреть все</Link>
<Link href="/pages/notifications" className="notification-link">
{t('view-all')}
</Link>
</div>
</>
)}
+20 -14
View File
@@ -56,45 +56,51 @@ export function IconEye() {
)
}
export function DoubleArrowRight() {
export function IconDoubleArrowRight() {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M6.41 6L5 7.41L9.58 12L5 16.59L6.41 18l6-6z" /><path fill="currentColor" d="m13 6l-1.41 1.41L16.17 12l-4.58 4.59L13 18l6-6z" /></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" className="icon"><path fill="currentColor" d="M6.41 6L5 7.41L9.58 12L5 16.59L6.41 18l6-6z" /><path fill="currentColor" d="m13 6l-1.41 1.41L16.17 12l-4.58 4.59L13 18l6-6z" /></svg>
)
}
export function DoubleArrowLeft() {
export function IconDoubleArrowLeft() {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M17.59 18L19 16.59L14.42 12L19 7.41L17.59 6l-6 6z" /><path fill="currentColor" d="m11 18l1.41-1.41L7.83 12l4.58-4.59L11 6l-6 6z" /></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" className="icon"><path fill="currentColor" d="M17.59 18L19 16.59L14.42 12L19 7.41L17.59 6l-6 6z" /><path fill="currentColor" d="m11 18l1.41-1.41L7.83 12l4.58-4.59L11 6l-6 6z" /></svg>
)
}
export function ArrowRight() {
export function IconArrowRight() {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M8.59 16.59L13.17 12L8.59 7.41L10 6l6 6l-6 6z" /></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" className="icon"><path fill="currentColor" d="M8.59 16.59L13.17 12L8.59 7.41L10 6l6 6l-6 6z" /></svg>
)
}
export function ArrowLeft() {
export function IconArrowLeft() {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M15.41 16.59L10.83 12l4.58-4.59L14 6l-6 6l6 6z" /></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" className="icon"><path fill="currentColor" d="M15.41 16.59L10.83 12l4.58-4.59L14 6l-6 6l6 6z" /></svg>
)
}
export function ArrowUp() {
export function IconArrowUp() {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="m7 14l5-5l5 5z" /></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" className="icon"><path fill="currentColor" d="m7 14l5-5l5 5z" /></svg>
)
}
export function ArrowDown() {
export function IconArrowDown() {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="m7 10l5 5l5-5z" /></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" className="icon"><path fill="currentColor" d="m7 10l5 5l5-5z" /></svg>
)
}
export function Filter() {
export function IconFilter() {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M11 18h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1M3 7c0 .55.45 1 1 1h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1m4 6h10c.55 0 1-.45 1-1s-.45-1-1-1H7c-.55 0-1 .45-1 1s.45 1 1 1" /></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" className="icon"><path fill="currentColor" d="M11 18h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1M3 7c0 .55.45 1 1 1h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1m4 6h10c.55 0 1-.45 1-1s-.45-1-1-1H7c-.55 0-1 .45-1 1s.45 1 1 1" /></svg>
)
}
export function IconNotification() {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" className="icon"><g fill="none"><path d="m12.594 23.258l-.012.002l-.071.035l-.02.004l-.014-.004l-.071-.036q-.016-.004-.024.006l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.016-.018m.264-.113l-.014.002l-.184.093l-.01.01l-.003.011l.018.43l.005.012l.008.008l.201.092q.019.005.029-.008l.004-.014l-.034-.614q-.005-.019-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.003-.011l.018-.43l-.003-.012l-.01-.01z" /><path fill="currentColor" d="M12 2a7 7 0 0 0-7 7v3.528a1 1 0 0 1-.105.447l-1.717 3.433A1.1 1.1 0 0 0 4.162 18h15.676a1.1 1.1 0 0 0 .984-1.592l-1.716-3.433a1 1 0 0 1-.106-.447V9a7 7 0 0 0-7-7m0 19a3 3 0 0 1-2.83-2h5.66A3 3 0 0 1 12 21" /></g></svg>
)
}
+14 -7
View File
@@ -1,31 +1,38 @@
import Link from 'next/link';
import { useTranslations } from 'next-intl';
export default function APISettings() {
const t = useTranslations('Global');
return (
<div className="settings-form">
<div className="form-section">
<h3 className="form-section-title">🔌 API настройки</h3>
<h3 className="form-section-title">
{t('api-settings')}
</h3>
<div className="form-group">
<label className="form-label">🔑 Ваш API ключ:</label>
<label className="form-label">
{t('your-api-key')}:
</label>
<div className="api-key-info-wrapper">
<div className="api-key-info">
<input readOnly className="form-input" value="testkey" id="api-key-input"></input>
<button type="button" className="btn btn-outline">
📋 Копировать
{t('copy')}
</button>
</div>
<button type="submit" className="btn btn-secondary">
🔄 Обновить ключ
🔄 {t('update-key')}
</button>
<small>
Используйте этот ключ для доступа к API. Не передавайте его третьим лицам.
{t('use-this-key-for-api-access')}
</small>
<div className="api-key-info-documentation">
<h4>
📚 Документация API
{t('api-documentation')}
</h4>
<p>
Полная документация API доступна по ссылке:
{t('full-api-documentation-available-at-link')}:
<br />
<Link href={'api.no-copy.ru/docs'}>api.no-copy.ru/docs</Link>
</p>
+17 -7
View File
@@ -1,24 +1,34 @@
import { useTranslations } from 'next-intl';
export default function DangerZone() {
const t = useTranslations('Global');
return (
<div className="danger-zone">
<h3> Опасная зона</h3>
<h3>
{t('danger-zone')}
</h3>
<div className="danger-zone-remove-account">
<h4>
🗑 Удаление аккаунта
{t('account-deletion')}
</h4>
<p>
Удаление аккаунта приведет к безвозвратной потере всех данных, включая загруженный контент, отчеты и настройки. Это действие нельзя отменить.
{t('account-deletion-warning')}
</p>
<button className="btn">🗑 Удалить аккаунт</button>
<button className="btn">
{t('delete-account')}
</button>
</div>
<div className="danger-zone-reset-settings">
<h4>
🔄 Сброс всех настроек
{t('reset-all-settings')}
</h4>
<p>
🔧 Восстановить все настройки аккаунта к значениям по умолчанию.
{t('reset-settings-description')}
</p>
<button className="btn">🔄 Сбросить настройки</button>
<button className="btn">
{t('reset-settings')}
</button>
</div>
</div>
)
@@ -1,11 +1,17 @@
import { useTranslations } from 'next-intl';
export default function LastActivitySettings() {
const t = useTranslations('Global');
return (
<div className="settings-form">
<div className="form-section">
<h3 className="form-section-title">🕒 Последняя активность</h3>
<h3 className="form-section-title">
{t('last-activity')}
</h3>
<div className="last-activiti-wrapper">
<div className="no-activiti">
📝 Пока нет записей о активности
{t('no-activity-records-yet')}
</div>
</div>
</div>
@@ -1,5 +1,6 @@
'use client'
import { useTranslations } from 'next-intl';
import { useActionState, useState } from 'react';
export default function NotificationsMonitoringSettings() {
@@ -12,35 +13,48 @@ export default function NotificationsMonitoringSettings() {
const [selectedMonitoringValue, setSelectedMonitoringValue] = useState('weekly');
const [selectedWatermarkValue, setSelectedWatermarkValue] = useState('high');
const t = useTranslations('Global');
return (
<div className="settings-form">
<div className="form-section">
<h3 className="form-section-title">🔔 Уведомления и мониторинг</h3>
<h3 className="form-section-title">
{t('notifications-and-monitoring')}
</h3>
<form action={formAction}>
<div className="form-group">
<label className="form-label">
<span>📧 Email уведомления</span>
<span>
{t('email-notifications')}
</span>
<span className="toggle-switch">
<input type="checkbox" name="notification_email" />
<span className="toggle-slider"></span>
</span>
</label>
<small>Получать уведомления о нарушениях на email</small>
<small>
{t('receive-violation-notifications-on-email')}
</small>
</div>
<div className="form-group">
<label className="form-label">
<span>🤖 Автоматический мониторинг</span>
<span>
{t('automatic-monitoring')}
</span>
<span className="toggle-switch">
<input type="checkbox" name="auto_monitoring" />
<span className="toggle-slider"></span>
</span>
</label>
<small>Автоматическая проверка контента в интернете</small>
<small>
{t('automatic-content-check-on-internet')}
</small>
</div>
<div className="form-group">
<label className="form-label"> Частота мониторинга:</label>
<label className="form-label">
{t('monitoring-frequency')}:
</label>
<select
name="monitoring_frequency"
className="form-input"
@@ -48,19 +62,21 @@ export default function NotificationsMonitoringSettings() {
onChange={(e) => setSelectedMonitoringValue(e.target.value)}
>
<option value="daily">
Ежедневно
{t('daily')}
</option>
<option value="weekly">
Еженедельно
{t('weekly')}
</option>
<option value="monthly">
Ежемесячно
{t('monthly')}
</option>
</select>
</div>
<div className="form-group">
<label className="form-label">💧 Интенсивность водяного знака:</label>
<label className="form-label">
{t('watermark-intensity')}:
</label>
<select
name="watermark_intensity"
className="form-input"
@@ -68,18 +84,20 @@ export default function NotificationsMonitoringSettings() {
onChange={(e) => setSelectedWatermarkValue(e.target.value)}
>
<option value="low">
Низкая (незаметный)
{t('low')}
</option>
<option value="medium">
Средняя (рекомендуется)
{t('medium')}
</option>
<option value="high">
Высокая (максимальная защита)
{t('high')}
</option>
</select>
</div>
<button type="submit" className="btn btn-primary">💾 Сохранить изменения</button>
<button type="submit" className="btn btn-primary">
{t('save-changes')}
</button>
</form>
</div>
</div>
+20 -6
View File
@@ -1,6 +1,7 @@
'use client'
import { useActionState, useState } from 'react';
import { useTranslations } from 'next-intl';
export default function SafetySetting() {
const [errorMessage, formAction, isPending] = useActionState(
@@ -9,26 +10,39 @@ export default function SafetySetting() {
},
undefined
);
const t = useTranslations('Global');
return (
<div className="settings-form">
<div className="form-section">
<h3 className="form-section-title">🔐 Безопасность</h3>
<h3 className="form-section-title">
{t('security')}
</h3>
<form action={formAction}>
<div className="form-group">
<label className="form-label">🔓 Текущий пароль:</label>
<label className="form-label">
{t('current-password')}:
</label>
<input type="password" name="current_password" className="form-input" />
</div>
<div className="form-group">
<label className="form-label">🔓 Новый пароль:</label>
<label className="form-label">
{t('new-password')}:
</label>
<input type="password" name="new_password" className="form-input" />
<small>Минимум 6 символов</small>
<small>
{t('minimum-8-characters')}
</small>
</div>
<div className="form-group">
<label className="form-label"> Подтвердите пароль:</label>
<label className="form-label">
{t('confirm-password')}:
</label>
<input type="password" name="confirm_password" className="form-input" />
</div>
<button type="submit" className="btn btn-primary">🔐 Изменить пароль</button>
<button type="submit" className="btn btn-primary">
{t('change-password')}
</button>
</form>
</div>
</div>
@@ -1,8 +1,14 @@
import { useTranslations } from 'next-intl';
export default function SubscriptionSettings() {
const t = useTranslations('Global');
return (
<div className="settings-form">
<div className="form-section">
<h3 className="form-section-title">💎 Подписка</h3>
<h3 className="form-section-title">
{t('subscription')}
</h3>
<div className="subscription-info">
<div className="subscription-info-header">
<div>