You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
131 lines
4.8 KiB
131 lines
4.8 KiB
import React, { useReducer } 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'; |
|
import Alert from '@material-ui/lab/Alert'; |
|
|
|
export enum LoginStatus { |
|
NoneSubmitted = 0, |
|
Unsuccessful, |
|
// Note: no "successful" status because that would lead to a redirect. |
|
} |
|
|
|
export interface LoginWindowState extends WindowState { |
|
email: string, |
|
password: string, |
|
status: LoginStatus, |
|
} |
|
export enum LoginWindowStateActions { |
|
SetEmail = "SetEmail", |
|
SetPassword = "SetPassword", |
|
SetStatus = "SetStatus", |
|
} |
|
export function LoginWindowReducer(state: LoginWindowState, action: any) { |
|
switch (action.type) { |
|
case LoginWindowStateActions.SetEmail: |
|
return { ...state, email: action.value } |
|
case LoginWindowStateActions.SetPassword: |
|
return { ...state, password: action.value } |
|
case LoginWindowStateActions.SetStatus: |
|
return { ...state, status: action.value } |
|
default: |
|
throw new Error("Unimplemented LoginWindow state update.") |
|
} |
|
} |
|
|
|
export default function LoginWindow(props: {}) { |
|
const [state, dispatch] = useReducer(LoginWindowReducer, { |
|
email: "", |
|
password: "", |
|
status: LoginStatus.NoneSubmitted, |
|
}); |
|
|
|
return <LoginWindowControlled state={state} dispatch={dispatch} /> |
|
} |
|
|
|
export function LoginWindowControlled(props: { |
|
state: LoginWindowState, |
|
dispatch: (action: any) => void, |
|
}) { |
|
let history: any = useHistory(); |
|
let location: any = useLocation(); |
|
let auth: Auth = useAuth(); |
|
let { from } = location.state || { from: { pathname: "/" } }; |
|
|
|
const onSubmit = (event: any) => { |
|
event.preventDefault(); |
|
auth.signin(props.state.email, props.state.password) |
|
.then(() => { |
|
history.replace(from); |
|
}).catch((e: any) => { |
|
props.dispatch({ |
|
type: LoginWindowStateActions.SetStatus, |
|
value: LoginStatus.Unsuccessful, |
|
}) |
|
}) |
|
} |
|
|
|
return <Box width="100%" justifyContent="center" display="flex" flexWrap="wrap"> |
|
<Box |
|
m={1} |
|
mt={4} |
|
width="500px" |
|
> |
|
<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) => props.dispatch({ |
|
type: LoginWindowStateActions.SetEmail, |
|
value: e.target.value |
|
})} |
|
/> |
|
<TextField |
|
variant="outlined" |
|
margin="normal" |
|
required |
|
fullWidth |
|
id="password" |
|
label="Password" |
|
name="password" |
|
type="password" |
|
onInput={(e: any) => props.dispatch({ |
|
type: LoginWindowStateActions.SetPassword, |
|
value: e.target.value |
|
})} |
|
/> |
|
{props.state.status === LoginStatus.Unsuccessful && <Alert severity="error"> |
|
Login failed - Please check your credentials. |
|
</Alert> |
|
} |
|
<Button |
|
type="submit" |
|
fullWidth |
|
variant="outlined" |
|
color="primary" |
|
>Sign in</Button> |
|
<Box display="flex" alignItems="center" mt={2}> |
|
<Typography>Need an account?</Typography> |
|
<Box flexGrow={1} ml={2}><Button |
|
onClick={() => history.replace("/register")} |
|
fullWidth |
|
variant="outlined" |
|
color="primary" |
|
>Sign up</Button></Box> |
|
</Box> |
|
</form> |
|
</Box> |
|
</Paper> |
|
</Box> |
|
</Box> |
|
} |