Skip to content

Commit

Permalink
wip #76 Implement sending messages to everyone in the study group
Browse files Browse the repository at this point in the history
  • Loading branch information
simon-bourque committed Mar 24, 2017
1 parent a110bce commit f61853d
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 32 deletions.
26 changes: 24 additions & 2 deletions client/modules/User/UserActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export const AUTHENTICATE_SESSION = 'AUTHENTICATE_SESSION';
export const FAILED_AUTHENTICATION = 'FAILED_AUTHENTICATION';
export const CREATE_GROUP = 'CREATE_GROUP';
export const SET_CURRENT_STUDY_GROUP = 'SET_CURRENT_STUDY_GROUP';
export const PREPARE_CHAT_MESSAGES = 'PREPARE_CHAT_MESSAGES';
export const PREPARE_CHAT_MESSAGE = 'PREPARE_CHAT_MESSAGE';

// Auth Pages
export const DASHBOARD_PAGE = 'DASHBOARD_PAGE';
Expand Down Expand Up @@ -154,9 +156,29 @@ export function createStudyGroupRequest(user,studyGroup) {
};
}

export function setCurrentStudyGroup(studyGroup) {
export function setCurrentStudyGroup(studyGroupIndex) {
return {
type: SET_CURRENT_STUDY_GROUP,
studyGroup,
studyGroupIndex,
};
}

export function prepareChatMessages(messages) {
return {
type: PREPARE_CHAT_MESSAGES,
messages,
};
}

export function prepareChatMessage(message) {
return {
type: PREPARE_CHAT_MESSAGE,
message,
};
}

export function switchChat(studyGroupIndex, studyGroup) {
return (dispatch) => {
return callApi(`message/${studyGroup.guid}`).then(res => dispatch(prepareChatMessages(res.messages)));
};
}
41 changes: 38 additions & 3 deletions client/modules/User/UserReducer.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { ADD_USER, UPDATE_USER, LOGIN_USER, AUTHENTICATE_SESSION, FAILED_AUTHENTICATION, LOGOUT_USER, SET_CURRENT_STUDY_GROUP } from './UserActions';
import { ADD_USER, UPDATE_USER, LOGIN_USER, AUTHENTICATE_SESSION, FAILED_AUTHENTICATION, LOGOUT_USER, SET_CURRENT_STUDY_GROUP, PREPARE_CHAT_MESSAGES, PREPARE_CHAT_MESSAGE } from './UserActions';

import { getColorFromUserIndex } from './components/ChatComponent/ChatComponent';
import React from 'react';

// Initial State
const initialState = { data: [], user: null, currentStudyGroup: null };
const initialState = { data: [], user: null, currentStudyGroup: -1, chat: { messages: [] } };

const UserReducer = (state = initialState, action) => {
switch (action.type) {
Expand All @@ -12,35 +15,67 @@ const UserReducer = (state = initialState, action) => {
case UPDATE_USER :
return {
user: action.user,
currentStudyGroup: state.currentStudyGroup,
chat: state.chat,
};
case LOGIN_USER: {
const user = (action.response.statusCode === 200) ? action.response.user : null;

return {
user,
currentStudyGroup: state.currentStudyGroup,
chat: state.chat,
};
}
case AUTHENTICATE_SESSION: {
const user = (action.response.statusCode === 200) ? action.response.user : null;

return {
user,
currentStudyGroup: state.currentStudyGroup,
chat: state.chat,
};
}
case FAILED_AUTHENTICATION: {
return {
user: null,
currentStudyGroup: -1,
chat: initialState.chat,
};
}
case LOGOUT_USER: {
return {
user: null,
currentStudyGroup: -1,
chat: initialState.chat,
};
}
case SET_CURRENT_STUDY_GROUP: {
return {
user: state.user, // Not sure if this is necessary
currentStudyGroup: action.studyGroup,
currentStudyGroup: action.studyGroupIndex,
chat: state.chat,
};
}
case PREPARE_CHAT_MESSAGES: {
const messages = [];

for (let i = 0; i < action.messages.length; i++) {
messages.push(<div key={i} style={{ color: getColorFromUserIndex(i) }}>{`${action.messages[i].author}: ${action.messages[i].messageContent}`}</div>);
}

return {
user: state.user,
currentStudyGroup: state.currentStudyGroup,
chat: { messages },
};
}
case PREPARE_CHAT_MESSAGE: {
state.chat.messages.push(<div key={state.chat.messages.length + 1} style={{ color: getColorFromUserIndex(0) }}>{`${action.message.user}: ${action.message.message}`}</div>);
return {
user: state.user,
currentStudyGroup: state.currentStudyGroup,
chat: state.chat,
};
}
default:
Expand Down
52 changes: 37 additions & 15 deletions client/modules/User/components/ChatComponent/ChatComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,39 +21,61 @@ const COLORS = [
];

// Ensure we have a color for every user, if we are out of colors just wrap back around.
function getColorFromUserIndex(index) {
export function getColorFromUserIndex(index) {
return COLORS[index % COLORS.length];
}

export class ChatComponent extends Component {
constructor(props) {
super(props);
this.state = { messages: [] };
this.populateMessages = this.populateMessages.bind(this);
this.state = { value: '' };
this.socket = null;
this.sendMessage = this.sendMessage.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
this.onMessageReceive = this.onMessageReceive.bind(this);
}

componentWillMount() {
console.log('Will Mount');
console.log(this.props.users);
this.socket = io.connect();
this.populateMessages();
this.socket.emit('UserSignedIn', `${this.props.users.user.firstName} ${this.props.users.user.lastName}`);
this.socket.on('UpdateMessages', this.onMessageReceive);

this.props.setChat(0);
}

componentWillUpdate(nextProps, nextState) {
console.log('Will Update');
this.populateMessages();

}

componentWillUnmount() {
console.log('Will Unmount');
this.socket.disconnect();
}

onMessageReceive(data) {
this.props.prepareChatMessage(data);
}

handleChange(event) {
this.setState({ value: event.target.value });
}

handleKeyDown(event) {
if (event.keyCode === 13 && !event.shiftKey) {
this.sendMessage();
event.preventDefault();
}
}

populateMessages() {
this.state.messages = [];
// Test messages for now
for (let i = 0; i < 100; i++) {
this.state.messages.push(<div key={i} style={{ color: getColorFromUserIndex(i) }}>Hello</div>);
sendMessage() {
if (this.state.value !== '') {
this.socket.emit('SaveMessage', {
message: this.state.value,
studyGroup: this.props.users.user.studyGroups[this.props.users.currentStudyGroup].guid,
});
this.state.value = '';
}
}

Expand All @@ -63,11 +85,11 @@ export class ChatComponent extends Component {
return (
<div className="col-md-9">
<div className="row-md-3 border rounded" id={styles['message-area']}>
{this.state.messages}
{this.props.users.chat.messages}
</div>
<div className="row">
<textarea className="col-md-11 form-control" rows="3"></textarea>
<button className="col-md-1 btn btn-primary">Send</button>
<textarea className="col-md-11 form-control" rows="3" value={this.state.value} onKeyDown={this.handleKeyDown} onChange={this.handleChange} ></textarea>
<button className="col-md-1 btn btn-primary" onClick={this.sendMessage}>Send</button>
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import UserStudyGroupComponent from '../UserStudyGroupComponent/UserStudyGroupCo
import styles from './UserInfoComponent.css';

function UserInfoComponent(props) {
if (Object.keys(props.users).length === 1) { // wait props.users not to be null
if (props.users.user !== null) { // wait props.users not to be null
return (
<div className="col-md-3" id={styles.sidebar}>
<img className="img-circle" id={styles['circle-image']}src="/static/images/user.png" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,19 @@ import styles from './UserStudyGroupComponent.css';

function UserStudyGroupComponent(props){
const arr = [
{'name': "Dream Team Study"}, // Mock data (study groups)
{'name': "SOEN 341 Study Group"},
{'name': "COMP 346 Exam Study"},
{'name': "Team \"Mandy's Salad\" Discussion"}
{ name: 'Dream Team Study' }, // Mock data (study groups)
{ name: 'SOEN 341 Study Group' },
{ name: 'COMP 346 Exam Study' },
{ name: 'Team "Mandy\'s Salad" Discussion' },
];
if((props.users.user.studyGroups).length !== 0){

if (props.users.user !== null) {
return (
<div className={styles.studyGroup}>
<h4>Study Groups</h4>
<ul>
{(arr).map(group => { // Displays group name in array of user study groups. Tested using mock data.
return <li><Link href="">{group.name}</Link></li>; // Missing routes to chat.
{(arr).map((group, i) => { // Displays group name in array of user study groups. Tested using mock data.
return <li key={i}><Link href="">{group.name}</Link></li>; // Missing routes to chat.
})}
</ul>
</div>
Expand Down
20 changes: 16 additions & 4 deletions client/modules/User/pages/UserDashboardPage/UserDashboardPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,33 @@ import { bindActionCreators } from 'redux';
import UserInfoComponent from '../../components/UserInfoComponent/UserInfoComponent';
import ChatComponent from '../../components/ChatComponent/ChatComponent';

import { authenticateSessionRequest } from '../../UserActions';
import { authenticateSessionRequest, switchChat, setCurrentStudyGroup, prepareChatMessage } from '../../UserActions';

import styles from './UserDashboardPage.css';

class UserDashboardPage extends Component {
constructor(props) {
super(props);
this.setChat = this.setChat.bind(this);
}
componentWillMount() {
// If I do not have any user data attempt to authenticate using cookie
if (this.props.users.user == null) {
this.props.authenticateSessionRequest();
}
}

setChat(studyGroupIndex) {
this.props.setCurrentStudyGroup(studyGroupIndex);
this.props.switchChat(studyGroupIndex, this.props.users.user.studyGroups[studyGroupIndex]);
}

render() {
if (this.props.users.user != null) {
return (
<div className={`row ${styles.dashboardContainer}`}>
<UserInfoComponent users={this.props.users} />
<ChatComponent users={this.props.users} />
<UserInfoComponent users={this.props.users} setChat={this.setChat} />
<ChatComponent users={this.props.users} setChat={this.setChat} prepareChatMessage={this.props.prepareChatMessage} />
</div>
);
}
Expand All @@ -34,7 +43,7 @@ class UserDashboardPage extends Component {

// Bind actions to props
function mapDispatchToProps(dispatch) {
return bindActionCreators({ authenticateSessionRequest }, dispatch);
return bindActionCreators({ authenticateSessionRequest, switchChat, setCurrentStudyGroup, prepareChatMessage }, dispatch);
}

// map Users from store to Props
Expand All @@ -45,6 +54,9 @@ function mapStateToProps({ users }) {
// Warning issued if prop not provided
UserDashboardPage.propTypes = {
authenticateSessionRequest: PropTypes.func.isRequired,
setCurrentStudyGroup: PropTypes.func.isRequired,
switchChat: PropTypes.func.isRequired,
prepareChatMessage: PropTypes.func.isRequired,
users: PropTypes.object,
};

Expand Down

0 comments on commit f61853d

Please sign in to comment.