| @ -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; | |||
| } | |||
| }; | |||