Spaces:
Paused
Paused
| 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 | |
| }; | |