make translate for login, register pages
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import Providers from '@/app/providers/getQueryServer'
|
||||
import type { Metadata } from "next";
|
||||
import { NextIntlClientProvider, hasLocale } from 'next-intl';
|
||||
import { notFound } from 'next/navigation';
|
||||
import { routing } from '@/i18n/routing';
|
||||
import "../styles/globals.css";
|
||||
import "../styles/global-styles.scss";
|
||||
|
||||
export function generateStaticParams() {
|
||||
return routing.locales.map((locale: any) => ({ locale }));
|
||||
}
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "No copy",
|
||||
description: "No copy",
|
||||
};
|
||||
|
||||
export default async function RootLayout({
|
||||
children,
|
||||
params
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
params: Promise<{ locale: string }>;
|
||||
}>) {
|
||||
const { locale } = await params;
|
||||
if (!hasLocale(routing.locales, locale)) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
return (
|
||||
<html lang={locale}>
|
||||
<body>
|
||||
<NextIntlClientProvider>
|
||||
<Providers>
|
||||
{children}
|
||||
</Providers>
|
||||
</NextIntlClientProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -3,45 +3,58 @@ import styles from '@/app/styles/login.module.scss'
|
||||
import LogoIcon from '@/app/ui/logo-icon';
|
||||
import Link from 'next/link';
|
||||
import LoginForm from '@/app/ui/login-form';
|
||||
import LanguageSwitcher from '@/app/components/LanguageSwitcher';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Login',
|
||||
};
|
||||
|
||||
export default function Page() {
|
||||
const t = useTranslations('Login-register-form');
|
||||
|
||||
return (
|
||||
<div className={`${styles['login-container-wrapper']}`}>
|
||||
<div className={`${styles['login-container-language']}`}>
|
||||
<LanguageSwitcher />
|
||||
</div>
|
||||
<div className={`${styles['login-container']}`}>
|
||||
<div className={`${styles['logo']}`}>
|
||||
<LogoIcon />
|
||||
<h1>NO COPY</h1>
|
||||
<p>Защита авторских прав</p>
|
||||
<p>
|
||||
{t('copyright-protection')}
|
||||
</p>
|
||||
</div>
|
||||
<LoginForm />
|
||||
<div className="divider">
|
||||
<span>или войти через</span>
|
||||
<span>
|
||||
{t('or-log-in-via')}
|
||||
</span>
|
||||
</div>
|
||||
<div className={`${styles['register-link']}`}>
|
||||
<p>Нет аккаунта? <Link href="register">Зарегистрироваться</Link></p>
|
||||
<p>{t('no-account')}?
|
||||
<Link href="register"> {t('register')}</Link>
|
||||
</p>
|
||||
</div>
|
||||
<div className={`${styles['features']}`}>
|
||||
<div className={`${styles['feature']}`}>
|
||||
<svg className={`${styles['feature-icon']}`} viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
Защита контента скрытыми водяными знаками
|
||||
{t('protecting-watermark')}
|
||||
</div>
|
||||
<div className={`${styles['feature']}`}>
|
||||
<svg className={`${styles['feature-icon']}`} viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M13 10V3L4 14h7v7l9-11h-7z"></path>
|
||||
</svg>
|
||||
Мониторинг нарушений в реальном времени
|
||||
{t('monitoring-violations')}
|
||||
</div>
|
||||
<div className={`${styles['feature']}`}>
|
||||
<svg className={`${styles['feature-icon']}`} viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 1L3 5v6c0 5.55 3.84 9.74 9 11 5.16-1.26 9-5.45 9-11V5l-9-4z"></path>
|
||||
</svg>
|
||||
Надежное хранение и безопасность данных
|
||||
{t('safe-storage')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,17 +1,21 @@
|
||||
import styles from "@/app/styles/page.module.scss";
|
||||
import { Metadata } from 'next';
|
||||
import Link from 'next/link';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Home page',
|
||||
};
|
||||
|
||||
export default function Home() {
|
||||
const t = useTranslations('HomePage');
|
||||
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<main className={styles.main}>
|
||||
<div className={styles.intro}>
|
||||
Home page
|
||||
{t('title')}
|
||||
</div>
|
||||
<Link key={'dashboard'}
|
||||
href={'/pages/dashboard'}
|
||||
@@ -1,25 +1,26 @@
|
||||
import { Metadata } from 'next';
|
||||
import { Suspense } from 'react';
|
||||
import ButtonTest from '@/app/ui/button-test'
|
||||
import ProtectionOverview from '@/app/ui/dashboard/protection-overview';
|
||||
import StatsGrid from '@/app/ui/dashboard/stats-grid';
|
||||
import StorageBreakdown from '@/app/ui/dashboard/storage-breakdown';
|
||||
import RecentFilesList from '@/app/ui/dashboard/recent-files-list';
|
||||
import ChartContainer from '@/app/ui/dashboard/chart-container';
|
||||
import UserInfo from '@/app/ui/dashboard/user-info';
|
||||
import ViolationsTable from '@/app/ui/dashboard/violations-table';
|
||||
import ViolationsTypeTable from '@/app/ui/dashboard/violations-type-table';
|
||||
import ActivityChart from '@/app/ui/dashboard/activity-chart';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Dashboard',
|
||||
};
|
||||
|
||||
export default function Page() {
|
||||
const t = useTranslations('Global');
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Suspense fallback={<>...</>}>
|
||||
<h1 className="page-title">Статистика</h1>
|
||||
<h1 className="page-title">
|
||||
{t("statistics")}
|
||||
</h1>
|
||||
<ProtectionOverview />
|
||||
<StatsGrid />
|
||||
<StorageBreakdown />
|
||||
@@ -1,6 +1,6 @@
|
||||
import NavLinks from '@/app/ui/nav-links'
|
||||
import styles from '@/app/styles/page.module.scss'
|
||||
import HeaderPanel from '../ui/header/headerPanel';
|
||||
import HeaderPanel from '@/app/ui/header/headerPanel';
|
||||
import { getQueryClient } from '@/app/providers/getQueryClient';
|
||||
import { HydrationBoundary, dehydrate } from '@tanstack/react-query';
|
||||
import { getUserData } from '@/app/actions/action';
|
||||
@@ -2,26 +2,39 @@ import LogoIcon from '@/app/ui/logo-icon';
|
||||
import styles from '@/app/styles/login.module.scss'
|
||||
import Link from 'next/link';
|
||||
import RegisterForm from '@/app/ui/register-form';
|
||||
import LanguageSwitcher from '@/app/components/LanguageSwitcher';
|
||||
import {useTranslations} from 'next-intl';
|
||||
|
||||
export default function Page() {
|
||||
const t = useTranslations('Login-register-form');
|
||||
|
||||
return (
|
||||
<div className={`${styles['login-container-wrapper']}`}>
|
||||
<div className={`${styles['login-container-language']}`}>
|
||||
<LanguageSwitcher />
|
||||
</div>
|
||||
<div className={`${styles['login-container']}`}>
|
||||
<div className={`${styles['logo']}`}>
|
||||
<LogoIcon />
|
||||
<h1>NO COPY</h1>
|
||||
<p>Создать аккаунт</p>
|
||||
<p>
|
||||
{t('create-an-account')}
|
||||
</p>
|
||||
</div>
|
||||
<div className={`${styles['subscription-info']}`}>
|
||||
<h4>🎉 Бесплатный старт</h4>
|
||||
<p>При регистрации вы получаете подписку "ДЕМО" с возможностью маркировки до 3 файлов в месяц и 10 МБ хранилища.</p>
|
||||
<h4>🎉 {t('free-start')}</h4>
|
||||
<p>
|
||||
{t('free-start-description')}
|
||||
</p>
|
||||
</div>
|
||||
<RegisterForm />
|
||||
<div className="divider">
|
||||
<span>или зарегистрироваться через</span>
|
||||
<span>
|
||||
{t('or-register-via')}
|
||||
</span>
|
||||
</div>
|
||||
<div className={`${styles['register-link']}`}>
|
||||
<p>Уже есть аккаунт? <Link href="login">Войти</Link></p>
|
||||
<p>{t('already-have-an-account')}? <Link href="login">{t('login')}</Link></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -83,7 +83,7 @@ export async function authorization(
|
||||
let parsed = await response.json();
|
||||
await createSession(parsed.token, parsed.email);
|
||||
} else {
|
||||
throw (`Запрос завершился с ошибкой: ${response.status}`);
|
||||
throw ('request-ended-with-an-error');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
@@ -146,7 +146,7 @@ export async function registration(
|
||||
path: string
|
||||
}) => {
|
||||
if (errors[obj.path[0]]) {
|
||||
errors[obj.path[0]] = `${errors[obj.path[0]]} ${obj.message}`;
|
||||
errors[obj.path[0]] = `${errors[obj.path[0]]}&${obj.message}`;
|
||||
} else {
|
||||
errors[obj.path[0]] = obj.message;
|
||||
}
|
||||
@@ -168,9 +168,9 @@ export async function registration(
|
||||
|
||||
try {
|
||||
const { full_name, email, password, phone } = validatedFields.data;
|
||||
const response = await fetch(`${API_BASE_URL}/v1/api/auth/register`, {
|
||||
const response = await fetch(`${API_BASE_URL}/v1/api/auth/register1`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ fullName: full_name, email, password, companyName: company, phone: phone}),
|
||||
body: JSON.stringify({ fullName: full_name, email, password, companyName: company, phone: phone }),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json"
|
||||
@@ -186,7 +186,7 @@ export async function registration(
|
||||
} catch (error) {
|
||||
if (error) {
|
||||
const errors: Record<string, string> = {};
|
||||
errors['server'] = `Запрос завершился с ошибкой: ${error}`
|
||||
errors['server'] = 'request-ended-with-an-error'
|
||||
|
||||
return {
|
||||
previousState: {
|
||||
|
||||
@@ -20,26 +20,26 @@ export const SignupFormSchema = z
|
||||
.object({
|
||||
full_name: z
|
||||
.string()
|
||||
.min(3, { error: 'Имя должно содержать не менее 3 символов.' })
|
||||
.min(3, { error: 'register-error-name' })
|
||||
.trim(),
|
||||
email: z.email({ error: 'Пожалуйста, введите правильный адрес электронной почты.' }).trim(),
|
||||
email: z.email({ error: 'register-error-valid-email' }).trim(),
|
||||
phone: z
|
||||
.string()
|
||||
.min(12, { error: 'Пожалуйста, введите телефонный номер.' }),
|
||||
.min(12, { error: 'register-error-phone' }),
|
||||
password: z
|
||||
.string()
|
||||
.min(8, { error: 'Длина пароля должна быть не менее 8 символов.' })
|
||||
.regex(/[a-zA-Zа-яёА-ЯЁ]/, { error: 'Пароль должен содержать как минимум 1 букву.' })
|
||||
.regex(/[0-9]/, { error: 'Пароль должен содержать как минимум 1 цифру.' })
|
||||
.min(8, { error: 'register-error-password-symbols' })
|
||||
.regex(/[a-zA-Zа-яёА-ЯЁ]/, { error: 'register-error-password-one-letter'})
|
||||
.regex(/[0-9]/, { error: 'register-error-password-one-digit' })
|
||||
.trim(),
|
||||
confirm_password: z
|
||||
.string(),
|
||||
agree: z
|
||||
.string()
|
||||
.min(2, { error: 'Пожалуйста, ознакомьтесь с условиями использования и политикой конфиденциальности.' })
|
||||
.min(2, { error: 'register-error-agree' })
|
||||
})
|
||||
.refine((data) => data.password === data.confirm_password, {
|
||||
message: 'Повторите пароль',
|
||||
message: 'repeat-password',
|
||||
path: ['confirm_password'],
|
||||
});
|
||||
|
||||
@@ -47,11 +47,11 @@ export const loginFormSchema = z
|
||||
.object({
|
||||
email: z
|
||||
.string()
|
||||
.min(1, { error: 'Адрес электронной почты не должен быть пустым.' })
|
||||
.min(1, { error: 'login-error-email' })
|
||||
.trim(),
|
||||
password: z
|
||||
.string()
|
||||
.min(1, { error: 'Пароль не должен быть пустым.' })
|
||||
.min(1, { error: 'login-error-password' })
|
||||
.trim(),
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
'use client'
|
||||
|
||||
import { useLocale } from 'next-intl'
|
||||
import { usePathname, useRouter } from '@/i18n/navigation'
|
||||
import { routing } from '@/i18n/routing'
|
||||
import { useState, useRef, useEffect } from 'react'
|
||||
import { useClickOutside } from '@/app/hooks/useClickOutside';
|
||||
|
||||
export default function LanguageSwitcher() {
|
||||
const locale = useLocale()
|
||||
const router = useRouter()
|
||||
const pathname = usePathname()
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const dropdownRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const switchLanguage = (newLocale: string) => {
|
||||
router.replace(pathname, { locale: newLocale })
|
||||
setIsOpen(false)
|
||||
}
|
||||
|
||||
useClickOutside(dropdownRef, () => {
|
||||
setIsOpen(false);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const handleEscape = (event: KeyboardEvent) => {
|
||||
if (event.key === 'Escape') setIsOpen(false)
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', handleEscape)
|
||||
return () => document.removeEventListener('keydown', handleEscape)
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="relative" ref={dropdownRef}>
|
||||
<button
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
className="flex items-center justify-between w-full px-4 py-2 text-sm font-medium text-[#6366f1] bg-white border-2 border-[#6366f1] rounded-md shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
aria-haspopup="listbox"
|
||||
aria-expanded={isOpen}
|
||||
>
|
||||
<span className="flex items-center">
|
||||
<span className="mr-2">{locale === 'ru' ? 'РУ' : locale.toUpperCase()}</span>
|
||||
</span>
|
||||
<svg
|
||||
className={`w-5 h-5 ml-2 transition-transform ${isOpen ? 'rotate-180' : ''}`}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{isOpen && (
|
||||
<div className="absolute right-0 z-10 w-full mt-2 origin-top-right bg-white rounded-md shadow-lg border-2 border-[#6366f1] focus:outline-none">
|
||||
<ul
|
||||
className="py-1"
|
||||
role="listbox"
|
||||
aria-labelledby="language-selector"
|
||||
>
|
||||
{routing.locales.map((lang) => (
|
||||
<li key={lang} role="option">
|
||||
<button
|
||||
onClick={() => switchLanguage(lang)}
|
||||
className={`flex items-center w-full px-4 py-2 text-sm text-left hover:bg-blue-100 ${locale === lang ? 'bg-blue-50 text-blue-600 font-medium' : 'text-[#6366f1]'
|
||||
}`}
|
||||
role="menuitem"
|
||||
>
|
||||
<span className="mr-2 font-medium">
|
||||
{lang === 'ru' ? 'РУ' : lang.toUpperCase()}
|
||||
</span>
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import Providers from './providers/getQueryServer'
|
||||
import type { Metadata } from "next";
|
||||
import "./styles/globals.css";
|
||||
import "./styles/global-styles.scss"
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "No copy",
|
||||
description: "No copy",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="ru">
|
||||
<body className={``}>
|
||||
<Providers>
|
||||
{children}
|
||||
</Providers>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -15,6 +15,12 @@
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.1);
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
|
||||
&-language {
|
||||
position: fixed;
|
||||
right: 20px;
|
||||
top: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import NotificationsButton from './notificationsButton';
|
||||
import UserMenuButton from './userMenuButton';
|
||||
import Link from 'next/link';
|
||||
import LanguageSwitcher from '@/app/components/LanguageSwitcher';
|
||||
|
||||
export default function HeaderPanel() {
|
||||
return (
|
||||
<header className="header">
|
||||
<div className="header-action">
|
||||
<LanguageSwitcher/>
|
||||
<Link
|
||||
href={'/pages/payment'}
|
||||
className="tokens-balance"
|
||||
|
||||
+28
-10
@@ -3,53 +3,71 @@
|
||||
import styles from '@/app/styles/login.module.scss'
|
||||
import { useActionState } from 'react';
|
||||
import { authorization } from '@/app/actions/auth';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export default function LoginForm() {
|
||||
const [state, formAction, isPending] = useActionState(
|
||||
authorization,
|
||||
undefined,
|
||||
);
|
||||
const t = useTranslations('Login-register-form');
|
||||
|
||||
return (
|
||||
<form action={formAction}>
|
||||
<div className={`${styles['form-group']}`}>
|
||||
<label className={`${styles['form-label']}`}>Email адрес</label>
|
||||
<label className={`${styles['form-label']}`}>
|
||||
{t('email-adress')}
|
||||
</label>
|
||||
<input
|
||||
type="readOnly"
|
||||
id="email"
|
||||
name="email"
|
||||
className={`${styles['form-input']}`}
|
||||
placeholder="Введите ваш email"
|
||||
placeholder={t('enter-email')}
|
||||
defaultValue={state?.previousState?.email ? state?.previousState?.email : ''}
|
||||
/>
|
||||
{state?.error?.email && (
|
||||
<p className={`${styles['form-error']}`}>{state?.error?.email}</p>
|
||||
<p className={`${styles['form-error']}`}>
|
||||
{t(state?.error?.email)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className={`${styles['form-group']}`}>
|
||||
<label className={`${styles['form-label']}`}>Пароль</label>
|
||||
<label className={`${styles['form-label']}`}>
|
||||
{t('password')}
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
name="password"
|
||||
className={`${styles['form-input']}`}
|
||||
placeholder="Введите пароль"
|
||||
placeholder={t('enter-password')}
|
||||
/>
|
||||
{state?.error?.password && (
|
||||
<p className={`${styles['form-error']}`}>{state?.error?.password}</p>
|
||||
<p className={`${styles['form-error']}`}>
|
||||
{t(state?.error?.password)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{state?.error.server && (
|
||||
<p className={`${styles['form-error']}`}>{state?.error.server}</p>
|
||||
<p className={`${styles['form-error']}`}>
|
||||
{t(state?.error.server)}
|
||||
</p>
|
||||
)}
|
||||
<div className={`${styles['form-options']}`}>
|
||||
<div className={`${styles['form-checkbox']}`}>
|
||||
<input type="checkbox" id="remember" name="remember" />
|
||||
<label>Запомнить меня</label>
|
||||
<label>
|
||||
{t('remember-me')}
|
||||
</label>
|
||||
</div>
|
||||
<a href="forgot-password" className={`${styles['forgot-password']}`} >Забыли пароль?</a>
|
||||
<a href="forgot-password" className={`${styles['forgot-password']}`} >
|
||||
{t('forgot-password')}?
|
||||
</a>
|
||||
</div>
|
||||
<button type="submit" className={`${styles['btn']}`}>Войти в систему</button>
|
||||
<button type="submit" className={`${styles['btn']}`}>
|
||||
{t('sign-in')}
|
||||
</button>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
@@ -5,12 +5,14 @@ import { useActionState } from 'react';
|
||||
import { registration } from '@/app/actions/auth';
|
||||
import PhoneInput from '@/app/ui/inputs/phone-input';
|
||||
import Link from 'next/link';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export default function RegisterForm() {
|
||||
const [state, formAction, isPending] = useActionState(
|
||||
registration,
|
||||
undefined,
|
||||
);
|
||||
const t = useTranslations('Login-register-form');
|
||||
|
||||
return (
|
||||
<form action={(e) => {
|
||||
@@ -20,23 +22,27 @@ export default function RegisterForm() {
|
||||
<label
|
||||
className={`${styles['form-label']} ${styles['required']}`}
|
||||
>
|
||||
Полное имя
|
||||
{t('full-name')}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="full_name"
|
||||
name="full_name"
|
||||
className={`${styles['form-input']}`}
|
||||
placeholder="Иванов Иван Иванович"
|
||||
placeholder={t('name-placeholder')}
|
||||
defaultValue={state?.previousState?.full_name ? state?.previousState?.full_name : ''}
|
||||
/>
|
||||
{state?.error?.full_name && (
|
||||
<p className="text-sm text-red-500">{state?.error?.full_name}</p>
|
||||
<p className="text-sm text-red-500">
|
||||
{t(state?.error?.full_name)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className={`${styles['form-row']}`}>
|
||||
<div className={`${styles['form-group']}`}>
|
||||
<label className={`${styles['form-label']} ${styles['required']}`}>Email адрес</label>
|
||||
<label className={`${styles['form-label']} ${styles['required']}`}>
|
||||
{t('email-adress')}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="email"
|
||||
@@ -46,14 +52,20 @@ export default function RegisterForm() {
|
||||
defaultValue={state?.previousState?.email ? state?.previousState?.email : ''}
|
||||
/>
|
||||
{state?.error?.email && (
|
||||
<p className="text-sm text-red-500">{state?.error?.email}</p>
|
||||
<p className="text-sm text-red-500">
|
||||
{t(state?.error?.email)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className={`${styles['form-group']}`}>
|
||||
<label className={`${styles['form-label']} ${styles['required']}`}>Телефон</label>
|
||||
<label className={`${styles['form-label']} ${styles['required']}`}>
|
||||
{t('phone')}
|
||||
</label>
|
||||
<PhoneInput phoneState={state?.previousState?.phone} />
|
||||
{state?.error?.phone && (
|
||||
<p className="text-sm text-red-500">{state?.error?.phone}</p>
|
||||
<p className="text-sm text-red-500">
|
||||
{t(state?.error?.phone)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -61,43 +73,55 @@ export default function RegisterForm() {
|
||||
<label
|
||||
className={`${styles['form-label']}`}
|
||||
>
|
||||
Компания
|
||||
{t('company')}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="company"
|
||||
name="company"
|
||||
className={`${styles['form-input']}`}
|
||||
placeholder="ООО «Ваша компания»"
|
||||
placeholder={t('company-placeholder')}
|
||||
defaultValue={state?.previousState?.company ? state?.previousState?.company : ''}
|
||||
/>
|
||||
</div>
|
||||
<div className={`${styles['form-row']}`}>
|
||||
<div className={`${styles['form-group']}`}>
|
||||
<label className={`${styles['form-label']} ${styles['required']}`}>Пароль</label>
|
||||
<label className={`${styles['form-label']} ${styles['required']}`}>
|
||||
{t('password')}
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
id="password" name="password"
|
||||
className={`${styles['form-input']}`}
|
||||
placeholder="Минимум 8 символов"
|
||||
placeholder={t('password-placeholder')}
|
||||
defaultValue={state?.previousState?.password ? state?.previousState?.password : ''}
|
||||
/>
|
||||
{state?.error?.password && (
|
||||
<p className="text-sm text-red-500">{state?.error?.password}</p>
|
||||
<p className="text-sm text-red-500">
|
||||
{
|
||||
state?.error?.password.split('&').map((e) => {
|
||||
return t(e)
|
||||
})
|
||||
}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className={`${styles['form-group']}`}>
|
||||
<label className={`${styles['form-label']} ${styles['required']}`}>Подтвердите пароль</label>
|
||||
<label className={`${styles['form-label']} ${styles['required']}`}>
|
||||
{t('confirm-password')}
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
id="confirm_password"
|
||||
name="confirm_password"
|
||||
className={`${styles['form-input']}`}
|
||||
placeholder="Повторите пароль"
|
||||
placeholder={t('repeat-password')}
|
||||
defaultValue={state?.previousState?.confirm_password ? state?.previousState?.confirm_password : ''}
|
||||
/>
|
||||
{state?.error?.confirm_password && (
|
||||
<p className="text-sm text-red-500">{state?.error?.confirm_password}</p>
|
||||
<p className="text-sm text-red-500">
|
||||
{t(state?.error?.confirm_password)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -108,22 +132,28 @@ export default function RegisterForm() {
|
||||
name="agree"
|
||||
defaultChecked={state?.previousState?.agree ? true : false}
|
||||
/>
|
||||
<label htmlFor="agree">Я соглашаюсь с
|
||||
<Link
|
||||
<label htmlFor="agree">
|
||||
{t('i-agree-to')} <Link
|
||||
href="/terms-and-privacy-policy"
|
||||
target="_blank"
|
||||
>
|
||||
условиями использования и политикой конфиденциальности
|
||||
>
|
||||
{t('terms-of-use')}
|
||||
</Link>
|
||||
</label>
|
||||
</div>
|
||||
{state?.error?.agree && (
|
||||
<p className="text-sm text-red-500">{state?.error?.agree}</p>
|
||||
<p className="text-sm text-red-500">
|
||||
{t(state?.error?.agree)}
|
||||
</p>
|
||||
)}
|
||||
{state?.error?.server && (
|
||||
<p className="text-sm text-red-500">{state?.error?.server}</p>
|
||||
<p className="text-sm text-red-500">
|
||||
{t(state?.error?.server)}
|
||||
</p>
|
||||
)}
|
||||
<button type="submit" className={`${styles['btn']}`}>Создать аккаунт</button>
|
||||
<button type="submit" className={`${styles['btn']}`}>
|
||||
{t('create-an-account')}
|
||||
</button>
|
||||
</form >
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user