From 93fc42831d648f3bd361aaf41321c2f47c7c751c Mon Sep 17 00:00:00 2001 From: Titouan Rigoudy Date: Tue, 24 May 2016 16:23:19 +0200 Subject: [PATCH] Add very basic UsersPane. --- src/actions/UserActions.js | 9 +++++++ src/components/Header.js | 3 +++ src/components/RoomList.js | 7 ++++-- src/components/UserList.js | 48 ++++++++++++++++++++++++++++++++++++ src/constants/ActionTypes.js | 3 +++ src/containers/UsersPane.js | 32 ++++++++++++++++++++++++ src/createRoutes.js | 2 ++ src/reducers/index.js | 2 ++ src/reducers/socket.js | 4 +++ src/reducers/users.js | 36 +++++++++++++++++++++++++++ src/utils/ControlRequest.js | 5 ++++ src/utils/OrderedMap.js | 18 +++++++++++--- 12 files changed, 164 insertions(+), 5 deletions(-) create mode 100644 src/actions/UserActions.js create mode 100644 src/components/UserList.js create mode 100644 src/containers/UsersPane.js create mode 100644 src/reducers/users.js diff --git a/src/actions/UserActions.js b/src/actions/UserActions.js new file mode 100644 index 0000000..86765a9 --- /dev/null +++ b/src/actions/UserActions.js @@ -0,0 +1,9 @@ +import { USER_GET_LIST } from "../constants/ActionTypes"; + +const UserActions = { + getList: () => ({ + type: USER_GET_LIST + }) +}; + +export default UserActions; diff --git a/src/components/Header.js b/src/components/Header.js index 70c1dfc..60eb534 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -8,6 +8,9 @@ const Header = (props) => { Rooms + + Users + ); }; diff --git a/src/components/RoomList.js b/src/components/RoomList.js index 173ccb1..5b6c17b 100644 --- a/src/components/RoomList.js +++ b/src/components/RoomList.js @@ -10,7 +10,10 @@ class RoomList extends React.Component { } componentDidMount() { - this.props.roomActions.getList(); + const { rooms, roomActions } = this.props; + if (rooms.shouldUpdate()) { + roomActions.getList(); + } } render() { @@ -18,7 +21,7 @@ class RoomList extends React.Component { const children = []; - for (const [roomName, roomData] of rooms.get("byName")) { + for (const [roomName, roomData] of rooms.byName) { children.push(
  • + {userName} +
  • + ); + } + + const onClick = (event) => { + event.preventDefault(); + userActions.getList(); + }; + + return ( +
    + + +
    + ); + } +} + +UserList.propTypes = { + users: ImmutablePropTypes.record.isRequired, + userActions: PropTypes.object.isRequired +}; + +export default UserList; diff --git a/src/constants/ActionTypes.js b/src/constants/ActionTypes.js index b76289c..1571f0d 100644 --- a/src/constants/ActionTypes.js +++ b/src/constants/ActionTypes.js @@ -18,3 +18,6 @@ export const ROOM_LEAVE = "ROOM_LEAVE"; export const ROOM_MESSAGE = "ROOM_MESSAGE"; export const ROOM_SHOW_USERS = "ROOM_SHOW_USERS"; export const ROOM_HIDE_USERS = "ROOM_HIDE_USERS"; + +// User actions +export const USER_GET_LIST = "USER_GET_LIST"; diff --git a/src/containers/UsersPane.js b/src/containers/UsersPane.js new file mode 100644 index 0000000..a300a80 --- /dev/null +++ b/src/containers/UsersPane.js @@ -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 ( +
    + +
    + ); +}; + +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); diff --git a/src/createRoutes.js b/src/createRoutes.js index 2865873..aa17be7 100644 --- a/src/createRoutes.js +++ b/src/createRoutes.js @@ -3,6 +3,7 @@ import { Route, IndexRoute } from 'react-router'; import ConnectPage from "./containers/ConnectPage"; import RoomsPane from "./containers/RoomsPane"; +import UsersPane from "./containers/UsersPane"; import SolsticeApp from "./components/SolsticeApp"; @@ -25,6 +26,7 @@ const createRoutes = (store) => { + ); diff --git a/src/reducers/index.js b/src/reducers/index.js index 2cb569a..7fe5266 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -4,11 +4,13 @@ import { reducer as form } from "redux-form"; import login from "./login"; import rooms from "./rooms"; import socket from "./socket"; +import users from "./users"; const rootReducer = combineReducers({ login, rooms, socket, + users, form }); diff --git a/src/reducers/socket.js b/src/reducers/socket.js index 1f04f8e..8b38243 100644 --- a/src/reducers/socket.js +++ b/src/reducers/socket.js @@ -79,6 +79,10 @@ export default (state = initialState, { type, payload }) => { return state; } + case types.USER_GET_LIST: + sendRequest(ControlRequest.userList()); + return state; + default: return state; } diff --git a/src/reducers/users.js b/src/reducers/users.js new file mode 100644 index 0000000..e5ca049 --- /dev/null +++ b/src/reducers/users.js @@ -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; diff --git a/src/utils/ControlRequest.js b/src/utils/ControlRequest.js index 332b457..cd84558 100644 --- a/src/utils/ControlRequest.js +++ b/src/utils/ControlRequest.js @@ -25,5 +25,10 @@ export default { room_name, message }] + }), + + userList: () =>({ + variant: "UserListRequest", + fields: [] }) }; diff --git a/src/utils/OrderedMap.js b/src/utils/OrderedMap.js index b370a0f..9c75c5c 100644 --- a/src/utils/OrderedMap.js +++ b/src/utils/OrderedMap.js @@ -1,9 +1,13 @@ import Immutable from "immutable"; import md5 from "md5"; +// Updates should be requested every 5 minutes at most. +const UPDATE_INTERVAL_MS = 5 * 60 * 1000; + const MapRecord = Immutable.Record({ - byName: Immutable.OrderedMap(), - byHash: Immutable.Map() + byName: Immutable.OrderedMap(), + byHash: Immutable.Map(), + lastUpdated: 0 }); class OrderedMap extends MapRecord { @@ -63,7 +67,15 @@ class OrderedMap extends MapRecord { newByName = newByName.set(name, mergedData); } - return new OrderedMap({ byName: newByName, byHash }); + return new OrderedMap({ + byName: newByName, + byHash, + lastUpdated: Date.now() + }); + } + + shouldUpdate() { + return (Date.now() - this.lastUpdated) > UPDATE_INTERVAL_MS; } }