fix #180, relates to #185 in that the user is redirected to where they were post signup/login

This commit is contained in:
Cassie Tarakajian 2016-11-10 16:13:00 -05:00
parent c959aec6a9
commit 66b83df0f2
12 changed files with 72 additions and 31 deletions

View file

@ -104,3 +104,4 @@ export const RESET_JUST_OPENED_PROJECT = 'RESET_JUST_OPENED_PROJECT';
export const SET_PROJECT_SAVED_TIME = 'SET_PROJECT_SAVED_TIME'; export const SET_PROJECT_SAVED_TIME = 'SET_PROJECT_SAVED_TIME';
export const RESET_PROJECT_SAVED_TIME = 'RESET_PROJECT_SAVED_TIME'; export const RESET_PROJECT_SAVED_TIME = 'RESET_PROJECT_SAVED_TIME';
export const SET_PREVIOUS_PATH = 'SET_PREVIOUS_PATH';

View file

@ -220,3 +220,10 @@ export function resetProjectSavedTime() {
type: ActionTypes.RESET_PROJECT_SAVED_TIME, type: ActionTypes.RESET_PROJECT_SAVED_TIME,
}; };
} }
export function setPreviousPath(path) {
return {
type: ActionTypes.SET_PREVIOUS_PATH,
path
};
}

View file

