diff --git a/app/assets/javascripts/app/controllers/_channel/chat.coffee b/app/assets/javascripts/app/controllers/_channel/chat.coffee index f4daca886..e09f0afb0 100644 --- a/app/assets/javascripts/app/controllers/_channel/chat.coffee +++ b/app/assets/javascripts/app/controllers/_channel/chat.coffee @@ -6,6 +6,11 @@ class App.ChannelChat extends App.ControllerTabs @title 'Chat', true @tabs = [ + { + name: 'Chat Channels', + target: 'channels', + controller: App.ChannelChatOverview + }, { name: 'Settings', target: 'setting', @@ -15,28 +20,125 @@ class App.ChannelChat extends App.ControllerTabs @render() -# enable/disable +class App.ChannelChatOverview extends App.Controller + events: + 'click .js-new': 'new' + 'click .js-edit': 'edit' + 'click .js-delete': 'delete' + 'click .js-widget': 'widget' -# show also if nobody is online / leave a message + constructor: -> + super + @interval(@load, 30000) + #@load() -# channels - # sales - en / authentication needed - # sales - de / authentication needed + load: => + @startLoading() + @ajax( + id: 'chat_index' + type: 'GET' + url: @apiPath + '/chats' + processData: true + success: (data, status, xhr) => + App.Collection.loadAssets(data.assets) + @stopLoading() + @render(data) + ) + render: (data = {}) => + chats = [] + for chat_id in data.chat_ids + chats.push App.Chat.find(chat_id) -# agent - # channes I'm work for + @html App.view('channel/chat_overview')( + chats: chats + ) - # x sales - de / greeting - # o sales - en / greeting + new: (e) => + new App.ControllerGenericNew( + pageData: + title: 'Chats' + object: 'Chat' + objects: 'Chats' + genericObject: 'Chat' + callback: @load + container: @el.closest('.content') + large: true + ) -# concurent chats + edit: (e) => + e.preventDefault() + id = $(e.target).closest('.action').data('id') + new App.ControllerGenericEdit( + id: id + genericObject: 'Chat' + pageData: + object: 'Chat' + container: @el.closest('.content') + callback: @load + ) -# active chats - # name, email, location/ip, age + delete: (e) => + e.preventDefault() + id = $(e.target).closest('.action').data('id') + item = App.Chat.find(id) + new App.ControllerGenericDestroyConfirm( + item: item + container: @el.closest('.content') + callback: @load + ) + widget: (e) => + e.preventDefault() + id = $(e.target).closest('.action').data('id') + new Widget( + permanent: + id: id + ) -# chat history +class Widget extends App.ControllerModal + events: + 'change .js-params': 'updateParams' + 'keyup .js-params': 'updateParams' + + constructor: -> + super + @head = 'Widget' + @close = true + @render() + @show() + + render: -> + @content = $( App.view('channel/chat_js_widget')( + baseurl: window.location.origin + )) + + onShown: => + @updateParams() + + updateParams: => + console.log('id', @id) + + quote = (value) -> + if value.replace + value = value.replace('\'', '\\\'') + .replace(/\/g, '>') + value + params = @formParam(@$('.js-params')) + if @permanent + for key, value of @permanent + params[key] = value + paramString = '' + for key, value of params + if value != '' + if paramString != '' + paramString += ",\n" + if value == 'true' || value == 'false' || _.isNumber(value) + paramString += " #{key}: #{value}" + else + paramString += " #{key}: '#{quote(value)}'" + @$('.js-modal-params').html(paramString) App.Config.set( 'Chat', { prio: 4000, name: 'Chat', parent: '#channels', target: '#channels/chat', controller: App.ChannelChat, role: ['Admin'] }, 'NavBarAdmin' ) diff --git a/app/assets/javascripts/app/controllers/chat.coffee b/app/assets/javascripts/app/controllers/chat.coffee index 7bd2133c1..80815b094 100644 --- a/app/assets/javascripts/app/controllers/chat.coffee +++ b/app/assets/javascripts/app/controllers/chat.coffee @@ -81,7 +81,10 @@ class App.CustomerChat extends App.Controller # play on changes if @lastWaitingChatCount isnt counter - @sounds.chat_new.play() + + # do not play sound on initial load + if counter > 0 && @lastWaitingChatCount isnt undefined + @sounds.chat_new.play() @lastWaitingChatCount = counter # collect chat window messages diff --git a/app/assets/javascripts/app/models/chat.coffee b/app/assets/javascripts/app/models/chat.coffee new file mode 100644 index 000000000..b80361ce0 --- /dev/null +++ b/app/assets/javascripts/app/models/chat.coffee @@ -0,0 +1,16 @@ +class App.Chat extends App.Model + @configure 'Chat', 'name', 'active', 'public', 'max_queue', 'note' + @extend Spine.Model.Ajax + @url: @apiPath + '/chats' + + @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: '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 }, + { name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 }, + { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 }, + ] diff --git a/app/assets/javascripts/app/views/channel/chat_js_widget.jst.eco b/app/assets/javascripts/app/views/channel/chat_js_widget.jst.eco new file mode 100644 index 000000000..915a90c46 --- /dev/null +++ b/app/assets/javascripts/app/views/channel/chat_js_widget.jst.eco @@ -0,0 +1,66 @@ +
+ +
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+ +
+ + + + + + + + + + + +
<%- @T('Option') %>
+ +
+ +
+
+ +

<%- @T('You need to add the following Java Script code snipped to your web page') %>: + +

+<script id="zammad_form_script" src="<%= @baseurl %>/assets/chat/chat.min.js"></script>
+
+<script>
+$(function() {
+  new ZammadChat({({
+
+  });
+});
+</script>
diff --git a/app/assets/javascripts/app/views/channel/chat_overview.jst.eco b/app/assets/javascripts/app/views/channel/chat_overview.jst.eco new file mode 100644 index 000000000..0d30c8ce5 --- /dev/null +++ b/app/assets/javascripts/app/views/channel/chat_overview.jst.eco @@ -0,0 +1,44 @@ + +

<%- @T('Channels') %>

+ +<% if _.isEmpty(@chats): %> +

<%- @T('You have no configured chat\'s right now.') %>

+<% else: %> + <% for chat in @chats: %> +
+ +
+
+

<%= chat.name %>

+
+ +
+
<%- @T('Note') %>
+ <%= chat.note %> +
+ +
+
<%- @T('At a glance') %>
+ <%- @T('Sessions last 24 h') %><%= chat.last_24_h %>
+ <%- @T('Sessions last week') %><%= chat.last_week %>
+ <%- @T('Sessions last month') %><%= chat.last_month %>
+
+ +
+
<%- @T('Public') %>
+ <%= chat.public %> +
+ +
+ +
+
<%- @T('Delete') %>
+
<%- @T('Edit') %>
+ <% if chat.public: %>
<%- @T('Design Widget') %>
<% end %> +
+ +
+ <% end %> +<% end %> + +<%- @T('New') %> diff --git a/app/controllers/chats_controller.rb b/app/controllers/chats_controller.rb new file mode 100644 index 000000000..78e4708c7 --- /dev/null +++ b/app/controllers/chats_controller.rb @@ -0,0 +1,39 @@ +# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ + +class ChatsController < ApplicationController + before_action :authentication_check + + def index + return if deny_if_not_role(Z_ROLENAME_ADMIN) + chat_ids = [] + assets = {} + Chat.order(:id).each {|chat| + chat_ids.push chat.id + assets = chat.assets(assets) + } + render json: { + chat_ids: chat_ids, + assets: assets, + } + end + + def show + return if deny_if_not_role(Z_ROLENAME_ADMIN) + model_show_render(Chat, params) + end + + def create + return if deny_if_not_role(Z_ROLENAME_ADMIN) + model_create_render(Chat, params) + end + + def update + return if deny_if_not_role(Z_ROLENAME_ADMIN) + model_update_render(Chat, params) + end + + def destroy + return if deny_if_not_role(Z_ROLENAME_ADMIN) + model_destory_render(Chat, params) + end +end diff --git a/app/models/chat.rb b/app/models/chat.rb index 96988d943..b9d6d7d99 100644 --- a/app/models/chat.rb +++ b/app/models/chat.rb @@ -1,8 +1,7 @@ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ class Chat < ApplicationModel - has_many :chat_topics - validates :name, presence: true + validates :name, presence: true def customer_state(session_id = nil) return { state: 'chat_disabled' } if !Setting.get('chat') @@ -68,6 +67,7 @@ class Chat < ApplicationModel waiting_chat_count: waiting_chat_count, running_chat_count: running_chat_count, active_sessions: Chat::Session.active_chats_by_user_id(user_id), + active_agents: active_agents, seads_available: seads_available, seads_total: seads_total, active: Chat::Agent.state(user_id) @@ -94,6 +94,10 @@ class Chat < ApplicationModel agents end + def self.active_agents(diff = 2.minutes) + Chat::Agent.where(active: true).where('updated_at > ?', Time.zone.now - diff).count + end + def self.seads_total(diff = 2.minutes) total = 0 available_agents(diff).each {|_user_id, concurrent| diff --git a/config/routes/chat.rb b/config/routes/chat.rb new file mode 100644 index 000000000..6de916036 --- /dev/null +++ b/config/routes/chat.rb @@ -0,0 +1,11 @@ +Zammad::Application.routes.draw do + api_path = Rails.configuration.api_path + + # groups + match api_path + '/chats', to: 'chats#index', via: :get + match api_path + '/chats/:id', to: 'chats#show', via: :get + match api_path + '/chats', to: 'chats#create', via: :post + match api_path + '/chats/:id', to: 'chats#update', via: :put + match api_path + '/chats/:id', to: 'chats#destroy', via: :delete + +end diff --git a/db/migrate/20151115000001_update2_chat.rb b/db/migrate/20151115000001_update2_chat.rb new file mode 100644 index 000000000..f0a23906b --- /dev/null +++ b/db/migrate/20151115000001_update2_chat.rb @@ -0,0 +1,6 @@ +class Update2Chat < ActiveRecord::Migration + def up + add_column :chats, :public, :boolean, null: false, default: false + drop_table :chat_topics + end +end