From 1154db69f5dbd074a8812814a6a4be62f47e70d7 Mon Sep 17 00:00:00 2001 From: Senad Uka Date: Sun, 23 Apr 2017 14:01:51 +0200 Subject: [PATCH] user login form done --- src/App.js | 1 - src/actions/user.js | 12 ++ src/components/user/authentication_dialog.js | 120 +++++++++++++++++++ src/components/user/user_display.css | 3 + src/components/user/user_display.js | 22 +++- src/reducers/user.js | 6 +- 6 files changed, 156 insertions(+), 8 deletions(-) create mode 100644 src/components/user/authentication_dialog.js create mode 100644 src/components/user/user_display.css diff --git a/src/App.js b/src/App.js index c623811..9fc7712 100644 --- a/src/App.js +++ b/src/App.js @@ -15,7 +15,6 @@ class App extends Component { return ( -
diff --git a/src/actions/user.js b/src/actions/user.js index d8ece20..b6af42c 100644 --- a/src/actions/user.js +++ b/src/actions/user.js @@ -4,3 +4,15 @@ export const authenticate = (user) => { user }; } + +export const openAuthenticationDialog = () => { + return { + type: 'openAuthenticationDialog' + } +} + +export const closeAuthenticationDialog = () => { + return { + type: 'closeAuthenticationDialog' + } +} diff --git a/src/components/user/authentication_dialog.js b/src/components/user/authentication_dialog.js new file mode 100644 index 0000000..95f9fda --- /dev/null +++ b/src/components/user/authentication_dialog.js @@ -0,0 +1,120 @@ +import React from 'react'; +import Dialog from 'material-ui/Dialog'; +import FlatButton from 'material-ui/FlatButton'; +import TextField from 'material-ui/TextField'; +import { bindActionCreators } from 'redux'; +import { connect } from 'react-redux'; +import * as userActions from '../../actions/user'; + +/** + * Dialog with action buttons. The actions are passed in as an array of React objects, + * in this example [FlatButtons](/#/components/flat-button). + * + * You can also close this dialog by clicking outside the dialog, or with the 'Esc' key. + */ +class AuthenticationDialog extends React.Component { + constructor(props) { + super(props); + const user = this.props.user.user ? this.props.user.user : { + name: "", + email: "" + }; + + this.state = { + name: user.name, + email: user.email + } + } + + handleOpen = () => { + this.props.actions.openAuthenticationDialog(); + }; + + authenticate = () => { + this.props.actions.authenticate(this.state); + }; + + handleClose = () => { + this.props.actions.closeAuthenticationDialog(); + }; + + emailValid = () => { + const emailRe = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + return emailRe.test(this.state.email); + } + + nameValid = () => { + const nameRe = /^[\w\s]+$/iu; + return nameRe.test(this.state.name); + } + userValid = () => { + return this.emailValid() && this.nameValid(); + } + + render() { + + console.log("is user valid ", this.userValid(), "state is", this.state); + const actions = [ + , + , + ]; + + return ( +
+ + + { this.setState({...this.state, email: e.target.value } )}} + type="email" + errorText={this.emailValid() ? null : "Email is required and must be in correct format."} + /> +
+ + { this.setState({...this.state, name: e.target.value } )}} + errorText={this.nameValid() ? null : "Name is required and must not contain any special characters."} + /> + + + +
+
+ ); + } +} + +function mapStateToProps(state, props) { + + return { + user: state.user + }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators(userActions, dispatch) + } +} +export default connect(mapStateToProps, mapDispatchToProps)(AuthenticationDialog); diff --git a/src/components/user/user_display.css b/src/components/user/user_display.css new file mode 100644 index 0000000..fcf9b4f --- /dev/null +++ b/src/components/user/user_display.css @@ -0,0 +1,3 @@ +.UserDisplay { + margin-top: 5px; +} diff --git a/src/components/user/user_display.js b/src/components/user/user_display.js index 9909845..8fbec26 100644 --- a/src/components/user/user_display.js +++ b/src/components/user/user_display.js @@ -9,6 +9,8 @@ import { } from 'react-redux'; import * as userActions from '../../actions/user'; import FlatButton from 'material-ui/FlatButton'; +import Avatar from 'material-ui/Avatar'; +import AuthenticationDialog from './authentication_dialog'; class UserDisplay extends Component { @@ -16,15 +18,23 @@ class UserDisplay extends Component { super(props); this.state = {} } + + initials(name) { + const extractedInitials = name.match(/\b\w/g) || []; + return ((extractedInitials.shift() || '') + (extractedInitials.pop() || '')).toUpperCase(); + } + render() { const user = this.props.user; - if (!user.name){ - return ( { alert("TouchTapped"); }} /> ) + if (!user){ + return ( { this.props.actions.openAuthenticationDialog()}} /> + + + + ) } else { return (
- { - user.name - } + {this.initials(user.name)}
); } @@ -33,7 +43,7 @@ class UserDisplay extends Component { function mapStateToProps(state, props) { return { - user: state.user + user: state.user.user }; } diff --git a/src/reducers/user.js b/src/reducers/user.js index 6469e00..98fa42e 100644 --- a/src/reducers/user.js +++ b/src/reducers/user.js @@ -1,7 +1,11 @@ export default(state = {}, payload) => { switch (payload.type) { case 'authenticate': - return {...state, user: payload.item }; + return {...state, user: payload.user, userAuthenticationDialogOpen: false }; + case 'openAuthenticationDialog': + return {...state, userAuthenticationDialogOpen: true } + case 'closeAuthenticationDialog': + return {...state, userAuthenticationDialogOpen: false } default: return state; }