Skip to content

Commit

Permalink
Merge pull request #2 from Prrromanssss/frontend_auth
Browse files Browse the repository at this point in the history
make authorization on frontend side: login/register forms, authorization header for jwt token
  • Loading branch information
Prrromanssss authored Apr 21, 2024
2 parents 25b13fb + f1f0cdb commit 9b62b60
Show file tree
Hide file tree
Showing 19 changed files with 213 additions and 25 deletions.
2 changes: 1 addition & 1 deletion frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/calculator.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Distributed arithmetic expression evaluator</title>
<title>Distributed arithmetic expression calculator</title>
</head>
<body>
<div id="root"></div>
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { ROUTES } from './ts/enums';
import { AgentsPage } from './pages/Agents/AgentsPage';
import { ExpressionsPage } from './pages/Expressions/ExpressionsPage';
import { OperationsPage } from './pages/Operations/OperationsPage';
import { LoginPage } from './pages/Login/LoginPage';
import axios from 'axios';

function App() {
const [activePage, setActivePage] = useState("");
Expand All @@ -16,7 +18,9 @@ function App() {

useEffect(() => {
const pageFromStorage = sessionStorage.getItem("page") || ROUTES.EXPRESSIONS;
const token = sessionStorage.getItem("token");
if (pageFromStorage) setActivePage(pageFromStorage);
if (token) axios.defaults.headers.common = { "Authorization": `Bearer ${token}` };
}, []);

return (
Expand All @@ -29,6 +33,7 @@ function App() {
{activePage === ROUTES.AGENTS && <AgentsPage />}
{activePage === ROUTES.EXPRESSIONS && <ExpressionsPage />}
{activePage === ROUTES.OPERATIONS && <OperationsPage />}
{activePage === ROUTES.LOGIN && <LoginPage />}
</div>
</>
)
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/components/AgentBlock/AgentBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ export const AgentBlock = ({ agent }: AgentBlockProps) => {
Number of parallel calculations: {agent.number_of_parallel_calculations}
</p>
<p className={styles.text}>
Created at: {createdAt}
Number of active calculations: {agent.number_of_active_calculations}
</p>
<p className={styles.text}>
Дата создания: {createdAt}
</p>
</div>
)
Expand Down
4 changes: 1 addition & 3 deletions frontend/src/components/Button/Button.module.css
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
.btn {
background: blueviolet;
color: white;
padding: 15px 20px;
border-radius: 10px;
border: none;
outline: none;
cursor: pointer;
height: 84px;
width: 120px;
font-size: 25px;
}

.btn:hover {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const ExpressionBlock = ({ expression }: ExpressionBlockProps) => {
</p>
</div>
<p className={styles.createdAt}>
Created at: {date}
Дата создания: {date}
</p>
</div>
)
Expand Down
4 changes: 1 addition & 3 deletions frontend/src/components/Input/Input.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
padding: 15px;
border-radius: 10px;
border: 1px solid blueviolet;
min-width: 500px;
height: 52px;
font-size: 25px;
min-width: 300px;
}

.input:focus-visible {
Expand Down
23 changes: 23 additions & 0 deletions frontend/src/components/LoginForm/LoginForm.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.container {
border-radius: 20px;
padding: 20px;
display: flex;
align-items: center;
flex-direction: column;
border: 1px solid black;
width: 100%;
max-width: 300px;
gap: 10px;

}

.input {
padding: 10px;
border-radius: 10px;
border: 1px solid black;
width: 100%;
}

.button {
padding: 10px;
}
31 changes: 31 additions & 0 deletions frontend/src/components/LoginForm/LoginForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import styles from "./LoginForm.module.css";
import { FormProps } from "src/ts/interfaces";

export const LoginForm = ({ variant, handler, data, setData }: FormProps) => {
return (
<div className={styles.container}>
<input
name="email"
onChange={(e) => setData({ ...data, email: e.target.value })}
value={data.email}
className={styles.input}
placeholder="Email..."
/>
<input
name="password"
type="password"
onChange={(e) => setData({ ...data, password: e.target.value })}
value={data.password}
className={styles.input}
placeholder="Password..."
/>
<button
className={styles.button}
disabled={!data.email.length || !data.password.length}
onClick={handler}
>
{variant === "login" ? "Войти" : "Регистрация"}
</button>
</div>
)
}
2 changes: 1 addition & 1 deletion frontend/src/components/OperationBlock/OperationBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const OperationBlock = ({ operation, saveChanges }: OperationBlockProps)

return (
<div>
<p className={styles.title}>Operation type (sec): {operation.operation_type}</p>
<p className={styles.title}>Тип операции (сек): {operation.operation_type}</p>
<div className={styles.block}>
<Input
type="number"
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<>
<App />
<ToastContainer />
</React.StrictMode>,
</>,
)
7 changes: 5 additions & 2 deletions frontend/src/pages/Expressions/ExpressionsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ export const ExpressionsPage = () => {

useEffect(() => {
getExpressions()
.then(data => setExpressions(data));
.then(data => setExpressions(data))
.catch(err => {
toast.error(err.response.data.error);
});
}, []);

return (
Expand All @@ -48,7 +51,7 @@ export const ExpressionsPage = () => {
<div className={styles.items}>
{expressions.map(expression => (
<ExpressionBlock
key={expression.id}
key={expression.expression_id}
expression={expression}
/>
))}
Expand Down
23 changes: 23 additions & 0 deletions frontend/src/pages/Login/LoginPage.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.container {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}

.containerBtn {
display: flex;
align-items: center;
justify-content: center;
gap: 5px;
margin-bottom: 10px;
}

.activeElement {
cursor: pointer;
padding: 5px 10px;
border-radius: 10px;
border: 1px solid black;
}
71 changes: 71 additions & 0 deletions frontend/src/pages/Login/LoginPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { LoginForm } from "src/components/LoginForm/LoginForm";
import styles from "./LoginPage.module.css";
import { useState } from "react";
import { FormVariant } from "src/ts/types";
import { login, registration } from "src/services/api";
import { toast } from "react-toastify";

export const LoginPage = () => {
const [variant, setVariant] = useState<FormVariant>("login");
const [data, setData] = useState({
email: "",
password: "",
});

const handler = () => {
if (variant === "login") {
login(data).then(() => {
setData({ email: "", password: "" })
toast.success("Успешно!");
});
} else {
registration(data).then(() => {
toast.success("Успешно!");
setVariant("login");
})
.catch((err) => {
toast.error(err.response.data.error);
});
}
};

return (
<div className={styles.container}>
<div className={styles.containerBtn}>
<div
onClick={() => {
setData({ email: "", password: "" });
setVariant("login");
}}
className={styles.activeElement}
style={{
background: variant === "login" ? "blue" : "white",
color: variant === "login" ? "white" : "black",
}}
>
Вход
</div>
<div>/</div>
<div
onClick={() => {
setData({ email: "", password: "" });
setVariant("reg");
}}
className={styles.activeElement}
style={{
background: variant === "reg" ? "blue" : "white",
color: variant === "reg" ? "white" : "black",
}}
>
Регистрация
</div>
</div>
<LoginForm
variant={variant}
handler={handler}
data={data}
setData={setData}
/>
</div>
)
}
7 changes: 5 additions & 2 deletions frontend/src/pages/Operations/OperationsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,17 @@ export const OperationsPage = () => {

useEffect(() => {
getOperations()
.then(data => setOperations(data));
.then(data => setOperations(data))
.catch(err => {
toast.error(err.response.data.error);
});
}, []);

return (
<div className={styles.container}>
{operations.map(operation => (
<OperationBlock
key={operation.id}
key={operation.operation_id}
operation={operation}
saveChanges={(newValue) => saveChanges(newValue, operation)}
/>
Expand Down
14 changes: 13 additions & 1 deletion frontend/src/services/api.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import axios from "axios"
import { Agent, Expression, Operation } from "src/ts/interfaces";
import { Agent, Expression, FormData, Operation } from "src/ts/interfaces";

axios.defaults.baseURL = "http://localhost:3000/v1";

Expand Down Expand Up @@ -27,4 +27,16 @@ export const updateOperation = async (operation: Operation): Promise<Operation>
export const getAgents = async (): Promise<Agent[]> => {
const { data } = await axios.get("/agents");
return data;
}

export const login = async (value: FormData): Promise<{ token: string }> => {
const { data } = await axios.post("/login", value);
sessionStorage.setItem("token", data.token);
axios.defaults.headers.common = { "Authorization": `Bearer ${data.token}` }
return data;
}

export const registration = async (value: FormData): Promise<{ user_id: number }> => {
const { data } = await axios.post("/register", value);
return data;
}
4 changes: 2 additions & 2 deletions frontend/src/ts/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ export const ICONS = {
[AGENT_STATUS.SLEEPING]: greenIcon,
[AGENT_STATUS.WAITING]: yellowIcon,
[AGENT_STATUS.TERMINATED]: redIcon,
[EXPRESSION_STATUS.READY_FOR_COMPUTATION]: yellowIcon,
[EXPRESSION_STATUS.READY_FOR_COMPUTATION]: blackIcon,
[EXPRESSION_STATUS.RESULT]: greenIcon,
[EXPRESSION_STATUS.COMPUTING]: blackIcon,
[EXPRESSION_STATUS.COMPUTING]: yellowIcon,
} as const;

export const AGENT_DESCRIPTION = {
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/ts/enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ export enum ROUTES {
EXPRESSIONS = "Expressions",
OPERATIONS = "Operations",
AGENTS = "Agents",
LOGIN = "Login",
}

export enum EXPRESSION_STATUS {
READY_FOR_COMPUTATION = "ready for computation",
READY_FOR_COMPUTATION = "ready_for_computation",
COMPUTING = "computing",
RESULT = "result",
TERMINATED = "terminated",
Expand Down
Loading

0 comments on commit 9b62b60

Please sign in to comment.