Fork of the excellent esp8266-react - https://github.com/rjwats/esp8266-react
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.

147 lines
4.3 KiB

  1. import React, { Component } from 'react';
  2. import { withSnackbar, WithSnackbarProps } from 'notistack';
  3. import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator';
  4. import { withStyles, createStyles, Theme, WithStyles } from '@material-ui/core/styles';
  5. import { Paper, Typography, Fab } from '@material-ui/core';
  6. import ForwardIcon from '@material-ui/icons/Forward';
  7. import { withAuthenticationContext, AuthenticationContextProps } from './authentication/AuthenticationContext';
  8. import {PasswordValidator} from './components';
  9. import { PROJECT_NAME, SIGN_IN_ENDPOINT } from './api';
  10. const styles = (theme: Theme) => createStyles({
  11. loginPage: {
  12. display: "flex",
  13. height: "100vh",
  14. margin: "auto",
  15. padding: theme.spacing(2),
  16. justifyContent: "center",
  17. flexDirection: "column",
  18. maxWidth: theme.breakpoints.values.sm
  19. },
  20. loginPanel: {
  21. textAlign: "center",
  22. padding: theme.spacing(2),
  23. paddingTop: "200px",
  24. backgroundImage: 'url("/app/icon.png")',
  25. backgroundRepeat: "no-repeat",
  26. backgroundPosition: "50% " + theme.spacing(2) + "px",
  27. backgroundSize: "auto 150px",
  28. width: "100%"
  29. },
  30. extendedIcon: {
  31. marginRight: theme.spacing(0.5),
  32. },
  33. button: {
  34. marginRight: theme.spacing(2),
  35. marginTop: theme.spacing(2),
  36. }
  37. });
  38. type SignInProps = WithSnackbarProps & WithStyles<typeof styles> & AuthenticationContextProps;
  39. interface SignInState {
  40. username: string,
  41. password: string,
  42. processing: boolean
  43. }
  44. class SignIn extends Component<SignInProps, SignInState> {
  45. constructor(props: SignInProps) {
  46. super(props);
  47. this.state = {
  48. username: '',
  49. password: '',
  50. processing: false
  51. };
  52. }
  53. updateInputElement = (event: React.ChangeEvent<HTMLInputElement>): void => {
  54. const { name, value } = event.currentTarget;
  55. this.setState(prevState => ({
  56. ...prevState,
  57. [name]: value,
  58. }))
  59. };
  60. onSubmit = () => {
  61. const { username, password } = this.state;
  62. const { authenticationContext } = this.props;
  63. this.setState({ processing: true });
  64. fetch(SIGN_IN_ENDPOINT, {
  65. method: 'POST',
  66. body: JSON.stringify({ username, password }),
  67. headers: new Headers({
  68. 'Content-Type': 'application/json'
  69. })
  70. })
  71. .then(response => {
  72. if (response.status === 200) {
  73. return response.json();
  74. } else if (response.status === 401) {
  75. throw Error("Invalid login details.");
  76. } else {
  77. throw Error("Invalid status code: " + response.status);
  78. }
  79. }).then(json => {
  80. authenticationContext.signIn(json.access_token);
  81. })
  82. .catch(error => {
  83. this.props.enqueueSnackbar(error.message, {
  84. variant: 'warning',
  85. });
  86. this.setState({ processing: false });
  87. });
  88. };
  89. render() {
  90. const { username, password, processing } = this.state;
  91. const { classes } = this.props;
  92. return (
  93. <div className={classes.loginPage}>
  94. <Paper className={classes.loginPanel}>
  95. <Typography variant="h4">{PROJECT_NAME}</Typography>
  96. <ValidatorForm onSubmit={this.onSubmit}>
  97. <TextValidator
  98. disabled={processing}
  99. validators={['required']}
  100. errorMessages={['Username is required']}
  101. name="username"
  102. label="Username"
  103. fullWidth
  104. variant="outlined"
  105. value={username}
  106. onChange={this.updateInputElement}
  107. margin="normal"
  108. inputProps={{
  109. autoCapitalize: "none",
  110. autoCorrect: "off",
  111. }}
  112. />
  113. <PasswordValidator
  114. disabled={processing}
  115. validators={['required']}
  116. errorMessages={['Password is required']}
  117. name="password"
  118. label="Password"
  119. fullWidth
  120. variant="outlined"
  121. value={password}
  122. onChange={this.updateInputElement}
  123. margin="normal"
  124. />
  125. <Fab variant="extended" color="primary" className={classes.button} type="submit" disabled={processing}>
  126. <ForwardIcon className={classes.extendedIcon} />
  127. Sign In
  128. </Fab>
  129. </ValidatorForm>
  130. </Paper>
  131. </div>
  132. );
  133. }
  134. }
  135. export default withAuthenticationContext(withSnackbar(withStyles(styles)(SignIn)));