Layout improvements, some additions
This commit is contained in:
15
front/components/ErrorMessage.tsx
Normal file
15
front/components/ErrorMessage.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import React from "react";
|
||||
|
||||
import styles from "styles/errorMessage.module.css";
|
||||
|
||||
interface IErrorMessageProps {
|
||||
message: string;
|
||||
}
|
||||
|
||||
const ErrorMessage: React.FC<IErrorMessageProps> = ({ message }) => (
|
||||
<div>
|
||||
<p className={styles.text}>{message}</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default ErrorMessage;
|
18
front/components/HomeHeader.tsx
Normal file
18
front/components/HomeHeader.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import { HomeRefContext } from "context/ref";
|
||||
import React, { useContext } from "react";
|
||||
|
||||
import styles from "styles/layout.module.css";
|
||||
|
||||
const HomeHeader: React.FC = () => {
|
||||
const ref = useContext(HomeRefContext);
|
||||
|
||||
const scrollToRef = () => ref?.current?.scrollIntoView();
|
||||
|
||||
return (
|
||||
<a onClick={scrollToRef} className={styles.link}>
|
||||
Регистрация
|
||||
</a>
|
||||
);
|
||||
};
|
||||
|
||||
export default HomeHeader;
|
33
front/components/Layout.tsx
Normal file
33
front/components/Layout.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import React, { useContext, useEffect, useState } from "react";
|
||||
|
||||
import styles from "styles/layout.module.css";
|
||||
import { LoadingContext } from "context/loading";
|
||||
import HomeHeader from "./HomeHeader";
|
||||
import UserHeader from "./UserHeader";
|
||||
|
||||
const Layout: React.FC<{ pathname: string }> = ({ children, pathname }) => {
|
||||
const { loading, setLoading } = useContext(LoadingContext);
|
||||
|
||||
useEffect(() => setLoading(false), []);
|
||||
|
||||
if (loading) return <h1>Loading...</h1>;
|
||||
|
||||
return (
|
||||
<div className={styles.content}>
|
||||
<nav className={styles.header}>
|
||||
<div className={styles.logo}>
|
||||
<img src="logo.svg" alt="" />
|
||||
<p className={styles.textLogo}>Ko.Map</p>
|
||||
</div>
|
||||
<div />
|
||||
<div>
|
||||
{pathname == "/" ? <HomeHeader /> : ""}
|
||||
{pathname == "/user" ? <UserHeader /> : ""}
|
||||
</div>
|
||||
</nav>
|
||||
<div>{children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Layout;
|
65
front/components/Login.tsx
Normal file
65
front/components/Login.tsx
Normal file
@ -0,0 +1,65 @@
|
||||
import React, { Dispatch, FormEvent, SetStateAction, useContext } from "react";
|
||||
import { NextRouter, useRouter } from "next/router";
|
||||
|
||||
import ErrorMessage from "components/ErrorMessage";
|
||||
import { UserContext, UserT } from "context/user";
|
||||
import useErrorHandler from "hooks/ErrorHandler";
|
||||
import { request } from "utils/index";
|
||||
|
||||
const dispatch = (err: Error) => "Error happened";
|
||||
|
||||
const setToken = async (
|
||||
token: string,
|
||||
setUserState: Dispatch<SetStateAction<UserT>>
|
||||
) => {
|
||||
localStorage.setItem("token", token);
|
||||
try {
|
||||
const user = await request("user", "GET");
|
||||
|
||||
setUserState(user);
|
||||
} catch (err) {
|
||||
console.log(err.message);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = (
|
||||
resetError: () => void,
|
||||
setUserState: Dispatch<SetStateAction<UserT>>,
|
||||
gotError: (err: Error) => void,
|
||||
router: NextRouter
|
||||
) => async (e: FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
|
||||
try {
|
||||
const formData = new FormData(e.currentTarget);
|
||||
const jsonData = Object.fromEntries(formData);
|
||||
|
||||
resetError();
|
||||
|
||||
const res = await request("login", "POST", jsonData);
|
||||
|
||||
setToken(res.token, setUserState);
|
||||
|
||||
router.push("/user");
|
||||
} catch (err) {
|
||||
gotError(err.message);
|
||||
}
|
||||
};
|
||||
|
||||
const Login: React.FC = () => {
|
||||
const router = useRouter();
|
||||
const { error, gotError, resetError } = useErrorHandler(dispatch);
|
||||
const { userState, setUserState } = useContext(UserContext);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(resetError, setUserState, gotError, router)}>
|
||||
<input type="email" name="email" id="email" />
|
||||
<input type="password" name="password" id="password" autoComplete="on" />
|
||||
<input type="submit" />
|
||||
{error.has ? <ErrorMessage message={error.message} /> : ""}
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default Login;
|
48
front/components/Register.tsx
Normal file
48
front/components/Register.tsx
Normal file
@ -0,0 +1,48 @@
|
||||
import React, { FormEvent, useState } from "react";
|
||||
|
||||
import ErrorMessage from "components/ErrorMessage";
|
||||
import useErrorHandler from "hooks/ErrorHandler";
|
||||
import { request } from "utils/index";
|
||||
|
||||
const dispatch = (err: Error) => "Error happened";
|
||||
|
||||
const Register: React.FC = () => {
|
||||
const [successfulAttempt, setSuccessfulAttempt] = useState<boolean>(false);
|
||||
const { error, gotError, resetError } = useErrorHandler(dispatch);
|
||||
|
||||
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
|
||||
try {
|
||||
const formData = new FormData(e.currentTarget);
|
||||
const jsonData = Object.fromEntries(formData);
|
||||
|
||||
resetError();
|
||||
|
||||
const res = await request("register", "POST", jsonData);
|
||||
|
||||
if (!res.ok) throw new Error("Couldn't register");
|
||||
|
||||
setSuccessfulAttempt(true);
|
||||
} catch (err) {
|
||||
gotError(err.message);
|
||||
}
|
||||
};
|
||||
|
||||
return successfulAttempt ? (
|
||||
<p>
|
||||
Для продолжения регистрации перейдите по ссылке, отправленной вам на
|
||||
введённую почту
|
||||
</p>
|
||||
) : (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<input type="text" name="username" id="username" />
|
||||
<input type="email" name="email" id="email" />
|
||||
<input type="password" name="password" id="password" autoComplete="on" />
|
||||
<input type="submit" />
|
||||
{error.has ? <ErrorMessage message={error.message} /> : ""}
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default Register;
|
@ -2,10 +2,12 @@ import React from "react";
|
||||
import { IRouteView } from "types/user";
|
||||
import RouteCard from "./RouteCard";
|
||||
|
||||
import styles from "styles/RouteView.module.css";
|
||||
|
||||
const RouteView: React.FC<IRouteView> = ({ header, routes }) => {
|
||||
return (
|
||||
<>
|
||||
<h1>{header}</h1>
|
||||
<h1 className={styles.header}>{header}</h1>
|
||||
{routes.map((route) => (
|
||||
<RouteCard key={route.id} route={route} />
|
||||
))}
|
||||
|
@ -1,12 +1,13 @@
|
||||
import React from "react";
|
||||
import { UserContext } from "context/user";
|
||||
import Link from "next/link";
|
||||
import React, { useContext } from "react";
|
||||
|
||||
import { IHeaderProps } from "types/user";
|
||||
const UserHeader: React.FC = () => {
|
||||
const user = useContext(UserContext);
|
||||
|
||||
const Header: React.FC<IHeaderProps> = ({ points }) => {
|
||||
return (
|
||||
<header>
|
||||
<div>Очки: {points}</div>
|
||||
<>
|
||||
<div>Очки: {user?.userState?.points || 0}</div>
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
@ -21,8 +22,8 @@ const Header: React.FC<IHeaderProps> = ({ points }) => {
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
export default UserHeader;
|
Reference in New Issue
Block a user