| @ -0,0 +1,11 @@ | |||||
| import React, { PropTypes } from "react"; | |||||
| const Room = ({ name }) => { | |||||
| return <div className="room">{name}</div>; | |||||
| }; | |||||
| Room.propTypes = { | |||||
| name: PropTypes.string.isRequired | |||||
| }; | |||||
| export default Room; | |||||
| @ -0,0 +1,26 @@ | |||||
| import React, { PropTypes } from "react"; | |||||
| import Room from "./Room"; | |||||
| const RoomList = ({ rooms }) => { | |||||
| const children = []; | |||||
| for (const [room_name, room_data] of rooms) { | |||||
| children.push( | |||||
| <li key={room_name}> | |||||
| <Room name={room_name} {...room_data} /> | |||||
| </li> | |||||
| ); | |||||
| } | |||||
| return ( | |||||
| <div id="room-list"> | |||||
| <div id="room-list-header">Room List</div> | |||||
| <ul> {children} </ul> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| RoomList.propTypes = { | |||||
| rooms: PropTypes.object.isRequired | |||||
| }; | |||||
| export default RoomList; | |||||
| @ -0,0 +1,40 @@ | |||||
| import React, { PropTypes } from "react"; | |||||
| import { connect } from "react-redux"; | |||||
| import RoomList from "../components/RoomList"; | |||||
| import ControlRequest from "../utils/ControlRequest"; | |||||
| const ID = "rooms-pane"; | |||||
| class RoomsPane extends React.Component { | |||||
| constructor(props) { | |||||
| super(props); | |||||
| } | |||||
| componentDidMount() { | |||||
| this.props.socketSend(ControlRequest.roomList()); | |||||
| } | |||||
| render() { | |||||
| const onClick = (event) => { | |||||
| this.props.socketSend(ControlRequest.roomList()); | |||||
| event.preventDefault(); | |||||
| }; | |||||
| return ( | |||||
| <div id={ID}> | |||||
| <button onClick={onClick}>Refresh</button> | |||||
| <RoomList rooms={this.props.rooms} /> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| } | |||||
| RoomsPane.propTypes = { | |||||
| rooms: PropTypes.object.isRequired, | |||||
| socketSend: PropTypes.func.isRequired | |||||
| }; | |||||
| export default connect( | |||||
| state => state.rooms | |||||
| )(RoomsPane); | |||||
| @ -0,0 +1,53 @@ | |||||
| import { SOCKET_RECEIVE_MESSAGE } from "../constants/ActionTypes"; | |||||
| const initialState = { | |||||
| rooms: new Map() | |||||
| }; | |||||
| const reduceRoomList = (old_rooms, room_list) => { | |||||
| // First sort the room list by room name | |||||
| room_list.sort((room_pair_1, room_pair_2) => { | |||||
| const name_1 = room_pair_1[0]; | |||||
| const name_2 = room_pair_2[0]; | |||||
| if (name_1 < name_2) { | |||||
| return -1; | |||||
| } else if (name_1 > name_2) { | |||||
| return 1; | |||||
| } | |||||
| return 0; | |||||
| }); | |||||
| // Then build the new rooms map | |||||
| const new_rooms = new Map(); | |||||
| for (const [ room_name, room_data ] of room_list) { | |||||
| const old_data = old_rooms.get(room_name); | |||||
| if (old_data) { | |||||
| new_rooms.set(room_name, { ...old_data, ...room_data }); | |||||
| } else { | |||||
| new_rooms.set(room_name, room_data); | |||||
| } | |||||
| } | |||||
| return new_rooms; | |||||
| }; | |||||
| const reduceReceiveMessage = (state, payload) => { | |||||
| switch (payload.variant) { | |||||
| case "RoomListResponse": | |||||
| { | |||||
| const rooms = reduceRoomList(state.rooms, payload.data.rooms); | |||||
| return { ...state, rooms }; | |||||
| } | |||||
| default: | |||||
| return state; | |||||
| } | |||||
| }; | |||||
| export default (state = initialState, action) => { | |||||
| const { type, payload } = action; | |||||
| switch (type) { | |||||
| case SOCKET_RECEIVE_MESSAGE: | |||||
| return reduceReceiveMessage(state, payload); | |||||
| default: | |||||
| return state; | |||||
| } | |||||
| }; | |||||