Commit f2d3dea0 authored by Vladimir Baranov's avatar Vladimir Baranov

rref #5392. Add instant messaging, add actions for message/channels, fixes and improvements

parent 470a5726
...@@ -2203,7 +2203,7 @@ table.dataTable thead .sorting:after { ...@@ -2203,7 +2203,7 @@ table.dataTable thead .sorting:after {
padding-left: 40px; padding-left: 40px;
} }
.chat-app .side-navigation ul.direct-messages li.active { .chat-app .side-navigation ul.direct-messages li.active, .chat-app .side-navigation ul.channels li.active {
background-color: #B51533; background-color: #B51533;
} }
...@@ -2521,7 +2521,7 @@ table.dataTable thead .sorting:after { ...@@ -2521,7 +2521,7 @@ table.dataTable thead .sorting:after {
color:#000000; color:#000000;
} }
.chat-app .create-new-message-window .search-results { .chat-app .create-new-message-window .search-results, .chat-app .add-user-unit .search-results {
width: 50%; width: 50%;
margin-left: 25%; margin-left: 25%;
margin-top: 25px; margin-top: 25px;
...@@ -2529,7 +2529,7 @@ table.dataTable thead .sorting:after { ...@@ -2529,7 +2529,7 @@ table.dataTable thead .sorting:after {
overflow: auto; overflow: auto;
} }
.chat-app .create-new-message-window .search-results .user { .chat-app .create-new-message-window .search-results .user, .chat-app .add-user-unit .search-results .user {
width: 100%; width: 100%;
display: inline-block; display: inline-block;
padding: 10px; padding: 10px;
...@@ -2537,18 +2537,18 @@ table.dataTable thead .sorting:after { ...@@ -2537,18 +2537,18 @@ table.dataTable thead .sorting:after {
cursor:pointer; cursor:pointer;
} }
.chat-app .create-new-message-window .search-results .user:hover { .chat-app .create-new-message-window .search-results .user:hover, .chat-app .add-user-unit .search-results .user:hover{
background-color:#efefef; background-color:#efefef;
} }
.chat-app .create-new-message-window .search-results .user img { .chat-app .create-new-message-window .search-results .user img, .chat-app .add-user-unit .search-results .user img{
width: 45px; width: 45px;
height: 45px; height: 45px;
border-radius: 100%; border-radius: 100%;
float: left; float: left;
} }
.chat-app .create-new-message-window .search-results .user .user-name { .chat-app .create-new-message-window .search-results .user .user-name, .chat-app .add-user-unit .search-results .user .user-name {
float: left; float: left;
margin-left: 15px; margin-left: 15px;
font-family: 'robotobold'; font-family: 'robotobold';
...@@ -2556,6 +2556,29 @@ table.dataTable thead .sorting:after { ...@@ -2556,6 +2556,29 @@ table.dataTable thead .sorting:after {
margin-top: 9px; margin-top: 9px;
} }
.chat-app-button {
display: block;
position: fixed;
bottom: 20px;
right: 20px;
background: white;
border: none;
border-radius: 50%;
width: 50px;
height: 50px;
padding: 0;
z-index: 1000;
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
text-align: center;
cursor: pointer;
}
.chat-app-button i {
top: 16px;
color: #333;
font-size: 20px;
}
.chat-app .create-new-channel-window h3 { .chat-app .create-new-channel-window h3 {
width: 400px; width: 400px;
margin-left: auto; margin-left: auto;
......
This diff is collapsed.
...@@ -12,8 +12,8 @@ angular.module('ulakbus.messaging', ['ui.bootstrap']) ...@@ -12,8 +12,8 @@ angular.module('ulakbus.messaging', ['ui.bootstrap'])
/** /**
* @memberof ulakbus.messaging * @memberof ulakbus.messaging
* @ngdoc factory * @ngdoc factory
* @name Generator * @name MessagingService
* @description form service's Generator factory service handles all generic form operations * @description Service handles all stuff related to messaging
*/ */
.factory('MessagingService', function ($q, $timeout, $sce, $location, $route, $compile, $log, $rootScope, Moment, WSOps, Utils) { .factory('MessagingService', function ($q, $timeout, $sce, $location, $route, $compile, $log, $rootScope, Moment, WSOps, Utils) {
var msg = {}; var msg = {};
...@@ -44,16 +44,21 @@ angular.module('ulakbus.messaging', ['ui.bootstrap']) ...@@ -44,16 +44,21 @@ angular.module('ulakbus.messaging', ['ui.bootstrap'])
}) })
} }
// prepare messages for UI
function prepareMessages (messages){ function prepareMessages (messages){
for (var i = 0; i < messages.length; i++){ for (var i = 0; i < messages.length; i++){
var message = messages[i]; var message = messages[i];
// FIXME: process timezone properly msg.prepareMessage(message);
var ts = message.timestamp.replace(/\.0+Z$/, "");
message.moment = Moment(ts);
} }
} }
// prepare message to show in UI
msg.prepareMessage = function(message){
var ts = message.timestamp.replace(/\.0+Z$/, "");
// FIXME: process timezone properly
message.moment = Moment(ts);
return message;
};
msg.list_channels = function list_channels (){ msg.list_channels = function list_channels (){
/** /**
* request channels list as below; * request channels list as below;
...@@ -83,6 +88,7 @@ angular.module('ulakbus.messaging', ['ui.bootstrap']) ...@@ -83,6 +88,7 @@ angular.module('ulakbus.messaging', ['ui.bootstrap'])
view: '_zops_list_channels' view: '_zops_list_channels'
}; };
return wsRequest(outgoing).then(function (data) { return wsRequest(outgoing).then(function (data) {
console.error("channels: ", data.channels);
return Utils.groupBy(data.channels||[], "type"); return Utils.groupBy(data.channels||[], "type");
}); });
}; };
...@@ -174,14 +180,14 @@ angular.module('ulakbus.messaging', ['ui.bootstrap']) ...@@ -174,14 +180,14 @@ angular.module('ulakbus.messaging', ['ui.bootstrap'])
msg.edit_channel = function (channelKey, name, desription) { msg.edit_channel = function (channelKey, name, desription) {
var outgoing = { var outgoing = {
view:'_zops_create_channel', view:'_zops_edit_channel',
channel_key: channelKey, channel_key: channelKey,
name: name, name: name,
description: desription description: desription
}; };
return wsRequest(outgoing).then(function(result){ return wsRequest(outgoing).then(function(result){
$log.info("Channel ", channelKey, " edited: ", result); $log.info("Channel ", channelKey, " edited: ", outgoing, result);
return result; return result;
}) })
}; };
...@@ -198,12 +204,14 @@ angular.module('ulakbus.messaging', ['ui.bootstrap']) ...@@ -198,12 +204,14 @@ angular.module('ulakbus.messaging', ['ui.bootstrap'])
}; };
msg.show_channel = function(channelKey){ msg.show_channel = function(channelKey){
var outgoing = { var outgoing = {
view: '_zops_show_channel', view: '_zops_show_channel',
channel_key: channelKey channel_key: channelKey
}; };
return wsRequest(outgoing).then(function(result){ return wsRequest(outgoing).then(function(result){
$log.info("Show channel ", channelKey, ": ", result); $log.info("Show channel ", channelKey, ": ", result);
console.error("channel: ", result);
prepareMessages(result.last_messages); prepareMessages(result.last_messages);
return result; return result;
}) })
...@@ -225,7 +233,7 @@ angular.module('ulakbus.messaging', ['ui.bootstrap']) ...@@ -225,7 +233,7 @@ angular.module('ulakbus.messaging', ['ui.bootstrap'])
var outgoing = { var outgoing = {
channel_key: channelKey, channel_key: channelKey,
msg_key: msgKey, msg_key: msgKey,
timestamp: timestamp, timestamp: timestamp
}; };
return wsRequest(outgoing).then(function(result){ return wsRequest(outgoing).then(function(result){
$log.info("Report last seen message ", channelKey, msgKey, timestamp, ": ", result); $log.info("Report last seen message ", channelKey, msgKey, timestamp, ": ", result);
...@@ -293,10 +301,8 @@ angular.module('ulakbus.messaging', ['ui.bootstrap']) ...@@ -293,10 +301,8 @@ angular.module('ulakbus.messaging', ['ui.bootstrap'])
msg.flag_message = function (msgKey, flag) { msg.flag_message = function (msgKey, flag) {
var outgoing = { var outgoing = {
view: '_zops_flag_message', view: '_zops_flag_message',
message: { key: msgKey,
'key': msgKey, flag: flag
'flag': flag
}
}; };
return wsRequest(outgoing).then(function(result){ return wsRequest(outgoing).then(function(result){
$log.info("Flag message ", msgKey, flag, ":", result); $log.info("Flag message ", msgKey, flag, ":", result);
...@@ -318,7 +324,7 @@ angular.module('ulakbus.messaging', ['ui.bootstrap']) ...@@ -318,7 +324,7 @@ angular.module('ulakbus.messaging', ['ui.bootstrap'])
msg.add_to_favorites = function (msgKey) { msg.add_to_favorites = function (msgKey) {
var outgoing = { var outgoing = {
view: '_zops_add_to_favorites', view: '_zops_add_to_favorites',
message_key: msgKey key: msgKey
}; };
return wsRequest(outgoing).then(function(result){ return wsRequest(outgoing).then(function(result){
$log.info("Add message ", msgKey, " to favorites: ", result); $log.info("Add message ", msgKey, " to favorites: ", result);
...@@ -329,7 +335,7 @@ angular.module('ulakbus.messaging', ['ui.bootstrap']) ...@@ -329,7 +335,7 @@ angular.module('ulakbus.messaging', ['ui.bootstrap'])
msg.remove_from_favorites = function (msgKey) { msg.remove_from_favorites = function (msgKey) {
var outgoing = { var outgoing = {
view: '_zops_remove_to_favorites', view: '_zops_remove_to_favorites',
message_key: msgKey key: msgKey
}; };
return wsRequest(outgoing).then(function(result){ return wsRequest(outgoing).then(function(result){
$log.info("Remove message ", msgKey, " from favorites: ", result); $log.info("Remove message ", msgKey, " from favorites: ", result);
...@@ -346,7 +352,7 @@ angular.module('ulakbus.messaging', ['ui.bootstrap']) ...@@ -346,7 +352,7 @@ angular.module('ulakbus.messaging', ['ui.bootstrap'])
$log.info("List favorites for channel", channelKey, ": ", result); $log.info("List favorites for channel", channelKey, ": ", result);
return result; return result;
}); });
} };
return msg; return msg;
}) })
......
<div class="chat-popup-window add-user-unit" style="display:block;"> <div class="chat-popup-window add-user-unit" style="display:block;">
<div class="close-chat-popup-window"><span class="glyphicon glyphicon-remove"></span></div> <div class="close-chat-popup-window" ng-click="cancel()"><span class="glyphicon glyphicon-remove"></span></div>
<h3>{{title}}</h3> <h3>{{title}}</h3>
<div class="text-center"> <div class="text-center">
<input type="text" placeholder="{{placeholder}}"> <input type="text" ng-model="query" ng-change="onChange(query)" placeholder="{{placeholder}}">
<div class="search-results"> </div>
<span class="loader" ng-show="loading"></span> <div class="search-results">
<div class="user" ng-repeat="item in searchResult" ng-click="done(item[1])"> <span class="loader" ng-show="loading"></span>
<img ng-src="{{item[2]}}" ng-show="item[2]"> <div class="user" ng-repeat="item in searchResult" ng-click="done(item[1])">
<div class="user-name">{{item[0]}}</div> <img ng-src="{{item[2]}}" ng-show="item[2]">
</div> <div class="user-name">{{item[0]}}</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
<div class="conversation-header"> <div class="conversation-header">
<div class="conversation-user"> <div class="conversation-user">
<div class="user-photo" ng-show="selectedChannel.avatar_url"><img ng-src="{{selectedChannel.avatar_url}}"></div> <div class="user-photo" ng-show="selectedChannel.avatar_url"><img ng-src="{{selectedChannel.avatar_url}}"></div>
<div class="user-name">{{selectedChannel.name}}</div> <div class="user-name" title="{{selectedChannel.description}}">{{selectedChannel.name}}</div>
</div> </div>
<div class="conversation-search"> <div class="conversation-search">
<input type="text" placeholder="Arama Yap"> <input type="text" placeholder="Arama Yap">
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
<span class="glyphicon glyphicon-option-vertical"></span> <span class="glyphicon glyphicon-option-vertical"></span>
</div> </div>
<ul class="dropdown-menu" ng-show="selectedChannel.actions.length > 0" aria-labelledby="chat-app-actions" style="left: inherit; top: 53px; right: 66px;" > <ul class="dropdown-menu" ng-show="selectedChannel.actions.length > 0" aria-labelledby="chat-app-actions" style="left: inherit; top: 53px; right: 66px;" >
<li><a ng-click="applyChannelAction(action)" ng-repeat="action in selectedChannel.actions">{{action[0]}}</a></li> <li><a ng-click="applyChannelAction(selectedChannel, action)" ng-repeat="action in selectedChannel.actions">{{action[0]}}</a></li>
</ul> </ul>
</div> </div>
<div class="close-chat-app" ng-click="hideApp()"> <div class="close-chat-app" ng-click="hideApp()">
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
</div> </div>
</div> </div>
<div class="conversation-body"> <div class="conversation-body" scroll-down-when-update="lastMessage">
<div class="conversation-body-inner"> <div class="conversation-body-inner">
<div class="beginning-of-conversation"> <div class="beginning-of-conversation">
...@@ -41,17 +41,16 @@ ...@@ -41,17 +41,16 @@
<div class="conversation-block clearfix" ng-repeat="msg in selectedChannel.messages"> <div class="conversation-block clearfix" ng-repeat="msg in selectedChannel.messages">
<div class="conversation-actions"> <div class="conversation-actions">
<div class="action"><span class="glyphicon glyphicon-star-empty"></span></div> <div class="action"><span class="glyphicon glyphicon-star-empty"></span></div>
<div class="action dropdown-toggle" data-toggle="dropdown"> <div class="action dropdown-toggle" data-toggle="dropdown" ng-click="getMessageActions(msg)">
<span class="glyphicon glyphicon-option-horizontal"></span> <span class="glyphicon glyphicon-option-horizontal"></span>
</div> </div>
<ul class="dropdown-menu" style="left:-86px;"> <ul class="dropdown-menu" style="left:-86px;" >
<li><a href="#">Edit</a></li> <li ng-repeat="act in msg.actions"><a href="#" ng-click="applyMessageAction(msg, act)">{{act[0]}}</a></li>
<li><a href="#" ng-click="deleteConfirmation()">Delete</a></li>
</ul> </ul>
</div> </div>
<div class="user-photo"> <div class="user-photo">
<img src="../../../img/erkan.jpg"> <img ng-src="{{msg.avatar_url}}" ng-show="msg.avatar_url">
</div> </div>
<div class="user-message"> <div class="user-message">
<div class="message-header clearfix"> <div class="message-header clearfix">
......
<div class="chat-popup-window create-new-channel-window"> <div class="chat-popup-window create-new-channel-window">
<div class="close-chat-popup-window" ng-click="cancel()"><span class="glyphicon glyphicon-remove"></span></div> <div class="close-chat-popup-window" ng-click="cancel()"><span class="glyphicon glyphicon-remove"></span></div>
<h3>Create New Channel</h3> <h3>{{title}}</h3>
<div class="text-center"> <div class="text-center">
<input type="text" placeholder="Channel Name" ng-model="channel.name"><br> <input type="text" placeholder="Channel Name" ng-model="channel.name"><br>
<textarea placeholder="Channel Description" ng-model="channel.description"></textarea> <textarea placeholder="Channel Description" ng-model="channel.description"></textarea>
<button class="btn btn-success" ng-click="done(channel)">Create</button> <button class="btn btn-success" ng-click="done(channel)">{{actionTitle}}</button>
</div> </div>
</div> </div>
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<div class="close-chat-popup-window" ng-click="cancel()"><span class="glyphicon glyphicon-remove"></span></div> <div class="close-chat-popup-window" ng-click="cancel()"><span class="glyphicon glyphicon-remove"></span></div>
<div class="text-center" style="margin-top: 150px;font-size: 26px;"> <div class="text-center" style="margin-top: 150px;font-size: 26px;">
<p>Are you sure you want to delete?</p> <p>{{title}}</p>
<button class="btn btn-success" style="font-size: 20px;" ng-click="done()">Yes</button> <button class="btn btn-success" style="font-size: 20px;" ng-click="done()">Yes</button>
<button class="btn btn-default" style="font-size: 20px;" ng-click="cancel()">Cancel</button> <button class="btn btn-default" style="font-size: 20px;" ng-click="cancel()">Cancel</button>
</div> </div>
......
<div> <div>
<button class="chat-app-button" ng-show="hidden" ng-click="hidden = false"><i class="glyphicon glyphicon-comment"></i></button> <a class="chat-app-button" ng-show="chatAppIsHidden" ng-click="showApp()"><i class="glyphicon glyphicon-comment"></i></a>
<div class="chat-app" ng-hide="hidden"> <div class="chat-app" ng-hide="chatAppIsHidden">
<div class="chat-app-container"> <div class="chat-app-container">
...@@ -11,12 +11,12 @@ ...@@ -11,12 +11,12 @@
<ul class="channels"> <ul class="channels">
<li class="title">CHANNELS <span class="add-action glyphicon glyphicon-plus-sign" ng-click="createChannel()"></span></li> <li class="title">CHANNELS <span class="add-action glyphicon glyphicon-plus-sign" ng-click="createChannel()"></span></li>
<li ng-class="{'notification': ch.unread, 'active': selectedChannel == ch}" ng-repeat="ch in publicChannels" ng-click="selectChannel(ch)">{{ch.name}}</li> <li ng-class="{'notification': ch.unread, 'active': isChannelSelected(ch)}" title="{{ch.description}}" ng-repeat="ch in publicChannels" ng-click="selectChannel(ch)">{{ch.name}}</li>
</ul> </ul>
<ul class="direct-messages"> <ul class="direct-messages">
<li class="title">DIRECT MESSAGES <span class="add-action glyphicon glyphicon-plus-sign" ng-click="searchUser()"></span></li> <li class="title">DIRECT MESSAGES <span class="add-action glyphicon glyphicon-plus-sign" ng-click="searchUser()"></span></li>
<li ng-class="{'notification': userChannel.unread, 'active': selectedChannel == userChannel}" ng-repeat="userChannel in directChannels" ng-click="selectChannel(userChannel)">{{userChannel.name}}</li> <li ng-class="{'notification': userChannel.unread, 'active': isChannelSelected(userChannel), 'online': userChannel.is_online}" ng-repeat="userChannel in directChannels" ng-click="selectChannel(userChannel)">{{userChannel.name}}</li>
</ul> </ul>
</div> </div>
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
<ng-include src="'components/messaging/templates/conversation.html'"></ng-include> <ng-include src="'components/messaging/templates/conversation.html'"></ng-include>
<div class="popup-placeholder"></div> <div class="popup-placeholder"></div>
</div> </div>
</div> </div>
</div> </div>
...@@ -12,6 +12,17 @@ angular.module("ulakbus") ...@@ -12,6 +12,17 @@ angular.module("ulakbus")
.service("Utils", function(){ .service("Utils", function(){
var self = this; var self = this;
// check if obj1 has properties values equal to corresponding properties in obj2
function hasEqualProperties(obj1, obj2){
var result = true
for (var prop in obj2){
if(obj2.hasOwnProperty(prop)){
result = result && obj2[prop] == obj1[prop];
}
}
return result;
}
/** /**
* @param list {Array} Array of objects to group * @param list {Array} Array of objects to group
* @param propName {String} property name to group array by * @param propName {String} property name to group array by
...@@ -24,4 +35,18 @@ angular.module("ulakbus") ...@@ -24,4 +35,18 @@ angular.module("ulakbus")
return acc; return acc;
}, {}); }, {});
}; };
/**
* @param list {Array} Array of objects to group
* @param condition {Object} conditions object. If object in collection has same values as in conditions object it will be removed
* @returns {Object}|undefined removed object or undefined
*/
this.deleteWhere = function(list, condition){
for (var i = 0; i < list.length; i++){
if (hasEqualProperties(list[i], condition)){
list.splice(i, 1);
return list[i];
}
}
}
}); });
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment