Added chat settings. Improved chat event backends.
This commit is contained in:
parent
838b91792c
commit
39b37e048b
16 changed files with 262 additions and 120 deletions
|
@ -3,6 +3,7 @@ class App.CustomerChat extends App.Controller
|
|||
|
||||
events:
|
||||
'click .js-acceptChat': 'acceptChat'
|
||||
'click .js-settings': 'settings'
|
||||
|
||||
sounds:
|
||||
chat_new: new Audio('assets/sounds/chat_new.mp3')
|
||||
|
@ -19,7 +20,11 @@ class App.CustomerChat extends App.Controller
|
|||
return
|
||||
|
||||
@chatWindows = {}
|
||||
@maxChats = 4
|
||||
@maxChatWindows = 4
|
||||
preferences = @Session.get('preferences')
|
||||
if preferences && preferences.chat && preferences.chat.max_windows
|
||||
@maxChatWindows = parseInt(preferences.chat.max_windows)
|
||||
|
||||
@pushStateStarted = false
|
||||
@messageCounter = 0
|
||||
@meta =
|
||||
|
@ -33,6 +38,8 @@ class App.CustomerChat extends App.Controller
|
|||
|
||||
# update navbar on new status
|
||||
@bind('chat_status_agent', (data) =>
|
||||
if data.assets
|
||||
App.Collection.loadAssets(data.assets)
|
||||
@meta = data
|
||||
@updateMeta()
|
||||
if !@pushStateStarted
|
||||
|
@ -42,6 +49,7 @@ class App.CustomerChat extends App.Controller
|
|||
|
||||
# add new chat window
|
||||
@bind('chat_session_start', (data) =>
|
||||
console.log('chat_session_start', data)
|
||||
if data.session
|
||||
@addChat(data.session)
|
||||
)
|
||||
|
@ -103,6 +111,16 @@ class App.CustomerChat extends App.Controller
|
|||
if state is undefined
|
||||
return @meta.active
|
||||
|
||||
# check if min one chat is active
|
||||
if state
|
||||
preferences = @Session.get('preferences')
|
||||
if !preferences || !preferences.chat || !preferences.chat.active || _.isEmpty(preferences.chat.active)
|
||||
@notify(
|
||||
type: 'error'
|
||||
msg: App.i18n.translateContent('To be able to chat you need to select min. one chat topic in settings!')
|
||||
)
|
||||
return
|
||||
|
||||
@meta.active = state
|
||||
|
||||
# write state
|
||||
|
@ -118,7 +136,7 @@ class App.CustomerChat extends App.Controller
|
|||
@delay(delay, 200, 'updateNavMenu')
|
||||
|
||||
updateMeta: =>
|
||||
if @meta.waiting_chat_count && @maxChats > @windowCount()
|
||||
if @meta.waiting_chat_count && @maxChatWindows > @windowCount()
|
||||
@$('.js-acceptChat').addClass('is-clickable is-blinking')
|
||||
else
|
||||
@$('.js-acceptChat').removeClass('is-clickable is-blinking')
|
||||
|
@ -130,6 +148,7 @@ class App.CustomerChat extends App.Controller
|
|||
if @meta.active_sessions
|
||||
for session in @meta.active_sessions
|
||||
@addChat(session)
|
||||
console.log('updateMeta aC', session)
|
||||
@meta.active_sessions = false
|
||||
|
||||
@updateNavMenu()
|
||||
|
@ -165,9 +184,14 @@ class App.CustomerChat extends App.Controller
|
|||
chat.trigger 'layout-changed'
|
||||
|
||||
acceptChat: =>
|
||||
return if @windowCount() >= @maxChats
|
||||
return if @windowCount() >= @maxChatWindows
|
||||
App.WebSocket.send(event:'chat_session_start')
|
||||
|
||||
settings: ->
|
||||
new Setting(
|
||||
maxChatWindows: @maxChatWindows
|
||||
)
|
||||
|
||||
class CustomerChatRouter extends App.ControllerPermanent
|
||||
constructor: (params) ->
|
||||
super
|
||||
|
@ -243,12 +267,21 @@ class ChatWindow extends App.Controller
|
|||
@el.addClass('is-open')
|
||||
|
||||
# @addMessage 'Hello. My name is Roger, how can I help you?', 'agent'
|
||||
if @session && @session.messages
|
||||
for message in @session.messages
|
||||
if message.created_by_id
|
||||
@addMessage message.content, 'agent'
|
||||
else
|
||||
@addMessage message.content, 'customer'
|
||||
if @session
|
||||
if @session.messages
|
||||
for message in @session.messages
|
||||
if message.created_by_id
|
||||
@addMessage message.content, 'agent'
|
||||
else
|
||||
@addMessage message.content, 'customer'
|
||||
|
||||
# send init reply
|
||||
if !@session.messages || _.isEmpty(@session.messages)
|
||||
preferences = @Session.get('preferences')
|
||||
if preferences.chat && preferences.chat.phrase
|
||||
phrases = preferences.chat.phrase[@session.chat_id]
|
||||
if phrases
|
||||
@sendMessage phrases
|
||||
|
||||
focus: =>
|
||||
@input.focus()
|
||||
|
@ -319,11 +352,12 @@ class ChatWindow extends App.Controller
|
|||
event.preventDefault()
|
||||
@sendMessage()
|
||||
|
||||
sendMessage: =>
|
||||
content = @input.html()
|
||||
sendMessage: (content) =>
|
||||
if !content
|
||||
content = @input.html()
|
||||
return if !content
|
||||
|
||||
#@trigger "answer", @input.html()
|
||||
console.log('send', content, @session.session_id)
|
||||
App.WebSocket.send(
|
||||
event:'chat_session_message'
|
||||
data:
|
||||
|
@ -431,6 +465,63 @@ class ChatWindow extends App.Controller
|
|||
scrollToBottom: ->
|
||||
@scrollHolder.scrollTop(@scrollHolder.prop('scrollHeight'))
|
||||
|
||||
class Setting extends App.ControllerModalNice
|
||||
buttonClose: true
|
||||
buttonCancel: true
|
||||
buttonSubmit: true
|
||||
head: 'Settings'
|
||||
|
||||
content: =>
|
||||
|
||||
preferences = @Session.get('preferences')
|
||||
if !preferences
|
||||
preferences = {}
|
||||
if !preferences.chat
|
||||
preferences.chat = {}
|
||||
if !preferences.chat.active
|
||||
preferences.chat.active = {}
|
||||
if !preferences.chat.phrase
|
||||
preferences.chat.phrase = {}
|
||||
if !preferences.chat.max_windows
|
||||
preferences.chat.max_windows = @maxChatWindows
|
||||
|
||||
App.view('customer_chat/setting')(
|
||||
chats: App.Chat.all()
|
||||
preferences: preferences
|
||||
)
|
||||
|
||||
submit: (e) =>
|
||||
e.preventDefault()
|
||||
params = @formParam(e.target)
|
||||
|
||||
@formDisable(e)
|
||||
|
||||
# get data
|
||||
@ajax(
|
||||
id: 'preferences'
|
||||
type: 'PUT'
|
||||
url: "#{@apiPath}/users/preferences"
|
||||
data: JSON.stringify({user:params})
|
||||
processData: true
|
||||
success: @success
|
||||
error: @error
|
||||
)
|
||||
|
||||
success: (data, status, xhr) =>
|
||||
App.User.full(
|
||||
App.Session.get('id'),
|
||||
=>
|
||||
@close()
|
||||
,
|
||||
true
|
||||
)
|
||||
|
||||
error: (xhr, status, error) =>
|
||||
data = JSON.parse(xhr.responseText)
|
||||
@notify(
|
||||
type: 'error'
|
||||
msg: App.i18n.translateContent(data.message)
|
||||
)
|
||||
|
||||
App.Config.set( 'customer_chat', CustomerChatRouter, 'Routes' )
|
||||
App.Config.set( 'CustomerChat', { controller: 'CustomerChat', authentication: true }, 'permanentTask' )
|
||||
|
|
|
@ -6,8 +6,8 @@ class App.Chat extends App.Model
|
|||
@configure_attributes = [
|
||||
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false },
|
||||
{ name: 'note', display: 'Note', tag: 'textarea', limit: 250, null: true },
|
||||
{ name: 'public', display: 'Public', tag: 'boolean', default: true },
|
||||
{ name: 'max_queue', display: 'Max. Queue', tag: 'input', default: 5 },
|
||||
#{ name: 'public', display: 'Public', tag: 'boolean', default: true },
|
||||
{ name: 'max_queue', display: 'Max. clients in waitlist', tag: 'input', default: 2 },
|
||||
{ name: 'active', display: 'Active', tag: 'active', default: true },
|
||||
{ name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 },
|
||||
{ name: 'created_at', display: 'Created', tag: 'datetime', readonly: 1 },
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
<div class="page-header">
|
||||
<div class="page-header-title">
|
||||
<h1><%- @T('Chat Widget') %> <small></small></h1>
|
||||
<h1><%- @T('Chat') %> <small></small></h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-content">
|
||||
<p><%- @T('You can create chat widgets for your webpages to allow visitors to chat with you.') %></p>
|
||||
|
||||
<h2><%- @T('Channels') %></h2>
|
||||
<p><%- @T('You can create multiple chat channels.') %></p>
|
||||
<h2><%- @T('Topics') %></h2>
|
||||
<p><%- @T('You can create multiple chat topics.') %></p>
|
||||
<table class="settings-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="white-space: nowrap;"><%- @T('Name') %></th>
|
||||
<th style="white-space: nowrap;"><%- @T('Note') %></th>
|
||||
<th style="white-space: nowrap;"><%- @T('Max Queue') %></th>
|
||||
<th style="white-space: nowrap;"><%- @T('Max. clients in waitlist') %></th>
|
||||
<th style="white-space: nowrap;"><%- @T('Delete') %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -41,7 +41,7 @@
|
|||
<% end %>
|
||||
<tr>
|
||||
<td colspan="4" class="settings-list-action-cell js-add">
|
||||
<%- @Icon('plus-small') %> Add Channel
|
||||
<%- @Icon('plus-small') %> <%- @T('Add') %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -57,7 +57,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<label for="preview-iframe" class="formGroup-label"><%- @T('Preview') %></label>
|
||||
<div class="browser chat-demo js-browser">
|
||||
<div class="browser-head">
|
||||
|
@ -149,7 +149,7 @@
|
|||
<div class="zammad-switch">
|
||||
<input name="flat" type="checkbox" id="form-chat-flat">
|
||||
<label for="form-chat-flat"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
@ -222,7 +222,7 @@ $(function() {
|
|||
</ol>
|
||||
<%- marked(@T('When you turn on debugging by setting the option `debug` to `true` the reason gets printed to the javascript console.')) %>
|
||||
</p>
|
||||
|
||||
|
||||
<h3><%- @T('Options') %></h3>
|
||||
|
||||
<table class="settings-list">
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="page-header-meta">
|
||||
<div class="btn btn--action" data-type="settings"><%- @T('Settings') %></div>
|
||||
<div class="btn btn--action js-settings"><%- @T('Settings') %></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat-workspace"></div>
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<table class="settings-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%- @T('Topic') %>
|
||||
<th width="100%"><%- @T('Greeting') %>
|
||||
<th><%- @T('Enabled') %>
|
||||
</th></tr>
|
||||
</thead>
|
||||
<% for chat in @chats: %>
|
||||
<tr>
|
||||
<td><%= chat.name %>
|
||||
<td><label class="inline-label"><input name="chat::phrase::<%- chat.id %>" value="<%= @preferences.chat.phrase[chat.id] %>" class="form-control form-control--small" placeholder="<%- @T('Hello, my name is %s, what can I do for you?', App.Session.get('firstname')) %>"/></label>
|
||||
<td>
|
||||
<label class="inline-label checkbox-replacement">
|
||||
<input type="checkbox" name="chat::active::<%- chat.id %>" <% if @preferences.chat.active[chat.id]: %>checked<% end %>>
|
||||
<%- @Icon('checkbox', 'icon-unchecked') %>
|
||||
<%- @Icon('checkbox-checked', 'icon-checked') %>
|
||||
</label>
|
||||
<% end %>
|
||||
</tbody>
|
||||
|
||||
<div class="select form-group">
|
||||
<label for="a"><%- @T('Max. concurrent chats') %></label>
|
||||
<div class="u-positionOrigin">
|
||||
<select id="a" class="form-control" name="chat::max_windows">
|
||||
<% for count in [1..20]: %>
|
||||
<option value="<%- count %>" <% if parseInt(@preferences.chat.max_windows) is count: %>selected<% end %>><%- count %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
<%- @Icon('arrow-down', 'dropdown-arrow') %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</table>
|
|
@ -572,10 +572,11 @@ curl http://localhost/api/v1/users/preferences.json -v -u #{login}:#{password} -
|
|||
return
|
||||
end
|
||||
if params[:user]
|
||||
user = User.find(current_user.id)
|
||||
params[:user].each {|key, value|
|
||||
current_user.preferences[key.to_sym] = value
|
||||
user.preferences[key.to_sym] = value
|
||||
}
|
||||
current_user.save
|
||||
user.save
|
||||
end
|
||||
render json: { message: 'ok' }, status: :ok
|
||||
end
|
||||
|
|
|
@ -51,10 +51,10 @@ class Chat < ApplicationModel
|
|||
end
|
||||
|
||||
# if all seads are used
|
||||
if Chat.active_chat_count >= max_queue
|
||||
if Chat.waiting_chat_count >= max_queue
|
||||
return {
|
||||
state: 'no_seats_available',
|
||||
queue: Chat.seads_available,
|
||||
queue: Chat.waiting_chat_count,
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -64,6 +64,10 @@ class Chat < ApplicationModel
|
|||
|
||||
def self.agent_state(user_id)
|
||||
return { state: 'chat_disabled' } if !Setting.get('chat')
|
||||
assets = {}
|
||||
Chat.where(active: true).each {|chat|
|
||||
assets = chat.assets(assets)
|
||||
}
|
||||
{
|
||||
waiting_chat_count: waiting_chat_count,
|
||||
running_chat_count: running_chat_count,
|
||||
|
@ -71,7 +75,8 @@ class Chat < ApplicationModel
|
|||
active_agents: active_agents,
|
||||
seads_available: seads_available,
|
||||
seads_total: seads_total,
|
||||
active: Chat::Agent.state(user_id)
|
||||
active: Chat::Agent.state(user_id),
|
||||
assets: assets,
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -2,18 +2,8 @@ class Sessions::Event::ChatAgentState < Sessions::Event::ChatBase
|
|||
|
||||
def run
|
||||
|
||||
# only agents can do this
|
||||
chat_id = 1
|
||||
chat = Chat.find_by(id: chat_id)
|
||||
if !@session['id']
|
||||
return {
|
||||
event: 'chat_agent_state',
|
||||
data: {
|
||||
state: 'failed',
|
||||
message: 'No such user_id.'
|
||||
},
|
||||
}
|
||||
end
|
||||
# check if user has permissions
|
||||
return if !agent_permission_check
|
||||
|
||||
Chat::Agent.state(@session['id'], @data['data']['active'])
|
||||
|
||||
|
|
|
@ -53,4 +53,92 @@ class Sessions::Event::ChatBase
|
|||
}
|
||||
end
|
||||
|
||||
def agent_permission_check
|
||||
if !@session
|
||||
error = {
|
||||
event: 'chat_error',
|
||||
data: {
|
||||
state: 'no_session',
|
||||
},
|
||||
}
|
||||
Sessions.send(@client_id, error)
|
||||
return
|
||||
end
|
||||
if !@session['id']
|
||||
error = {
|
||||
event: 'chat_error',
|
||||
data: {
|
||||
state: 'no_session_user_id',
|
||||
},
|
||||
}
|
||||
Sessions.send(@client_id, error)
|
||||
return
|
||||
end
|
||||
user = User.lookup(id: @session['id'])
|
||||
if !user
|
||||
error = {
|
||||
event: 'chat_error',
|
||||
data: {
|
||||
state: 'no_such_user',
|
||||
},
|
||||
}
|
||||
Sessions.send(@client_id, error)
|
||||
return
|
||||
end
|
||||
if !user.role?('Agent')
|
||||
error = {
|
||||
event: 'chat_error',
|
||||
data: {
|
||||
state: 'no_permission',
|
||||
},
|
||||
}
|
||||
Sessions.send(@client_id, error)
|
||||
return
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
def current_chat_session
|
||||
Chat::Session.find_by(session_id: @data['data']['session_id'])
|
||||
end
|
||||
|
||||
def check_chat_session_exists
|
||||
if !@data['data'] || !@data['data']['session_id']
|
||||
error = {
|
||||
event: 'chat_error',
|
||||
data: {
|
||||
state: 'Need session_id.',
|
||||
},
|
||||
}
|
||||
Sessions.send(@client_id, error)
|
||||
return
|
||||
end
|
||||
return true if current_chat_session
|
||||
error = {
|
||||
event: 'chat_error',
|
||||
data: {
|
||||
state: "No such session id #{@data['data']['session_id']}",
|
||||
},
|
||||
}
|
||||
Sessions.send(@client_id, error)
|
||||
false
|
||||
end
|
||||
|
||||
def current_chat
|
||||
Chat.find_by(id: @data['data']['chat_id'])
|
||||
end
|
||||
|
||||
def check_chat_exists
|
||||
chat = current_chat
|
||||
return true if chat
|
||||
error = {
|
||||
event: 'chat_error',
|
||||
data: {
|
||||
state: 'no_such_chat',
|
||||
},
|
||||
}
|
||||
Sessions.send(@client_id, error)
|
||||
false
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -2,24 +2,7 @@ class Sessions::Event::ChatSessionClose < Sessions::Event::ChatBase
|
|||
|
||||
def run
|
||||
|
||||
if !@data['data'] || !@data['data']['session_id']
|
||||
return {
|
||||
event: 'chat_status_close',
|
||||
data: {
|
||||
state: 'Need session_id.',
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
chat_session = Chat::Session.find_by(session_id: @data['data']['session_id'])
|
||||
if !chat_session
|
||||
return {
|
||||
event: 'chat_status_close',
|
||||
data: {
|
||||
state: "No such session id #{@data['data']['session_id']}",
|
||||
},
|
||||
}
|
||||
end
|
||||
return if !check_chat_session_exists
|
||||
|
||||
realname = 'Anonymous'
|
||||
if @session && @session['id']
|
||||
|
@ -28,6 +11,7 @@ class Sessions::Event::ChatSessionClose < Sessions::Event::ChatBase
|
|||
|
||||
# check count of participents
|
||||
participents_count = 0
|
||||
chat_session = current_chat_session
|
||||
if chat_session.preferences[:participents]
|
||||
participents_count = chat_session.preferences[:participents].count
|
||||
end
|
||||
|
|
|
@ -1,21 +1,11 @@
|
|||
class Sessions::Event::ChatSessionInit < Sessions::Event::ChatBase
|
||||
|
||||
def run
|
||||
|
||||
chat_id = 1
|
||||
chat = Chat.find_by(id: chat_id)
|
||||
if !chat
|
||||
return {
|
||||
event: 'chat_session_init',
|
||||
data: {
|
||||
state: 'no_such_chat',
|
||||
},
|
||||
}
|
||||
end
|
||||
return if !check_chat_exists
|
||||
|
||||
# create chat session
|
||||
chat_session = Chat::Session.create(
|
||||
chat_id: chat_id,
|
||||
chat_id: @data['data']['chat_id'],
|
||||
name: '',
|
||||
state: 'waiting',
|
||||
preferences: {
|
||||
|
|
|
@ -1,25 +1,8 @@
|
|||
class Sessions::Event::ChatSessionMessage < Sessions::Event::ChatBase
|
||||
|
||||
def run
|
||||
|
||||
if !@data['data'] || !@data['data']['session_id']
|
||||
return {
|
||||
event: 'chat_session_message',
|
||||
data: {
|
||||
state: 'Need session_id.',
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
chat_session = Chat::Session.find_by(session_id: @data['data']['session_id'])
|
||||
if !chat_session
|
||||
return {
|
||||
event: 'chat_session_message',
|
||||
data: {
|
||||
state: "No such session id #{@data['data']['session_id']}",
|
||||
},
|
||||
}
|
||||
end
|
||||
return if !check_chat_session_exists
|
||||
chat_session = current_chat_session
|
||||
|
||||
user_id = nil
|
||||
if @session
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
class Sessions::Event::ChatSessionStart < Sessions::Event::ChatBase
|
||||
|
||||
def run
|
||||
agent_permission_check
|
||||
|
||||
# find first in waiting list
|
||||
chat_session = Chat::Session.where(state: 'waiting').order('created_at ASC').first
|
||||
|
@ -34,6 +35,7 @@ class Sessions::Event::ChatSessionStart < Sessions::Event::ChatBase
|
|||
state: 'ok',
|
||||
agent: user,
|
||||
session_id: chat_session.session_id,
|
||||
chat_id: chat_session.chat_id,
|
||||
},
|
||||
}
|
||||
chat_session.send_to_recipients(data)
|
||||
|
|
|
@ -1,25 +1,8 @@
|
|||
class Sessions::Event::ChatSessionTyping < Sessions::Event::ChatBase
|
||||
|
||||
def run
|
||||
|
||||
if !@data['data'] || !@data['data']['session_id']
|
||||
return {
|
||||
event: 'chat_session_typing',
|
||||
data: {
|
||||
state: 'Need session_id.',
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
chat_session = Chat::Session.find_by(session_id: @data['data']['session_id'])
|
||||
if !chat_session
|
||||
return {
|
||||
event: 'chat_session_typing',
|
||||
data: {
|
||||
state: "No such session id #{@data['data']['session_id']}",
|
||||
},
|
||||
}
|
||||
end
|
||||
return if !check_chat_session_exists
|
||||
chat_session = current_chat_session
|
||||
|
||||
user_id = nil
|
||||
if @session
|
||||
|
|
|
@ -3,6 +3,7 @@ class Sessions::Event::ChatStatusAgent < Sessions::Event::ChatBase
|
|||
def run
|
||||
|
||||
# check if user has permissions
|
||||
return if !agent_permission_check
|
||||
|
||||
# renew timestamps
|
||||
state = Chat::Agent.state(@session['id'])
|
||||
|
|
|
@ -1,17 +1,7 @@
|
|||
class Sessions::Event::ChatStatusCustomer < Sessions::Event::ChatBase
|
||||
|
||||
def run
|
||||
|
||||
chat_id = 1
|
||||
chat = Chat.find_by(id: chat_id)
|
||||
if !chat
|
||||
return {
|
||||
event: 'chat_status_customer',
|
||||
data: {
|
||||
state: 'no_such_chat',
|
||||
},
|
||||
}
|
||||
end
|
||||
return if !check_chat_exists
|
||||
|
||||
# check if it's a chat sessin reconnect
|
||||
session_id = nil
|
||||
|
@ -24,7 +14,7 @@ class Sessions::Event::ChatStatusCustomer < Sessions::Event::ChatBase
|
|||
end
|
||||
{
|
||||
event: 'chat_status_customer',
|
||||
data: chat.customer_state(session_id),
|
||||
data: current_chat.customer_state(session_id),
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue