Implemented feature to transfer chat sessions to another chat topic.

This commit is contained in:
Martin Edenhofer 2019-12-03 07:29:02 +01:00
parent 3c788ca426
commit 133b570fba
15 changed files with 491 additions and 160 deletions

View file

@ -4,11 +4,12 @@ class App.CustomerChat extends App.Controller
'click .js-settings': 'settings'
elements:
'.js-acceptChat': 'acceptChatElement'
'.js-badgeWaitingCustomers': 'badgeWaitingCustomers'
'.js-acceptChat': 'acceptChatElement'
'.js-badgeWaitingCustomers': 'badgeWaitingCustomers'
'.js-totalInfo': 'totalInfo'
'.js-badgeChattingCustomers': 'badgeChattingCustomers'
'.js-badgeActiveAgents': 'badgeActiveAgents'
'.chat-workspace': 'workspace'
'.js-badgeActiveAgents': 'badgeActiveAgents'
'.chat-workspace': 'workspace'
sounds:
chat_new: new Audio('assets/sounds/chat_new.mp3')
@ -28,7 +29,9 @@ class App.CustomerChat extends App.Controller
@meta =
active: false
waiting_chat_count: 0
waiting_chat_count_by_chat: {}
waiting_chat_session_list: []
waiting_chat_session_list_by_chat: {}
running_chat_count: 0
running_chat_session_list: []
active_agent_count: 0
@ -99,65 +102,23 @@ class App.CustomerChat extends App.Controller
@html App.view('customer_chat/index')()
chatSessionList = (list) ->
for chat_session in list
chat = App.Chat.find(chat_session.chat_id)
chat_session.name = "#{chat.displayName()} [##{chat_session.id}]"
chat_session.geo_data = ''
if chat_session.preferences && chat_session.preferences.geo_ip
if chat_session.preferences.geo_ip.country_name
chat_session.geo_data += chat_session.preferences.geo_ip.country_name
if chat_session.preferences.geo_ip.city_name
chat_session.geo_data += " #{chat_session.preferences.geo_ip.city_name}"
if chat_session.user_id
chat_session.user = App.User.find(chat_session.user_id)
App.view('customer_chat/chat_list')(
chat_sessions: list
)
@el.find('.js-waitingCustomers .js-info').popover(
trigger: 'hover'
html: true
animation: false
delay: 0
placement: 'bottom'
container: 'body' # place in body do prevent it from animating
title: ->
App.i18n.translateContent('Waiting Customers')
content: =>
chatSessionList(@meta.waiting_chat_session_list)
chatSessionList: (list) ->
list = [] if !list
for chat_session in list
chat = App.Chat.find(chat_session.chat_id)
chat_session.name = "#{chat.displayName()} [##{chat_session.id}]"
chat_session.geo_data = ''
if chat_session.preferences && chat_session.preferences.geo_ip
if chat_session.preferences.geo_ip.country_name
chat_session.geo_data += chat_session.preferences.geo_ip.country_name
if chat_session.preferences.geo_ip.city_name
chat_session.geo_data += " #{chat_session.preferences.geo_ip.city_name}"
if chat_session.user_id
chat_session.user = App.User.find(chat_session.user_id)
App.view('customer_chat/chat_list')(
chat_sessions: list
)
@el.find('.js-chattingCustomers .js-info').popover(
trigger: 'hover'
html: true
animation: false
delay: 0
placement: 'bottom'
container: 'body'
title: ->
App.i18n.translateContent('Chatting Customers')
content: =>
chatSessionList(@meta.running_chat_session_list)
)
@el.find('.js-activeAgents .js-info').popover(
trigger: 'hover'
html: true
animation: false
delay: 0
placement: 'bottom'
container: 'body'
title: ->
App.i18n.translateContent('Active Agents')
content: =>
users = []
for user_id in @meta.active_agent_ids
users.push App.User.find(user_id)
App.view('customer_chat/user_list')(
users: users
)
)
show: (params) =>
@title 'Customer Chat', true
@ -248,15 +209,68 @@ class App.CustomerChat extends App.Controller
@stopPushState()
@pushState()
activeChatTopcis: =>
preferences = @Session.get('preferences')
return [] if !preferences
return [] if !preferences.chat
return [] if !preferences.chat.active
chats = []
for chat in App.Chat.all()
if preferences.chat.active[chat.id] is 'on' || preferences.chat.active[chat.id.toString()] is 'on'
chats.push chat
chats
updateMeta: =>
$('.popover').remove()
activeChatTopcis = @activeChatTopcis()
@$('.js-header').html(App.view('customer_chat/chat_header')(chats: activeChatTopcis))
@refreshElements()
if @meta.waiting_chat_count && @maxChatWindows > @windowCount()
@acceptChatElement.addClass('is-clickable is-blinking')
# activate normal button
@acceptChatElement.not('[data-chat-id]').addClass('is-active pulsate-animation')
# activate specific chat buttons
if activeChatTopcis.length > 1
for chat in activeChatTopcis
if @meta.waiting_chat_count_by_chat[chat.id]
@$(".js-header .js-acceptChat[data-chat-id=#{chat.id}]").addClass('is-active pulsate-animation').attr('disabled', false)
@idleTimeoutStart()
else
@acceptChatElement.removeClass('is-clickable is-blinking')
@acceptChatElement.removeClass('is-active pulsate-animation')
@idleTimeoutStop()
@badgeWaitingCustomers.text(@meta.waiting_chat_count)
if activeChatTopcis.length > 1
for chat in App.Chat.all()
do (chat) =>
@$(".js-header .js-waitingCustomers[data-chat-id=#{chat.id}] .js-badgeWaitingCustomers").text(@meta.waiting_chat_count_by_chat[chat.id])
@el.find(".js-waitingCustomers[data-chat-id=#{chat.id}] .js-info").popover(
trigger: 'hover'
html: true
animation: false
delay: 0
placement: 'bottom'
container: 'body' # place in body do prevent it from animating
title: ->
App.i18n.translateContent('Waiting Customers')
content: =>
@chatSessionList(@meta.waiting_chat_session_list_by_chat[chat.id])
)
else
@badgeWaitingCustomers.text(@meta.waiting_chat_count)
@el.find('.js-waitingCustomers .js-totalInfo').popover(
trigger: 'hover'
html: true
animation: false
delay: 0
placement: 'bottom'
container: 'body' # place in body do prevent it from animating
title: ->
App.i18n.translateContent('Waiting Customers')
content: =>
@chatSessionList(@meta.waiting_chat_session_list_by_chat[activeChatTopcis[0].id])
)
@badgeChattingCustomers.text(@meta.running_chat_count)
@badgeActiveAgents.text(@meta.active_agent_count)
@ -266,6 +280,37 @@ class App.CustomerChat extends App.Controller
@addChat(session)
@meta.active_sessions = false
@el.find('.js-chattingCustomers .js-info').popover(
trigger: 'hover'
html: true
animation: false
delay: 0
placement: 'bottom'
container: 'body'
title: ->
App.i18n.translateContent('Chatting Customers')
content: =>
@chatSessionList(@meta.running_chat_session_list)
)
@el.find('.js-activeAgents .js-info').popover(
trigger: 'hover'
html: true
animation: false
delay: 0
placement: 'bottom'
container: 'body'
title: ->
App.i18n.translateContent('Active Agents')
content: =>
users = []
for user_id in @meta.active_agent_ids
users.push App.User.find(user_id)
App.view('customer_chat/user_list')(
users: users
)
)
@updateNavMenu()
addChat: (session) ->
@ -298,9 +343,10 @@ class App.CustomerChat extends App.Controller
for session_id, chat of @chatWindows
chat.trigger('layout-changed')
acceptChat: =>
acceptChat: (e) =>
return if @windowCount() >= @maxChatWindows
App.WebSocket.send(event:'chat_session_start')
chat_id = $(e.currentTarget).attr('data-chat-id')
App.WebSocket.send(event:'chat_session_start', chat_id: chat_id)
@idleTimeoutStop()
settings: (params = {}) ->
@ -344,6 +390,7 @@ class ChatWindow extends App.Controller
'click .js-scrollHint': 'onScrollHintClick'
'click .js-info': 'toggleMeta'
'click .js-createTicket': 'ticketCreate'
'click .js-transferChat': 'transfer'
'submit .js-metaForm': 'sendMetaForm'
elements:
@ -450,6 +497,7 @@ class ChatWindow extends App.Controller
@html App.view('customer_chat/chat_window')(
name: @name
session: @session
chats: App.Chat.all()
)
@el.one('transitionend', @onTransitionend)
@ -766,6 +814,12 @@ class ChatWindow extends App.Controller
else if showHint
@showScrollHint()
transfer: (e) =>
e.preventDefault()
chat_id = $(e.currentTarget).attr('data-chat-id')
App.WebSocket.send(event:'chat_transfer', chat_id: chat_id, session_id: @session.id)
@close()
ticketCreate: (e) =>
e.preventDefault()

View file

@ -0,0 +1,40 @@
<div class="status-fields">
<% if @chats.length > 1: %>
<div class="buttonDropdown dropdown">
<div class="status-field status-field--spacer js-acceptChat">
<span class="badge js-badgeWaitingCustomers"></span> <%- @T('Waiting Customers') %>
</div>
<div class="status-field status-field--arrow" data-toggle="dropdown">
<%- @Icon('arrow-down') %>
</div>
<ul class="dropdown-menu" role="menu">
<% for chat in @chats: %>
<li class="js-waitingCustomers js-acceptChat" disabled data-chat-id="<%= chat.id %>" role="menuitem">
<span class="badge js-badgeWaitingCustomers"></span> <%- @T('Waiting in %s', chat.name) %> <span class="flex-spacer"></span>
<div class="status-badge js-info">
<div class="info-badge"><%- @Icon('info') %></div>
</div>
<% end %>
</ul>
</div>
<% else: %>
<div class="status-field js-acceptChat js-waitingCustomers">
<span class="badge js-badgeWaitingCustomers"></span> <%- @T('Waiting Customers') %>
<div class="status-badge js-totalInfo">
<div class="info-badge"><%- @Icon('info') %></div>
</div>
</div>
<% end %>
<div class="status-field js-chattingCustomers">
<span class="badge js-badgeChattingCustomers"></span> <%- @T('Chatting Customers') %>
<div class="status-badge js-info">
<div class="info-badge"><%- @Icon('info') %></div>
</div>
</div>
<div class="status-field js-activeAgents">
<span class="badge js-badgeActiveAgents"></span> <%- @T('Active Agents') %>
<div class="status-badge js-info">
<div class="info-badge"><%- @Icon('info') %></div>
</div>
</div>
</div>

View file

@ -24,6 +24,15 @@
<div class="chat-body js-body"></div>
<div class="chat-body js-meta hidden">
<% if @session: %>
<%- @T('Transfer conversation to another chat:') %>
<ul>
<% for chat in @chats: %>
<% if @session.chat_id isnt chat.id: %>
<li><a data-chat-id="<%= chat.id %>" class="js-transferChat" href="#"><%- chat.name %></a>
<% end %>
<% end %>
</ul>
<hr>
<ul>
<li><%- @T('Created at') %>: <%- @Ttimestamp(@session.created_at) %></li>
<% if @session && @session.preferences: %>

View file

@ -3,28 +3,7 @@
<div class="page-header-title">
<h1><%- @T('Customer Chat') %></h1>
</div>
<div class="page-header-center">
<div class="status-fields">
<div class="status-field js-acceptChat js-waitingCustomers">
<span class="badge js-badgeWaitingCustomers"></span> <%- @T('Waiting Customers') %>
<div class="status-badge js-info">
<div class="info-badge"><%- @Icon('info') %></div>
</div>
</div>
<div class="status-field js-chattingCustomers">
<span class="badge js-badgeChattingCustomers"></span> <%- @T('Chatting Customers') %>
<div class="status-badge js-info">
<div class="info-badge"><%- @Icon('info') %></div>
</div>
</div>
<div class="status-field js-activeAgents">
<span class="badge js-badgeActiveAgents"></span> <%- @T('Active Agents') %>
<div class="status-badge js-info">
<div class="info-badge"><%- @Icon('info') %></div>
</div>
</div>
</div>
</div>
<div class="page-header-center js-header"></div>
<div class="page-header-meta">
<div class="btn btn--action js-settings"><%- @T('Settings') %></div>
</div>

View file

@ -29,11 +29,11 @@
<%- @Icon('arrow-down', 'dropdown-arrow') %>
</div>
</div>
<table class="settings-list">
<table class="settings-list settings-list--stretch">
<thead>
<tr>
<th><%- @T('Topic') %>
<th width="100%"><%- @T('Greeting') %> (<%- @T('Separate multiple values by ;') %>)
<th><%- @T('Greeting') %> (<%- @T('Separate multiple values by ;') %>)
<th><%- @T('Enabled') %>
</th></tr>
</thead>

View file

@ -889,6 +889,23 @@ pre code.hljs {
.status-fields {
display: flex;
max-width: 100%;
.dropdown li {
display: flex;
align-items: center;
padding: 0 10px;
}
.dropdown-menu .status-badge {
margin-left: 10px;
}
.dropdown-menu .badge {
margin-top: -2px;
margin-right: 7px;
background: hsla(0,0%,0%,.5);
}
}
.status-field {
@ -896,10 +913,15 @@ pre code.hljs {
border: 1px solid hsl(0,0%,90%);
display: flex;
height: 34px;
flex-shrink: 1;
min-width: 20px;
padding: 5px 0;
align-items: center;
line-height: 35px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
&.is-clickable {
&.is-active {
background: hsl(203,65%,55%);
color: white;
border-color: hsl(203,65%,45%);
@ -908,10 +930,6 @@ pre code.hljs {
@extend %clickable;
}
&.is-blinking {
animation: pulsate 667ms ease-in-out infinite alternate;
}
&:not(:last-child):not(:only-child) {
@include bidi-style(border-right-width, 0, border-left-width, 1px);
}
@ -919,6 +937,12 @@ pre code.hljs {
&:first-child {
border-radius: 5px 0 0 5px;
@include rtl(border-radius, 0 5px 5px 0);
.dropdown.open & {
border-radius: 5px 0 0 0;
@include rtl(border-radius, 0 5px 0 0);
}
}
&:last-child {
@ -931,7 +955,7 @@ pre code.hljs {
}
.badge {
@include bidi-style(margin, 0 5px 0 10px, margin, 0 10px 0 5px);
@include bidi-style(margin, 0 7px 0 10px, margin, 0 10px 0 7px);
background: hsla(210,50%,10%,.24);
}
@ -942,6 +966,22 @@ pre code.hljs {
justify-content: center;
align-self: stretch;
}
&--arrow {
@extend %clickable;
border-left: none;
width: 34px;
justify-content: center;
.icon {
fill: currentColor;
}
}
&--spacer {
padding-left: 16px;
padding-right: 2px;
}
}
.status-badge {
@ -2945,6 +2985,10 @@ ol.tabs li {
.tab {
flex: none;
&:nth-last-child(2) {
@include bidi-style(border-right-width, 0, border-right-width, 1px);
}
}
}
@ -7386,6 +7430,12 @@ footer {
.dropdown-menu > li[disabled] {
opacity: 0.33;
&:hover,
&.is-active {
background: none;
cursor: default;
}
}
.dropdown-menu > li > a {
@ -7404,7 +7454,7 @@ footer {
display: block;
}
.dropdown-menu .badge {
.dropdown-menu .badge--text {
@include bidi-style(padding-left, 10px, padding-right, 0);
}

View file

@ -201,6 +201,7 @@ returns
end
running_chat_session_list_local = running_chat_session_list(chat_ids)
running_chat_session_list_local.each do |session|
next if !session['user_id']
@ -211,16 +212,18 @@ returns
end
{
waiting_chat_count: waiting_chat_count(chat_ids),
waiting_chat_session_list: waiting_chat_session_list(chat_ids),
running_chat_count: running_chat_count(chat_ids),
running_chat_session_list: running_chat_session_list_local,
active_agent_count: active_agent_count(chat_ids),
active_agent_ids: active_agent_ids,
seads_available: seads_available(chat_ids),
seads_total: seads_total(chat_ids),
active: Chat::Agent.state(user_id),
assets: assets,
waiting_chat_count: waiting_chat_count(chat_ids),
waiting_chat_count_by_chat: waiting_chat_count_by_chat(chat_ids),
waiting_chat_session_list: waiting_chat_session_list(chat_ids),
waiting_chat_session_list_by_chat: waiting_chat_session_list_by_chat(chat_ids),
running_chat_count: running_chat_count(chat_ids),
running_chat_session_list: running_chat_session_list_local,
active_agent_count: active_agent_count(chat_ids),
active_agent_ids: active_agent_ids,
seads_available: seads_available(chat_ids),
seads_total: seads_total(chat_ids),
active: Chat::Agent.state(user_id),
assets: assets,
}
end
@ -305,6 +308,14 @@ returns
Chat::Session.where(state: ['waiting'], chat_id: chat_ids).count
end
def self.waiting_chat_count_by_chat(chat_ids)
list = {}
Chat.where(active: true, id: chat_ids).pluck(:id).each do |chat_id|
list[chat_id] = Chat::Session.where(chat_id: chat_id, state: ['waiting']).count
end
list
end
def self.waiting_chat_session_list(chat_ids)
sessions = []
Chat::Session.where(state: ['waiting'], chat_id: chat_ids).each do |session|
@ -313,6 +324,17 @@ returns
sessions
end
def self.waiting_chat_session_list_by_chat(chat_ids)
sessions = {}
Chat.where(active: true, id: chat_ids).pluck(:id).each do |chat_id|
Chat::Session.where(chat_id: chat_id, state: ['waiting']).each do |session|
sessions[chat_id] ||= []
sessions[chat_id].push session.attributes
end
end
sessions
end
=begin
get count running sessions in given chats

View file

@ -22,7 +22,11 @@ return is sent as message back to peer
# find first in waiting list
chat_user = User.lookup(id: @session['id'])
chat_ids = Chat.agent_active_chat_ids(chat_user)
chat_session = Chat::Session.where(state: 'waiting', chat_id: chat_ids).order(created_at: :asc).first
chat_session = if @payload['chat_id']
Chat::Session.where(state: 'waiting', chat_id: @payload['chat_id']).order(created_at: :asc).first
else
Chat::Session.where(state: 'waiting', chat_id: chat_ids).order(created_at: :asc).first
end
if !chat_session
return {
event: 'chat_session_start',
@ -37,25 +41,32 @@ return is sent as message back to peer
chat_session.preferences[:participants] = chat_session.add_recipient(@client_id)
chat_session.save
# send chat_session_init to client
user = chat_session.agent_user
data = {
event: 'chat_session_start',
data: {
state: 'ok',
agent: user,
session_id: chat_session.session_id,
chat_id: chat_session.chat_id,
},
}
# send to customer
chat_session.send_to_recipients(data, @client_id)
session_attributes = chat_session.attributes
session_attributes['messages'] = []
Chat::Message.where(chat_session_id: chat_session.id).order(created_at: :asc).each do |message|
session_attributes['messages'].push message.attributes
end
# send chat_session_init to customer client
if session_attributes['messages'].blank?
user = chat_session.agent_user
data = {
event: 'chat_session_start',
data: {
state: 'ok',
agent: user,
session_id: chat_session.session_id,
chat_id: chat_session.chat_id,
},
}
chat_session.send_to_recipients(data, @client_id)
end
# send to agent
data = {
event: 'chat_session_start',
data: {
session: chat_session.attributes,
session: session_attributes,
},
}
Sessions.send(@client_id, data)

View file

@ -0,0 +1,39 @@
class Sessions::Event::ChatTransfer < Sessions::Event::ChatBase
def run
return super if super
return if !permission_check('chat.agent', 'chat')
# find chat session
chat_session = Chat::Session.find_by(id: @payload['session_id'])
if !chat_session
return {
event: 'chat_session_start',
data: {
state: 'failed',
message: 'No session available.',
},
}
end
chat_ids_to_notify = [chat_session.chat_id, @payload['chat_id']]
chat_session.chat_id = @payload['chat_id']
chat_session.state = 'waiting'
chat_session.save
# send state update with sessions to agents
Chat.broadcast_agent_state_update(chat_ids_to_notify)
# send transfer message to client
message = {
event: 'chat_session_notice',
data: {
session_id: chat_session.session_id,
message: 'Conversation transfered into other chat. Please stay tuned.',
},
}
chat_session.send_to_recipients(message, @client_id)
nil
end
end

View file

@ -753,6 +753,8 @@ do($ = window.jQuery, window) ->
@onSessionClosed pipe.data
when 'chat_session_left'
@onSessionClosed pipe.data
when 'chat_session_notice'
@addStatus @T(pipe.data.message)
when 'chat_status_customer'
switch pipe.data.state
when 'online'

View file

@ -1032,6 +1032,9 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
case 'chat_session_left':
this.onSessionClosed(pipe.data);
break;
case 'chat_session_notice':
this.addStatus(this.T(pipe.data.message));
break;
case 'chat_status_customer':
switch (pipe.data.state) {
case 'online':

File diff suppressed because one or more lines are too long

View file

@ -1858,42 +1858,40 @@ figcaption {
}
-->
<script>
var chat = new ZammadChat({
chatId: 1,
host: 'ws://localhost:6042',
cssUrl: 'http://localhost:5000/assets/chat/chat.css',
debug: true
});
function getSearchParameters() {
var prmstr = window.location.search.substr(1);
return prmstr != null && prmstr != '' ? transformToAssocArray(prmstr) : {};
}
function transformToAssocArray( prmstr ) {
var params = {};
var prmarr = prmstr.split('&');
for ( var i = 0; i < prmarr.length; i++) {
var tmparr = prmarr[i].split('=');
params[tmparr[0]] = tmparr[1];
}
return params;
}
var hostname = window.location.hostname;
var port = window.location.port;
var params = getSearchParameters();
var host = 'ws://'+ (location.host || 'localhost').split(':')[0] +':6042'
if (params['port']) {
host = 'ws://' + hostname + ':' + params['port']
}
cssUrl = 'http://' + hostname + ':' + port + '/assets/chat/chat.css'
$('.settings :input').on({
change: function(){
switch($(this).attr('data-option')){
case "flat":
$('.zammad-chat').toggleClass('zammad-chat--flat', this.checked);
break;
case "color":
setScssVariable('themeColor', this.value);
updateStyle();
break;
case "borderRadius":
setScssVariable('borderRadius', this.value + "px");
updateStyle();
break;
}
},
input: function(){
switch($(this).attr('data-option')){
case "borderRadius":
$('[data-option="borderRadius"]').val(this.value);
setScssVariable('borderRadius', this.value + "px");
updateStyle();
break;
case "fontSize":
$('[data-option="fontSize"]').val(this.value);
setScssVariable('fontSize', this.value + "px");
updateStyle();
break;
}
}
var chat = new ZammadChat({
chatId: 2,
host: host,
cssUrl: cssUrl,
debug: true,
background: '#494d52',
flat: true,
idleTimeout: 1,
idleTimeoutIntervallCheck: 0.5,
inactiveTimeout: 2,
inactiveTimeoutIntervallCheck: 0.5,
waitingListTimeout: 1.2,
waitingListTimeoutIntervallCheck: 0.5,
});
</script>

View file

@ -47,6 +47,12 @@ RSpec.describe Sessions::Event::ChatSessionStart do
session: { 'id' => agent.id },
)
end
let(:chat_message_history) do
Chat::Message.create!(
chat_session_id: chat_session.id,
content: 'some message',
)
end
before do
Setting.set('chat', true)
@ -186,4 +192,37 @@ RSpec.describe Sessions::Event::ChatSessionStart do
end
end
context 'when starting a chat session as agent with transfered conversation' do
it 'send out chat_session_start to customer and agent with already created messages' do
chat_message_history
expect(subject_as_agent.run).to eq(nil)
messages_to_customer = Sessions.queue('customer_session_id')
expect(messages_to_customer.count).to eq(0)
messages_to_agent = Sessions.queue(client_id)
expect(messages_to_agent.count).to eq(1)
expect(messages_to_agent[0]).to include(
'event' => 'chat_session_start',
'data' => hash_including(
'session' => hash_including(
'user_id' => agent.id,
'state' => 'running',
'preferences' => hash_including(
'participants' => ['customer_session_id', client_id]
),
'messages' => array_including(
hash_including(
'content' => 'some message',
),
),
'id' => chat_session.id,
'chat_id' => chat_session.chat_id,
'session_id' => chat_session.session_id,
'name' => nil,
)
)
)
end
end
end

View file

@ -0,0 +1,84 @@
require 'rails_helper'
RSpec.describe Sessions::Event::ChatTransfer do
let(:client_id) { rand(123_456_789) }
let(:chat) { Chat.first }
let(:chat_transfer_into) { Chat.create!(name: 'chat 2', updated_by_id: 1, created_by_id: 1) }
let(:chat_session) do
Sessions.create('customer_session_id', { 'id' => customer.id }, {})
Sessions.queue('customer_session_id')
Chat::Session.create(
chat_id: chat.id,
user_id: nil,
preferences: { participants: ['customer_session_id'] },
state: 'running',
)
end
let!(:agent) do
create(:agent_user, preferences: { chat: { active: { chat.id.to_s => 'on' } } })
end
let!(:customer) { create(:customer_user) }
let(:subject_as_agent) do
Sessions.create(client_id, { 'id' => agent.id }, {})
Sessions.queue(client_id)
described_class.new(
payload: { 'data' => { 'session_id' => chat_session.session_id }, 'session_id' => chat_session.id, 'chat_id' => chat_transfer_into.id },
user_id: agent.id,
client_id: client_id,
clients: {},
session: { 'id' => agent.id },
)
end
before do
Setting.set('chat', true)
end
context 'when transfering a chat session as customer' do
let(:subject_as_customer) do
Sessions.create(client_id, { 'id' => customer.id }, {})
Sessions.queue(client_id)
described_class.new(
payload: { 'data' => { 'session_id' => chat_session.session_id }, 'chat_id' => chat_transfer_into.id },
user_id: customer.id,
client_id: client_id,
clients: {},
session: { 'id' => customer.id },
)
end
context 'without chat.agent permissions' do
it 'send out no_permission event to user' do
expect(subject_as_customer.run).to eq(nil)
messages = Sessions.queue(client_id)
expect(messages.count).to eq(1)
expect(messages).to eq([
'event' => 'chat_error',
'data' => {
'state' => 'no_permission'
}
])
end
end
end
context 'when transfering a chat session as agent' do
it 'send out chat_session_notice to customer and agent and set chat session to waiting' do
expect(subject_as_agent.run).to eq(nil)
messages_to_customer = Sessions.queue('customer_session_id')
expect(messages_to_customer.count).to eq(1)
expect(messages_to_customer[0]).to eq(
'event' => 'chat_session_notice',
'data' => {
'message' => 'Conversation transfered into other chat. Please stay tuned.',
'session_id' => chat_session.session_id,
},
)
messages_to_agent = Sessions.queue(client_id)
expect(messages_to_agent.count).to eq(0)
end
end
end