Added set of auto offline if agent is not answering chats for 120 seconds.
This commit is contained in:
parent
4803fa9383
commit
f5fa05bf96
12 changed files with 143 additions and 40 deletions
|
@ -18,6 +18,7 @@ class App.CustomerChat extends App.Controller
|
|||
@maxChatWindows = parseInt(preferences.chat.max_windows)
|
||||
|
||||
@pushStateIntervalOn = undefined
|
||||
@idleTimeout = parseInt(@Config.get('chat_agent_idle_timeout') || 120)
|
||||
@messageCounter = 0
|
||||
@meta =
|
||||
active: false
|
||||
|
@ -107,10 +108,10 @@ class App.CustomerChat extends App.Controller
|
|||
|
||||
@el.find('.js-waitingCustomers').popover(
|
||||
trigger: 'hover'
|
||||
container: 'body'
|
||||
html: true
|
||||
animation: false
|
||||
delay: 100
|
||||
placement: 'bottom'
|
||||
title: ->
|
||||
App.i18n.translateContent('Waiting Customers')
|
||||
content: =>
|
||||
|
@ -119,10 +120,10 @@ class App.CustomerChat extends App.Controller
|
|||
|
||||
@el.find('.js-chattingCustomers').popover(
|
||||
trigger: 'hover'
|
||||
container: 'body'
|
||||
html: true
|
||||
animation: false
|
||||
delay: 100
|
||||
placement: 'bottom'
|
||||
title: ->
|
||||
App.i18n.translateContent('Chatting Customers')
|
||||
content: =>
|
||||
|
@ -131,10 +132,10 @@ class App.CustomerChat extends App.Controller
|
|||
|
||||
@el.find('.js-activeAgents').popover(
|
||||
trigger: 'hover'
|
||||
container: 'body'
|
||||
html: true
|
||||
animation: false
|
||||
delay: 100
|
||||
placement: 'bottom'
|
||||
title: ->
|
||||
App.i18n.translateContent('Active Agents')
|
||||
content: =>
|
||||
|
@ -225,8 +226,11 @@ class App.CustomerChat extends App.Controller
|
|||
updateMeta: =>
|
||||
if @meta.waiting_chat_count && @maxChatWindows > @windowCount()
|
||||
@$('.js-acceptChat').addClass('is-clickable is-blinking')
|
||||
@idleTimeoutStart()
|
||||
else
|
||||
@$('.js-acceptChat').removeClass('is-clickable is-blinking')
|
||||
@idleTimeoutStop()
|
||||
|
||||
@$('.js-badgeWaitingCustomers').text(@meta.waiting_chat_count)
|
||||
@$('.js-badgeChattingCustomers').text(@meta.running_chat_count)
|
||||
@$('.js-badgeActiveAgents').text(@meta.active_agent_count)
|
||||
|
@ -271,6 +275,7 @@ class App.CustomerChat extends App.Controller
|
|||
acceptChat: =>
|
||||
return if @windowCount() >= @maxChatWindows
|
||||
App.WebSocket.send(event:'chat_session_start')
|
||||
@idleTimeoutStop()
|
||||
|
||||
settings: (errors = {}) ->
|
||||
new Setting(
|
||||
|
@ -278,6 +283,21 @@ class App.CustomerChat extends App.Controller
|
|||
errors: errors
|
||||
)
|
||||
|
||||
idleTimeoutStart: =>
|
||||
return if @idleTimeoutId
|
||||
switchOff = =>
|
||||
@switch(false)
|
||||
@notify(
|
||||
type: 'notice'
|
||||
msg: App.i18n.translateContent('Chat not answered, set to offline automatically.')
|
||||
)
|
||||
@idleTimeoutId = @delay(switchOff, @idleTimeout * 1000)
|
||||
|
||||
idleTimeoutStop: =>
|
||||
return if !@idleTimeoutId
|
||||
@clearDelay(@idleTimeoutId)
|
||||
@idleTimeoutId = undefined
|
||||
|
||||
class CustomerChatRouter extends App.ControllerPermanent
|
||||
constructor: (params) ->
|
||||
super
|
||||
|
|
|
@ -165,6 +165,57 @@ class Chat < ApplicationModel
|
|||
|
||||
=begin
|
||||
|
||||
broadcast new agent status to all agents
|
||||
|
||||
Chat.broadcast_agent_state_update
|
||||
|
||||
optional you can ignore it for dedecated user
|
||||
|
||||
Chat.broadcast_agent_state_update(ignore_user_id)
|
||||
|
||||
=end
|
||||
|
||||
def self.broadcast_agent_state_update(ignore_user_id = nil)
|
||||
|
||||
# send broadcast to agents
|
||||
Chat::Agent.where('active = ? OR updated_at > ?', true, Time.zone.now - 15.minutes).each {|item|
|
||||
next if item.updated_by_id == ignore_user_id
|
||||
data = {
|
||||
event: 'chat_status_agent',
|
||||
data: Chat.agent_state(item.updated_by_id),
|
||||
}
|
||||
Sessions.send_to(item.updated_by_id, data)
|
||||
}
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
broadcast new customer queue position to all waiting customers
|
||||
|
||||
Chat.broadcast_customer_state_update
|
||||
|
||||
=end
|
||||
|
||||
def self.broadcast_customer_state_update
|
||||
|
||||
# send position update to other waiting sessions
|
||||
position = 0
|
||||
Chat::Session.where(state: 'waiting').order('created_at ASC').each {|local_chat_session|
|
||||
position += 1
|
||||
data = {
|
||||
event: 'chat_session_queue',
|
||||
data: {
|
||||
state: 'queue',
|
||||
position: position,
|
||||
session_id: local_chat_session.session_id,
|
||||
},
|
||||
}
|
||||
local_chat_session.send_to_recipients(data)
|
||||
}
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
cleanup old chat messages
|
||||
|
||||
Chat.cleanup
|
||||
|
|
|
@ -31,6 +31,7 @@ class Observer::Chat::Leave::BackgroundJob
|
|||
}
|
||||
chat_session.send_to_recipients(message, @client_id)
|
||||
|
||||
Chat.broadcast_agent_state_update
|
||||
end
|
||||
|
||||
end
|
||||
|
|
25
db/migrate/20160106000001_update_chat5.rb
Normal file
25
db/migrate/20160106000001_update_chat5.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
class UpdateChat5 < ActiveRecord::Migration
|
||||
def change
|
||||
|
||||
Setting.create_if_not_exists(
|
||||
title: 'Agent idle timeout',
|
||||
name: 'chat_agent_idle_timeout',
|
||||
area: 'Chat::Extended',
|
||||
description: 'Idle timeout in seconds till agent is set offline automatically.',
|
||||
options: {
|
||||
form: [
|
||||
{
|
||||
display: '',
|
||||
null: false,
|
||||
name: 'chat_agent_idle_timeout',
|
||||
tag: 'input',
|
||||
},
|
||||
],
|
||||
},
|
||||
preferences: {},
|
||||
state: '120',
|
||||
frontend: true
|
||||
)
|
||||
|
||||
end
|
||||
end
|
20
db/seeds.rb
20
db/seeds.rb
|
@ -1214,6 +1214,26 @@ Setting.create_if_not_exists(
|
|||
frontend: true
|
||||
)
|
||||
|
||||
Setting.create_if_not_exists(
|
||||
title: 'Agent idle timeout',
|
||||
name: 'chat_agent_idle_timeout',
|
||||
area: 'Chat::Extended',
|
||||
description: 'Idle timeout in seconds till agent is set offline automatically.',
|
||||
options: {
|
||||
form: [
|
||||
{
|
||||
display: '',
|
||||
null: false,
|
||||
name: 'chat_agent_idle_timeout',
|
||||
tag: 'input',
|
||||
},
|
||||
],
|
||||
},
|
||||
preferences: {},
|
||||
state: '120',
|
||||
frontend: true
|
||||
)
|
||||
|
||||
Setting.create_if_not_exists(
|
||||
title: 'Define searchable models.',
|
||||
name: 'models_searchable',
|
||||
|
|
|
@ -9,7 +9,7 @@ class Sessions::Event::ChatAgentState < Sessions::Event::ChatBase
|
|||
Chat::Agent.state(@session['id'], @payload['data']['active'])
|
||||
|
||||
# broadcast new state to agents
|
||||
broadcast_agent_state_update(@session['id'])
|
||||
Chat.broadcast_agent_state_update(@session['id'])
|
||||
|
||||
{
|
||||
event: 'chat_agent_state',
|
||||
|
|
|
@ -23,37 +23,6 @@ class Sessions::Event::ChatBase < Sessions::Event::Base
|
|||
}
|
||||
end
|
||||
|
||||
def broadcast_agent_state_update(ignore_user_id = nil)
|
||||
|
||||
# send broadcast to agents
|
||||
Chat::Agent.where(active: true).each {|item|
|
||||
next if item.updated_by_id == ignore_user_id
|
||||
data = {
|
||||
event: 'chat_status_agent',
|
||||
data: Chat.agent_state(item.updated_by_id),
|
||||
}
|
||||
Sessions.send_to(item.updated_by_id, data)
|
||||
}
|
||||
end
|
||||
|
||||
def broadcast_customer_state_update
|
||||
|
||||
# send position update to other waiting sessions
|
||||
position = 0
|
||||
Chat::Session.where(state: 'waiting').order('created_at ASC').each {|local_chat_session|
|
||||
position += 1
|
||||
data = {
|
||||
event: 'chat_session_queue',
|
||||
data: {
|
||||
state: 'queue',
|
||||
position: position,
|
||||
session_id: local_chat_session.session_id,
|
||||
},
|
||||
}
|
||||
local_chat_session.send_to_recipients(data)
|
||||
}
|
||||
end
|
||||
|
||||
def agent_permission_check
|
||||
if !@session
|
||||
error = {
|
||||
|
|
|
@ -32,10 +32,10 @@ class Sessions::Event::ChatSessionClose < Sessions::Event::ChatBase
|
|||
chat_session.save
|
||||
|
||||
# set state update to all agents
|
||||
broadcast_agent_state_update
|
||||
Chat.broadcast_agent_state_update
|
||||
|
||||
# send position update to other waiting sessions
|
||||
broadcast_customer_state_update
|
||||
Chat.broadcast_customer_state_update
|
||||
|
||||
# notify about "leaving"
|
||||
else
|
||||
|
|
|
@ -23,7 +23,7 @@ class Sessions::Event::ChatSessionInit < Sessions::Event::ChatBase
|
|||
)
|
||||
|
||||
# send broadcast to agents
|
||||
broadcast_agent_state_update
|
||||
Chat.broadcast_agent_state_update
|
||||
|
||||
# return new session
|
||||
{
|
||||
|
|
|
@ -52,10 +52,10 @@ class Sessions::Event::ChatSessionStart < Sessions::Event::ChatBase
|
|||
Sessions.send(@client_id, data)
|
||||
|
||||
# send state update with sessions to agents
|
||||
broadcast_agent_state_update
|
||||
Chat.broadcast_agent_state_update
|
||||
|
||||
# send position update to other waiting sessions
|
||||
broadcast_customer_state_update
|
||||
Chat.broadcast_customer_state_update
|
||||
|
||||
nil
|
||||
end
|
||||
|
|
|
@ -8,6 +8,7 @@ export ZAMMAD_SETTING_TTL=15
|
|||
rails r "Setting.set('developer_mode', true)"
|
||||
rails r "Setting.set('websocket_port', '$WS_PORT')"
|
||||
rails r "Setting.set('fqdn', '$IP:$BROWSER_PORT')"
|
||||
rails r "Setting.set('chat_agent_idle_timeout', '45')"
|
||||
|
||||
pumactl start --pidfile tmp/pids/puma.pid -d -p $APP_PORT -e $RAILS_ENV
|
||||
script/websocket-server.rb start -d -p $WS_PORT
|
||||
|
|
|
@ -576,6 +576,11 @@ class ChatTest < TestCase
|
|||
)
|
||||
agent.find_elements( { css: '.active .chat-window .js-close' } ).each(&:click)
|
||||
|
||||
exists(
|
||||
browser: agent,
|
||||
css: '#navigation .js-switch input[checked]'
|
||||
)
|
||||
|
||||
# no customer action, hide widget
|
||||
customer = browser_instance
|
||||
location(
|
||||
|
@ -618,6 +623,17 @@ class ChatTest < TestCase
|
|||
timeout: 120,
|
||||
)
|
||||
|
||||
# check if agent is offline, idle timeout, chat not answered
|
||||
exists_not(
|
||||
browser: agent,
|
||||
css: '#navigation .js-switch input[checked]'
|
||||
)
|
||||
switch(
|
||||
browser: agent,
|
||||
css: '#navigation .js-switch',
|
||||
type: 'on',
|
||||
)
|
||||
|
||||
# no customer action, show sorry screen
|
||||
reload(
|
||||
browser: customer,
|
||||
|
|
Loading…
Reference in a new issue