@ -1,5 +1,4 @@
import * as ActionTypes from '../../../constants'; import * as ActionTypes from '../../../constants';
import { browserHistory } from 'react-router';
import axios from 'axios'; import axios from 'axios';
const ROOT_URL = location.href.indexOf('localhost') > 0 ? 'http://localhost:8000/api' : '/api'; const ROOT_URL = location.href.indexOf('localhost') > 0 ? 'http://localhost:8000/api' : '/api';
@ -26,10 +25,6 @@ export function getProjects(username) {
}; };
} }
export function closeSketchList() {
browserHistory.goBack();
}
export function deleteProject(id) { export function deleteProject(id) {
return (dispatch) => { return (dispatch) => {
axios.delete(`${ROOT_URL}/projects/${id}`, { withCredentials: true }) axios.delete(`${ROOT_URL}/projects/${id}`, { withCredentials: true })

View file

@ -1,15 +1,20 @@
import React from 'react'; import React, { PropTypes } from 'react';
import InlineSVG from 'react-inlinesvg'; import InlineSVG from 'react-inlinesvg';
const exitUrl = require('../../../images/exit.svg'); const exitUrl = require('../../../images/exit.svg');
import { browserHistory } from 'react-router'; import { browserHistory } from 'react-router';
class About extends React.Component { class About extends React.Component {
constructor(props) {
super(props);
this.closeAboutModal = this.closeAboutModal.bind(this);
}
componentDidMount() { componentDidMount() {
this.refs.about.focus(); this.refs.about.focus();
} }
closeAboutModal() { closeAboutModal() {
browserHistory.goBack(); browserHistory.push(this.props.previousPath);
} }
render() { render() {
@ -42,4 +47,8 @@ class About extends React.Component {
} }
} }
About.propTypes = {
previousPath: PropTypes.string.isRequired
};
export default About; export default About;

View file

@ -3,7 +3,7 @@ import React, { PropTypes } from 'react';
function LoginForm(props) { function LoginForm(props) {
const { fields: { email, password }, handleSubmit, submitting, pristine } = props; const { fields: { email, password }, handleSubmit, submitting, pristine } = props;
return ( return (
<form className="login-form" onSubmit={handleSubmit(props.validateAndLoginUser.bind(this))}> <form className="login-form" onSubmit={handleSubmit(props.validateAndLoginUser.bind(this, props.previousPath))}>
<p className="login-form__field"> <p className="login-form__field">
<input <input
className="login-form__email-input" className="login-form__email-input"
@ -38,7 +38,8 @@ LoginForm.propTypes = {
validateAndLoginUser: PropTypes.func.isRequired, validateAndLoginUser: PropTypes.func.isRequired,
submitting: PropTypes.bool, submitting: PropTypes.bool,
invalid: PropTypes.bool, invalid: PropTypes.bool,
pristine: PropTypes.bool pristine: PropTypes.bool,
previousPath: PropTypes.string.isRequired
}; };
export default LoginForm; export default LoginForm;

View file

@ -32,9 +32,10 @@ class LoginView extends React.Component {
} }
} }
function mapStateToProps(state) { function mapStateToProps(state, ownProps) {
return { return {
user: state.user user: state.user,
previousPath: ownProps.previousPath
}; };
} }

View file

@ -3,7 +3,7 @@ import React, { PropTypes } from 'react';
function SignupForm(props) { function SignupForm(props) {
const { fields: { username, email, password, confirmPassword }, handleSubmit, submitting, invalid, pristine } = props; const { fields: { username, email, password, confirmPassword }, handleSubmit, submitting, invalid, pristine } = props;
return ( return (
<form className="signup-form" onSubmit={handleSubmit(props.signUpUser.bind(this))}> <form className="signup-form" onSubmit={handleSubmit(props.signUpUser.bind(this, props.previousPath))}>
<p className="signup-form__field"> <p className="signup-form__field">
<input <input
className="signup-form__username-input" className="signup-form__username-input"
@ -60,7 +60,8 @@ SignupForm.propTypes = {
signUpUser: PropTypes.func.isRequired, signUpUser: PropTypes.func.isRequired,
submitting: PropTypes.bool, submitting: PropTypes.bool,
invalid: PropTypes.bool, invalid: PropTypes.bool,
pristine: PropTypes.bool pristine: PropTypes.bool,
previousPath: PropTypes.string.isRequired
}; };
export default SignupForm; export default SignupForm;

View file

@ -26,9 +26,10 @@ class SignupView extends React.Component {
} }
} }
function mapStateToProps(state) { function mapStateToProps(state, ownProps) {
return { return {
user: state.user user: state.user,
previousPath: ownProps.previousPath
}; };
} }

View file

@ -2,7 +2,7 @@ import React, { PropTypes } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import moment from 'moment'; import moment from 'moment';
import { Link } from 'react-router'; import { Link, browserHistory } from 'react-router';
import * as SketchActions from '../actions/projects'; import * as SketchActions from '../actions/projects';
import * as ProjectActions from '../actions/project'; import * as ProjectActions from '../actions/project';
import InlineSVG from 'react-inlinesvg'; import InlineSVG from 'react-inlinesvg';
@ -10,17 +10,26 @@ const exitUrl = require('../../../images/exit.svg');
const trashCan = require('../../../images/trash-can.svg'); const trashCan = require('../../../images/trash-can.svg');
class SketchList extends React.Component { class SketchList extends React.Component {
constructor(props) {
super(props);
this.closeSketchList = this.closeSketchList.bind(this);
}
componentDidMount() { componentDidMount() {
this.props.getProjects(this.props.username); this.props.getProjects(this.props.username);
document.getElementById('sketchlist').focus(); document.getElementById('sketchlist').focus();
} }
closeSketchList() {
browserHistory.push(this.props.previousPath);
}
render() { render() {
return ( return (
<section className="sketch-list" aria-label="project list" tabIndex="0" role="main" id="sketchlist"> <section className="sketch-list" aria-label="project list" tabIndex="0" role="main" id="sketchlist">
<header className="sketch-list__header"> <header className="sketch-list__header">
<h2>Sketches</h2> <h2>Sketches</h2>
<button className="sketch-list__exit-button" onClick={this.props.closeSketchList}> <button className="sketch-list__exit-button" onClick={this.closeSketchList}>
<InlineSVG src={exitUrl} alt="Close Sketch List Overlay" /> <InlineSVG src={exitUrl} alt="Close Sketch List Overlay" />
</button> </button>
</header> </header>
@ -72,9 +81,9 @@ SketchList.propTypes = {
user: PropTypes.object.isRequired, user: PropTypes.object.isRequired,
getProjects: PropTypes.func.isRequired, getProjects: PropTypes.func.isRequired,
sketches: PropTypes.array.isRequired, sketches: PropTypes.array.isRequired,
closeSketchList: PropTypes.func.isRequired,
username: PropTypes.string, username: PropTypes.string,
deleteProject: PropTypes.func.isRequired deleteProject: PropTypes.func.isRequired,
previousPath: PropTypes.string.isRequired
}; };
function mapStateToProps(state) { function mapStateToProps(state) {

View file

@ -69,6 +69,12 @@ class IDEView extends React.Component {
document.body.className = this.props.preferences.theme; document.body.className = this.props.preferences.theme;
} }
componentWillReceiveProps(nextProps) {
if (nextProps.location !== this.props.location) {
this.props.setPreviousPath(this.props.location.pathname);
}
}
componentWillUpdate(nextProps) { componentWillUpdate(nextProps) {
if (this.props.ide.consoleIsExpanded !== nextProps.ide.consoleIsExpanded) { if (this.props.ide.consoleIsExpanded !== nextProps.ide.consoleIsExpanded) {
this.consoleSize = nextProps.ide.consoleIsExpanded ? 180 : 29; this.consoleSize = nextProps.ide.consoleIsExpanded ? 180 : 29;
@ -366,7 +372,10 @@ class IDEView extends React.Component {
if (this.props.location.pathname.match(/sketches$/)) { if (this.props.location.pathname.match(/sketches$/)) {
return ( return (
<Overlay> <Overlay>
<SketchList username={this.props.params.username} /> <SketchList
username={this.props.params.username}
previousPath={this.props.ide.previousPath}
/>
</Overlay> </Overlay>
); );
} }
@ -375,7 +384,7 @@ class IDEView extends React.Component {
if (this.props.location.pathname === '/about') { if (this.props.location.pathname === '/about') {
return ( return (
<Overlay> <Overlay>
<About /> <About previousPath={this.props.ide.previousPath} />
</Overlay> </Overlay>
); );
} }
@ -407,7 +416,7 @@ class IDEView extends React.Component {
if (this.props.location.pathname === '/login') { if (this.props.location.pathname === '/login') {
return ( return (
<Overlay> <Overlay>
<LoginView /> <LoginView previousPath={this.props.ide.previousPath} />
</Overlay> </Overlay>
); );
} }
@ -416,7 +425,7 @@ class IDEView extends React.Component {
if (this.props.location.pathname === '/signup') { if (this.props.location.pathname === '/signup') {
return ( return (
<Overlay> <Overlay>
<SignupView /> <SignupView previousPath={this.props.ide.previousPath} />
</Overlay> </Overlay>
); );
} }
@ -434,7 +443,9 @@ class IDEView extends React.Component {
if (this.props.location.pathname.match(/\/reset-password\/[a-fA-F0-9]+/)) { if (this.props.location.pathname.match(/\/reset-password\/[a-fA-F0-9]+/)) {
return ( return (
<Overlay> <Overlay>
<NewPasswordView token={this.props.params.reset_password_token} /> <NewPasswordView
token={this.props.params.reset_password_token}
/>
</Overlay> </Overlay>
); );
} }
@ -479,7 +490,8 @@ IDEView.propTypes = {
infiniteLoop: PropTypes.bool.isRequired, infiniteLoop: PropTypes.bool.isRequired,
previewIsRefreshing: PropTypes.bool.isRequired, previewIsRefreshing: PropTypes.bool.isRequired,
infiniteLoopMessage: PropTypes.string.isRequired, infiniteLoopMessage: PropTypes.string.isRequired,
projectSavedTime: PropTypes.string.isRequired projectSavedTime: PropTypes.string.isRequired,
previousPath: PropTypes.string.isRequired
}).isRequired, }).isRequired,
startSketch: PropTypes.func.isRequired, startSketch: PropTypes.func.isRequired,
stopSketch: PropTypes.func.isRequired, stopSketch: PropTypes.func.isRequired,
@ -578,7 +590,8 @@ IDEView.propTypes = {
startSketchAndRefresh: PropTypes.func.isRequired, startSketchAndRefresh: PropTypes.func.isRequired,
endSketchRefresh: PropTypes.func.isRequired, endSketchRefresh: PropTypes.func.isRequired,
startRefreshSketch: PropTypes.func.isRequired, startRefreshSketch: PropTypes.func.isRequired,
setBlobUrl: PropTypes.func.isRequired setBlobUrl: PropTypes.func.isRequired,
setPreviousPath: PropTypes.func.isRequired
}; };
function mapStateToProps(state) { function mapStateToProps(state) {

View file

@ -18,7 +18,8 @@ const initialState = {
previewIsRefreshing: false, previewIsRefreshing: false,
infiniteLoopMessage: '', infiniteLoopMessage: '',
projectJustOpened: false, projectJustOpened: false,
projectSavedTime: '' projectSavedTime: '',
previousPath: '/'
}; };
const ide = (state = initialState, action) => { const ide = (state = initialState, action) => {
@ -89,6 +90,8 @@ const ide = (state = initialState, action) => {
return Object.assign({}, state, { projectSavedTime: action.value }); return Object.assign({}, state, { projectSavedTime: action.value });
case ActionTypes.RESET_PROJECT_SAVED_TIME: case ActionTypes.RESET_PROJECT_SAVED_TIME:
return Object.assign({}, state, { projectSavedTime: '' }); return Object.assign({}, state, { projectSavedTime: '' });
case ActionTypes.SET_PREVIOUS_PATH:
return Object.assign({}, state, { previousPath: action.path });
default: default:
return state; return state;
} }

View file

@ -12,14 +12,14 @@ export function authError(error) {
}; };
} }
export function signUpUser(formValues) { export function signUpUser(previousPath, formValues) {
return (dispatch) => { return (dispatch) => {
axios.post(`${ROOT_URL}/signup`, formValues, { withCredentials: true }) axios.post(`${ROOT_URL}/signup`, formValues, { withCredentials: true })
.then(response => { .then(response => {
dispatch({ type: ActionTypes.AUTH_USER, dispatch({ type: ActionTypes.AUTH_USER,
user: response.data user: response.data
}); });
browserHistory.push('/'); browserHistory.push(previousPath);
}) })
.catch(response => dispatch(authError(response.data.error))); .catch(response => dispatch(authError(response.data.error)));
}; };
@ -43,7 +43,7 @@ export function loginUserFailure(error) {
}; };
} }
export function validateAndLoginUser(formProps, dispatch) { export function validateAndLoginUser(previousPath, formProps, dispatch) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
loginUser(formProps) loginUser(formProps)
.then(response => { .then(response => {
@ -54,7 +54,7 @@ export function validateAndLoginUser(formProps, dispatch) {
type: ActionTypes.SET_PREFERENCES, type: ActionTypes.SET_PREFERENCES,
preferences: response.data.preferences preferences: response.data.preferences
}); });
browserHistory.push('/'); browserHistory.push(previousPath);
resolve(); resolve();
}) })
.catch(response => { .catch(response => {