✨ Add Login to new frontend (#585)
This commit is contained in:
@@ -1,13 +1,14 @@
|
|||||||
<!doctype html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Vite + React + TS</title>
|
<title>Full Stack Project Generator</title>
|
||||||
|
<link rel="icon" type="image/x-icon" href="./src/assets/images/favicon.png" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<script type="module" src="/src/main.tsx"></script>
|
<script type="module" src="./src/main.tsx"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@@ -11,10 +11,18 @@
|
|||||||
"generate-client": "openapi --input ./openapi.json --useOptions --useUnionTypes --output ./src/client --client axios --exportSchemas true"
|
"generate-client": "openapi --input ./openapi.json --useOptions --useUnionTypes --output ./src/client --client axios --exportSchemas true"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@chakra-ui/icons": "2.1.1",
|
||||||
|
"@chakra-ui/react": "2.8.2",
|
||||||
|
"@emotion/react": "11.11.3",
|
||||||
|
"@emotion/styled": "11.11.0",
|
||||||
|
"@types/react-router-dom": "5.3.3",
|
||||||
"axios": "1.6.2",
|
"axios": "1.6.2",
|
||||||
"form-data": "4.0.0",
|
"form-data": "4.0.0",
|
||||||
|
"framer-motion": "10.16.16",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0",
|
||||||
|
"react-hook-form": "7.49.3",
|
||||||
|
"react-router-dom": "6.21.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "20.10.5",
|
"@types/node": "20.10.5",
|
||||||
|
@@ -1,11 +1,16 @@
|
|||||||
import './App.css'
|
import { BrowserRouter, Route, Routes } from 'react-router-dom';
|
||||||
|
|
||||||
|
import Login from './pages/auth/Login';
|
||||||
|
import RecoverPassword from './pages/auth/RecoverPassword';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<BrowserRouter>
|
||||||
</>
|
<Routes>
|
||||||
|
<Route path="/login" element={<Login />} />
|
||||||
|
<Route path="/recover-password" element={<RecoverPassword />} />
|
||||||
|
</Routes>
|
||||||
|
</BrowserRouter>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BIN
src/new-frontend/src/assets/images/fastapi-logo.png
Normal file
BIN
src/new-frontend/src/assets/images/fastapi-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
BIN
src/new-frontend/src/assets/images/favicon.png
Normal file
BIN
src/new-frontend/src/assets/images/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 412 B |
@@ -1,10 +1,21 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom/client'
|
import ReactDOM from 'react-dom/client';
|
||||||
import App from './App.tsx'
|
|
||||||
import './index.css'
|
import { ChakraProvider } from '@chakra-ui/react';
|
||||||
|
|
||||||
|
import App from './App';
|
||||||
|
import { OpenAPI } from './client';
|
||||||
|
|
||||||
|
OpenAPI.BASE = import.meta.env.VITE_API_URL;
|
||||||
|
OpenAPI.TOKEN = async () => {
|
||||||
|
return localStorage.getItem('access_token') || '';
|
||||||
|
}
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<App />
|
<ChakraProvider>
|
||||||
|
<App />
|
||||||
|
</ChakraProvider>
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
72
src/new-frontend/src/pages/auth/Login.tsx
Normal file
72
src/new-frontend/src/pages/auth/Login.tsx
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { ViewIcon, ViewOffIcon } from "@chakra-ui/icons";
|
||||||
|
import { Button, Center, Container, FormControl, Icon, Image, Input, InputGroup, InputRightElement, Link, useBoolean } from "@chakra-ui/react";
|
||||||
|
import { SubmitHandler, useForm } from "react-hook-form";
|
||||||
|
import { Link as ReactRouterLink, useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
|
import Logo from "../../assets/images/fastapi-logo.png";
|
||||||
|
import { LoginService } from "../../client";
|
||||||
|
import { Body_login_login_access_token as AccessToken } from "../../client/models/Body_login_login_access_token";
|
||||||
|
|
||||||
|
const Login: React.FC = () => {
|
||||||
|
const [show, setShow] = useBoolean();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { register, handleSubmit } = useForm<AccessToken>();
|
||||||
|
|
||||||
|
const onSubmit: SubmitHandler<AccessToken> = async (data) => {
|
||||||
|
const response = await LoginService.loginAccessToken({
|
||||||
|
formData: data,
|
||||||
|
});
|
||||||
|
localStorage.setItem("access_token", response.access_token);
|
||||||
|
navigate("/");
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container
|
||||||
|
as="form"
|
||||||
|
onSubmit={handleSubmit(onSubmit)}
|
||||||
|
h="100vh"
|
||||||
|
maxW="sm"
|
||||||
|
alignItems="stretch"
|
||||||
|
justifyContent="center"
|
||||||
|
gap={4}
|
||||||
|
centerContent
|
||||||
|
>
|
||||||
|
<Image src={Logo} alt="FastAPI logo" height="auto" maxW="2xs" alignSelf="center" />
|
||||||
|
<FormControl id="email">
|
||||||
|
<Input {...register("username")} focusBorderColor="blue.200" placeholder="Email" type="text" />
|
||||||
|
</FormControl>
|
||||||
|
<FormControl id="password">
|
||||||
|
<InputGroup>
|
||||||
|
<Input
|
||||||
|
{...register("password")}
|
||||||
|
type={show ? "text" : "password"}
|
||||||
|
focusBorderColor="blue.200"
|
||||||
|
placeholder="Password"
|
||||||
|
/>
|
||||||
|
<InputRightElement
|
||||||
|
color="gray.500"
|
||||||
|
_hover={{
|
||||||
|
cursor: "pointer",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon onClick={setShow.toggle} aria-label={show ? "Hide password" : "Show password"}>
|
||||||
|
{show ? <ViewOffIcon /> : <ViewIcon />}
|
||||||
|
</Icon>
|
||||||
|
</InputRightElement>
|
||||||
|
</InputGroup>
|
||||||
|
<Center>
|
||||||
|
<Link as={ReactRouterLink} to="/recover-password" color="blue.500" mt={2}>
|
||||||
|
Forgot password?
|
||||||
|
</Link>
|
||||||
|
</Center>
|
||||||
|
</FormControl>
|
||||||
|
<Button colorScheme="teal" type="submit">
|
||||||
|
Log In
|
||||||
|
</Button>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Login;
|
Reference in New Issue
Block a user