Skip to content

Commit 167f059

Browse files
authored
✨ Add Login to new frontend (fastapi#585)
1 parent 4a4efec commit 167f059

7 files changed

Lines changed: 111 additions & 14 deletions

File tree

src/new-frontend/index.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
<!doctype html>
1+
<!DOCTYPE html>
22
<html lang="en">
33
<head>
44
<meta charset="UTF-8" />
55
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7-
<title>Vite + React + TS</title>
7+
<title>Full Stack Project Generator</title>
8+
<link rel="icon" type="image/x-icon" href="./src/assets/images/favicon.png" />
89
</head>
910
<body>
1011
<div id="root"></div>
11-
<script type="module" src="/src/main.tsx"></script>
12+
<script type="module" src="./src/main.tsx"></script>
1213
</body>
1314
</html>

src/new-frontend/package.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,18 @@
1111
"generate-client": "openapi --input ./openapi.json --useOptions --useUnionTypes --output ./src/client --client axios --exportSchemas true"
1212
},
1313
"dependencies": {
14+
"@chakra-ui/icons": "2.1.1",
15+
"@chakra-ui/react": "2.8.2",
16+
"@emotion/react": "11.11.3",
17+
"@emotion/styled": "11.11.0",
18+
"@types/react-router-dom": "5.3.3",
1419
"axios": "1.6.2",
1520
"form-data": "4.0.0",
21+
"framer-motion": "10.16.16",
1622
"react": "^18.2.0",
17-
"react-dom": "^18.2.0"
23+
"react-dom": "^18.2.0",
24+
"react-hook-form": "7.49.3",
25+
"react-router-dom": "6.21.1"
1826
},
1927
"devDependencies": {
2028
"@types/node": "20.10.5",

src/new-frontend/src/App.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
import './App.css'
2-
3-
function App() {
1+
import { BrowserRouter, Route, Routes } from 'react-router-dom';
42

3+
import Login from './pages/auth/Login';
4+
import RecoverPassword from './pages/auth/RecoverPassword';
55

6+
function App() {
67
return (
7-
<>
8-
</>
8+
<BrowserRouter>
9+
<Routes>
10+
<Route path="/login" element={<Login />} />
11+
<Route path="/recover-password" element={<RecoverPassword />} />
12+
</Routes>
13+
</BrowserRouter>
914
)
1015
}
1116

17.3 KB
Loading
412 Bytes
Loading

src/new-frontend/src/main.tsx

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
1-
import React from 'react'
2-
import ReactDOM from 'react-dom/client'
3-
import App from './App.tsx'
4-
import './index.css'
1+
import React from 'react';
2+
import ReactDOM from 'react-dom/client';
3+
4+
import { ChakraProvider } from '@chakra-ui/react';
5+
6+
import App from './App';
7+
import { OpenAPI } from './client';
8+
9+
OpenAPI.BASE = import.meta.env.VITE_API_URL;
10+
OpenAPI.TOKEN = async () => {
11+
return localStorage.getItem('access_token') || '';
12+
}
513

614
ReactDOM.createRoot(document.getElementById('root')!).render(
715
<React.StrictMode>
8-
<App />
16+
<ChakraProvider>
17+
<App />
18+
</ChakraProvider>
919
</React.StrictMode>,
1020
)
21+
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import React from "react";
2+
3+
import { ViewIcon, ViewOffIcon } from "@chakra-ui/icons";
4+
import { Button, Center, Container, FormControl, Icon, Image, Input, InputGroup, InputRightElement, Link, useBoolean } from "@chakra-ui/react";
5+
import { SubmitHandler, useForm } from "react-hook-form";
6+
import { Link as ReactRouterLink, useNavigate } from "react-router-dom";
7+
8+
import Logo from "../../assets/images/fastapi-logo.png";
9+
import { LoginService } from "../../client";
10+
import { Body_login_login_access_token as AccessToken } from "../../client/models/Body_login_login_access_token";
11+
12+
const Login: React.FC = () => {
13+
const [show, setShow] = useBoolean();
14+
const navigate = useNavigate();
15+
const { register, handleSubmit } = useForm<AccessToken>();
16+
17+
const onSubmit: SubmitHandler<AccessToken> = async (data) => {
18+
const response = await LoginService.loginAccessToken({
19+
formData: data,
20+
});
21+
localStorage.setItem("access_token", response.access_token);
22+
navigate("/");
23+
};
24+
25+
return (
26+
<Container
27+
as="form"
28+
onSubmit={handleSubmit(onSubmit)}
29+
h="100vh"
30+
maxW="sm"
31+
alignItems="stretch"
32+
justifyContent="center"
33+
gap={4}
34+
centerContent
35+
>
36+
<Image src={Logo} alt="FastAPI logo" height="auto" maxW="2xs" alignSelf="center" />
37+
<FormControl id="email">
38+
<Input {...register("username")} focusBorderColor="blue.200" placeholder="Email" type="text" />
39+
</FormControl>
40+
<FormControl id="password">
41+
<InputGroup>
42+
<Input
43+
{...register("password")}
44+
type={show ? "text" : "password"}
45+
focusBorderColor="blue.200"
46+
placeholder="Password"
47+
/>
48+
<InputRightElement
49+
color="gray.500"
50+
_hover={{
51+
cursor: "pointer",
52+
}}
53+
>
54+
<Icon onClick={setShow.toggle} aria-label={show ? "Hide password" : "Show password"}>
55+
{show ? <ViewOffIcon /> : <ViewIcon />}
56+
</Icon>
57+
</InputRightElement>
58+
</InputGroup>
59+
<Center>
60+
<Link as={ReactRouterLink} to="/recover-password" color="blue.500" mt={2}>
61+
Forgot password?
62+
</Link>
63+
</Center>
64+
</FormControl>
65+
<Button colorScheme="teal" type="submit">
66+
Log In
67+
</Button>
68+
</Container>
69+
);
70+
};
71+
72+
export default Login;

0 commit comments

Comments
 (0)