parent
ad114b52eb
commit
7144d07832
7 changed files with 268 additions and 22 deletions
@ -0,0 +1,70 @@ |
||||
import React, { useState } from 'react'; |
||||
import { WindowState } from "../Windows"; |
||||
import { Box, Paper, Typography, TextField, Button } from "@material-ui/core"; |
||||
import { useHistory, useLocation } from 'react-router'; |
||||
import { useAuth, Auth } from '../../../lib/useAuth'; |
||||
|
||||
export interface LoginWindowState extends WindowState { } |
||||
export enum LoginWindowStateActions { } |
||||
export function LoginWindowReducer(state: LoginWindowState, action: any) { } |
||||
|
||||
export default function LoginWindow(props: {}) { |
||||
let history: any = useHistory(); |
||||
let location: any = useLocation(); |
||||
let auth: Auth = useAuth(); |
||||
let { from } = location.state || { from: { pathname: "/" } }; |
||||
|
||||
const [email, setEmail] = useState<string>(""); |
||||
const [password, setPassword] = useState<string>(""); |
||||
|
||||
const onSubmit = (event: any) => { |
||||
event.preventDefault(); |
||||
auth.signin(email, password) |
||||
.then(() => { |
||||
history.replace(from); |
||||
}) |
||||
} |
||||
|
||||
return <Box width="100%" justifyContent="center" display="flex" flexWrap="wrap"> |
||||
<Box |
||||
m={1} |
||||
mt={4} |
||||
> |
||||
<Paper> |
||||
<Box p={3}> |
||||
<Typography variant="h5">Sign in</Typography> |
||||
<form noValidate onSubmit={onSubmit}> |
||||
<TextField |
||||
variant="outlined" |
||||
margin="normal" |
||||
required |
||||
fullWidth |
||||
id="email" |
||||
label="Email" |
||||
name="email" |
||||
autoFocus |
||||
onInput={(e: any) => setEmail(e.target.value)} |
||||
/> |
||||
<TextField |
||||
variant="outlined" |
||||
margin="normal" |
||||
required |
||||
fullWidth |
||||
id="password" |
||||
label="Password" |
||||
name="password" |
||||
type="password" |
||||
onInput={(e: any) => setPassword(e.target.value)} |
||||
/> |
||||
<Button |
||||
type="submit" |
||||
fullWidth |
||||
variant="outlined" |
||||
color="primary" |
||||
>Sign in</Button> |
||||
</form> |
||||
</Box> |
||||
</Paper> |
||||
</Box> |
||||
</Box> |
||||
} |
@ -0,0 +1,140 @@ |
||||
// Note: Based on https://usehooks.com/useAuth/
|
||||
|
||||
// import React from "react";
|
||||
// import { ProvideAuth } from "./use-auth.js";
|
||||
// function App(props) {
|
||||
// return (
|
||||
// <ProvideAuth>
|
||||
// {/*
|
||||
// Route components here, depending on how your app is structured.
|
||||
// If using Next.js this would be /pages/_app.js
|
||||
// */}
|
||||
// </ProvideAuth>
|
||||
// );
|
||||
// }
|
||||
|
||||
// // Any component that wants auth state
|
||||
// import React from "react";
|
||||
// import { useAuth } from "./use-auth.js";
|
||||
|
||||
// function Navbar(props) {
|
||||
// // Get auth state and re-render anytime it changes
|
||||
// const auth = useAuth();
|
||||
|
||||
// return (
|
||||
// <NavbarContainer>
|
||||
// <Logo />
|
||||
// <Menu>
|
||||
// <Link to="/about">About</Link>
|
||||
// <Link to="/contact">Contact</Link>
|
||||
// {auth.user ? (
|
||||
// <Fragment>
|
||||
// <Link to="/account">Account ({auth.user.email})</Link>
|
||||
// <Button onClick={() => auth.signout()}>Signout</Button>
|
||||
// </Fragment>
|
||||
// ) : (
|
||||
// <Link to="/signin">Signin</Link>
|
||||
// )}
|
||||
// </Menu>
|
||||
// </NavbarContainer>
|
||||
// );
|
||||
// }
|
||||
|
||||
// Hook (use-auth.js)
|
||||
|
||||
import React, { useState, useEffect, useContext, createContext } from "react"; |
||||
import * as serverApi from '../api'; |
||||
|
||||
export interface AuthUser { |
||||
id: number, |
||||
} |
||||
|
||||
export interface Auth { |
||||
user: AuthUser | null, |
||||
signout: () => void, |
||||
signin: (email: string, password: string) => Promise<AuthUser>, |
||||
signup: (email: string, password: string) => void, |
||||
}; |
||||
|
||||
const authContext = createContext<Auth>({ |
||||
user: null, |
||||
signout: () => { }, |
||||
signin: (email: string, password: string) => { |
||||
throw new Error("Auth object not initialized."); |
||||
}, |
||||
signup: (email: string, password: string) => { |
||||
throw new Error("Auth object not initialized."); |
||||
}, |
||||
}); |
||||
|
||||
export function ProvideAuth(props: { children: any }) { |
||||
const auth = useProvideAuth(); |
||||
return <authContext.Provider value={auth}>{props.children}</authContext.Provider>; |
||||
} |
||||
|
||||
export const useAuth = () => { |
||||
return useContext(authContext); |
||||
}; |
||||
|
||||
function useProvideAuth() { |
||||
const [user, setUser] = useState<AuthUser | null>(null); |
||||
|
||||
// FIXME: password shouldn't be encoded into the URL.
|
||||
const signin = (email: string, password: string) => { |
||||
return (async () => { |
||||
const urlBase = (process.env.REACT_APP_BACKEND || "") + serverApi.LoginEndpoint; |
||||
const url = `${urlBase}?username=${encodeURIComponent(email)}&password=${encodeURIComponent(password)}`; |
||||
|
||||
const response = await fetch(url, { method: "POST" }); |
||||
const json = await response.json(); |
||||
if(!("userId" in json)) { |
||||
throw new Error("No UserID received from login."); |
||||
} |
||||
|
||||
const user = { |
||||
id: json.userId |
||||
} |
||||
setUser(user); |
||||
return user; |
||||
})(); |
||||
}; |
||||
|
||||
const signup = (email: string, password: string) => { |
||||
return (async () => { |
||||
const requestOpts = { |
||||
method: 'POST', |
||||
headers: { 'Content-Type': 'application/json' }, |
||||
body: JSON.stringify({ |
||||
email: email, |
||||
password: password, |
||||
}) |
||||
}; |
||||
|
||||
return (async () => { |
||||
const response = await fetch((process.env.REACT_APP_BACKEND || "") + serverApi.RegisterUserEndpoint, requestOpts) |
||||
if(!response.ok) { |
||||
throw new Error("Failed to register user.") |
||||
} |
||||
})(); |
||||
})(); |
||||
}; |
||||
|
||||
const signout = () => { |
||||
return (async () => { |
||||
const url = (process.env.REACT_APP_BACKEND || "") + serverApi.LogoutEndpoint; |
||||
const response = await fetch(url, { method: "POST" }); |
||||
if(!response.ok) { |
||||
throw new Error("Failed to log out."); |
||||
} |
||||
setUser(null); |
||||
})(); |
||||
}; |
||||
|
||||
// Return the user object and auth methods
|
||||
return { |
||||
user, |
||||
signin, |
||||
signup, |
||||
signout, |
||||
}; |
||||
} |
Loading…
Reference in new issue