| @ -1,51 +1,21 @@ | |||
| import React, {PropTypes} from "react"; | |||
| import { STATE_OPEN } from "../constants/socket"; | |||
| import { LOGIN_STATUS_SUCCESS } from "../constants/login"; | |||
| import ConnectForm from "./ConnectForm"; | |||
| import Header from "./Header"; | |||
| import LoginStatusPane from "./LoginStatusPane"; | |||
| import Footer from "../containers/Footer"; | |||
| import RoomsPane from "../containers/RoomsPane"; | |||
| const ID = "solstice-app"; | |||
| const SolsticeApp = (props) => { | |||
| const { actions, login, socket } = props; | |||
| if (socket.state !== STATE_OPEN ) { | |||
| return ( | |||
| <div id={ID}> | |||
| <ConnectForm socket={socket} actions={actions} /> | |||
| </div> | |||
| ); | |||
| } | |||
| if (login.status !== LOGIN_STATUS_SUCCESS) { | |||
| return ( | |||
| <div id={ID}> | |||
| <ConnectForm socket={socket} actions={actions} /> | |||
| <LoginStatusPane {...login} loginActions={actions.login} /> | |||
| </div> | |||
| ); | |||
| } | |||
| return ( | |||
| <div id={ID}> | |||
| <Header /> | |||
| <main> | |||
| <RoomsPane roomActions={actions.room}/> | |||
| </main> | |||
| <Footer actions={actions} /> | |||
| </div> | |||
| ); | |||
| }; | |||
| const SolsticeApp = ({ children }) => ( | |||
| <div id="solstice-app"> | |||
| <Header /> | |||
| <main> | |||
| {children} | |||
| </main> | |||
| <Footer /> | |||
| </div> | |||
| ); | |||
| SolsticeApp.propTypes = { | |||
| actions: PropTypes.object.isRequired, | |||
| login: PropTypes.object.isRequired, | |||
| socket: PropTypes.object.isRequired | |||
| children: PropTypes.element | |||
| }; | |||
| export default SolsticeApp; | |||
| @ -1,38 +0,0 @@ | |||
| // This file bootstraps the app with the boilerplate necessary | |||
| // to support hot reloading in Redux | |||
| import React, {PropTypes} from "react"; | |||
| import { bindActionCreators } from "redux"; | |||
| import { connect } from "react-redux"; | |||
| import LoginActions from "../actions/LoginActions"; | |||
| import RoomActions from "../actions/RoomActions"; | |||
| import SocketActions from "../actions/SocketActions"; | |||
| import SocketHandlerActions from "../actions/SocketHandlerActions"; | |||
| import SolsticeApp from "../components/SolsticeApp"; | |||
| const App = (props) => (<SolsticeApp {...props} />); | |||
| App.propTypes = { | |||
| actions: PropTypes.object.isRequired, | |||
| login: PropTypes.object.isRequired, | |||
| socket: PropTypes.object.isRequired | |||
| }; | |||
| const mapStateToProps = ({ socket, login }) => ({ socket, login }); | |||
| function mapDispatchToProps(dispatch) { | |||
| return { | |||
| actions: { | |||
| login: bindActionCreators(LoginActions, dispatch), | |||
| room: bindActionCreators(RoomActions, dispatch), | |||
| socket: bindActionCreators(SocketActions, dispatch), | |||
| socketHandlers: bindActionCreators(SocketHandlerActions, dispatch) | |||
| } | |||
| }; | |||
| } | |||
| export default connect( | |||
| mapStateToProps, | |||
| mapDispatchToProps | |||
| )(App); | |||
| @ -0,0 +1,95 @@ | |||
| import React, { PropTypes } from "react"; | |||
| import { connect } from "react-redux"; | |||
| import { bindActionCreators } from "redux"; | |||
| import { hashHistory, withRouter } from "react-router"; | |||
| import LoginActions from "../actions/LoginActions"; | |||
| import SocketActions from "../actions/SocketActions"; | |||
| import SocketHandlerActions from "../actions/SocketHandlerActions"; | |||
| import { STATE_OPEN } from "../constants/socket"; | |||
| import { | |||
| LOGIN_STATUS_SUCCESS, | |||
| LOGIN_STATUS_UNKNOWN | |||
| } from "../constants/login"; | |||
| import ConnectForm from "../components/ConnectForm"; | |||
| import LoginStatusPane from "../components/LoginStatusPane"; | |||
| class ConnectPage extends React.Component { | |||
| constructor(props) { | |||
| super(props); | |||
| } | |||
| componentDidMount() { | |||
| this.getLoginStatusOrRedirect(this.props); | |||
| } | |||
| componentWillReceiveProps(nextProps) { | |||
| this.getLoginStatusOrRedirect(nextProps); | |||
| } | |||
| getLoginStatusOrRedirect(props) { | |||
| const { actions, login, router, socket } = props; | |||
| if (socket.state === STATE_OPEN) | |||
| { | |||
| switch (login.status) { | |||
| case LOGIN_STATUS_UNKNOWN: | |||
| actions.login.getStatus(); | |||
| break; | |||
| case LOGIN_STATUS_SUCCESS: | |||
| router.push("/app/rooms"); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| render() { | |||
| const { actions, login, socket } = this.props; | |||
| let loginStatusPane; | |||
| if (socket.state === STATE_OPEN && | |||
| login.status === LOGIN_STATUS_UNKNOWN) | |||
| { | |||
| loginStatusPane = ( | |||
| <LoginStatusPane {...login} loginActions={actions.login} /> | |||
| ); | |||
| } | |||
| return ( | |||
| <div id="connect-page"> | |||
| <ConnectForm socket={socket} actions={actions} /> | |||
| {loginStatusPane} | |||
| </div> | |||
| ); | |||
| } | |||
| } | |||
| ConnectPage.propTypes = { | |||
| actions: PropTypes.shape({ | |||
| login: PropTypes.object.isRequired, | |||
| socket: PropTypes.object.isRequired, | |||
| socketHandlers: PropTypes.object.isRequired | |||
| }).isRequired, | |||
| login: PropTypes.object.isRequired, | |||
| router: PropTypes.object.isRequired, | |||
| socket: PropTypes.object.isRequired | |||
| }; | |||
| const mapStateToProps = ({ login, socket }) => ({ login, socket }); | |||
| const mapDispatchToProps = (dispatch) => ({ | |||
| actions: { | |||
| login: bindActionCreators(LoginActions, dispatch), | |||
| socket: bindActionCreators(SocketActions, dispatch), | |||
| socketHandlers: bindActionCreators(SocketHandlerActions, dispatch) | |||
| } | |||
| }); | |||
| export default connect( | |||
| mapStateToProps, | |||
| mapDispatchToProps | |||
| )(withRouter(ConnectPage)); | |||
| @ -0,0 +1,33 @@ | |||
| import React, { PropTypes } from 'react'; | |||
| import { Route, IndexRoute } from 'react-router'; | |||
| import ConnectPage from "./containers/ConnectPage"; | |||
| import RoomsPane from "./containers/RoomsPane"; | |||
| import SolsticeApp from "./components/SolsticeApp"; | |||
| import { STATE_OPEN } from "./constants/socket"; | |||
| import { LOGIN_STATUS_SUCCESS } from "./constants/login"; | |||
| const createRoutes = (store) => { | |||
| const requireLoggedIn = (nextState, replaceState) => { | |||
| let { socket, login } = store.getState(); | |||
| if (socket.state !== STATE_OPEN || | |||
| login.status !== LOGIN_STATUS_SUCCESS) | |||
| { | |||
| replaceState({}, "/"); | |||
| } | |||
| }; | |||
| return ( | |||
| <Route path="/"> | |||
| <IndexRoute component={ConnectPage} /> | |||
| <Route path="app" onEnter={requireLoggedIn} component={SolsticeApp}> | |||
| <Route path="rooms(/:roomName)" component={RoomsPane} /> | |||
| </Route> | |||
| </Route> | |||
| ); | |||
| }; | |||
| export default createRoutes; | |||
| @ -1,14 +1,20 @@ | |||
| import React from 'react'; | |||
| import {render} from 'react-dom'; | |||
| import { Provider } from 'react-redux'; | |||
| import App from './containers/App'; | |||
| import { Router, hashHistory } from "react-router"; | |||
| import configureStore from './store/configureStore'; | |||
| import createRoutes from "./createRoutes"; | |||
| import './styles/styles.scss'; //Yep, that's right. You can import SASS/CSS files too! Webpack will run the associated loader and plug this into the page. | |||
| const store = configureStore(); | |||
| const routes = createRoutes(store); | |||
| render( | |||
| <Provider store={store}> | |||
| <App /> | |||
| <Router history={hashHistory}> | |||
| {routes} | |||
| </Router> | |||
| </Provider>, document.getElementById('app') | |||
| ); | |||