+
-
+
-
+
);
};
diff --git a/src/constants/ActionTypes.js b/src/constants/ActionTypes.js
index b57911c..5d86977 100644
--- a/src/constants/ActionTypes.js
+++ b/src/constants/ActionTypes.js
@@ -1,11 +1,12 @@
// Socket actions
-export const SOCKET_SET_OPEN = Symbol("SOCKET_SET_OPEN");
-export const SOCKET_SET_OPENING = Symbol("SOCKET_SET_OPENING");
-export const SOCKET_SET_CLOSED = Symbol("SOCKET_SET_CLOSED");
-export const SOCKET_SET_CLOSING = Symbol("SOCKET_SET_CLOSING");
-export const SOCKET_SET_ERROR = Symbol("SOCKET_SET_ERROR");
+export const SOCKET_SET_OPEN = Symbol("SOCKET_SET_OPEN");
+export const SOCKET_SET_OPENING = Symbol("SOCKET_SET_OPENING");
+export const SOCKET_SET_CLOSED = Symbol("SOCKET_SET_CLOSED");
+export const SOCKET_SET_CLOSING = Symbol("SOCKET_SET_CLOSING");
+export const SOCKET_SET_ERROR = Symbol("SOCKET_SET_ERROR");
export const SOCKET_RECEIVE_MESSAGE = Symbol("SOCKET_RECEIVE_MESSAGE");
-export const SOCKET_SEND_MESSAGE = Symbol("SOCKET_SEND_MESSAGE");
+export const SOCKET_SEND_MESSAGE = Symbol("SOCKET_SEND_MESSAGE");
// Room actions
export const ROOM_SELECT = Symbol("ROOM_SELECT");
+export const ROOM_JOIN = Symbol("ROOM_JOIN");
diff --git a/src/containers/App.js b/src/containers/App.js
index 9c25550..3a31357 100644
--- a/src/containers/App.js
+++ b/src/containers/App.js
@@ -4,9 +4,12 @@ import React, {PropTypes} from "react";
import { bindActionCreators } from "redux";
import { connect } from "react-redux";
+import SocketActionsFactory from "../actions/SocketActionsFactory";
+import SocketHandlerActions from "../actions/SocketHandlerActions";
+import RoomActionsFactory from "../actions/RoomActionsFactory";
+
import SolsticeApp from "../components/SolsticeApp";
-import socketActionsFactory from "../actions/socketActionsFactory";
-import socketHandlerActions from "../actions/socketHandlerActions";
+
import SocketClient from "../utils/SocketClient";
const App = (props) => (
);
@@ -16,19 +19,17 @@ App.propTypes = {
socket: PropTypes.object.isRequired
};
-function mapStateToProps(state) {
- return {
- socket: state.socket
- };
-}
+const mapStateToProps = ({ socket }) => ({ socket });
function mapDispatchToProps(dispatch) {
- const callbacks = bindActionCreators(socketHandlerActions, dispatch);
+ const callbacks = bindActionCreators(SocketHandlerActions, dispatch);
const socketClient = new SocketClient(callbacks);
- const socketActions = socketActionsFactory(socketClient);
+ const socketActions = SocketActionsFactory(socketClient);
+ const roomActions = RoomActionsFactory(socketActions);
return {
actions: {
- socketActions: bindActionCreators(socketActions, dispatch)
+ room: bindActionCreators(roomActions, dispatch),
+ socket: bindActionCreators(socketActions, dispatch)
}
};
}
diff --git a/src/containers/Footer.js b/src/containers/Footer.js
new file mode 100644
index 0000000..664d389
--- /dev/null
+++ b/src/containers/Footer.js
@@ -0,0 +1,26 @@
+import React, { PropTypes } from "react";
+import { connect } from "react-redux";
+
+import LoginStatusPane from "../components/LoginStatusPane";
+import SocketStatusPane from "../components/SocketStatusPane";
+
+const Footer = ({ actions, login, socket }) => {
+ return (
+
+ );
+};
+
+Footer.propTypes = {
+ actions: PropTypes.object.isRequired,
+ login: PropTypes.object.isRequired,
+ socket: PropTypes.object.isRequired
+};
+
+const mapStateToProps = ({ socket, login }) => ({ socket, login });
+
+export default connect(
+ mapStateToProps
+)(Footer);
diff --git a/src/containers/RoomChat.js b/src/containers/RoomChat.js
index 2f6cccc..b1d0206 100644
--- a/src/containers/RoomChat.js
+++ b/src/containers/RoomChat.js
@@ -6,7 +6,7 @@ const RoomChat = ({ name }) => {
};
RoomChat.propTypes = {
- name: PropTypes.string.isRequired
+ name: PropTypes.string
};
export default connect(
diff --git a/src/containers/RoomsPane.js b/src/containers/RoomsPane.js
index bfff689..ab1fee1 100644
--- a/src/containers/RoomsPane.js
+++ b/src/containers/RoomsPane.js
@@ -6,8 +6,6 @@ import RoomList from "../components/RoomList";
import RoomChat from "../containers/RoomChat";
-import roomActions from "../actions/roomActions";
-
import ControlRequest from "../utils/ControlRequest";
class RoomsPane extends React.Component {
@@ -15,40 +13,27 @@ class RoomsPane extends React.Component {
super(props);
}
- componentDidMount() {
- this.props.socketSend(ControlRequest.roomList());
- }
-
render() {
- const refresh = () => {
- this.props.socketSend(ControlRequest.roomList());
- };
-
return (
-
+ roomActions={this.props.actions.room}
+ selected={this.props.selected}
+ />
+
);
}
}
RoomsPane.propTypes = {
- rooms: PropTypes.object.isRequired,
- roomActions: PropTypes.object.isRequired,
- socketSend: PropTypes.func.isRequired
+ actions: PropTypes.object.isRequired,
+ rooms: PropTypes.object.isRequired
};
const mapStateToProps = (state) => state.rooms;
-const mapDispatchToProps = (dispatch) => ({
- roomActions: bindActionCreators(roomActions, dispatch)
-});
-
export default connect(
mapStateToProps,
- mapDispatchToProps
)(RoomsPane);
diff --git a/src/reducers/rooms.js b/src/reducers/rooms.js
index afd3ed9..ade3b60 100644
--- a/src/reducers/rooms.js
+++ b/src/reducers/rooms.js
@@ -1,7 +1,13 @@
-import { ROOM_SELECT, SOCKET_RECEIVE_MESSAGE } from "../constants/ActionTypes";
+import Immutable from "immutable";
+
+import {
+ ROOM_JOIN,
+ ROOM_SELECT,
+ SOCKET_RECEIVE_MESSAGE
+} from "../constants/ActionTypes";
const initialState = {
- rooms: new Map(),
+ rooms: Immutable.OrderedMap(),
selected: null
};
@@ -19,13 +25,16 @@ const reduceRoomList = (old_rooms, room_list) => {
});
// Then build the new rooms map
- const new_rooms = new Map();
+ let new_rooms = Immutable.OrderedMap();
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 });
+ new_rooms = new_rooms.set(room_name, {
+ ...old_data,
+ ...room_data
+ });
} else {
- new_rooms.set(room_name, room_data);
+ new_rooms = new_rooms.set(room_name, room_data);
}
}
return new_rooms;
@@ -34,10 +43,11 @@ const reduceRoomList = (old_rooms, room_list) => {
const reduceReceiveMessage = (state, payload) => {
switch (payload.variant) {
case "RoomListResponse":
- {
- const rooms = reduceRoomList(state.rooms, payload.data.rooms);
- return { ...state, rooms };
- }
+ return {
+ ...state,
+ rooms: reduceRoomList(state.rooms, payload.data.rooms)
+ };
+
default:
return state;
}
@@ -50,7 +60,23 @@ export default (state = initialState, action) => {
return reduceReceiveMessage(state, payload);
case ROOM_SELECT:
- return { ...state, selected: payload };
+ return {
+ ...state,
+ selected: payload
+ };
+
+ case ROOM_JOIN:
+ {
+ const rooms = state.rooms.merge({
+ [payload]: {
+ joined: true
+ }
+ });
+ return {
+ ...state,
+ rooms
+ };
+ }
default:
return state;
diff --git a/src/store/configureStore.js b/src/store/configureStore.js
index 540c6f1..ecde3a1 100644
--- a/src/store/configureStore.js
+++ b/src/store/configureStore.js
@@ -1,5 +1,7 @@
import { applyMiddleware } from "redux";
import thunk from "redux-thunk";
+import promise from "redux-promise";
+import createLogger from "redux-logger";
let configureStore;
if (process.env.NODE_ENV === 'production') {
@@ -8,4 +10,10 @@ if (process.env.NODE_ENV === 'production') {
configureStore = require('./configureStore.dev').default;
}
-export default () => configureStore(undefined, applyMiddleware(thunk));
+export default () => {
+ const logger = createLogger();
+ return configureStore(
+ undefined,
+ applyMiddleware(thunk, promise, logger)
+ );
+};
diff --git a/src/styles/styles.scss b/src/styles/styles.scss
index 531deae..806f87f 100644
--- a/src/styles/styles.scss
+++ b/src/styles/styles.scss
@@ -26,6 +26,8 @@ html {
#solstice-app {
display: flex;
flex-flow: column;
+ justify-content: center;
+ align-items: center;
}
header {
@@ -42,6 +44,7 @@ footer {
}
main {
+ width: 100%;
height: 85%;
margin: 0;
padding: 0;
@@ -64,7 +67,6 @@ main {
flex-flow: column;
border: solid grey 0.1em;
height: 100%;
- overflow: auto;
}
#room-chat {
@@ -72,23 +74,27 @@ main {
}
#room-list-header {
+ flex: 1;
display: flex;
flex-flow: row;
border: solid grey 0.1em;
}
-#room-list-header div {
+#room-list-header > div {
flex: 1;
border: solid grey 0.1em;
}
#room-list ul {
+ display: block;
list-style: none;
padding: 0;
margin: 0;
+ height: 84%;
+ overflow-y: auto;
}
-.room {
+a.room {
display: flex;
color: inherit;
text-decoration: inherit;
@@ -96,14 +102,24 @@ main {
border: solid grey 0.1em;
}
-.room:hover {
+a.room:hover {
background: lightgrey;
}
-.room:active {
+a.room:active {
background: grey;
}
+a.room-selected {
+ background: orange;
+}
+
#login-status-pane, #socket-status-pane {
flex: 1;
}
+
+#connect-form {
+ display: flex;
+ flex-flow: column;
+ align-items: center;
+}
diff --git a/src/utils/ControlRequest.js b/src/utils/ControlRequest.js
index d377fe7..d697a01 100644
--- a/src/utils/ControlRequest.js
+++ b/src/utils/ControlRequest.js
@@ -7,5 +7,10 @@ export default {
roomList: () => ({
"variant": "RoomListRequest",
"fields": []
+ }),
+
+ joinRoom: (room) => ({
+ "variant": "JoinRoomRequest",
+ "fields": [{ room }]
})
};