diff --git a/package.json b/package.json
index c5db1ea..a1f07e0 100644
--- a/package.json
+++ b/package.json
@@ -28,7 +28,8 @@
"redux-thunk": "~2.0.1",
"redux-logger": "~2.6.1",
"redux-promise": "~0.5.1",
- "immutable": "~3.7.6"
+ "immutable": "~3.7.6",
+ "react-immutable-proptypes": "~1.7.0"
},
"devDependencies": {
"babel-cli": "6.5.1",
diff --git a/src/actions/RoomActions.js b/src/actions/RoomActions.js
index a941384..d6ea652 100644
--- a/src/actions/RoomActions.js
+++ b/src/actions/RoomActions.js
@@ -11,7 +11,13 @@ import ControlRequest from "../utils/ControlRequest";
export default ({
getRoomList: () => SocketActions.send(ControlRequest.roomList()),
- join: (room) => SocketActions.send(ControlRequest.joinRoom(room)),
+ join: (room) => (dispatch) => {
+ dispatch({
+ type: ROOM_JOIN,
+ payload: room
+ });
+ dispatch(SocketActions.send(ControlRequest.joinRoom(room)));
+ },
select: (room) => ({
type: ROOM_SELECT,
@@ -19,7 +25,6 @@ export default ({
}),
say: (room, message) => (dispatch) => {
- dispatch(SocketActions.send(ControlRequest.sayRoom(room, message)));
dispatch({
type: ROOM_SAY,
payload: {
@@ -27,5 +32,6 @@ export default ({
message
}
});
+ dispatch(SocketActions.send(ControlRequest.sayRoom(room, message)));
}
});
diff --git a/src/components/RoomChatMessageList.js b/src/components/RoomChatMessageList.js
new file mode 100644
index 0000000..883c9ef
--- /dev/null
+++ b/src/components/RoomChatMessageList.js
@@ -0,0 +1,29 @@
+import React, { PropTypes } from "react";
+import ImmutablePropTypes from "react-immutable-proptypes";
+
+const RoomChatMessageList = ({ messages }) => {
+ // Append all messages in the chat room.
+ const children = [];
+ let i = 0;
+ for (const { user_name, message } of messages) {
+ children.push(
+
+ {user_name}: {message}
+
+ );
+ i++;
+ }
+
+ return (
+
+ );
+};
+
+RoomChatMessageList.propTypes = {
+ messages: ImmutablePropTypes.list.isRequired
+};
+
+export default RoomChatMessageList;
+
diff --git a/src/components/RoomList.js b/src/components/RoomList.js
index 884c3b3..d0e720d 100644
--- a/src/components/RoomList.js
+++ b/src/components/RoomList.js
@@ -20,9 +20,6 @@ class RoomList extends React.Component {
for (const [room_name, room_data] of rooms) {
const onClick = (event) => {
roomActions.select(room_name);
- if (!room_data.joined) {
- roomActions.join(room_name);
- }
};
children.push(
diff --git a/src/containers/RoomChat.js b/src/containers/RoomChat.js
index 2c70dd1..2662a5e 100644
--- a/src/containers/RoomChat.js
+++ b/src/containers/RoomChat.js
@@ -1,42 +1,73 @@
import React, { PropTypes } from "react";
-import { connect } from "react-redux";
-import RoomActions from "../actions/RoomActions";
import RoomChatForm from "../components/RoomChatForm";
+import RoomChatMessageList from "../components/RoomChatMessageList";
-const RoomChat = ({ name, data, roomActions }) => {
- if (!name) {
- return Select a room
;
+const ID = "room-chat";
+const ID_HEADER = "room-chat-header";
+
+class RoomChat extends React.Component {
+ constructor(props) {
+ super(props);
+ }
+
+ componentDidMount() {
+ this.join_if_non_member(this.props);
+ }
+
+ componentWillReceiveProps(props) {
+ this.join_if_non_member(props);
+ }
+
+ join_if_non_member(props) {
+ const { name, room, roomActions } = props;
+ if (room && room.membership == "NonMember") {
+ roomActions.join(name);
+ }
}
- // Append all messages in the chat room.
- const children = [];
- let i = 0;
- for (const { user_name, message } of data.messages) {
- children.push(
-
- {user_name}: {message}
-
+ render_only_header(string) {
+ return (
+
+
+
);
- i++;
}
- return (
-
-
-
-
+ render() {
+ const { name, room, roomActions } = this.props;
+
+ // If no room is selected, just tell the user to select one.
+ if (!name || !room) {
+ return this.render_only_header("Select a room");
+ }
+
+ switch (room.membership) {
+ case "NonMember":
+ return this.render_only_header(`Not a member of ${name}`);
+
+ case "Joining":
+ return this.render_only_header(`Joining ${name}`);
+
+ case "Leaving":
+ return this.render_only_header(`Leaving ${name}`);
+ }
+
+ // room.membership == "Member"
+ return (
+
+
+
+
-
-
- );
-};
+ );
+ }
+}
RoomChat.propTypes = {
- data: PropTypes.object,
+ room: PropTypes.object,
name: PropTypes.string,
roomActions: PropTypes.object.isRequired
};
diff --git a/src/containers/RoomsPane.js b/src/containers/RoomsPane.js
index f384a97..a4b0ed3 100644
--- a/src/containers/RoomsPane.js
+++ b/src/containers/RoomsPane.js
@@ -14,17 +14,18 @@ class RoomsPane extends React.Component {
}
render() {
+ const { actions, rooms, selected } = this.props;
return (
);
diff --git a/src/reducers/rooms.js b/src/reducers/rooms.js
index 71a45b6..5a30646 100644
--- a/src/reducers/rooms.js
+++ b/src/reducers/rooms.js
@@ -43,14 +43,24 @@ const reduceRoomList = (old_rooms, room_list) => {
return new_rooms;
};
-const reduceReceiveMessage = (rooms, payload) => {
- switch (payload.variant) {
+const reduceReceiveMessage = (rooms, { variant, data }) => {
+ switch (variant) {
+ case "JoinRoomResponse":
+ {
+ const { room_name } = data;
+ const room = rooms.get(room_name);
+ return rooms.set(room_name, {
+ ...room,
+ membership: "Member"
+ });
+ }
+
case "RoomListResponse":
- return reduceRoomList(rooms, payload.data.rooms);
+ return reduceRoomList(rooms, data.rooms);
case "SayRoomResponse":
{
- const { room_name, user_name, message } = payload.data;
+ const { room_name, user_name, message } = data;
const room_data = rooms.get(room_name);
if (!room_data) {
console.log(`Error: room "${room_name} not found`);
@@ -88,10 +98,9 @@ export default (state = initialState, action) => {
case ROOM_JOIN:
{
- const rooms = state.rooms.merge({
- [payload]: {
- joined: true
- }
+ const rooms = state.rooms.set(payload, {
+ ...state.rooms.get(payload),
+ membership: "Joining"
});
return {
...state,
diff --git a/src/styles/styles.scss b/src/styles/styles.scss
index 806f87f..dc31882 100644
--- a/src/styles/styles.scss
+++ b/src/styles/styles.scss
@@ -58,7 +58,6 @@ main {
#room-chat {
border: solid grey 0.1em;
- padding: 2em;
}
#room-list {
@@ -71,6 +70,35 @@ main {
#room-chat {
flex: 3;
+ display: flex;
+ flex-flow: column;
+}
+
+#room-chat-header {
+ text-align: center;
+ font-size: 1.3em;
+ padding: 0.8em;
+ border: solid grey 0.1em;
+}
+
+#room-chat-messages {
+ flex: 1;
+}
+
+#room-chat-form {
+ width: 100%;
+ border: solid grey 0.1em;
+}
+
+#room-chat-form form {
+ width: 100%;
+ display: flex;
+ flex-flow: row;
+}
+
+#room-chat-form input {
+ flex: 1;
+ padding: 0.8em;
}
#room-list-header {