diff --git a/src/actions/index.js b/src/actions/index.js
index 3713bc6a..ff572b84 100644
--- a/src/actions/index.js
+++ b/src/actions/index.js
@@ -35,3 +35,5 @@ export const users = require('./users');
export const quotes = require('./quotes');
export const tools = require('./tools');
+
+export const userMessages = require('./user-messages');
diff --git a/src/actions/user-messages.js b/src/actions/user-messages.js
new file mode 100644
index 00000000..613ceb90
--- /dev/null
+++ b/src/actions/user-messages.js
@@ -0,0 +1,37 @@
+/*
+ This file is a part of libertysoil.org website
+ Copyright (C) 2016 Loki Education (Social Enterprise)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+// When updating the whole message chain.
+export const SET_USER_MESSAGES = 'SET_USER_MESSAGES';
+// When sending a new message.
+export const ADD_USER_MESSAGE = 'ADD_USER_MESSAGE';
+
+export function setUserMessages(userId, messages) {
+ return {
+ type: SET_USER_MESSAGES,
+ messages,
+ userId
+ };
+}
+
+export function addUserMessage(userId, message) {
+ return {
+ type: ADD_USER_MESSAGE,
+ message,
+ userId
+ };
+}
diff --git a/src/api/controller.js b/src/api/controller.js
index 93fe30eb..40aedff6 100644
--- a/src/api/controller.js
+++ b/src/api/controller.js
@@ -3314,6 +3314,16 @@ export default class ApiController {
.orderBy('created_at', 'ASC');
})
.fetch();
+ await UserMessage.collection()
+ .query(qb => {
+ qb
+ .where({ sender_id: ctx.session.user, reciever_id: ctx.params.id })
+ // TODO: Replace with a single orWhere() when knex is upgraded from 0.10
+ .orWhere({ sender_id: ctx.params.id })
+ .andWhere({ reciever_id: ctx.session.user })
+ .orderBy('created_at', 'ASC');
+ })
+ .fetch();
ctx.body = messages;
}
diff --git a/src/components/tools/conversation.js b/src/components/tools/conversation.js
new file mode 100644
index 00000000..ef7a23fb
--- /dev/null
+++ b/src/components/tools/conversation.js
@@ -0,0 +1,105 @@
+/*
+ This file is a part of libertysoil.org website
+ Copyright (C) 2016 Loki Education (Social Enterprise)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+import React, { PropTypes } from 'react';
+
+import Avatar from '../user/avatar';
+import Time from '../time';
+import { Immutable as ImmutablePropType } from '../../prop-types/common';
+import { User as UserPropType } from '../../prop-types/users';
+
+
+function Message({ currentUser, selectedUser, message, hideAvatar = false }) {
+ const isMyMessage = message.get('sender_id') === currentUser.get('id');
+ let className = 'conversations_tool__message';
+ if (isMyMessage) {
+ className += ' conversations_tool__message-my';
+ } else {
+ className += ' conversations_tool__message-their';
+ }
+
+ let user = currentUser;
+ if (!isMyMessage) {
+ user = selectedUser;
+ }
+
+ return (
+
@@ -84,17 +140,30 @@ class ConversationsToolPage extends React.Component {
{userItems}
+
+
+
+
);
}
}
const selector = createSelector(
+ state => state.get('current_user'),
state => state.getIn(['tools', 'conversations_river']), // for the list of followed users
state => state.get('users'),
- (conversations_river, users) => ({
+ state => state.get('user_messages'),
+ (current_user, conversations_river, users, user_messages) => ({
+ current_user,
conversations_river,
- users
+ users,
+ user_messages
})
);
diff --git a/src/store/index.js b/src/store/index.js
index 26c2e649..40bf28d2 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -51,7 +51,8 @@ import related_posts from './related_posts';
import comments from './comments';
import quotes from './quotes';
import search from './search';
-import tools from './tools';
+import * as tools from './tools';
+import * as user_messages from './user_messages';
export const theReducer = combineReducers(i.Map({
routing: routerReducer,
@@ -85,7 +86,8 @@ export const theReducer = combineReducers(i.Map({
comments,
quotes,
search,
- tools
+ tools: tools.reducer,
+ user_messages: user_messages.reducer
}));
const initialState = i.Map({
@@ -139,7 +141,8 @@ const initialState = i.Map({
schools: i.List([])
})
}),
- tools: tools.initialState
+ tools: tools.initialState,
+ user_messages: user_messages.initialState
});
const browserHasDevTools = typeof window === 'object' && typeof window.devToolsExtension !== 'undefined';
diff --git a/src/store/tools.js b/src/store/tools.js
index b88fc56d..53942280 100644
--- a/src/store/tools.js
+++ b/src/store/tools.js
@@ -20,7 +20,7 @@ import i from 'immutable';
import { tools } from '../actions';
-const initialState = i.fromJS({
+export const initialState = i.fromJS({
schools_river: [],
all_schools_loaded: false,
schools_alphabet: [],
@@ -29,7 +29,7 @@ const initialState = i.fromJS({
conversations_river: []
});
-export default function reducer(state = initialState, action) {
+export function reducer(state = initialState, action) {
switch (action.type) {
case tools.TOOLS__ADD_SCHOOLS_TO_RIVER: {
const ids = i.List(action.schools.map(school => school.id));
diff --git a/src/store/user_messages.js b/src/store/user_messages.js
new file mode 100644
index 00000000..e4894c26
--- /dev/null
+++ b/src/store/user_messages.js
@@ -0,0 +1,42 @@
+/*
+ This file is a part of libertysoil.org website
+ Copyright (C) 2016 Loki Education (Social Enterprise)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+import i from 'immutable';
+
+import { userMessages } from '../actions';
+
+
+// user_id => list of messages
+export const initialState = i.Map();
+
+export function reducer(state = initialState, action) {
+ switch (action.type) {
+ case userMessages.SET_USER_MESSAGES: {
+ state = state.set(action.userId, i.fromJS(action.messages));
+
+ break;
+ }
+
+ case userMessages.ADD_USER_MESSAGE: {
+ state = state.update(action.userId, messages => (messages || i.List()).push(i.fromJS(action.message)));
+
+ break;
+ }
+ }
+
+ return state;
+}
diff --git a/src/triggers/index.js b/src/triggers/index.js
index c68cea35..991903de 100644
--- a/src/triggers/index.js
+++ b/src/triggers/index.js
@@ -823,4 +823,22 @@ export class ActionsTrigger {
this.dispatch(a.messages.addError(e.message));
}
}
+
+ sendMessage = async (userId, text) => {
+ try {
+ const message = await this.client.sendMessage(userId, text);
+ this.dispatch(a.userMessages.addUserMessage(userId, message));
+ } catch (e) {
+ this.dispatch(a.messages.addError(e.message));
+ }
+ }
+
+ updateUserMessages = async (userId) => {
+ try {
+ const messages = await this.client.userMessages(userId);
+ this.dispatch(a.userMessages.setUserMessages(userId, messages));
+ } catch (e) {
+ this.dispatch(a.messages.addError(e.message));
+ }
+ }
}