Initial commit
This commit is contained in:
		
							
								
								
									
										34
									
								
								js/actions/ErrorActions.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								js/actions/ErrorActions.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | var ErrorConstants = require('../constants/ErrorConstants'); | ||||||
|  |  | ||||||
|  | var models = require('../models.js'); | ||||||
|  | var Error = models.Error; | ||||||
|  |  | ||||||
|  | function serverError(error) { | ||||||
|  | 	return { | ||||||
|  | 		type: ErrorConstants.ERROR_SERVER, | ||||||
|  | 		error: error | ||||||
|  | 	}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function ajaxError(error) { | ||||||
|  | 	var e = new Error(); | ||||||
|  | 	e.ErrorId = 5; | ||||||
|  | 	e.ErrorString = "Request Failed: " + status + error; | ||||||
|  |  | ||||||
|  | 	return { | ||||||
|  | 		type: ErrorConstants.ERROR_AJAX, | ||||||
|  | 		error: e | ||||||
|  | 	}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function clearError() { | ||||||
|  | 	return { | ||||||
|  | 		type: ErrorConstants.CLEAR_ERROR, | ||||||
|  | 	}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module.exports = { | ||||||
|  | 	serverError: serverError, | ||||||
|  | 	ajaxError: ajaxError, | ||||||
|  | 	clearError: clearError | ||||||
|  | }; | ||||||
							
								
								
									
										204
									
								
								js/actions/UserActions.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								js/actions/UserActions.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,204 @@ | |||||||
|  | var UserConstants = require('../constants/UserConstants'); | ||||||
|  |  | ||||||
|  | var ErrorActions = require('./ErrorActions'); | ||||||
|  |  | ||||||
|  | var models = require('../models.js'); | ||||||
|  | var User = models.User; | ||||||
|  | var Session = models.Session; | ||||||
|  | var Error = models.Error; | ||||||
|  |  | ||||||
|  | function loginUser() { | ||||||
|  | 	return { | ||||||
|  | 		type: UserConstants.LOGIN_USER | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function userLoggedIn(session) { | ||||||
|  | 	return { | ||||||
|  | 		type: UserConstants.USER_LOGGEDIN, | ||||||
|  | 		session: session | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function logoutUser() { | ||||||
|  | 	return { | ||||||
|  | 		type: UserConstants.LOGOUT_USER | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function userLoggedOut() { | ||||||
|  | 	return { | ||||||
|  | 		type: UserConstants.USER_LOGGEDOUT | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function fetchUser(userId) { | ||||||
|  | 	return { | ||||||
|  | 		type: UserConstants.FETCH_USER, | ||||||
|  | 		userId: userId | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function userFetched(user) { | ||||||
|  | 	return { | ||||||
|  | 		type: UserConstants.USER_FETCHED, | ||||||
|  | 		user: user | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function updateUser(user) { | ||||||
|  | 	return { | ||||||
|  | 		type: UserConstants.UPDATE_USER, | ||||||
|  | 		user: user | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function userUpdated(user) { | ||||||
|  | 	return { | ||||||
|  | 		type: UserConstants.USER_UPDATED, | ||||||
|  | 		user: user | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function fetch(userId) { | ||||||
|  | 	return function (dispatch) { | ||||||
|  | 		dispatch(fetchUser()); | ||||||
|  |  | ||||||
|  | 		$.ajax({ | ||||||
|  | 			type: "GET", | ||||||
|  | 			dataType: "json", | ||||||
|  | 			url: "user/"+userId+"/", | ||||||
|  | 			success: function(data, status, jqXHR) { | ||||||
|  | 				var e = new Error(); | ||||||
|  | 				e.fromJSON(data); | ||||||
|  | 				if (e.isError()) { | ||||||
|  | 					ErrorActions.serverError(e); | ||||||
|  | 				} else { | ||||||
|  | 					var u = new User(); | ||||||
|  | 					u.fromJSON(data); | ||||||
|  | 					dispatch(userFetched(u)); | ||||||
|  | 				} | ||||||
|  | 			}, | ||||||
|  | 			error: function(jqXHR, status, error) { | ||||||
|  | 				ErrorActions.ajaxError(e); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 	}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function initializeSession(dispatch, session) { | ||||||
|  | 	dispatch(userLoggedIn(session)); | ||||||
|  | 	dispatch(fetch(session.UserId)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function login(user) { | ||||||
|  | 	return function (dispatch) { | ||||||
|  | 		dispatch(loginUser()); | ||||||
|  |  | ||||||
|  | 		$.ajax({ | ||||||
|  | 			type: "POST", | ||||||
|  | 			dataType: "json", | ||||||
|  | 			url: "session/", | ||||||
|  | 			data: {user: user.toJSON()}, | ||||||
|  | 			success: function(data, status, jqXHR) { | ||||||
|  | 				var e = new Error(); | ||||||
|  | 				e.fromJSON(data); | ||||||
|  | 				if (e.isError()) { | ||||||
|  | 					ErrorActions.serverError(e); | ||||||
|  | 				} else { | ||||||
|  | 					var s = new Session(); | ||||||
|  | 					s.fromJSON(data); | ||||||
|  | 					initializeSession(dispatch, s); | ||||||
|  | 				} | ||||||
|  | 			}, | ||||||
|  | 			error: function(jqXHR, status, error) { | ||||||
|  | 				ErrorActions.ajaxError(e); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 	}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function tryResumingSession() { | ||||||
|  | 	return function (dispatch) { | ||||||
|  | 		$.ajax({ | ||||||
|  | 			type: "GET", | ||||||
|  | 			dataType: "json", | ||||||
|  | 			url: "session/", | ||||||
|  | 			success: function(data, status, jqXHR) { | ||||||
|  | 				var e = new Error(); | ||||||
|  | 				e.fromJSON(data); | ||||||
|  | 				if (e.isError()) { | ||||||
|  | 					if (e.ErrorId != 1 /* Not Signed In*/) | ||||||
|  | 						ErrorActions.serverError(e); | ||||||
|  | 				} else { | ||||||
|  | 					var s = new Session(); | ||||||
|  | 					s.fromJSON(data); | ||||||
|  | 					dispatch(loginUser()); | ||||||
|  | 					initializeSession(dispatch, s); | ||||||
|  | 				} | ||||||
|  | 			}, | ||||||
|  | 			error: function(jqXHR, status, error) { | ||||||
|  | 				ErrorActions.ajaxError(e); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 	}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function logout() { | ||||||
|  | 	return function (dispatch) { | ||||||
|  | 		dispatch(logoutUser()); | ||||||
|  |  | ||||||
|  | 		$.ajax({ | ||||||
|  | 			type: "DELETE", | ||||||
|  | 			dataType: "json", | ||||||
|  | 			url: "session/", | ||||||
|  | 			success: function(data, status, jqXHR) { | ||||||
|  | 				var e = new Error(); | ||||||
|  | 				e.fromJSON(data); | ||||||
|  | 				if (e.isError()) { | ||||||
|  | 					ErrorActions.serverError(e); | ||||||
|  | 				} else { | ||||||
|  | 					dispatch(userLoggedOut()); | ||||||
|  | 				} | ||||||
|  | 			}, | ||||||
|  | 			error: function(jqXHR, status, error) { | ||||||
|  | 				ErrorActions.ajaxError(e); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 	}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function update(user) { | ||||||
|  | 	return function (dispatch) { | ||||||
|  | 		dispatch(updateUser()); | ||||||
|  |  | ||||||
|  | 		$.ajax({ | ||||||
|  | 			type: "PUT", | ||||||
|  | 			dataType: "json", | ||||||
|  | 			url: "user/"+user.UserId+"/", | ||||||
|  | 			data: {user: user.toJSON()}, | ||||||
|  | 			success: function(data, status, jqXHR) { | ||||||
|  | 				var e = new Error(); | ||||||
|  | 				e.fromJSON(data); | ||||||
|  | 				if (e.isError()) { | ||||||
|  | 					ErrorActions.serverError(e); | ||||||
|  | 				} else { | ||||||
|  | 					var u = new User(); | ||||||
|  | 					u.fromJSON(data); | ||||||
|  | 					dispatch(userUpdated(u)); | ||||||
|  | 				} | ||||||
|  | 			}, | ||||||
|  | 			error: function(jqXHR, status, error) { | ||||||
|  | 				ErrorActions.ajaxError(e); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 	}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module.exports = { | ||||||
|  | 	fetch: fetch, | ||||||
|  | 	login: login, | ||||||
|  | 	logout: logout, | ||||||
|  | 	update: update, | ||||||
|  | 	tryResumingSession: tryResumingSession | ||||||
|  | }; | ||||||
							
								
								
									
										158
									
								
								js/components/AccountSettingsModal.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								js/components/AccountSettingsModal.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,158 @@ | |||||||
|  | var React = require('react'); | ||||||
|  |  | ||||||
|  | var ReactDOM = require('react-dom'); | ||||||
|  |  | ||||||
|  | var ReactBootstrap = require('react-bootstrap'); | ||||||
|  | var Modal = ReactBootstrap.Modal; | ||||||
|  | var Button = ReactBootstrap.Button; | ||||||
|  | var ButtonGroup = ReactBootstrap.ButtonGroup; | ||||||
|  | var Form = ReactBootstrap.Form; | ||||||
|  | var FormGroup = ReactBootstrap.FormGroup; | ||||||
|  | var FormControl = ReactBootstrap.FormControl; | ||||||
|  | var ControlLabel = ReactBootstrap.ControlLabel; | ||||||
|  | var Col = ReactBootstrap.Col; | ||||||
|  |  | ||||||
|  | var User = require('../models').User; | ||||||
|  |  | ||||||
|  | module.exports = React.createClass({ | ||||||
|  | 	displayName: "AccountSettingsModal", | ||||||
|  | 	_getInitialState: function(props) { | ||||||
|  | 		return {error: "", | ||||||
|  | 			name: props.user.Name, | ||||||
|  | 			username: props.user.Username, | ||||||
|  | 			email: props.user.Email, | ||||||
|  | 			password: models.BogusPassword, | ||||||
|  | 			confirm_password: models.BogusPassword, | ||||||
|  | 			passwordChanged: false, | ||||||
|  | 			initial_password: models.BogusPassword}; | ||||||
|  | 	}, | ||||||
|  | 	getInitialState: function() { | ||||||
|  | 		 return this._getInitialState(this.props); | ||||||
|  | 	}, | ||||||
|  | 	componentWillReceiveProps: function(nextProps) { | ||||||
|  | 		if (nextProps.show && !this.props.show) { | ||||||
|  | 			this.setState(this._getInitialState(nextProps)); | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	passwordValidationState: function() { | ||||||
|  | 		if (this.state.passwordChanged) { | ||||||
|  | 			if (this.state.password.length >= 10) | ||||||
|  | 				return "success"; | ||||||
|  | 			else if (this.state.password.length >= 6) | ||||||
|  | 				return "warning"; | ||||||
|  | 			else | ||||||
|  | 				return "error"; | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	confirmPasswordValidationState: function() { | ||||||
|  | 		if (this.state.confirm_password.length > 0) { | ||||||
|  | 			if (this.state.confirm_password == this.state.password) | ||||||
|  | 				return "success"; | ||||||
|  | 			else | ||||||
|  | 				return "error"; | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	handleCancel: function() { | ||||||
|  | 		if (this.props.onCancel != null) | ||||||
|  | 			this.props.onCancel(); | ||||||
|  | 	}, | ||||||
|  | 	handleChange: function() { | ||||||
|  | 		if (ReactDOM.findDOMNode(this.refs.password).value != this.state.initial_password) | ||||||
|  | 			this.setState({passwordChanged: true}); | ||||||
|  | 		this.setState({ | ||||||
|  | 			name: ReactDOM.findDOMNode(this.refs.name).value, | ||||||
|  | 			username: ReactDOM.findDOMNode(this.refs.username).value, | ||||||
|  | 			email: ReactDOM.findDOMNode(this.refs.email).value, | ||||||
|  | 			password: ReactDOM.findDOMNode(this.refs.password).value, | ||||||
|  | 			confirm_password: ReactDOM.findDOMNode(this.refs.confirm_password).value | ||||||
|  | 		}); | ||||||
|  | 	}, | ||||||
|  | 	handleSubmit: function(e) { | ||||||
|  | 		var u = new User(); | ||||||
|  | 		e.preventDefault(); | ||||||
|  |  | ||||||
|  | 		u.UserId = this.props.user.UserId; | ||||||
|  | 		u.Name = this.state.name; | ||||||
|  | 		u.Username = this.state.username; | ||||||
|  | 		u.Email = this.state.email; | ||||||
|  | 		if (this.state.passwordChanged) { | ||||||
|  | 			u.Password = this.state.password; | ||||||
|  | 			if (u.Password != this.state.confirm_password) { | ||||||
|  | 				this.setState({error: "Error: password do not match"}); | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			u.Password = models.BogusPassword; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		this.props.onUpdateUser(u); | ||||||
|  | 		this.props.onSubmit(); | ||||||
|  | 	}, | ||||||
|  | 	render: function() { | ||||||
|  | 		return ( | ||||||
|  | 			<Modal show={this.props.show} onHide={this.handleCancel} bsSize="large"> | ||||||
|  | 				<Modal.Header closeButton> | ||||||
|  | 					<Modal.Title>Edit Account Settings</Modal.Title> | ||||||
|  | 				</Modal.Header> | ||||||
|  | 				<Modal.Body> | ||||||
|  | 				<span color="red">{this.state.error}</span> | ||||||
|  | 				<Form horizontal onSubmit={this.handleSubmit}> | ||||||
|  | 					<FormGroup> | ||||||
|  | 						<Col componentClass={ControlLabel} xs={2}>Name</Col> | ||||||
|  | 						<Col xs={10}> | ||||||
|  | 						<FormControl type="text" | ||||||
|  | 								value={this.state.name} | ||||||
|  | 								onChange={this.handleChange} | ||||||
|  | 								ref="name"/> | ||||||
|  | 						</Col> | ||||||
|  | 					</FormGroup> | ||||||
|  | 					<FormGroup> | ||||||
|  | 						<Col componentClass={ControlLabel} xs={2}>Username</Col> | ||||||
|  | 						<Col xs={10}> | ||||||
|  | 						<FormControl type="text" | ||||||
|  | 							value={this.state.username} | ||||||
|  | 							onChange={this.handleChange} | ||||||
|  | 							ref="username"/> | ||||||
|  | 						</Col> | ||||||
|  | 					</FormGroup> | ||||||
|  | 					<FormGroup> | ||||||
|  | 						<Col componentClass={ControlLabel} xs={2}>Email</Col> | ||||||
|  | 						<Col xs={10}> | ||||||
|  | 						<FormControl type="email" | ||||||
|  | 							value={this.state.email} | ||||||
|  | 							onChange={this.handleChange} | ||||||
|  | 							ref="email"/> | ||||||
|  | 						</Col> | ||||||
|  | 					</FormGroup> | ||||||
|  | 					<FormGroup validationState={this.passwordValidationState()}> | ||||||
|  | 						<Col componentClass={ControlLabel} xs={2}>Password</Col> | ||||||
|  | 						<Col xs={10}> | ||||||
|  | 						<FormControl type="password" | ||||||
|  | 							value={this.state.password} | ||||||
|  | 							onChange={this.handleChange} | ||||||
|  | 							ref="password"/> | ||||||
|  | 						<FormControl.Feedback/> | ||||||
|  | 						</Col> | ||||||
|  | 					</FormGroup> | ||||||
|  | 					<FormGroup validationState={this.confirmPasswordValidationState()}> | ||||||
|  | 						<Col componentClass={ControlLabel} xs={2}>Confirm Password</Col> | ||||||
|  | 						<Col xs={10}> | ||||||
|  | 						<FormControl type="password" | ||||||
|  | 							value={this.state.confirm_password} | ||||||
|  | 							onChange={this.handleChange} | ||||||
|  | 							ref="confirm_password"/> | ||||||
|  | 						<FormControl.Feedback/> | ||||||
|  | 						</Col> | ||||||
|  | 					</FormGroup> | ||||||
|  | 				</Form> | ||||||
|  | 				</Modal.Body> | ||||||
|  | 				<Modal.Footer> | ||||||
|  | 					<ButtonGroup> | ||||||
|  | 						<Button onClick={this.handleCancel} bsStyle="warning">Cancel</Button> | ||||||
|  | 						<Button onClick={this.handleSubmit} bsStyle="success">Save Settings</Button> | ||||||
|  | 					</ButtonGroup> | ||||||
|  | 				</Modal.Footer> | ||||||
|  | 			</Modal> | ||||||
|  | 		); | ||||||
|  | 	} | ||||||
|  | }); | ||||||
							
								
								
									
										95
									
								
								js/components/LunchApp.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								js/components/LunchApp.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | |||||||
|  | var React = require('react'); | ||||||
|  |  | ||||||
|  | var ReactBootstrap = require('react-bootstrap'); | ||||||
|  | var Jumbotron = ReactBootstrap.Jumbotron; | ||||||
|  | var Tabs = ReactBootstrap.Tabs; | ||||||
|  | var Tab = ReactBootstrap.Tab; | ||||||
|  | var Modal = ReactBootstrap.Modal; | ||||||
|  |  | ||||||
|  | var TopBarContainer = require('../containers/TopBarContainer'); | ||||||
|  | var NewUserForm = require('./NewUserForm'); | ||||||
|  | var AccountSettingsModalContainer = require('../containers/AccountSettingsModalContainer'); | ||||||
|  |  | ||||||
|  | module.exports = React.createClass({ | ||||||
|  | 	displayName: "LunchApp", | ||||||
|  | 	getInitialState: function() { | ||||||
|  | 		return { | ||||||
|  | 			hash: "home", | ||||||
|  | 			showAccountSettingsModal: false | ||||||
|  | 		}; | ||||||
|  | 	}, | ||||||
|  | 	componentDidMount: function() { | ||||||
|  | 		this.props.tryResumingSession(); | ||||||
|  | 		this.handleHashChange(); | ||||||
|  | 		if ("onhashchange" in window) { | ||||||
|  | 			window.onhashchange = this.handleHashChange; | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	handleHashChange: function() { | ||||||
|  | 		var hash = location.hash.replace(/^#/, ''); | ||||||
|  | 		if (hash.length == 0) | ||||||
|  | 			hash = "home"; | ||||||
|  | 		if (hash != this.state.hash) | ||||||
|  | 			this.setHash(hash); | ||||||
|  | 	}, | ||||||
|  | 	setHash: function(hash) { | ||||||
|  | 		location.hash = hash; | ||||||
|  | 		if (this.state.hash != hash) | ||||||
|  | 		this.setState({hash: hash}); | ||||||
|  | 	}, | ||||||
|  | 	handleAccountSettings: function() { | ||||||
|  | 		this.setState({showAccountSettingsModal: true}); | ||||||
|  | 	}, | ||||||
|  | 	handleSettingsSubmitted: function(user) { | ||||||
|  | 		this.setState({ | ||||||
|  | 			showAccountSettingsModal: false | ||||||
|  | 		}); | ||||||
|  | 	}, | ||||||
|  | 	handleSettingsCanceled: function() { | ||||||
|  | 		this.setState({showAccountSettingsModal: false}); | ||||||
|  | 	}, | ||||||
|  | 	handleCreateNewUser: function() { | ||||||
|  | 		this.setHash("new_user"); | ||||||
|  | 	}, | ||||||
|  | 	handleGoHome: function() { | ||||||
|  | 		this.setHash("home"); | ||||||
|  | 	}, | ||||||
|  | 	render: function() { | ||||||
|  | 		var mainContent; | ||||||
|  | 		if (this.state.hash == "new_user") { | ||||||
|  | 			mainContent = <NewUserForm onNewUser={this.handleGoHome} onCancel={this.handleGoHome}/> | ||||||
|  | 		} else { | ||||||
|  | 			if (this.props.user.isUser()) | ||||||
|  | 				mainContent = ( | ||||||
|  | 					<Tabs defaultActiveKey={1} id='mainNavigationTabs'> | ||||||
|  | 						<Tab title="Accounts" eventKey={1} >accounts | ||||||
|  | 						</Tab> | ||||||
|  | 						<Tab title="Securities" eventKey={2} >securities | ||||||
|  | 						</Tab> | ||||||
|  | 						<Tab title="Scheduled Transactions" eventKey={3} >Scheduled transactions go here...</Tab> | ||||||
|  | 						<Tab title="Budgets" eventKey={4} >Budgets go here...</Tab> | ||||||
|  | 						<Tab title="Reports" eventKey={5} >Reports go here...</Tab> | ||||||
|  | 					</Tabs>); | ||||||
|  | 			else | ||||||
|  | 				mainContent = ( | ||||||
|  | 					<Jumbotron> | ||||||
|  | 						<center> | ||||||
|  | 							<h1>Lunch App</h1> | ||||||
|  | 						</center> | ||||||
|  | 					</Jumbotron>); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return ( | ||||||
|  | 			<div className="fullheight ui"> | ||||||
|  | 				<TopBarContainer | ||||||
|  | 					onCreateNewUser={this.handleCreateNewUser} | ||||||
|  | 					onAccountSettings={this.handleAccountSettings} /> | ||||||
|  | 				{mainContent} | ||||||
|  | 				<AccountSettingsModalContainer | ||||||
|  | 					show={this.state.showAccountSettingsModal} | ||||||
|  | 					onSubmit={this.handleSettingsSubmitted} | ||||||
|  | 					onCancel={this.handleSettingsCanceled}/> | ||||||
|  | 			</div> | ||||||
|  | 		); | ||||||
|  | 	} | ||||||
|  | }); | ||||||
							
								
								
									
										165
									
								
								js/components/NewUserForm.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								js/components/NewUserForm.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,165 @@ | |||||||
|  | var React = require('react'); | ||||||
|  | var ReactDOM = require('react-dom'); | ||||||
|  |  | ||||||
|  | var ReactBootstrap = require('react-bootstrap'); | ||||||
|  | var Panel = ReactBootstrap.Panel; | ||||||
|  | var Form = ReactBootstrap.Form; | ||||||
|  | var FormGroup = ReactBootstrap.FormGroup; | ||||||
|  | var FormControl = ReactBootstrap.FormControl; | ||||||
|  | var ControlLabel = ReactBootstrap.ControlLabel; | ||||||
|  | var Col = ReactBootstrap.Col; | ||||||
|  | var Button = ReactBootstrap.Button; | ||||||
|  | var ButtonGroup = ReactBootstrap.ButtonGroup; | ||||||
|  |  | ||||||
|  | var models = require('../models'); | ||||||
|  | var User = models.User; | ||||||
|  | var Error = models.Error; | ||||||
|  |  | ||||||
|  | module.exports = React.createClass({ | ||||||
|  | 	getInitialState: function() { | ||||||
|  | 		return {error: "", | ||||||
|  | 			name: "", | ||||||
|  | 			username: "", | ||||||
|  | 			email: "", | ||||||
|  | 			password: "", | ||||||
|  | 			confirm_password: "", | ||||||
|  | 			passwordChanged: false, | ||||||
|  | 			initial_password: ""}; | ||||||
|  | 	}, | ||||||
|  | 	passwordValidationState: function() { | ||||||
|  | 		if (this.state.passwordChanged) { | ||||||
|  | 			if (this.state.password.length >= 10) | ||||||
|  | 				return "success"; | ||||||
|  | 			else if (this.state.password.length >= 6) | ||||||
|  | 				return "warning"; | ||||||
|  | 			else | ||||||
|  | 				return "error"; | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	confirmPasswordValidationState: function() { | ||||||
|  | 		if (this.state.confirm_password.length > 0) { | ||||||
|  | 			if (this.state.confirm_password == this.state.password) | ||||||
|  | 				return "success"; | ||||||
|  | 			else | ||||||
|  | 				return "error"; | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	handleCancel: function() { | ||||||
|  | 		if (this.props.onCancel != null) | ||||||
|  | 			this.props.onCancel(); | ||||||
|  | 	}, | ||||||
|  | 	handleChange: function() { | ||||||
|  | 		if (ReactDOM.findDOMNode(this.refs.password).value != this.state.initial_password) | ||||||
|  | 			this.setState({passwordChanged: true}); | ||||||
|  | 		this.setState({ | ||||||
|  | 			name: ReactDOM.findDOMNode(this.refs.name).value, | ||||||
|  | 			username: ReactDOM.findDOMNode(this.refs.username).value, | ||||||
|  | 			email: ReactDOM.findDOMNode(this.refs.email).value, | ||||||
|  | 			password: ReactDOM.findDOMNode(this.refs.password).value, | ||||||
|  | 			confirm_password: ReactDOM.findDOMNode(this.refs.confirm_password).value | ||||||
|  | 		}); | ||||||
|  | 	}, | ||||||
|  | 	handleSubmit: function(e) { | ||||||
|  | 		var u = new User(); | ||||||
|  | 		var error = ""; | ||||||
|  | 		e.preventDefault(); | ||||||
|  |  | ||||||
|  | 		u.Name = this.state.name; | ||||||
|  | 		u.Username = this.state.username; | ||||||
|  | 		u.Email = this.state.email; | ||||||
|  | 		u.Password = this.state.password; | ||||||
|  | 		if (u.Password != this.state.confirm_password) { | ||||||
|  | 			this.setState({error: "Error: password do not match"}); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		this.handleCreateNewUser(u); | ||||||
|  | 	}, | ||||||
|  | 	handleCreateNewUser: function(user) { | ||||||
|  | 		$.ajax({ | ||||||
|  | 			type: "POST", | ||||||
|  | 			dataType: "json", | ||||||
|  | 			url: "user/", | ||||||
|  | 			data: {user: user.toJSON()}, | ||||||
|  | 			success: function(data, status, jqXHR) { | ||||||
|  | 				var e = new Error(); | ||||||
|  | 				e.fromJSON(data); | ||||||
|  | 				if (e.isError()) { | ||||||
|  | 					this.setState({error: e}); | ||||||
|  | 				} else { | ||||||
|  | 					this.props.onNewUser(); | ||||||
|  | 				} | ||||||
|  | 			}.bind(this), | ||||||
|  | 			error: function(jqXHR, status, error) { | ||||||
|  | 				var e = new Error(); | ||||||
|  | 				e.ErrorId = 5; | ||||||
|  | 				e.ErrorString = "Request Failed: " + status + error; | ||||||
|  | 				this.setState({error: e}); | ||||||
|  | 			}.bind(this), | ||||||
|  | 		}); | ||||||
|  | 	}, | ||||||
|  | 	render: function() { | ||||||
|  | 		var title = <h3>Create New User</h3>; | ||||||
|  | 		return ( | ||||||
|  | 			<Panel header={title} bsStyle="info"> | ||||||
|  | 				<span color="red">{this.state.error}</span> | ||||||
|  | 				<Form horizontal onSubmit={this.handleSubmit}> | ||||||
|  | 					<FormGroup> | ||||||
|  | 						<Col componentClass={ControlLabel} xs={2}>Name</Col> | ||||||
|  | 						<Col xs={10}> | ||||||
|  | 						<FormControl type="text" | ||||||
|  | 							value={this.state.name} | ||||||
|  | 							onChange={this.handleChange} | ||||||
|  | 							ref="name"/> | ||||||
|  | 						</Col> | ||||||
|  | 					</FormGroup> | ||||||
|  | 					<FormGroup> | ||||||
|  | 						<Col componentClass={ControlLabel} xs={2}>Username</Col> | ||||||
|  | 						<Col xs={10}> | ||||||
|  | 						<FormControl type="text" | ||||||
|  | 							value={this.state.username} | ||||||
|  | 							onChange={this.handleChange} | ||||||
|  | 							ref="username"/> | ||||||
|  | 						</Col> | ||||||
|  | 					</FormGroup> | ||||||
|  | 					<FormGroup> | ||||||
|  | 						<Col componentClass={ControlLabel} xs={2}>Email</Col> | ||||||
|  | 						<Col xs={10}> | ||||||
|  | 						<FormControl type="email" | ||||||
|  | 							value={this.state.email} | ||||||
|  | 							onChange={this.handleChange} | ||||||
|  | 							ref="email"/> | ||||||
|  | 						</Col> | ||||||
|  | 					</FormGroup> | ||||||
|  | 					<FormGroup validationState={this.passwordValidationState()}> | ||||||
|  | 						<Col componentClass={ControlLabel} xs={2}>Password</Col> | ||||||
|  | 						<Col xs={10}> | ||||||
|  | 						<FormControl type="password" | ||||||
|  | 							value={this.state.password} | ||||||
|  | 							onChange={this.handleChange} | ||||||
|  | 							ref="password"/> | ||||||
|  | 						<FormControl.Feedback/> | ||||||
|  | 						</Col> | ||||||
|  | 					</FormGroup> | ||||||
|  | 					<FormGroup validationState={this.confirmPasswordValidationState()}> | ||||||
|  | 						<Col componentClass={ControlLabel} xs={2}>Confirm Password</Col> | ||||||
|  | 						<Col xs={10}> | ||||||
|  | 						<FormControl type="password" | ||||||
|  | 							value={this.state.confirm_password} | ||||||
|  | 							onChange={this.handleChange} | ||||||
|  | 							ref="confirm_password"/> | ||||||
|  | 						<FormControl.Feedback/> | ||||||
|  | 						</Col> | ||||||
|  | 					</FormGroup> | ||||||
|  |  | ||||||
|  | 					<ButtonGroup className="pull-right"> | ||||||
|  | 						<Button onClick={this.handleCancel} | ||||||
|  | 								bsStyle="warning">Cancel</Button> | ||||||
|  | 						<Button type="submit" | ||||||
|  | 								bsStyle="success">Create New User</Button> | ||||||
|  | 					</ButtonGroup> | ||||||
|  | 				</Form> | ||||||
|  | 			</Panel> | ||||||
|  | 		); | ||||||
|  | 	} | ||||||
|  | }); | ||||||
							
								
								
									
										123
									
								
								js/components/TopBar.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								js/components/TopBar.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | |||||||
|  | var React = require('react'); | ||||||
|  |  | ||||||
|  | var ReactBootstrap = require('react-bootstrap'); | ||||||
|  | var Alert = ReactBootstrap.Alert; | ||||||
|  | var FormGroup = ReactBootstrap.FormGroup; | ||||||
|  | var FormControl = ReactBootstrap.FormControl; | ||||||
|  | var Button = ReactBootstrap.Button; | ||||||
|  | var DropdownButton = ReactBootstrap.DropdownButton; | ||||||
|  | var MenuItem = ReactBootstrap.MenuItem; | ||||||
|  | var Row = ReactBootstrap.Row; | ||||||
|  | var Col = ReactBootstrap.Col; | ||||||
|  |  | ||||||
|  | var ReactDOM = require('react-dom'); | ||||||
|  |  | ||||||
|  | var User = require('../models').User; | ||||||
|  |  | ||||||
|  | const LoginBar = React.createClass({ | ||||||
|  | 	getInitialState: function() { | ||||||
|  | 		return {username: '', password: ''}; | ||||||
|  | 	}, | ||||||
|  | 	onUsernameChange: function(e) { | ||||||
|  | 		this.setState({username: e.target.value}); | ||||||
|  | 	}, | ||||||
|  | 	onPasswordChange: function(e) { | ||||||
|  | 		this.setState({password: e.target.value}); | ||||||
|  | 	}, | ||||||
|  | 	handleSubmit: function(e) { | ||||||
|  | 		var user = new User(); | ||||||
|  | 		e.preventDefault(); | ||||||
|  | 		user.Username = ReactDOM.findDOMNode(this.refs.username).value; | ||||||
|  | 		user.Password = ReactDOM.findDOMNode(this.refs.password).value; | ||||||
|  | 		this.props.onLogin(user); | ||||||
|  | 	}, | ||||||
|  | 	handleNewUserSubmit: function(e) { | ||||||
|  | 		e.preventDefault(); | ||||||
|  | 		this.props.onCreateNewUser(); | ||||||
|  | 	}, | ||||||
|  | 	render: function() { | ||||||
|  | 		return ( | ||||||
|  | 			<form onSubmit={this.handleSubmit}> | ||||||
|  | 			<FormGroup> | ||||||
|  | 				<Row> | ||||||
|  | 					<Col xs={4}></Col> | ||||||
|  | 					<Col xs={2}> | ||||||
|  | 						<Button bsStyle="link" | ||||||
|  | 							onClick={this.handleNewUserSubmit}>Create New User</Button> | ||||||
|  | 					</Col> | ||||||
|  | 					<Col xs={2}> | ||||||
|  | 						<FormControl type="text" | ||||||
|  | 							placeholder="Username..." | ||||||
|  | 							ref="username"/> | ||||||
|  | 					</Col> | ||||||
|  | 					<Col xs={2}> | ||||||
|  | 						<FormControl type="password" | ||||||
|  | 							placeholder="Password..." | ||||||
|  | 							ref="password"/> | ||||||
|  | 					</Col> | ||||||
|  | 					<Col xs={2}> | ||||||
|  | 						<Button type="submit" bsStyle="primary" block> | ||||||
|  | 							Login</Button> | ||||||
|  | 					</Col> | ||||||
|  | 				</Row> | ||||||
|  | 			</FormGroup> | ||||||
|  | 			</form> | ||||||
|  | 		); | ||||||
|  | 	} | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | const LogoutBar = React.createClass({ | ||||||
|  | 	handleOnSelect: function(key) { | ||||||
|  | 		if (key == 1) { | ||||||
|  | 			if (this.props.onAccountSettings != null) | ||||||
|  | 				this.props.onAccountSettings(); | ||||||
|  | 		} else if (key == 2) { | ||||||
|  | 			this.props.onLogout(); | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	render: function() { | ||||||
|  | 		var signedInString = "Signed in as "+this.props.user.Name; | ||||||
|  | 		return ( | ||||||
|  | 			<FormGroup> | ||||||
|  | 				<Row> | ||||||
|  | 					<Col xs={2}><label className="control-label pull-left">Lunch App</label></Col> | ||||||
|  | 					<Col xs={6}></Col> | ||||||
|  | 					<Col xs={4}> | ||||||
|  | 						<div className="pull-right"> | ||||||
|  | 						<DropdownButton id="logout-settings-dropdown" title={signedInString} onSelect={this.handleOnSelect} bsStyle="info"> | ||||||
|  | 							<MenuItem eventKey={1}>Account Settings</MenuItem> | ||||||
|  | 							<MenuItem eventKey={2}>Logout</MenuItem> | ||||||
|  | 						</DropdownButton> | ||||||
|  | 						</div> | ||||||
|  | 					</Col> | ||||||
|  | 				</Row> | ||||||
|  | 			</FormGroup> | ||||||
|  | 		); | ||||||
|  | 	} | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | module.exports = React.createClass({ | ||||||
|  | 	displayName: "TopBar", | ||||||
|  | 	render: function() { | ||||||
|  | 		var barContents; | ||||||
|  | 		var errorAlert; | ||||||
|  | 		if (!this.props.user.isUser()) | ||||||
|  | 			barContents = <LoginBar onLogin={this.props.onLogin} onCreateNewUser={this.props.onCreateNewUser} />; | ||||||
|  | 		else | ||||||
|  | 			barContents = <LogoutBar user={this.props.user} onLogout={this.props.onLogout} onAccountSettings={this.props.onAccountSettings}/>; | ||||||
|  | 		if (this.props.error.isError()) | ||||||
|  | 			errorAlert = | ||||||
|  | 					<Alert bsStyle="danger" onDismiss={this.props.onClearError}> | ||||||
|  | 						<h4>Error!</h4> | ||||||
|  | 						<p>Error {this.props.error.ErrorId}: {this.props.error.ErrorString}</p> | ||||||
|  | 						<Button onClick={this.props.onClearError}>Clear</Button> | ||||||
|  | 					</Alert>; | ||||||
|  |  | ||||||
|  | 		return ( | ||||||
|  | 			<div> | ||||||
|  | 				{barContents} | ||||||
|  | 				{errorAlert} | ||||||
|  | 			</div> | ||||||
|  | 		); | ||||||
|  | 	} | ||||||
|  | }); | ||||||
							
								
								
									
										9
									
								
								js/constants/ErrorConstants.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								js/constants/ErrorConstants.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | var keyMirror = require('keymirror'); | ||||||
|  |  | ||||||
|  | module.exports = keyMirror({ | ||||||
|  | 	ERROR_AJAX: null, | ||||||
|  | 	ERROR_SERVER: null, | ||||||
|  | 	ERROR_CLIENT: null, | ||||||
|  | 	ERROR_USER: null, | ||||||
|  | 	CLEAR_ERROR: null | ||||||
|  | }); | ||||||
							
								
								
									
										12
									
								
								js/constants/UserConstants.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								js/constants/UserConstants.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | var keyMirror = require('keymirror'); | ||||||
|  |  | ||||||
|  | module.exports = keyMirror({ | ||||||
|  | 	LOGIN_USER: null, | ||||||
|  | 	USER_LOGGEDIN: null, | ||||||
|  | 	LOGOUT_USER: null, | ||||||
|  | 	USER_LOGGEDOUT: null, | ||||||
|  | 	FETCH_USER: null, | ||||||
|  | 	USER_FETCHED: null, | ||||||
|  | 	UPDATE_USER: null, | ||||||
|  | 	USER_UPDATED: null | ||||||
|  | }); | ||||||
							
								
								
									
										21
									
								
								js/containers/AccountSettingsModalContainer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								js/containers/AccountSettingsModalContainer.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | var connect = require('react-redux').connect; | ||||||
|  |  | ||||||
|  | var UserActions = require('../actions/UserActions'); | ||||||
|  | var AccountSettingsModal = require('../components/AccountSettingsModal'); | ||||||
|  |  | ||||||
|  | function mapStateToProps(state) { | ||||||
|  | 	return { | ||||||
|  | 		user: state.user | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function mapDispatchToProps(dispatch) { | ||||||
|  | 	return { | ||||||
|  | 		onUpdateUser: function(user) {dispatch(UserActions.update(user))} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module.exports = connect( | ||||||
|  | 	mapStateToProps, | ||||||
|  | 	mapDispatchToProps | ||||||
|  | )(AccountSettingsModal) | ||||||
							
								
								
									
										22
									
								
								js/containers/LunchAppContainer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								js/containers/LunchAppContainer.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | var connect = require('react-redux').connect; | ||||||
|  |  | ||||||
|  | var UserActions = require('../actions/UserActions'); | ||||||
|  |  | ||||||
|  | var LunchApp = require('../components/LunchApp'); | ||||||
|  |  | ||||||
|  | function mapStateToProps(state) { | ||||||
|  | 	return { | ||||||
|  | 		user: state.user | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function mapDispatchToProps(dispatch) { | ||||||
|  | 	return { | ||||||
|  | 		tryResumingSession: function() {dispatch(UserActions.tryResumingSession())}, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module.exports = connect( | ||||||
|  | 	mapStateToProps, | ||||||
|  | 	mapDispatchToProps | ||||||
|  | )(LunchApp) | ||||||
							
								
								
									
										27
									
								
								js/containers/TopBarContainer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								js/containers/TopBarContainer.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | var connect = require('react-redux').connect; | ||||||
|  |  | ||||||
|  | var UserActions = require('../actions/UserActions'); | ||||||
|  | var ErrorActions = require('../actions/ErrorActions'); | ||||||
|  |  | ||||||
|  | var TopBar = require('../components/TopBar'); | ||||||
|  |  | ||||||
|  | function mapStateToProps(state) { | ||||||
|  | 	return { | ||||||
|  | 		user: state.user, | ||||||
|  | 		error: state.error | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function mapDispatchToProps(dispatch) { | ||||||
|  | 	return { | ||||||
|  | 		onLogin: function(user) {dispatch(UserActions.login(user))}, | ||||||
|  | 		onLogout: function() {dispatch(UserActions.logout())}, | ||||||
|  | 		onUpdateUser: function(user) {dispatch(UserActions.update(user))}, | ||||||
|  | 		onClearError: function() {dispatch(ErrorActions.clearError())} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module.exports = connect( | ||||||
|  | 	mapStateToProps, | ||||||
|  | 	mapDispatchToProps | ||||||
|  | )(TopBar) | ||||||
							
								
								
									
										40
									
								
								js/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								js/main.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | var React = require('react'); | ||||||
|  | var ReactDOM = require('react-dom'); | ||||||
|  |  | ||||||
|  | var Provider = require('react-redux').Provider; | ||||||
|  | var Redux = require('redux'); | ||||||
|  | var ReduxThunk = require('redux-thunk').default; | ||||||
|  |  | ||||||
|  | var Globalize = require('globalize'); | ||||||
|  | var globalizeLocalizer = require('react-widgets/lib/localizers/globalize'); | ||||||
|  |  | ||||||
|  | var LunchAppContainer = require('./containers/LunchAppContainer'); | ||||||
|  | var LunchReducer = require('./reducers/LunchReducer'); | ||||||
|  |  | ||||||
|  | // Setup globalization for react-widgets | ||||||
|  | //Globalize.load(require("cldr-data").entireSupplemental()); | ||||||
|  | Globalize.load( | ||||||
|  | 	require("cldr-data/main/en/ca-gregorian"), | ||||||
|  | 	require("cldr-data/main/en/numbers"), | ||||||
|  | 	require("cldr-data/supplemental/likelySubtags"), | ||||||
|  | 	require("cldr-data/supplemental/timeData"), | ||||||
|  | 	require("cldr-data/supplemental/weekData") | ||||||
|  | ); | ||||||
|  | Globalize.locale('en'); | ||||||
|  | globalizeLocalizer(Globalize); | ||||||
|  |  | ||||||
|  | $(document).ready(function() { | ||||||
|  | 	var store = Redux.createStore( | ||||||
|  | 		LunchReducer, | ||||||
|  | 		Redux.applyMiddleware( | ||||||
|  | 			ReduxThunk | ||||||
|  | 		) | ||||||
|  | 	); | ||||||
|  |  | ||||||
|  | 	ReactDOM.render( | ||||||
|  | 		<Provider store={store}> | ||||||
|  | 			<LunchAppContainer /> | ||||||
|  | 		</Provider>, | ||||||
|  | 		document.getElementById("content") | ||||||
|  | 	); | ||||||
|  | }); | ||||||
							
								
								
									
										115
									
								
								js/models.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								js/models.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,115 @@ | |||||||
|  | var Big = require('big.js'); | ||||||
|  |  | ||||||
|  | function getJSONObj(json_input) { | ||||||
|  | 	if (typeof json_input == "string") | ||||||
|  | 		return $.parseJSON(json_input) | ||||||
|  | 	else if (typeof json_input == "object") | ||||||
|  | 		return json_input; | ||||||
|  |  | ||||||
|  | 	console.error("Unable to parse json:", json_input); | ||||||
|  | 	return null | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function User() { | ||||||
|  | 	this.UserId = -1; | ||||||
|  | 	this.Name = ""; | ||||||
|  | 	this.Username = ""; | ||||||
|  | 	this.Password = ""; | ||||||
|  | 	this.Email = ""; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | User.prototype.toJSON = function() { | ||||||
|  | 	var json_obj = {}; | ||||||
|  | 	json_obj.UserId = this.UserId; | ||||||
|  | 	json_obj.Name = this.Name; | ||||||
|  | 	json_obj.Username = this.Username; | ||||||
|  | 	json_obj.Password = this.Password; | ||||||
|  | 	json_obj.Email = this.Email; | ||||||
|  | 	return JSON.stringify(json_obj); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | User.prototype.fromJSON = function(json_input) { | ||||||
|  | 	var json_obj = getJSONObj(json_input); | ||||||
|  |  | ||||||
|  | 	if (json_obj.hasOwnProperty("UserId")) | ||||||
|  | 		this.UserId = json_obj.UserId; | ||||||
|  | 	if (json_obj.hasOwnProperty("Name")) | ||||||
|  | 		this.Name = json_obj.Name; | ||||||
|  | 	if (json_obj.hasOwnProperty("Username")) | ||||||
|  | 		this.Username = json_obj.Username; | ||||||
|  | 	if (json_obj.hasOwnProperty("Password")) | ||||||
|  | 		this.Password = json_obj.Password; | ||||||
|  | 	if (json_obj.hasOwnProperty("Email")) | ||||||
|  | 		this.Email = json_obj.Email; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | User.prototype.isUser = function() { | ||||||
|  | 	var empty_user = new User(); | ||||||
|  | 	return this.UserId != empty_user.UserId || | ||||||
|  | 		this.Username != empty_user.Username; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function Session() { | ||||||
|  | 	this.SessionId = -1; | ||||||
|  | 	this.UserId = -1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Session.prototype.toJSON = function() { | ||||||
|  | 	var json_obj = {}; | ||||||
|  | 	json_obj.SessionId = this.SessionId; | ||||||
|  | 	json_obj.UserId = this.UserId; | ||||||
|  | 	return JSON.stringify(json_obj); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Session.prototype.fromJSON = function(json_input) { | ||||||
|  | 	var json_obj = getJSONObj(json_input); | ||||||
|  |  | ||||||
|  | 	if (json_obj.hasOwnProperty("SessionId")) | ||||||
|  | 		this.SessionId = json_obj.SessionId; | ||||||
|  | 	if (json_obj.hasOwnProperty("UserId")) | ||||||
|  | 		this.UserId = json_obj.UserId; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Session.prototype.isSession = function() { | ||||||
|  | 	var empty_session = new Session(); | ||||||
|  | 	return this.SessionId != empty_session.SessionId || | ||||||
|  | 		this.UserId != empty_session.UserId; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function Error() { | ||||||
|  | 	this.ErrorId = -1; | ||||||
|  | 	this.ErrorString = ""; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Error.prototype.toJSON = function() { | ||||||
|  | 	var json_obj = {}; | ||||||
|  | 	json_obj.ErrorId = this.ErrorId; | ||||||
|  | 	json_obj.ErrorString = this.ErrorString; | ||||||
|  | 	return JSON.stringify(json_obj); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Error.prototype.fromJSON = function(json_input) { | ||||||
|  | 	var json_obj = getJSONObj(json_input); | ||||||
|  |  | ||||||
|  | 	if (json_obj.hasOwnProperty("ErrorId")) | ||||||
|  | 		this.ErrorId = json_obj.ErrorId; | ||||||
|  | 	if (json_obj.hasOwnProperty("ErrorString")) | ||||||
|  | 		this.ErrorString = json_obj.ErrorString; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Error.prototype.isError = function() { | ||||||
|  | 	var empty_error = new Error(); | ||||||
|  | 	return this.ErrorId != empty_error.ErrorId || | ||||||
|  | 		this.ErrorString != empty_error.ErrorString; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module.exports = models = { | ||||||
|  |  | ||||||
|  | 	// Classes | ||||||
|  | 	User: User, | ||||||
|  | 	Session: Session, | ||||||
|  | 	Error: Error, | ||||||
|  |  | ||||||
|  | 	// Constants | ||||||
|  | 	BogusPassword: "password" | ||||||
|  | }; | ||||||
							
								
								
									
										17
									
								
								js/reducers/ErrorReducer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								js/reducers/ErrorReducer.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | var ErrorConstants = require('../constants/ErrorConstants'); | ||||||
|  |  | ||||||
|  | var Error = require('../models').Error; | ||||||
|  |  | ||||||
|  | module.exports = function(state = new Error(), action) { | ||||||
|  | 	switch (action.type) { | ||||||
|  | 		case ErrorConstants.ERROR_AJAX: | ||||||
|  | 		case ErrorConstants.ERROR_SERVER: | ||||||
|  | 		case ErrorConstants.ERROR_CLIENT: | ||||||
|  | 		case ErrorConstants.ERROR_USER: | ||||||
|  | 			return action.error; | ||||||
|  | 		case ErrorConstants.CLEAR_ERROR: | ||||||
|  | 			return new Error(); | ||||||
|  | 		default: | ||||||
|  | 			return state; | ||||||
|  | 	} | ||||||
|  | }; | ||||||
							
								
								
									
										11
									
								
								js/reducers/LunchReducer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								js/reducers/LunchReducer.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | var Redux = require('redux'); | ||||||
|  |  | ||||||
|  | var UserReducer = require('./UserReducer'); | ||||||
|  | var SessionReducer = require('./SessionReducer'); | ||||||
|  | var ErrorReducer = require('./ErrorReducer'); | ||||||
|  |  | ||||||
|  | module.exports = Redux.combineReducers({ | ||||||
|  | 	user: UserReducer, | ||||||
|  | 	session: SessionReducer, | ||||||
|  | 	error: ErrorReducer | ||||||
|  | }); | ||||||
							
								
								
									
										14
									
								
								js/reducers/SessionReducer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								js/reducers/SessionReducer.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | var UserConstants = require('../constants/UserConstants'); | ||||||
|  |  | ||||||
|  | var Session = require('../models').Session; | ||||||
|  |  | ||||||
|  | module.exports = function(state = new Session(), action) { | ||||||
|  | 	switch (action.type) { | ||||||
|  | 		case UserConstants.USER_LOGGEDIN: | ||||||
|  | 			return action.session; | ||||||
|  | 		case UserConstants.USER_LOGGEDOUT: | ||||||
|  | 			return new Session(); | ||||||
|  | 		default: | ||||||
|  | 			return state; | ||||||
|  | 	} | ||||||
|  | }; | ||||||
							
								
								
									
										15
									
								
								js/reducers/UserReducer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								js/reducers/UserReducer.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | var UserConstants = require('../constants/UserConstants'); | ||||||
|  |  | ||||||
|  | var User = require('../models').User; | ||||||
|  |  | ||||||
|  | module.exports = function(state = new User(), action) { | ||||||
|  | 	switch (action.type) { | ||||||
|  | 		case UserConstants.USER_FETCHED: | ||||||
|  | 		case UserConstants.USER_UPDATED: | ||||||
|  | 			return action.user; | ||||||
|  | 		case UserConstants.USER_LOGGEDOUT: | ||||||
|  | 			return new User(); | ||||||
|  | 		default: | ||||||
|  | 			return state; | ||||||
|  | 	} | ||||||
|  | }; | ||||||
							
								
								
									
										18
									
								
								static/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								static/index.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | <html> | ||||||
|  | <head> | ||||||
|  | <title>Lunch</title> | ||||||
|  |  | ||||||
|  | <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> | ||||||
|  | <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css"> | ||||||
|  | <link rel="stylesheet" href="static/react-widgets/css/react-widgets.css"> | ||||||
|  | <link rel="stylesheet" href="static/stylesheet.css"> | ||||||
|  |  | ||||||
|  | <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.js"></script> | ||||||
|  |  | ||||||
|  | <script type="text/javascript" src="static/bundle.js"></script> | ||||||
|  |  | ||||||
|  | </head> | ||||||
|  | <body> | ||||||
|  | <div id="content"></div> | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
							
								
								
									
										16
									
								
								static/stylesheet.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								static/stylesheet.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | html, body { | ||||||
|  | 	height: 100%; | ||||||
|  | } | ||||||
|  | div#content { | ||||||
|  | 	display: block; | ||||||
|  | 	width: 95%; | ||||||
|  | 	height: 100%; | ||||||
|  | 	min-width: 75em; | ||||||
|  | 	max-width: 100em; | ||||||
|  | 	margin: auto; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Keep the main windows sized to the full viewable height */ | ||||||
|  | .fullheight { | ||||||
|  | 	height: 100%; | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user