Admin Login & Admin FrontPage to NextJS

This commit is contained in:
Aarni Halinen
2020-12-29 21:55:30 +02:00
parent 1593deea61
commit 118c3b42e0
3 changed files with 76 additions and 117 deletions
+17 -9
View File
@@ -1,13 +1,21 @@
import React from "react";
import { Helmet } from "react-helmet";
import { NextPage } from "next";
import Head from "next/head";
import PageWrapper from "@views/common/AdminPageWrapper";
const AdminFrontView: React.FC = () => (
<main data-e2e="admin-front-page">
<Helmet>
const AdminFrontPage: NextPage = () => {
return (
<>
<Head>
<link rel="canonical" href="https://sik.ayy.fi/admin" />
</Helmet>
<h1>SIK Admin</h1>
</main>
);
</Head>
<PageWrapper requiresAuthentication>
<div data-e2e="admin-front-page">
<h1>SIK Admin</h1>
</div>
</PageWrapper>
</>
)
};
export default AdminFrontView;
export default AdminFrontPage;
+47 -91
View File
@@ -1,9 +1,9 @@
import React from "react";
import React, { useState, useEffect } from "react";
import styled from "styled-components";
import { Helmet } from "react-helmet";
import { withRouter } from "next/router";
import { WithRouterProps } from "next/dist/client/with-router";
import { useRouter } from "next/router";
import { generateToken, setTokenCookie, isAuthenticated } from "@utils/auth";
import PageWrapper from "@views/common/AdminPageWrapper";
const Main = styled.div`
input {
@@ -11,118 +11,74 @@ const Main = styled.div`
}
`;
type AdminLoginPageProps = WithRouterProps;
interface AdminLoginPageState {
username: string;
password: string;
isAuthenticated: boolean;
error: string;
}
const DEFAULT_REDIRECT = "/admin";
class AdminLoginPage extends React.Component<AdminLoginPageProps, AdminLoginPageState> {
constructor(props) {
super(props);
this.state = {
username: "",
password: "",
isAuthenticated: false,
error: "",
};
const AdminLoginPage: React.FC = () => {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const router = useRouter();
const next = router.query.next as string || DEFAULT_REDIRECT;
this.handleUserAuthenticated();
}
useEffect(() => {
isAuthenticated().then(res => {
if (res) {
router.push(next);
}
})
}, []);
handleUserAuthenticated = async () => {
const authenticated = await isAuthenticated();
if (authenticated) {
this.setState({
isAuthenticated: true,
});
}
}
handleSubmit = async (e) => {
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const { username, password } = this.state;
const { router } = this.props;
try {
const token = await generateToken(username, password);
console.log("JWT token:", token);
setTokenCookie(token);
const next = this.getRedirectURL();
router.push(next);
} catch (err) {
this.setState({
error: "Failed to log in!",
});
console.error("Failed to log in!");
setError("Failed to log in!");
}
}
handleUserNameChange = (e) => {
this.setState({
username: e.target.value,
});
}
handlePasswordChange = (e) => {
this.setState({
password: e.target.value,
});
}
renderError = () => {
const { error } = this.state;
if (!error) return null;
return (
<div className="error">
{ error }
</div>
);
}
getRedirectURL = () => {
const { router: { query } } = this.props;
const { next } = query;
// TODO: Any change of next being string[]? We get type error on without the cast.
return next as string || DEFAULT_REDIRECT;
}
render() {
const { router } = this.props;
const { username, password, isAuthenticated } = this.state;
const next = this.getRedirectURL();
if (isAuthenticated) {
router.push(next);
}
return (
return (
<PageWrapper requiresAuthentication={false}>
<Main>
<Helmet>
<link rel="canonical" href="https://sik.ayy.fi/admin/login" />
</Helmet>
<h1>Log in to SIK Admin</h1>
{ next && next !== DEFAULT_REDIRECT && (
{next && next !== DEFAULT_REDIRECT && (
<div className="error">You have to log in first.</div>
) }
<form className="admin-login-form" onSubmit={this.handleSubmit}>
)}
<form className="admin-login-form" onSubmit={handleSubmit}>
<label>Username
<input id="login-username" type="text" name="username" value={username} onChange={this.handleUserNameChange} />
<input
id="login-username"
type="text"
name="username"
value={username}
onChange={(e) => {
setUsername(e.target.value);
}} />
</label>
<label>Password
<input id="login-password" type="password" name="password" value={password} onChange={this.handlePasswordChange} />
<input
id="login-password"
type="password"
name="password"
value={password}
onChange={(e) => {
setPassword(e.target.value);
}} />
</label>
<input id="login-submit" type="submit" value="Log in" />
</form>
{ this.renderError() }
{error && (
<div className="error">
{error}
</div>
)}
</Main>
);
}
</PageWrapper>
);
}
export default withRouter(AdminLoginPage);
export default AdminLoginPage;
+12 -17
View File
@@ -1,11 +1,11 @@
import React, { useEffect, useState, ReactNode, ComponentType } from "react";
import React, { useEffect, useState } from "react";
import styled from "styled-components";
import { RouteComponentProps, Redirect } from "react-router-dom";
import colors from "@theme/colors";
import breakpoints from "@theme/breakpoints";
import AdminHeader from "@components/AdminHeader";
import AdminSidebar from "@components/AdminSidebar";
import { isAuthenticated } from "@utils/auth";
import { useRouter } from "next/router";
const Main = styled.main`
display: flex;
@@ -57,19 +57,19 @@ const useShouldRedirect = (enabled = true) => {
}
type PageProps = RouteComponentProps & {
page: ComponentType;
type PageProps = {
requiresAuthentication: boolean;
}
const PageWrapper: React.FC<PageProps> = ({ page, requiresAuthentication, ...props }) => {
const { path } = props.match;
const Page = page;
const PageWrapper: React.FC<PageProps> = ({ requiresAuthentication, children }) => {
const router = useRouter();
const { completed, redirecting } = useShouldRedirect(requiresAuthentication);
const { pathname } = router;
if (redirecting) {
const loginURL = `/admin/login?next=${path}`;
return <Redirect to={loginURL} />;
const loginURL = `/admin/login?next=${pathname}`;
router.push(loginURL);
}
// TODO: Loading screen
@@ -81,16 +81,11 @@ const PageWrapper: React.FC<PageProps> = ({ page, requiresAuthentication, ...pro
<>
<AdminHeader />
<Main>
<AdminSidebar path={path} />
<Page {...props} />
<AdminSidebar path={pathname} />
{children}
</Main>
</>
)
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
const renderPage = (Page: ReactNode, requiresAuthentication = true) => (props: any): JSX.Element => (
<PageWrapper page={Page} requiresAuthentication={requiresAuthentication} {...props} />
);
export default renderPage;
export default PageWrapper;