TT#4316 ngcp-csc chat section implementation.

Change-Id: I3062559fc0b26efc8890131d9e12dd3d71f3d5aa
changes/12/9212/2
Carlo 9 years ago
parent 649b97df7d
commit e4376d5687

@ -192,7 +192,6 @@ Ext.define('Ngcp.csc.locales', {
sp: 'all calls'
}
},
filters: {
search: {
en: 'SEARCH',
@ -237,7 +236,6 @@ Ext.define('Ngcp.csc.locales', {
sp: 'reset filter'
}
},
voicemails: {
title: {
en: 'Your voicemail recordings.',
@ -305,7 +303,7 @@ Ext.define('Ngcp.csc.locales', {
fr: 'Send notification of new messages to the following e-mail adddress',
sp: 'Send notification of new messages to the following e-mail adddress'
},
attach_recording:{
attach_recording: {
en: 'attach recording',
it: 'attach recording',
de: 'attach recording',
@ -336,6 +334,31 @@ Ext.define('Ngcp.csc.locales', {
}
},
chat: {
title: {
en: 'Team',
it: 'Team',
de: 'Team',
fr: 'Team',
sp: 'Team'
},
msg_box:{
empty_text:{
en: 'Type a message',
it: 'Type a message',
de: 'Type a message',
fr: 'Type a message',
sp: 'Type a message'
}
},
start_conversation: {
en: 'You can start a private conversation with {0} here.',
it: 'You can start a private conversation with {0} here.',
de: 'You can start a private conversation with {0} here.',
fr: 'You can start a private conversation with {0} here.',
sp: 'You can start a private conversation with {0} here.'
}
},
common: {
today: {
en: 'Today',
@ -372,14 +395,14 @@ Ext.define('Ngcp.csc.locales', {
fr: 'no',
sp: 'no'
},
delete:{
delete: {
en: 'Delete',
it: 'Delete',
de: 'Delete',
fr: 'Delete',
sp: 'Delete'
},
listen:{
listen: {
en: 'Listen',
it: 'Listen',
de: 'Listen',
@ -413,7 +436,15 @@ Ext.define('Ngcp.csc.locales', {
de: 'Successfully removed.',
fr: 'Successfully removed.',
sp: 'Successfully removed.'
},
submit: {
en: 'submit',
it: 'submit',
de: 'submit',
fr: 'submit',
sp: 'submit'
}
}
}
})

@ -0,0 +1,16 @@
Ext.define('NgcpCsc.model.ChatList', {
extend: 'Ext.data.Model',
fields: [{
type: 'int',
name: 'id'
}, {
type: 'string',
name: 'name'
}, {
type: 'string',
name: 'thumbnail'
}, {
type: 'boolean',
name: 'online'
}]
});

@ -0,0 +1,20 @@
Ext.define('NgcpCsc.model.ChatNotification', {
extend: 'Ext.data.Model',
fields: [{
name: '_id'
}, {
name: 'parent_id'
}, {
name: 'name'
}, {
name: 'source'
}, {
name: 'date'
}, {
name: 'isActive'
}, {
name: 'time'
}, {
name: 'content'
}]
});

@ -0,0 +1,18 @@
Ext.define('NgcpCsc.store.Chat', {
extend: 'Ext.data.Store',
storeId: 'Chat',
model: 'NgcpCsc.model.ChatNotification',
autoLoad: true,
proxy: {
type: 'ajax',
url: '/resources/data/chat.json',
reader: {
type: 'json',
rootProperty: 'data'
}
}
});

@ -0,0 +1,25 @@
Ext.define('NgcpCsc.store.ChatList', {
extend: 'Ext.data.Store',
alias: 'store.chatlist',
storeId: 'ChatList',
model: 'NgcpCsc.model.ChatList',
autoLoad: true,
proxy: {
type: 'ajax',
url: '/resources/data/chatlist.json',
reader: {
type: 'json',
rootProperty: 'data'
}
},
sorters: {
direction: 'DESC',
property: 'online'
}
});

@ -27,6 +27,12 @@ Ext.define('NgcpCsc.store.NavigationTree', {
viewType: 'voicemails',
routeId: 'voicebox',
leaf: true
}, {
text: 'Chat',
iconCls: 'x-fa fa-wechat',
viewType: 'chat',
routeId: 'chat',
leaf: true
}, {
text: 'Address book',
iconCls: 'x-fa fa-book',

@ -334,3 +334,6 @@
.red-txt {
color: red;
}
.x-panel-bodyWrap {
background-color: white;
}

@ -0,0 +1,295 @@
.user-notifications {
padding: 15px;
background: #fff;
.x-view-item-focused {
outline: 0 !important;
}
}
.timeline-item {
.line-wrap {
position: relative;
&:before {
content: "";
position: absolute;
width: 50px;
height: 100%;
border-right: solid 2px $base-color;
left: 0;
top: 70px;
}
}
.profile-pic-wrap {
width: 100px;
float: left;
font-size: 10px;
text-align: center;
position: relative;
background: $lightest-color;
padding: 5px 0;
img {
height: 46px;
width: 46px;
@include border-radius($circle-border-radius);
}
}
.contents-wrap {
margin: 0 0 15px 110px;
border: 1px solid $base-border-color;
position: relative;
padding: 15px;
white-space: normal;
&:after,
&:before {
content: "";
display: block;
position: absolute;
width: 0;
height: 0;
left: 0;
top: 0;
}
&:before {
border-top: 9px solid transparent;
border-bottom: 9px solid transparent;
border-right: 9px solid $base-border-color;
margin: 15px 0 0 -9px;
}
&:after {
border-top: 9px solid transparent;
border-bottom: 9px solid transparent;
border-right: 9px solid $lightest-color;
margin: 15px 0 0 -8px;
}
.followed-by,
.shared-by {
font-size: 12px;
line-height: 18px;
margin-bottom: 10px;
a {
color: $base-color;
text-decoration: none;
font-weight: bold;
}
}
.shared-img {
width: 100%;
display: block;
}
.job-meeting a {
color: $base-color;
text-decoration: none;
font-weight: bold;
margin-bottom: 10px;
display: block;
}
}
.article-comment {
border-left: 5px solid $base-border-color;
padding: 10px 20px;
span {
margin-right: 10px;
color: $article-comment-color;
}
}
.followed-by {
img {
height: 32px;
width: 32px;
@include border-radius($circle-border-radius);
margin-right: 5px;
float: left;
}
.followed-by-inner {
margin-left: 40px;
padding: 5px 0;
}
}
}
.comments {
margin-bottom: 10px;
cursor: pointer;
img.profile-icon {
height: 50px;
width: 50px;
border: 2px solid $base-border-color;
@include border-radius($circle-border-radius);
float: left;
}
h4 {
font-size: 14px;
float: left;
span {
margin-left: 8px;
font-size: 18px;
position: relative;
top: 2px;
}
}
.from-now {
float: right;
span {
margin-right: 5px;
font-size: 16px;
position: relative;
top: 1px;
}
}
.content-wrap {
margin-left: 65px;
.content {
margin-bottom: 15px;
white-space: normal;
clear: both;
}
}
&.sub-comments {
margin: 0 0 10px 60px;
.like-comment-btn-wrap {
border-bottom: none;
}
}
}
.like-comment-btn-wrap {
text-align: right;
padding-bottom: 15px;
button {
margin-left: 15px;
height: 30px;
width: 30px;
background-color: $like-comment-btn-background-color;
font-size: 14px;
color: $color;
border: none;
cursor: pointer;
}
}
.menu-item-common {
padding-right: 20px;
position: absolute;
font-family: FontAwesome;
right: 0;
}
.navigation-email {
// @include box-shadow(0px,2px,8px,0px,rgba(0,0,0,.15));
@include box-shadow(0, 1px, 2px, 0, rgba(0,0,0,0.2));
&.x-menu-default {
border-width: 0;
}
.x-menu-header {
line-height: 20px;
background-color: $lightest-color;
padding: 22px 15px;
border-bottom: 1px solid #ccc !important;
.x-title-icon-wrap {
width: 40px;
padding-right: 28px;
text-align: left;
}
.x-title-text {
font-size: 16px;
}
}
.x-menu-item-icon-default {
padding-top: 10px;
padding-left: 12px;
font-size: 16px;
line-height: 24px;
}
.x-menu-item {
line-height: 50px;
.x-menu-item-text-default.x-menu-item-indent-no-separator {
margin-left: 56px;
}
&.online-user {
.x-menu-item-text-default.x-menu-item-indent-no-separator {
margin-left: 18px;
}
.x-menu-item-link:after {
color: $online-menu-item-color;
content: "\f111";
@extend .menu-item-common;
}
&.x-menu-item-active {
.x-menu-item-link:after {
color: white;
}
}
}
&.offline-user {
.x-menu-item-link:after {
color: $offline-menu-item-color;
content: "\f111";
@extend .menu-item-common;
}
.x-menu-item-text-default.x-menu-item-indent-no-separator {
margin-left: 20px;
}
}
.x-menu-item-link:after {
@extend .menu-item-common;
color: $default-menu-item-color;
content: "\f105";
}
}
}
.new-message-cont {
margin-left: 203px;
}
.submit-new-message {
float: right;
top: 0 !important;
}
.hide-pm {
display: none;
}
.private-conversation-text {
padding: 30px;
}

@ -1 +0,0 @@
$dialog-trigger-color : #e5e5e5;

@ -14,3 +14,8 @@ $social-envelope-btn-background: #7754aa;
// custom vars
$console-msg-font-size: 16px;
$default-menu-item-color: #858585;
$online-menu-item-color: #86c747;
$offline-menu-item-color: #9e9f9f;
$menu-item-focus-color: #88bf4c;

@ -0,0 +1,3 @@
$like-comment-btn-background-color: #f4f4f4;
$like-comment-btn-color: #979797;
$article-comment-color: #eee;

@ -19,6 +19,8 @@ Ext.define('NgcpCsc.Application', {
'NavigationTree',
'Calls',
'VoiceMails',
'Chat',
'ChatList',
'Languages'
],

@ -78,6 +78,7 @@ Ext.define('NgcpCsc.view.main.Main', {
id: 'main-view-detail-wrap',
reference: 'mainContainerWrap',
flex: 1,
scrollable: false,
items: [{
xtype: 'treelist',
reference: 'navigationTreeList',
@ -96,9 +97,9 @@ Ext.define('NgcpCsc.view.main.Main', {
reference: 'mainCardPanel',
cls: 'sencha-dash-right-main-container',
itemId: 'contentPanel',
height: 500,
layout: {
type: 'card',
anchor: '100%'
type: 'card'
}
}]
}]

@ -0,0 +1,60 @@
Ext.define('NgcpCsc.view.pages.chat.Chat', {
extend: 'Ext.panel.Panel',
xtype: 'chat',
viewModel: 'chat',
controller: 'chat',
layout: 'hbox',
items: [{
xtype: 'chatlist',
width: 200,
padding: '10 20 20',
height: '100%'
}, {
xtype: 'tabpanel',
width: '90%',
height: '100%',
items: [{
title: Ngcp.csc.locales.chat.title[localStorage.getItem('languageSelected')],
xtype: 'chat-notifications',
id: 'chat-notifications',
scrollable: true,
bind: {
store: '{notifications}'
}
}]
}],
dockedItems: [{
xtype: 'toolbar',
cls: 'new-message-cont',
fixed: true,
padding: '0 0 10 0',
dock: 'bottom',
items: [{
xtype: 'textarea',
bind: {
value: '{new_message}'
},
cls: 'new-message',
name: 'new-message',
enableKeyEvents: true,
height: 100,
width: '95%',
listeners: {
keypress: 'onPressEnter'
},
emptyText: Ngcp.csc.locales.chat.msg_box.empty_text[localStorage.getItem('languageSelected')]
}, {
xtype: 'button',
cls: 'submit-new-message',
text: Ngcp.csc.locales.common.submit[localStorage.getItem('languageSelected')],
handler: 'onPressSubmitBtn'
}]
}]
});

@ -0,0 +1,80 @@
Ext.define('NgcpCsc.view.pages.chat.ChatController', {
extend: 'Ext.app.ViewController',
alias: 'controller.chat',
listen: {
controller: {
'#chatlist': {
openpmtab: 'openPM'
}
}
},
onPressEnter: function(field, e) {
if (e.getKey() == e.ENTER) {
e.preventDefault();
this.submitMessage();
}
},
onPressSubmitBtn: function(field, e) {
this.submitMessage();
},
submitMessage: function(msg, user) {
var message = msg || this.getViewModel().get('new_message');
if (message.length < 1)
return;
var chatStore = this.getView().down('tabpanel').getActiveTab().getStore('notifications');
var lastMsg = chatStore.getAt(chatStore.getCount() - 1) || this.getViewModel().getStore('notifications').findRecord('id', this.getView().down('tabpanel').getActiveTab().name);
var date = new Date();
var minutes = date.getMinutes();
var hour = date.getHours();
var day = date.getDate();
var month = date.getMonth() + 1;
var messageModel = Ext.create('NgcpCsc.model.ChatNotification', {
/// "id": (user) ? user.get('id') : 0,
"name": (user) ? user.get('name') : localStorage.getItem('username'),
"date": Ext.String.format("{0}.{1}", day, month),
"isActive": true,
"time": Ext.String.format("{0}:{1}", hour, minutes),
"thumbnail": (user) ? user.get('thumbnail') : "resources/images/user-profile/2.png",
"content": message
});
chatStore.add(messageModel);
this.clearMsg();
this.focusLastMsg();
},
clearMsg: function() {
this.getView().down('[name=new-message]').reset();
},
focusLastMsg: function(rec) {
var chatCmp = this.getView().down('tabpanel').getActiveTab();
chatCmp.scrollTo(0, chatCmp.getEl().dom.scrollHeight);
},
openPM: function(item, rec) {
var tab = this.getView().down('[name=' + rec.get('id') + ']');
if (rec.get('name') == 'administrator') // hardcoded administrator
return;
if (!tab) {
tab = this.getView().down('tabpanel').add({
xtype: 'chat-notifications',
title: rec.get('name'),
closable: true,
scrollable: true,
cls: 'private-conversation-text',
deferEmptyText: false,
emptyText: Ext.String.format(Ngcp.csc.locales.chat.start_conversation[localStorage.getItem('languageSelected')], rec.get('name')),
name: rec.get('id'),
store: Ext.create('Ext.data.Store', {
model: 'NgcpCsc.model.ChatNotification'
})
});
}
this.getView().down('tabpanel').setActiveTab(tab);
}
});

@ -0,0 +1,23 @@
Ext.define('NgcpCsc.view.pages.chat.ChatList', {
extend: 'Ext.menu.Menu',
alias: 'widget.chatlist',
viewModel: {
type: 'chatlist'
},
controller: 'chatlist',
title: Ngcp.csc.locales.chat.title[localStorage.getItem('languageSelected')],
cls: 'navigation-email',
iconCls: 'x-fa fa-group',
floating: false,
listeners: {
click: 'itemListClicked'
}
});

@ -0,0 +1,51 @@
Ext.define('NgcpCsc.view.pages.chat.ChatListController', {
extend: 'Ext.app.ViewController',
alias: 'controller.chatlist',
id: 'chatlist', // needed as reference in ChatController listeners
init: function() {
var me = this,
friendsStore = me.getViewModel().getStore('friends');
//Trigger local sorting once new data is available
friendsStore.on('load', function(store) {
store.sort();
});
//Sort locally and then update menu
friendsStore.on('sort', function(store) {
me.mutateData(store, store.getRange());
});
me.callParent(arguments);
},
mutateData: function(store, records) {
var view = this.getView(),
arr = [],
len = records.length,
i;
for (i = 0; i < len; i++) {
arr.push({
xtype: 'menuitem',
uId: records[i].get('id'),
text: records[i].get('name'),
cls: 'font-icon ' + (records[i].get('online') ? 'online-user' : 'offline-user')
});
}
Ext.suspendLayouts();
view.removeAll(true);
view.add(arr);
Ext.resumeLayouts(true);
},
itemListClicked: function(menu, item) {
var selectedUser = Ext.getStore('ChatList').findRecord('id', item.uId, 0, false, true, true);
if (selectedUser && selectedUser.get('online'))
this.fireEvent('openpmtab', null, selectedUser);
}
});

@ -0,0 +1,15 @@
Ext.define('NgcpCsc.view.pages.chat.ChatListModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.chatlist',
stores: {
friends: {
//Store reference
type: 'chatlist',
//Auto load
autoLoad: true
}
}
});

@ -0,0 +1,11 @@
Ext.define('NgcpCsc.view.pages.chat.ChatModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.chat',
data: {
new_message:''
},
formulas: {},
stores: {
notifications: 'Chat'
}
});

@ -0,0 +1,28 @@
Ext.define('NgcpCsc.view.pages.chat.ChatNotifications', {
extend: 'Ext.DataView',
xtype: 'chat-notifications',
cls: 'user-notifications',
scrollable: false,
listeners: {
itemclick: 'openPM'
},
itemTpl: [
"<div class='comments'>",
"<img src='{thumbnail}' alt='' class='profile-icon'>",
"<div class='content-wrap'>",
"<div>",
"<h4 class='profilenotifications-username'>{name}</h4>",
"<span class='from-now'><span class='x-fa fa-clock-o'></span>{time} {date}",
"<span class='like-comment-btn-wrap'>", // hide the private message button in case the message comes from the user (in this case _d = 0);
"<button type='button' id='{name}' class='x-fa fa-comments {[values.name === 'administrator' ? 'hide-pm' : '']}'></button>",
"</span></span>",
"</div>",
"<div class='content'>{content}</div>",
"</div>",
"</div>"
]
});

@ -0,0 +1,27 @@
{
"data": [{
"id": 840,
"name": "Jil Sanchez",
"date": "10/27/2016",
"isActive": true,
"time": "13:42",
"thumbnail": "resources/images/user-profile/9.png",
"content": "There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don\'t look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn\'t anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc."
}, {
"id": 252,
"name": "Ben Wright",
"date": "10/27/2010",
"isActive": true,
"time": "14:03",
"thumbnail": "resources/images/user-profile/10.png",
"content": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
}, {
"id": 162,
"name": "Allen Morris",
"date": "10/27/2016",
"isActive": true,
"time": "4:57",
"thumbnail": "resources/images/user-profile/11.png",
"content": "There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don\'t look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn\'t anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc."
}]
}

@ -0,0 +1,27 @@
{
"data": [{
"id": 840,
"online": true,
"name": "Jil Sanchez"
}, {
"id": 1,
"online": false,
"name": "Oneill Franklin"
}, {
"id": 3,
"online": false,
"name": "Branch Allison"
}, {
"id": 252,
"online": true,
"name": "Ben Wright"
}, {
"id": 162,
"online": true,
"name": "Allen Morris"
}, {
"id": 5,
"online": false,
"name": "Suzette Powell"
}]
}
Loading…
Cancel
Save