From b604d613a3ec25f24ffa0781c2ba6e88108bd455 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 11 Jul 2018 21:01:29 +0200 Subject: [PATCH] improve authentication --- scm-ui/src/components/ErrorNotification.js | 23 ++++ scm-ui/src/components/Footer.js | 20 ++++ scm-ui/src/components/Header.js | 2 +- scm-ui/src/components/InputField.js | 12 +++ scm-ui/src/components/Loading.js | 43 ++++++++ scm-ui/src/components/Logo.js | 4 +- scm-ui/src/components/Notification.js | 37 +++++++ scm-ui/src/components/PrimaryNavigation.js | 2 + .../src/components/PrimaryNavigationLink.js | 2 +- scm-ui/src/components/SubmitButton.js | 16 ++- scm-ui/src/containers/App.js | 31 +++--- scm-ui/src/containers/Login.js | 39 +++++-- scm-ui/src/createReduxStore.js | 4 +- scm-ui/src/images/loading.svg | 36 +++++++ scm-ui/src/modules/login.js | 100 ++++-------------- scm-ui/src/modules/me.js | 98 +++++++++++++++++ 16 files changed, 359 insertions(+), 110 deletions(-) create mode 100644 scm-ui/src/components/ErrorNotification.js create mode 100644 scm-ui/src/components/Footer.js create mode 100644 scm-ui/src/components/Loading.js create mode 100644 scm-ui/src/components/Notification.js create mode 100644 scm-ui/src/images/loading.svg create mode 100644 scm-ui/src/modules/me.js diff --git a/scm-ui/src/components/ErrorNotification.js b/scm-ui/src/components/ErrorNotification.js new file mode 100644 index 0000000000..a10ceea6a3 --- /dev/null +++ b/scm-ui/src/components/ErrorNotification.js @@ -0,0 +1,23 @@ +//@flow +import React from "react"; +import Notification from "./Notification"; + +type Props = { + error: Error +}; + +class ErrorNotification extends React.Component { + render() { + const { error } = this.props; + if (error) { + return ( + + Error: {error.message} + + ); + } + return ""; + } +} + +export default ErrorNotification; diff --git a/scm-ui/src/components/Footer.js b/scm-ui/src/components/Footer.js new file mode 100644 index 0000000000..5cc2cc9f2c --- /dev/null +++ b/scm-ui/src/components/Footer.js @@ -0,0 +1,20 @@ +//@flow +import React from "react"; + +type Props = { + me: any +}; + +class Footer extends React.Component { + render() { + return ( +
+
+

{this.props.me.username}

+
+
+ ); + } +} + +export default Footer; diff --git a/scm-ui/src/components/Header.js b/scm-ui/src/components/Header.js index b1475c397a..6b93546827 100644 --- a/scm-ui/src/components/Header.js +++ b/scm-ui/src/components/Header.js @@ -1,5 +1,5 @@ //@flow -import React from "react"; +import * as React from "react"; import Logo from "./Logo"; type Props = { diff --git a/scm-ui/src/components/InputField.js b/scm-ui/src/components/InputField.js index 9b1ec724db..7534419bf8 100644 --- a/scm-ui/src/components/InputField.js +++ b/scm-ui/src/components/InputField.js @@ -6,6 +6,7 @@ type Props = { label?: string, placeholder?: string, type?: string, + autofocus?: boolean, onChange: string => void }; @@ -15,6 +16,14 @@ class InputField extends React.Component { placeholder: "" }; + field: ?HTMLInputElement; + + componentDidMount() { + if (this.props.autofocus && this.field) { + this.field.focus(); + } + } + handleInput = (event: SyntheticInputEvent) => { this.props.onChange(event.target.value); }; @@ -35,6 +44,9 @@ class InputField extends React.Component { {this.renderLabel()}
{ + this.field = input; + }} className="input" type={type} placeholder={placeholder} diff --git a/scm-ui/src/components/Loading.js b/scm-ui/src/components/Loading.js new file mode 100644 index 0000000000..d9b370b40f --- /dev/null +++ b/scm-ui/src/components/Loading.js @@ -0,0 +1,43 @@ +//@flow +import React from "react"; +import injectSheet from "react-jss"; +import Image from "../images/loading.svg"; + +const styles = { + wrapper: { + position: "relative" + }, + loading: { + width: "128px", + height: "128px", + + position: "absolute", + top: "50%", + left: "50%", + + margin: "64px 0 0 -64px" + }, + image: { + width: "128px", + height: "128px" + } +}; + +type Props = { + classes: any +}; + +class Loading extends React.Component { + render() { + const { classes } = this.props; + return ( +
+
+ Loading ... +
+
+ ); + } +} + +export default injectSheet(styles)(Loading); diff --git a/scm-ui/src/components/Logo.js b/scm-ui/src/components/Logo.js index 78f5e9e0c3..3ffdb3139e 100644 --- a/scm-ui/src/components/Logo.js +++ b/scm-ui/src/components/Logo.js @@ -2,7 +2,9 @@ import React from "react"; import Image from "../images/logo.png"; -class Logo extends React.PureComponent { +type Props = {}; + +class Logo extends React.Component { render() { return SCM-Manager logo; } diff --git a/scm-ui/src/components/Notification.js b/scm-ui/src/components/Notification.js new file mode 100644 index 0000000000..a66fc1cd9c --- /dev/null +++ b/scm-ui/src/components/Notification.js @@ -0,0 +1,37 @@ +//@flow +import * as React from "react"; +import classNames from "classnames"; + +type NotificationType = "primary" | "info" | "success" | "warning" | "danger"; + +type Props = { + type: NotificationType, + onClose?: () => void, + children?: React.Node +}; + +class Notification extends React.Component { + static defaultProps = { + type: "info" + }; + + renderCloseButton() { + const { onClose } = this.props; + if (onClose) { + return
); diff --git a/scm-ui/src/containers/App.js b/scm-ui/src/containers/App.js index 25f80a9598..c8da53a852 100644 --- a/scm-ui/src/containers/App.js +++ b/scm-ui/src/containers/App.js @@ -1,45 +1,50 @@ import React, { Component } from "react"; import Main from "./Main"; import Login from "./Login"; -import { getIsAuthenticated } from "../modules/login"; import { connect } from "react-redux"; import { withRouter } from "react-router-dom"; import { ThunkDispatch } from "redux-thunk"; +import { fetchMe } from "../modules/me"; import "./App.css"; import Header from "../components/Header"; import PrimaryNavigation from "../components/PrimaryNavigation"; +import Loading from "../components/Loading"; +import Notification from "../components/Notification"; +import Footer from "../components/Footer"; type Props = { login: boolean, - username: string, - getAuthState: () => void, + me: any, + fetchMe: () => void, loading: boolean }; class App extends Component { componentDidMount() { - this.props.getAuthState(); + this.props.fetchMe(); } render() { - const { login, loading } = this.props; + const { me, loading } = this.props; - let content; + let content = []; let navigation; if (loading) { - content =
Loading...
; - } else if (!login) { - content = ; + content.push(); + } else if (!me) { + content.push(); } else { - content =
; + content.push(
,