| @ -0,0 +1,9 @@ | |||
| import { USER_GET_LIST } from "../constants/ActionTypes"; | |||
| const UserActions = { | |||
| getList: () => ({ | |||
| type: USER_GET_LIST | |||
| }) | |||
| }; | |||
| export default UserActions; | |||
| @ -0,0 +1,48 @@ | |||
| import React, { PropTypes } from "react"; | |||
| import ImmutablePropTypes from "react-immutable-proptypes"; | |||
| class UserList extends React.Component { | |||
| constructor(props) { | |||
| super(props); | |||
| } | |||
| componentDidMount() { | |||
| const { users, userActions } = this.props; | |||
| if (users.shouldUpdate()) { | |||
| userActions.getList(); | |||
| } | |||
| } | |||
| render() { | |||
| const { users, userActions } = this.props; | |||
| let children = []; | |||
| for (const [ userName, userData ] of users.byName) { | |||
| children.push( | |||
| <li key={userName}> | |||
| {userName} | |||
| </li> | |||
| ); | |||
| } | |||
| const onClick = (event) => { | |||
| event.preventDefault(); | |||
| userActions.getList(); | |||
| }; | |||
| return ( | |||
| <div className="user-list"> | |||
| <button onClick={onClick}>Refresh</button> | |||
| <ul> | |||
| {children} | |||
| </ul> | |||
| </div> | |||
| ); | |||
| } | |||
| } | |||
| UserList.propTypes = { | |||
| users: ImmutablePropTypes.record.isRequired, | |||
| userActions: PropTypes.object.isRequired | |||
| }; | |||
| export default UserList; | |||
| @ -0,0 +1,32 @@ | |||
| import React, { PropTypes } from "react"; | |||
| import { connect } from "react-redux"; | |||
| import { bindActionCreators } from "redux"; | |||
| import ImmutablePropTypes from "react-immutable-proptypes"; | |||
| import UserActions from "../actions/UserActions"; | |||
| import UserList from "../components/UserList"; | |||
| const UsersPane = ({ users, userActions }) => { | |||
| return ( | |||
| <div id="users-pane"> | |||
| <UserList users={users} userActions={userActions} /> | |||
| </div> | |||
| ); | |||
| }; | |||
| UsersPane.propTypes = { | |||
| users: ImmutablePropTypes.record.isRequired, | |||
| userActions: PropTypes.object.isRequired | |||
| }; | |||
| const mapStateToProps = ({ users }) => ({ users }); | |||
| const mapDispatchToProps = (dispatch) => ({ | |||
| userActions: bindActionCreators(UserActions, dispatch) | |||
| }); | |||
| export default connect( | |||
| mapStateToProps, | |||
| mapDispatchToProps | |||
| )(UsersPane); | |||
| @ -0,0 +1,36 @@ | |||
| import Immutable from "immutable"; | |||
| import OrderedMap from "../utils/OrderedMap"; | |||
| import { SOCKET_RECEIVE_MESSAGE } from "../constants/ActionTypes"; | |||
| const initialState = OrderedMap(); | |||
| const reduceUsersReceiveMessage = (users, message) => { | |||
| switch (message.variant) { | |||
| case "UserListResponse": | |||
| return users.updateAll(message.data.user_list, | |||
| (newUser, oldUser) => { | |||
| if (!oldUser) { | |||
| oldUser = Immutable.Map(); | |||
| } | |||
| oldUser.merge(newUser); | |||
| } | |||
| ); | |||
| default: | |||
| return users; | |||
| } | |||
| }; | |||
| const reduceUsers = (users = initialState, action) => { | |||
| switch (action.type) { | |||
| case SOCKET_RECEIVE_MESSAGE: | |||
| return reduceUsersReceiveMessage(users, action.payload); | |||
| default: | |||
| return users; | |||
| } | |||
| }; | |||
| export default reduceUsers; | |||