Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions apps/frontend/app/auth/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function AuthLayout({ children }: { children: React.ReactNode }) {
return (
<main className="min-h-screen flex items-center justify-center bg-gray-100">
<div className="w-full max-w-md p-8 bg-white rounded-xl shadow">{children}</div>
</main>
);
}
1 change: 1 addition & 0 deletions apps/frontend/app/auth/login/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { LoginPage as default } from 'pages/login';
1 change: 1 addition & 0 deletions apps/frontend/app/auth/register/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { RegisterPage as default } from 'pages/register';
2 changes: 1 addition & 1 deletion apps/frontend/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference types="next/navigation-types/compat/navigation" />
import './.next/types/routes.d.ts';
import './.next/dev/types/routes.d.ts';

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
1 change: 1 addition & 0 deletions apps/frontend/src/pages/login/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as LoginPage } from './ui/LoginPage';
8 changes: 8 additions & 0 deletions apps/frontend/src/pages/login/model/loginSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { z } from 'zod';

export const formSchema = z.object({
email: z.email('Неверный формат email'),
password: z.string().min(6, 'Минимум 6 символов').max(32, 'Слишком длинный пароль'),
});

export type FormState = z.infer<typeof formSchema>;
55 changes: 55 additions & 0 deletions apps/frontend/src/pages/login/ui/LoginForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
'use client';
import Link from 'next/link';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { formSchema, FormState } from '../model/loginSchema';
import { Field, FieldDescription, FieldLabel, Button, Input } from 'shared/ui';

export function LoginForm() {
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm({
resolver: zodResolver(formSchema),
mode: 'onChange',
});
const onSubmit = (data: FormState): void => {
console.log(data);
reset();
};
return (
<form className="space-y-6 mb-4" onSubmit={handleSubmit(onSubmit)}>
<div className="flex flex-col space-y-4">
<Field>
<FieldLabel htmlFor="email">Почта</FieldLabel>
<Input type="email" {...register('email')} id="email" placeholder="example@company.com" />
{errors.email && (
<FieldDescription className="text-red-500">{errors.email.message}</FieldDescription>
)}
</Field>
<Field className="grid gap-2">
<div className="flex items-center">
<FieldLabel htmlFor="password">Пароль</FieldLabel>
<Link
href="/auth/reset-password"
className="ml-auto text-sm underline-offset-4 hover:underline text-muted-foreground"
>
Забыли пароль?
</Link>
</div>

<Input id="password" type="password" placeholder="********" {...register('password')} />

{errors.password && (
<FieldDescription className="text-red-500 text-sm">
{errors.password.message}
</FieldDescription>
)}
</Field>
</div>
<Button className="w-full bg-blue-600 text-white py-2 rounded">Войти</Button>
</form>
);
}
21 changes: 21 additions & 0 deletions apps/frontend/src/pages/login/ui/LoginPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'use client';
import { LoginForm } from './LoginForm';
import Link from 'next/link';
export default function LoginPage() {
return (
<div>
<h1 className="text-2xl font-semibold mb-2"># Task-tracker</h1>

<h2 className="text-lg font-medium mb-4">С возвращением</h2>
<LoginForm />
<div className="flex flex-col justify-center items-center gap-10">
<div className="flex gap-2">
<p className="text-gray-500">Нет аккаунта?</p>
<Link className="text-blue-700" href="/auth/register">
Зарегистрироваться
</Link>
</div>
</div>
</div>
);
}
1 change: 1 addition & 0 deletions apps/frontend/src/pages/register/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as RegisterPage } from './ui/RegisterPage';
9 changes: 9 additions & 0 deletions apps/frontend/src/pages/register/model/registerSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { z } from 'zod';

export const formSchema = z.object({
email: z.email('Неверный формат email'),
name: z.string().min(2, 'Слишком короткое имя').max(15, 'Слишком длинное имя'),
password: z.string().min(6, 'Минимум 6 символов').max(32, 'Слишком длинный пароль'),
});

export type FormState = z.infer<typeof formSchema>;
54 changes: 54 additions & 0 deletions apps/frontend/src/pages/register/ui/RegisterForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
'use client';

import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { Input } from 'shared/ui/input';
import { formSchema, FormState } from '../model/registerSchema';
import { Field, FieldDescription, FieldLabel } from 'shared/ui/field';
import { Button } from 'shared/ui';

export function RegisterForm() {
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm({
resolver: zodResolver(formSchema),
mode: 'onChange',
});
const onSubmit = (data: FormState): void => {
console.log(data);
reset();
};
return (
<form className="space-y-6 mb-4" onSubmit={handleSubmit(onSubmit)}>
<div className="flex flex-col space-y-4">
<Field>
<FieldLabel htmlFor="email">Почта</FieldLabel>
<Input type="email" {...register('email')} id="email" placeholder="example@company.com" />
{errors.email && (
<FieldDescription className="text-red-500">{errors.email.message}</FieldDescription>
)}
</Field>
<Field>
<FieldLabel htmlFor="name">Имя</FieldLabel>
<Input id="name" type="text" placeholder="example" {...register('name')} />
{errors.name && (
<FieldDescription className="text-red-500 text-sm">
{errors.name.message}
</FieldDescription>
)}
</Field>
<Field>
<FieldLabel htmlFor="password">Пароль</FieldLabel>
<Input id="password" type="password" placeholder="*********" {...register('password')} />
{errors.password && (
<FieldDescription className="text-red-500">{errors.password.message}</FieldDescription>
)}
</Field>
</div>
<Button className="w-full bg-blue-600 text-white py-2 rounded">Зарегистрироваться</Button>
</form>
);
}
12 changes: 12 additions & 0 deletions apps/frontend/src/pages/register/ui/RegisterPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'use client';
import { RegisterForm } from './RegisterForm';

export default function RegisterPage() {
return (
<div>
<h1 className="text-2xl font-semibold mb-2"># Task-tracker</h1>
<h2 className="text-lg font-medium mb-4">С возвращением</h2>
<RegisterForm />
</div>
);
}
Loading
Loading