feat: register page

This commit is contained in:
2025-05-10 14:19:41 +03:00
parent cc7307a655
commit e342da34c0
4 changed files with 149 additions and 1 deletions

View File

@@ -9,5 +9,6 @@
"[\"'`]([^\"'`]*).*?[\"'`]" "[\"'`]([^\"'`]*).*?[\"'`]"
] ]
], ],
"editor.formatOnSave": true "editor.formatOnSave": true,
"editor.tabSize": 2
} }

View File

@@ -5,6 +5,7 @@ import { addLocale, locale, PrimeReactProvider } from "primereact/api";
import { useMountEffect } from "primereact/hooks"; import { useMountEffect } from "primereact/hooks";
import Page404 from "./pages/404"; import Page404 from "./pages/404";
import LoginPage from "./pages/login"; import LoginPage from "./pages/login";
import RegisterPage from "./pages/register";
import { AppProvider, useAppContext } from "./providers/AuthProvider"; import { AppProvider, useAppContext } from "./providers/AuthProvider";
const HomePage: FunctionComponent = () => { const HomePage: FunctionComponent = () => {
@@ -32,6 +33,7 @@ export function App() {
<Router> <Router>
<Route path="/" component={HomePage} /> <Route path="/" component={HomePage} />
<Route path="/login" component={LoginPage} /> <Route path="/login" component={LoginPage} />
<Route path="/register" component={RegisterPage} />
<Route path="/profile/*" component={lazy(() => import("./pages/profile"))} /> <Route path="/profile/*" component={lazy(() => import("./pages/profile"))} />
<Route default component={() => <Page404 />} /> <Route default component={() => <Page404 />} />
</Router> </Router>

View File

@@ -23,6 +23,7 @@ const LoginPage: FunctionComponent = () => {
}); });
const login: SubmitHandler<ILoginForm> = async (data) => { const login: SubmitHandler<ILoginForm> = async (data) => {
try { try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const response = await apiClient<{ success: boolean; user?: any; error?: string }>( const response = await apiClient<{ success: boolean; user?: any; error?: string }>(
"/api/login/", "/api/login/",
{ {
@@ -42,6 +43,7 @@ const LoginPage: FunctionComponent = () => {
setError("login", { message: errorMessage }); setError("login", { message: errorMessage });
setError("password", { message: " " }); setError("password", { message: " " });
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) { } catch (error: any) {
console.error("Login failed:", error); console.error("Login failed:", error);
const errorMessage = const errorMessage =
@@ -88,6 +90,17 @@ const LoginPage: FunctionComponent = () => {
Войти Войти
</Button> </Button>
</form> </form>
<span class="mt-5 text-center text-xs">
Еще нет аккаунта?{" "}
<button
class="cursor-pointer text-blue-500 underline"
onClick={() => {
route("/register", true);
}}
>
Зарегистрироваться
</button>
</span>
</div> </div>
</div> </div>
) : ( ) : (

132
src/pages/register.tsx Normal file
View File

@@ -0,0 +1,132 @@
import Button from "@/components/ui/Button";
import Input from "@/components/ui/Input";
import { withTitle } from "@/constructors/Component";
import { UrlsTitle } from "@/enums/urls";
import { useAppContext } from "@/providers/AuthProvider";
import apiClient from "@/services/api";
import { FunctionComponent } from "preact";
import { useLocation } from "preact-iso";
import "preact/debug";
import { Controller, SubmitHandler, useForm } from "react-hook-form";
import { ILoginForm } from "./login.dto";
import classes from "./login.module.scss";
interface IRegisterForm extends ILoginForm {
confirmPassword: string;
}
const RegisterPage: FunctionComponent = () => {
const { isLoggedIn } = useAppContext();
const { route } = useLocation();
const { control, handleSubmit, formState, setError } = useForm({
defaultValues: {
login: "",
password: "",
confirmPassword: "",
},
mode: "onChange",
});
const register: SubmitHandler<IRegisterForm> = async (data) => {
if (data.password !== data.confirmPassword) {
setError("confirmPassword", { message: "Пароли не совпадают" });
return;
}
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const response = await apiClient<{ success: boolean; user?: any; error?: string }>("/api/register/", {
method: "POST",
body: JSON.stringify({ username: data.login, password: data.password }),
needsCsrf: true,
});
if (response.success) {
route("/login", true);
} else {
const errorMessage = response.error || "Неверный логин или пароль";
setError("login", { message: errorMessage });
setError("password", { message: " " });
setError("confirmPassword", { message: " " });
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
console.error("Register failed:", error);
const errorMessage = "Ошибка входа. Попробуйте позже.";
setError("login", { message: errorMessage });
setError("password", { message: " " });
setError("confirmPassword", { message: " " });
}
};
if (isLoggedIn.value) route("/profile/tasks", true);
return !isLoggedIn.value ? (
<div class={classes.login_container}>
<div class={classes.login_card}>
<p class={classes.login_card_name}>Антихвост</p>
<form onSubmit={handleSubmit(register)}>
<Controller
name="login"
control={control}
rules={{
required: "Введите логин",
minLength: { value: 3, message: "Логин должен быть не менее 3 символов" },
}}
render={({ field }) => (
<Input placeholder="Логин" textAlign="center" error={formState.errors.login?.message} {...field} />
)}
/>
<Controller
name="password"
control={control}
rules={{
required: "Введите пароль",
minLength: { value: 8, message: "Пароль должен быть не менее 8 символов" },
}}
render={({ field }) => (
<Input
placeholder="Пароль"
textAlign="center"
type="password"
error={formState.errors.password?.message}
{...field}
/>
)}
/>
<Controller
name="confirmPassword"
control={control}
rules={{
required: "Введите пароль",
minLength: { value: 8, message: "Пароль должен быть не менее 8 символов" },
}}
render={({ field }) => (
<Input
placeholder="Повторите пароль"
textAlign="center"
type="password"
error={formState.errors.confirmPassword?.message}
{...field}
/>
)}
/>
<Button type="submit" color="secondary" className="w-full">
Зарегистрироваться
</Button>
</form>
<span class="mt-5 text-center text-xs">
Уже есть аккаунт?{" "}
<button
class="cursor-pointer text-blue-500 underline"
onClick={() => {
route("/login", true);
}}
>
Войти
</button>
</span>
</div>
</div>
) : (
<p>Redirecting...</p>
);
};
export default withTitle(UrlsTitle.REGISTER, RegisterPage);