Spaces:
Running
Running
import bindAll from 'lodash.bindall'; | |
import React from 'react'; | |
import PropTypes from 'prop-types'; | |
import {connect} from 'react-redux'; | |
import { | |
defaultProjectId, | |
getIsFetchingWithoutId, | |
setProjectId | |
} from '../reducers/project-state'; | |
/* Higher Order Component to get the project id from location.hash | |
* @param {React.Component} WrappedComponent: component to render | |
* @returns {React.Component} component with hash parsing behavior | |
*/ | |
const HashParserHOC = function (WrappedComponent) { | |
class HashParserComponent extends React.Component { | |
constructor (props) { | |
super(props); | |
bindAll(this, [ | |
'handleHashChange' | |
]); | |
} | |
componentDidMount () { | |
window.addEventListener('hashchange', this.handleHashChange); | |
this.handleHashChange(); | |
} | |
componentDidUpdate (prevProps) { | |
// if we are newly fetching a non-hash project... | |
if (this.props.isFetchingWithoutId && !prevProps.isFetchingWithoutId) { | |
// ...clear the hash from the url | |
history.pushState('new-project', 'new-project', | |
window.location.pathname + window.location.search); | |
} | |
} | |
componentWillUnmount () { | |
window.removeEventListener('hashchange', this.handleHashChange); | |
} | |
handleHashChange () { | |
const hashMatch = window.location.hash.slice(1); | |
const hashProjectId = hashMatch === '' ? defaultProjectId : hashMatch; | |
this.props.setProjectId(hashProjectId.toString()); | |
} | |
render () { | |
const { | |
/* eslint-disable no-unused-vars */ | |
isFetchingWithoutId: isFetchingWithoutIdProp, | |
reduxProjectId, | |
setProjectId: setProjectIdProp, | |
/* eslint-enable no-unused-vars */ | |
...componentProps | |
} = this.props; | |
return ( | |
<WrappedComponent | |
{...componentProps} | |
/> | |
); | |
} | |
} | |
HashParserComponent.propTypes = { | |
isFetchingWithoutId: PropTypes.bool, | |
reduxProjectId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), | |
setProjectId: PropTypes.func | |
}; | |
const mapStateToProps = state => { | |
const loadingState = state.scratchGui.projectState.loadingState; | |
return { | |
isFetchingWithoutId: getIsFetchingWithoutId(loadingState), | |
reduxProjectId: state.scratchGui.projectState.projectId | |
}; | |
}; | |
const mapDispatchToProps = dispatch => ({ | |
setProjectId: projectId => { | |
dispatch(setProjectId(projectId)); | |
} | |
}); | |
// Allow incoming props to override redux-provided props. Used to mock in tests. | |
const mergeProps = (stateProps, dispatchProps, ownProps) => Object.assign( | |
{}, stateProps, dispatchProps, ownProps | |
); | |
return connect( | |
mapStateToProps, | |
mapDispatchToProps, | |
mergeProps | |
)(HashParserComponent); | |
}; | |
export { | |
HashParserHOC as default | |
}; | |