403Webshell
Server IP : 14.225.204.176  /  Your IP : 216.73.216.169
Web Server : nginx/1.24.0
System : Linux nodejs-ybgk 6.8.0-40-generic #40-Ubuntu SMP PREEMPT_DYNAMIC Fri Jul 5 10:34:03 UTC 2024 x86_64
User : root ( 0)
PHP Version : 8.1.34
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /var/www/html/php/supportboard/js/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/html/php/supportboard/js/admin.js
/*
 * ==========================================================
 * ADMINISTRATION SCRIPT
 * ==========================================================
 *
 * Main Javascript admin file. © 2017-2021 board.support. All rights reserved.
 * 
 */

'use strict';
(function ($) {

    // Global
    var admin;
    var header;

    // Conversation  
    var conversations = [];
    var conversations_area;
    var conversations_admin_list;
    var conversations_admin_list_ul;
    var saved_replies = false;
    var saved_replies_list = false;
    var woocommerce_products_box = false;
    var woocommerce_products_box_ul = false;
    var pagination = 1;
    var notes_panel;
    var attachments_panel;
    var direct_message_box;
    var dialogflow_intent_box;
    var suggestions_area;
    var pagination_count = 1;

    // Users
    var users_area;
    var users_table;
    var users_table_menu;
    var users = {};
    var users_pagination = 1;
    var users_pagination_count = 1;
    var profile_box;
    var profile_edit_box;

    // Settings
    var settings_area;
    var articles_area;
    var articles_category_selects;
    var articles_category_parent_select;
    var automations_area;
    var automations_area_select;
    var automations_area_nav;
    var conditions_area;

    // Reports
    var reports_area;

    // Miscellaneus
    var upload_target;
    var upload_on_success;
    var language_switcher_target;
    var timeout;
    var alertOnConfirmation;
    var responsive = $(window).width() < 429;
    var scrolls = { last: 0, header: true, always_hidden: false };
    var localhost = location.hostname === 'localhost' || location.hostname === '127.0.0.1';
    var today = new Date();
    var is_busy = false;
    var agent_online = true;
    var active_interval = false;
    var pusher_timeout;
    var temp;
    var overlay;
    var SITE_URL;
    var ND = 'undefined';
    var wp_admin = false;

    /*
    * ----------------------------------------------------------
    * External plugins
    * ----------------------------------------------------------
    */

    // miniTip 1.5.3 | (c) 2011, James Simpson | Dual licensed under the MIT and GPL
    $.fn.miniTip = function (t) { var e = $.extend({ title: '', content: !1, delay: 300, anchor: 'n', event: 'hover', fadeIn: 200, fadeOut: 200, aHide: !0, maxW: '250px', offset: 5, stemOff: 0, doHide: !1 }, t); 0 == admin.find('#miniTip').length && admin.append('<div id="miniTip" class="sb-tooltip"><div></div></div>'); var n = admin.find('#miniTip'), a = n.find('div'); return e.doHide ? (n.stop(!0, !0).fadeOut(e.fadeOut), !1) : this.each(function () { var t = $(this), o = e.content ? e.content : t.attr('title'); if ('' != o && void 0 !== o) { window.delay = !1; var i = !1, r = !0; e.content || t.removeAttr('title'), 'hover' == e.event ? (t.hover(function () { n.removeAttr('click'), r = !0, s.call(this) }, function () { r = !1, d() }), e.aHide || n.hover(function () { i = !0 }, function () { i = !1, setTimeout(function () { !r && !n.attr('click') && d() }, 20) })) : 'click' == e.event && (e.aHide = !0, t.click(function () { return n.attr('click', 't'), n.data('last_target') !== t ? s.call(this) : 'none' == n.css("display") ? s.call(this) : d(), n.data('last_target', t), $('html').unbind('click').click(function (t) { 'block' == n.css('display') && !$(t.target).closest('#miniTip').length && ($('html').unbind('click'), d()) }), !1 })); var s = function () { e.show && e.show.call(this, e), e.content && '' != e.content && (o = e.content), a.html(o), e.render && e.render(n), n.hide().width('').width(n.width()).css('max-width', e.maxW); var i = t.is('area'); if (i) { var r, s = [], d = [], c = t.attr('coords').split(','); function h(t, e) { return t - e } for (r = 0; r < c.length; r++)s.push(c[r++]), d.push(c[r]); var f = t.parent().attr('name'), l = $('img[usemap=\\#' + f + ']').offset(), p = parseInt(l.left, 10) + parseInt((parseInt(s.sort(h)[0], 10) + parseInt(s.sort(h)[s.length - 1], 10)) / 2, 10), u = parseInt(l.top, 10) + parseInt((parseInt(d.sort(h)[0], 10) + parseInt(d.sort(h)[d.length - 1], 10)) / 2, 10) } else u = parseInt(t.offset().top, 10), p = parseInt(t.offset().left, 10); var m = i ? 0 : parseInt(t.outerWidth(), 10), I = i ? 0 : parseInt(t.outerHeight(), 10), v = n.outerWidth(), w = n.outerHeight(), g = Math.round(p + Math.round((m - v) / 2)), T = Math.round(u + I + e.offset + 8), b = Math.round(v - 16) / 2 - parseInt(n.css('borderLeftWidth'), 10), y = 0, H = p + m + v + e.offset + 8 > parseInt($(window).width(), 10), W = v + e.offset + 8 > p, k = w + e.offset + 8 > u - $(window).scrollTop(), M = u + I + w + e.offset + 8 > parseInt($(window).height() + $(window).scrollTop(), 10), x = e.anchor; W || 'e' == e.anchor && !H ? 'w' != e.anchor && 'e' != e.anchor || (x = 'e', y = Math.round(w / 2 - 8 - parseInt(n.css('borderRightWidth'), 10)), b = -8 - parseInt(n.css('borderRightWidth'), 10), g = p + m + e.offset + 8, T = Math.round(u + I / 2 - w / 2)) : (H || 'w' == e.anchor && !W) && ('w' != e.anchor && 'e' != e.anchor || (x = 'w', y = Math.round(w / 2 - 8 - parseInt(n.css('borderLeftWidth'), 10)), b = v - parseInt(n.css('borderLeftWidth'), 10), g = p - v - e.offset - 8, T = Math.round(u + I / 2 - w / 2))), M || 'n' == e.anchor && !k ? 'n' != e.anchor && 's' != e.anchor || (x = 'n', y = w - parseInt(n.css('borderTopWidth'), 10), T = u - (w + e.offset + 8)) : (k || 's' == e.anchor && !M) && ('n' != e.anchor && 's' != e.anchor || (x = 's', y = -8 - parseInt(n.css('borderBottomWidth'), 10), T = u + I + e.offset + 8)), 'n' == e.anchor || 's' == e.anchor ? v / 2 > p ? (g = g < 0 ? b + g : b, b = 0) : p + v / 2 > parseInt($(window).width(), 10) && (g -= b, b *= 2) : k ? (T += y, y = 0) : M && (T -= y, y *= 2), delay && clearTimeout(delay), delay = setTimeout(function () { n.css({ 'margin-left': g + 'px', 'margin-top': T + 'px' }).stop(!0, !0).fadeIn(e.fadeIn) }, e.delay), n.attr('class', 'sb-tooltip ' + x) }, d = function () { (!e.aHide && !i || e.aHide) && (delay && clearTimeout(delay), delay = setTimeout(function () { c() }, e.delay)) }, c = function () { !e.aHide && !i || e.aHide ? (n.stop(!0, !0).fadeOut(e.fadeOut), e.hide && e.hide.call(this)) : setTimeout(function () { d() }, 200) } } }) };

    /*
    * ----------------------------------------------------------
    * # Functions
    * ----------------------------------------------------------
    */

    // Language switcher
    $.fn.sbLanguageSwitcher = function (langs = [], source = '', active_language = false) {
        let code = `<div class="sb-language-switcher" data-source="${source}">`;
        let added = [];
        let element = $(this).hasClass('sb-language-switcher-cnt') ? $(this) : $(this).find('.sb-language-switcher-cnt');
        for (var i = 0; i < langs.length; i++) {
            if (added.includes(langs[i])) continue;
            code += `<span ${active_language == langs[i] ? 'class="sb-active" ' : ''}data-language="${langs[i]}"><i class="sb-icon-close"></i><img src="${SB_URL}/media/flags/${langs[i].toLowerCase()}.png" /></span>`;
            added.push(langs[i]);
        }
        element.find('.sb-language-switcher').remove();
        element.append(code + `<i data-sb-tooltip="${sb_('Add translation')}" class="sb-icon-plus"></i></div>`);
        element.sbInitTooltips();
        return this;
    }

    // Lightbox
    $.fn.sbShowLightbox = function (popup = false, action = '') {
        admin.find('.sb-lightbox').sbActivate(false);
        overlay.sbActivate();
        $(this).sbActivate();
        if (popup) {
            $(this).addClass('sb-popup-lightbox').attr('data-action', action);
        } else {
            $(this).css({ 'margin-top': ($(this).outerHeight() / -2) + 'px', 'margin-left': ($(this).outerWidth() / -2) + 'px' })
        }
        $('body').addClass('sb-lightbox-active');
        setTimeout(() => { SBAdmin.open_popup = this }, 500);
        this.preventDefault;
        return this;
    }

    $.fn.sbHideLightbox = function () {
        $(this).find('.sb-lightbox,.sb-popup-lightbox').sbActivate(false).removeClass('sb-popup-lightbox').removeAttr('data-action');
        overlay.sbActivate(false);
        $('body').removeClass('sb-lightbox-active');
        SBAdmin.open_popup = false;
        return this;
    }

    //Tooltip init
    $.fn.sbInitTooltips = function () {
        $(this).find('[data-sb-tooltip]').each(function () {
            $(this).miniTip({
                content: $(this).attr('data-sb-tooltip'),
                anchor: 's',
                delay: 500
            });
        });
        return this;
    }

    // Display the bottom card information box
    function showResponse(text, type) {
        var card = admin.find('.sb-info-card');
        if (SBF.null(type)) {
            card.removeClass('sb-info-card-error sb-info-card-warning sb-info-card-info');
            clearTimeout(timeout);
            timeout = setTimeout(() => { card.sbActivate(false) }, 5000);
        } else if (!SBF.null(type) && type == 'error') {
            card.addClass('sb-info-card-error');
        } else {
            card.addClass('sb-info-card-info');
        }
        card.html(`<h3>${sb_(text)}</h3>`).sbActivate();
    }

    // Access the global user variable
    function activeUser(value) {
        if (typeof value == ND) {
            return window.sb_current_user;
        } else {
            window.sb_current_user = value;
        }
    }

    // Show alert and information lightbox
    function dialog(text, type, onConfirm = false, id = '', title = '', scroll = false) {
        let box = admin.find('.sb-dialog-box').attr('data-type', type);
        let p = box.find('p');
        box.attr('id', id).setClass('sb-scroll-area', scroll).css('height', scroll ? (parseInt($(window).height()) - 160) + 'px' : '');
        box.find('.sb-title').html(title);
        p.html((type == 'alert' ? sb_('Are you sure?') + ' ' : '') + sb_(text));
        box.sbActivate().css({ 'margin-top': (box.outerHeight() / -2) + 'px', 'margin-left': (box.outerWidth() / -2) + 'px' });
        overlay.sbActivate();
        alertOnConfirmation = onConfirm;
        setTimeout(() => { SBAdmin.open_popup = box }, 500);
    }

    // Loading box
    function loadingGlobal(show = true, is_overlay = true) {
        admin.find('.sb-loading-global').sbActivate(show);
        if (is_overlay) {
            overlay.sbActivate(show);
            $('body').setClass('sb-lightbox-active', show);
        }
    }

    // Check if an elemen is loading and set it status to loading
    function loading(element) {
        if ($(element).sbLoading()) return true;
        else $(element).sbLoading(true);
        return false;
    }

    // Support Board js translations
    function sb_(text) {
        return SB_TRANSLATIONS && text in SB_TRANSLATIONS ? SB_TRANSLATIONS[text] : text;
    }

    // PWA functions
    function isPWA() {
        return (window.matchMedia('(display-mode: standalone)').matches) || (window.navigator.standalone) || document.referrer.includes('android-app://');
    }

    function clearCache() {
        if (typeof caches !== ND) caches.delete('sb-pwa-cache');
    }

    // Collapse
    function collapse(target, max_height) {
        target = $(target);
        let content = target.find(' > div, > ul');
        content.css({ 'height': '', 'max-height': '' });
        if (target.hasClass('sb-collapse') && $(content).prop('scrollHeight') > max_height) {
            target.sbActivate().attr('data-height', max_height);
            target.find('.sb-collapse-btn').remove();
            target.append(`<a class="sb-btn-text sb-collapse-btn">${sb_('View more')}</a>`);
            content.css({ 'height': max_height + 'px', 'max-height': max_height + 'px' });
        };
    }

    function searchInput(input, searchFunction) {
        let icon = $(input).parent().find('i');
        let search = $(input).val();
        if (!icon.sbLoading()) {
            SBF.search(search, () => {
                icon.sbLoading(true);
                searchFunction(search, icon);
            });
        };
    }

    function scrollPagination(area, check = false, offset = 0) {
        if (check) return $(area).scrollTop() + $(area).innerHeight() >= ($(area)[0].scrollHeight - 1);
        $(area).scrollTop($(area)[0].scrollHeight - offset);
    }

    // Save a browser history state
    function pushState(url_parameters) {
        if (wp_admin) return;
        window.history.pushState('', '', url_parameters);
    }

    // Cloud
    function cloudURL() {
        return SB_ADMIN_SETTINGS.cloud ? ('&rand=' + SBF.random() + '&cloud=' + SBF.loginCookie()) : '';
    }

    /*
    * ----------------------------------------------------------
    * # Apps
    * ----------------------------------------------------------
    */

    var SBApps = {

        dialogflow: {
            intents: false,
            token: SBF.storage('dialogflow-token'),
            smart_reply_data: false,

            smartReply: function (message) {
                SBF.ajax({
                    function: 'dialogflow-smart-reply',
                    message: message,
                    smart_reply_data: this.smart_reply_data ? this.smart_reply_data : { 'conversation_id': SBChat.conversation.id },
                    token: this.token,
                    dialogflow_language: [activeUser().language ? activeUser().language : 'en'],
                    language_detection: SB_ADMIN_SETTINGS['smart-reply-language-detection'] && SBChat.conversation && !SBChat.conversation.getLastUserMessage(false, true) && (!SB_ADMIN_SETTINGS['smart-reply-language-detection-bot'] || !SBChat.conversation.getLastUserMessage(false, 'bot'))
                }, (response) => {
                    let suggestions = response['suggestions'];
                    let code = '';
                    let area = conversations_area.find('.sb-conversation .sb-list');
                    let is_bottom = area[0].scrollTop === (area[0].scrollHeight - area[0].offsetHeight);
                    let last_conversation_message = SBChat.conversation && SBChat.conversation.getLastMessage() ? SBChat.conversation.getLastMessage().message : false;
                    if (response['token'] && this.token != response['token']) {
                        this.token = response['token'];
                        SBF.storage('dialogflow-token', response['token']);
                    }
                    for (var i = 0; i < suggestions.length; i++) {
                        if (suggestions[i] != last_conversation_message) {
                            code += `<span>${suggestions[i]}</span>`;
                        }
                    }
                    this.smart_reply_data = response['smart_reply'];
                    suggestions_area.html(code);
                    if (is_bottom) SBChat.scrollBottom();
                });
            },

            smartReplyUpdate: function (message, user_type = 'agent') {
                SBF.ajax({
                    function: 'dialogflow-smart-reply-update',
                    message: message,
                    smart_reply_data: this.smart_reply_data ? this.smart_reply_data : { 'conversation_id': SBChat.conversation.id },
                    token: this.token,
                    dialogflow_language: [activeUser().language],
                    user_type: user_type
                });
            },

            showCreateIntentBox: function (message_id) {
                let expression = '';
                let message = SBChat.conversation.getMessage(message_id);
                let response = message.message;
                if (SBF.isAgent(message.get('user_type'))) {
                    expression = SBChat.conversation.getLastUserMessage(message.get('index'));
                    if (expression && expression.payload('sb-human-takeover')) expression = SBChat.conversation.getLastUserMessage(expression.get('index'));
                    if (expression == false) {
                        expression = '';
                    } else {
                        expression = expression.message;
                    }
                } else {
                    expression = response;
                    let messages = SBChat.conversation.messages;
                    for (var i = message.get('index'); i < messages.length; i++) {
                        if (['agent', 'admin'].includes(messages[i].get('user_type'))) {
                            response = messages[i].message;
                            break;
                        }
                    }
                }
                if (this.intents === false) {
                    SBF.ajax({ function: 'dialogflow-get-intents' }, (response) => {
                        let code = '';
                        if (Array.isArray(response)) {
                            for (var i = 0; i < response.length; i++) {
                                code += `<option value="${response[i].name}">${response[i].displayName}</option>`;
                            }
                            dialogflow_intent_box.find('#sb-intents-select').append(code);
                            this.intents = response;
                        } else this.intents = [];
                    });
                }
                dialogflow_intent_box.attr('data-message-id', message.id);
                dialogflow_intent_box.find('.sb-type-text:not(.sb-first)').remove();
                dialogflow_intent_box.find('.sb-type-text input').val(expression);
                dialogflow_intent_box.find('textarea').val(response);
                dialogflow_intent_box.find('#sb-intents-select').val('');
                dialogflow_intent_box.sbShowLightbox();
            },

            submitIntent: function (button) {
                if (loading(button)) return;
                let expressions = [];
                let response = dialogflow_intent_box.find('textarea').val();
                let intent_name = dialogflow_intent_box.find('#sb-intents-select').val();
                dialogflow_intent_box.find('.sb-type-text input').each(function () {
                    if ($(this).val()) {
                        expressions.push($(this).val());
                    }
                });
                if ((response == '' && !intent_name) || expressions.length == 0) {
                    SBForm.showErrorMessage(dialogflow_intent_box, 'Please insert the bot response and at least one user expression.');
                    $(button).sbLoading(false);
                } else {
                    SBF.ajax({
                        function: intent_name == '' ? 'dialogflow-create-intent' : 'dialogflow-update-intent',
                        expressions: expressions,
                        response: response,
                        agent_language: dialogflow_intent_box.find('.sb-dialogflow-languages select').val(),
                        conversation_id: SBChat.conversation.id,
                        intent_name: intent_name
                    }, (response) => {
                        $(button).sbLoading(false);
                        if (response === true) {
                            admin.sbHideLightbox();
                            showResponse(intent_name == '' ? 'Intent created' : 'Intent updated');
                        } else {
                            let message = 'Error';
                            if ('error' in response && 'message' in response['error']) {
                                message = response['error']['message'];
                            }
                            SBForm.showErrorMessage(dialogflow_intent_box, message);
                        }
                    });
                }
            },

            searchIntents: function (search) {
                search = search.toLowerCase();
                SBF.search(search, () => {
                    let all = search.length > 1 ? false : true;
                    let code = all ? `<option value="">${sb_('New Intent')}</option>` : '';
                    let intents = this.intents;
                    for (var i = 0; i < intents.length; i++) {
                        let found = all || intents[i].displayName.toLowerCase().includes(search);
                        if (!found && 'trainingPhrases' in intents[i]) {
                            let training_phrases = intents[i].trainingPhrases;
                            for (var j = 0; j < training_phrases.length; j++) {
                                for (var y = 0; y < training_phrases[j].parts.length; y++) {
                                    if (training_phrases[j].parts[y].text.toLowerCase().includes(search)) {
                                        found = true;
                                        break;
                                    }
                                }
                                if (found) break;
                            }
                        }
                        if (found) {
                            code += `<option value="${intents[i].name}">${intents[i].displayName}</option>`;
                        }
                    }
                    dialogflow_intent_box.find('#sb-intents-select').html(code);
                });
            },

            previewIntent: function (name) {
                let code = '';
                for (var i = 0; i < this.intents.length; i++) {
                    if (this.intents[i].name == name) {
                        let training_phrases = 'trainingPhrases' in this.intents[i] ? this.intents[i].trainingPhrases : [];
                        let count = training_phrases.length;
                        if (count > 1) {
                            for (var j = 0; j < count; j++) {
                                for (var y = 0; y < training_phrases[j].parts.length; y++) {
                                    code += `<span>${training_phrases[j].parts[y].text}</span>`;
                                    if (y == 15) break;
                                }
                            }
                            dialog(code, 'info', false, 'intent-preview-box', '', 350);
                        }
                        break;
                    }
                }
            },

            translate: function (strings, language_code, onSuccess) {
                if (strings.length) {
                    SBF.ajax({
                        function: 'google-translate',
                        strings: strings,
                        language_code: language_code,
                        token: this.token
                    }, (response) => {
                        this.token = response[1]
                        if ('data' in response[0] && 'translations' in response[0].data) {
                            onSuccess(response[0].data.translations);
                        } else {
                            SBF.error(JSON.stringify(response[0]), 'SBApps.dialogflow.translate');
                            return false;
                        }
                    });
                }
            }
        },

        messenger: {

            check: function (conversation) {
                return ['fb', 'ig'].includes(conversation.get('source'));
            },

            send: function (PSID, facebook_page_id, message = '', attachments = [], metadata, onSuccess = false) {
                SBF.ajax({
                    function: 'messenger-send-message',
                    psid: PSID,
                    facebook_page_id: facebook_page_id,
                    message: message,
                    attachments: attachments,
                    metadata: metadata
                }, (response) => {
                    if (onSuccess) onSuccess(response);
                });
            }
        },

        whatsapp: {

            check: function (conversation) {
                return conversation.get('source') == 'wa';
            },

            send: function (to, message = '', attachments = [], onSuccess = false) {
                SBF.ajax({
                    function: 'whatsapp-send-message',
                    to: to,
                    message: message,
                    attachments: attachments
                }, (response) => {
                    if (onSuccess) onSuccess(response);
                });
            },

            activeUserPhone: function () {
                return activeUser().getExtra('phone') ? activeUser().getExtra('phone').value.replace('+', '') : false
            }
        },

        telegram: {

            check: function (conversation) {
                return conversation.get('source') == 'tg';
            },

            send: function (chat_id, message = '', attachments = [], onSuccess = false) {
                SBF.ajax({
                    function: 'telegram-send-message',
                    chat_id: chat_id,
                    message: message,
                    attachments: attachments
                }, (response) => {
                    if (onSuccess) onSuccess(response);
                });
            }
        },

        aecommerce: {

            panel: false,

            conversationPanel: function () {
                let code = '';
                let aecommerce_id = activeUser().getExtra('aecommerce-id');
                if (!this.panel) this.panel = conversations_area.find('.sb-panel-aecommerce');
                if (aecommerce_id && !loading(this.panel)) {
                    SBF.ajax({
                        function: 'aecommerce-get-conversation-details',
                        aecommerce_id: aecommerce_id['value']
                    }, (response) => {
                        code = `<h3>${SB_ADMIN_SETTINGS['aecommerce-panel-title']}</h3><div><div class="sb-split"><div><div class="sb-title">${sb_('Number of orders')}</div><span>${response['orders_count']} ${sb_('orders')}</span></div><div><div class="sb-title">${sb_('Total spend')}</div><span>${response['currency_symbol']}${response['total']}</span></div></div><div class="sb-title">${sb_('Cart')}</div><div class="sb-list-items sb-list-links sb-aecommerce-cart">`;
                        for (var i = 0; i < response['cart'].length; i++) {
                            let product = response['cart'][i];
                            code += `<a href="${product['url']}" target="_blank" data-id="${product['id']}"><span>#${product['id']}</span> <span>${product['name']}</span> <span>x ${product['quantity']}</span></a>`;
                        }
                        code += (response['cart'].length ? '' : '<p>' + sb_('The cart is currently empty.') + '</p>') + '</div>';
                        if (response['orders'].length) {
                            code += `<div class="sb-title">${sb_('Orders')}</div><div class="sb-list-items sb-list-links sb-aecommerce-orders">`;
                            for (var i = 0; i < response['orders'].length; i++) {
                                let order = response['orders'][i];
                                let id = order['id'];
                                code += `<a data-id="${id}" href="${order['url']}" target="_blank"><span>#${order['id']}</span> <span>${SBF.beautifyTime(order['time'], true)}</span> <span>${response['currency_symbol']}${order['price']}</span></a>`;
                            }
                            code += '</div>';
                        }
                        $(this.panel).html(code).sbLoading(false);
                        collapse(this.panel, 160);
                    });
                }
                $(this.panel).html(code);
            }
        },

        whmcs: {

            panel: false,

            conversationPanel: function () {
                let code = '';
                let whmcs_id = activeUser().getExtra('whmcs-id');
                if (!this.panel) this.panel = conversations_area.find('.sb-panel-whmcs');
                if (whmcs_id && !loading(this.panel)) {
                    SBF.ajax({
                        function: 'whmcs-get-conversation-details',
                        whmcs_id: whmcs_id['value']
                    }, (response) => {
                        let services = ['products', 'addons', 'domains'];
                        code = `<h3>WHMCS</h3><div><div class="sb-split"><div><div class="sb-title">${sb_('Number of services')}</div><span>${response['services_count']} ${sb_('services')}</span></div><div><div class="sb-title">${sb_('Total spend')}</div><span>${response['currency_symbol']}${response['total']}</span></div></div>`;
                        code += `</div>`;
                        for (var i = 0; i < services.length; i++) {
                            let items = response[services[i]];
                            if (items.length) {
                                code += `<div class="sb-title">${sb_(SBF.slugToString(services[i]))}</div><div class="sb-list-items">`;
                                for (var j = 0; j < items.length; j++) {
                                    code += `<div>${items[j]['name']}</div>`;
                                }
                                code += '</div>';
                            }
                        }
                        code += `<a href="${SB_ADMIN_SETTINGS['whmcs-url']}/clientssummary.php?userid=${response['client-id']}" target="_blank" class="sb-btn sb-whmcs-link">${sb_('View on WHMCS')}</a>`;
                        $(this.panel).html(code).sbLoading(false);
                        collapse(this.panel, 160);
                    });
                }
                $(this.panel).html(code);
            }
        },

        perfex: {

            conversationPanel: function () {
                let perfex_id = activeUser().getExtra('perfex-id');
                conversations_area.find('.sb-panel-perfex').html(perfex_id == '' ? '' : `<a href="${SB_ADMIN_SETTINGS['perfex-url']}/admin/clients/client/${perfex_id['value']}" target="_blank" class="sb-btn sb-perfex-link">${sb_('View on Perfex')}</a>`);
            }
        },

        ump: {

            panel: false,

            conversationPanel: function () {
                if (loading(this.panel)) return;
                if (!this.panel) this.panel = conversations_area.find('.sb-panel-ump');
                let code = '';
                let subscriptions;
                SBF.ajax({
                    function: 'ump-get-conversation-details'
                }, (response) => {
                    subscriptions = response['subscriptions'];
                    if (subscriptions.length) {
                        code = '<i class="sb-icon-refresh"></i><h3>Membership</h3><div class="sb-list-names">';
                        for (var i = 0; i < subscriptions.length; i++) {
                            let expired = subscriptions[i]['expired'];
                            code += `<div${expired ? ' class="sb-expired"' : ''}><span>${subscriptions[i]['label']}</span><span>${sb_(expired ? 'Expired on' : 'Expires on')} ${SBF.beautifyTime(subscriptions[i]['expire_time'], false, !expired)}</span></div>`;
                        }
                        code += `</div><span class="sb-title">${sb_('Total spend')} ${response['currency_symbol']}${response['total']}</span>`;
                    }
                    $(this.panel).html(code).sbLoading(false);
                    collapse(this.panel, 160);
                });
            }
        },

        armember: {

            panel: false,

            conversationPanel: function () {
                let wp_user_id = activeUser().getExtra('wp-id');
                if (!this.panel) this.panel = conversations_area.find('.sb-panel-armember');
                if (!SBF.null(wp_user_id) && !loading(this.panel)) {
                    let code = '';
                    let subscriptions;
                    wp_user_id = wp_user_id.value;
                    SBF.ajax({
                        function: 'armember-get-conversation-details',
                        wp_user_id: wp_user_id
                    }, (response) => {
                        subscriptions = response['subscriptions'];
                        if (subscriptions.length) {
                            code = '<i class="sb-icon-refresh"></i><h3>Plans</h3><div class="sb-list-names">';
                            for (var i = 0; i < subscriptions.length; i++) {
                                let expired = subscriptions[i]['expired'];
                                code += `<div${expired ? ' class="sb-expired"' : ''}><span>${subscriptions[i].arm_current_plan_detail.arm_subscription_plan_name}</span><span>${subscriptions[i]['expire_time'] == 'never' ? '' : (sb_(expired ? 'Expired on' : 'Expires on') + ' ' + SBF.beautifyTime(subscriptions[i]['expire_time'], false, !expired))}</span></div>`;
                            }
                            code += `</div><span class="sb-title">${sb_('Total spend')} ${response['currency_symbol']}${response['total']}<a href="${window.location.href.substr(0, window.location.href.lastIndexOf('/')) + '?page=arm_manage_members&member_id=' + activeUser().getExtra('wp-id').value}" target="_blank" class="sb-btn-text"><i class="sb-icon-user"></i> ${sb_('View member')}</a></span>`;
                        }
                        $(this.panel).html(code).sbLoading(false);
                        collapse(this.panel, 160);
                    });
                } else $(this.panel).html('');
            }
        },

        woocommerce: {

            popupPaginationNumber: 1,
            popupLanguage: '',
            popupCache: [],
            panel: false,
            timeout: false,

            // Products popup
            popupCode: function (items, label = true) {
                let code = '';
                for (var i = 0; i < items.length; i++) {
                    code += `<li data-id="${items[i]['id']}"><div class="sb-image" style="background-image:url('${items[i]['image']}')"></div><div><span>${items[i]['name']}</span><span>${SB_ADMIN_SETTINGS['currency']}${items[i]['price']}</span></div></li>`;
                }
                return label ? (code == '' ? `<p>${sb_('No products found')}</p>` : code) : code;
            },

            popupSearch: function (input) {
                searchInput(input, (search, icon) => {
                    if (search == '') {
                        this.popupPopulate(function () {
                            $(icon).sbLoading(false);
                        });
                    } else {
                        this.popupPaginationNumber = 1;
                        SBF.ajax({
                            function: 'woocommerce-search-products',
                            search: search
                        }, (response) => {
                            woocommerce_products_box_ul.html(this.popupCode(response));
                            $(icon).sbLoading(false);
                        });
                    }
                });
            },

            popupFilter: function (item) {
                if (loading(woocommerce_products_box_ul)) return;
                woocommerce_products_box_ul.html('');
                this.popupPaginationNumber = 1;
                SBF.ajax({
                    function: 'woocommerce-get-products',
                    user_language: this.popupLanguage,
                    filters: { taxonomy: $(item).data('value') }
                }, (response) => {
                    woocommerce_products_box_ul.html(this.popupCode(response)).sbLoading(false);
                });
            },

            popupPopulate: function (onSuccess = false) {
                this.popupLanguage = activeUser() != false && SB_ADMIN_SETTINGS['languages'].includes(activeUser().language) ? activeUser().language : '';
                this.popupPaginationNumber = 1;
                woocommerce_products_box_ul.html('').sbLoading(true);
                SBF.ajax({
                    function: 'woocommerce-products-popup',
                    user_language: this.popupLanguage
                }, (response) => {
                    let code = '';
                    let select = woocommerce_products_box.find('.sb-select');
                    for (var i = 0; i < response[1].length; i++) {
                        code += `<li data-value="${response[1][i]['id']}">${response[1][i]['name']}</li>`;
                    }
                    select.find('> p').html(sb_('All'));
                    select.find('ul').html(`<li data-value="" class="sb-active">${sb_('All')}</li>` + code);
                    woocommerce_products_box_ul.html(this.popupCode(response[0])).sbLoading(false);
                    if (onSuccess !== false) onSuccess();
                });
            },

            popupPagination: function (area) {
                woocommerce_products_box_ul.sbLoading(area);
                SBF.ajax({
                    function: 'woocommerce-get-products',
                    filters: { taxonomy: $(area).parent().find('.sb-select p').attr('data-value') },
                    pagination: this.popupPaginationNumber,
                    user_language: this.popupLanguage
                }, (response) => {
                    woocommerce_products_box_ul.append(this.popupCode(response, false)).sbLoading(false);
                    this.popupPaginationNumber++;
                    scrollPagination(area);
                });
            },

            // Conversation panel
            conversationPanel: function () {
                if (loading(this.panel)) return;
                if (!this.panel) this.panel = conversations_area.find('.sb-panel-woocommerce');
                let code = '';
                SBF.ajax({
                    function: 'woocommerce-get-conversation-details'
                }, (response) => {
                    code = `<i class="sb-icon-refresh"></i><h3>WooCommerce</h3><div><div class="sb-split"><div><div class="sb-title">${sb_('Number of orders')}</div><span>${response['orders_count']} ${sb_('orders')}</span></div><div><div class="sb-title">${sb_('Total spend')}</div><span>${response['currency_symbol']}${response['total']}</span></div></div><div class="sb-title">${sb_('Cart')}<i class="sb-add-cart-btn sb-icon-plus"></i></div><div class="sb-list-items sb-list-links sb-woocommerce-cart">`;
                    for (var i = 0; i < response['cart'].length; i++) {
                        let product = response['cart'][i];
                        code += `<a href="${product['url']}" target="_blank" data-id="${product['id']}"><span>#${product['id']}</span> <span>${product['name']}</span> <span>x ${product['quantity']}</span><i class="sb-icon-close"></i></a>`;
                    }
                    code += (response['cart'].length ? '' : '<p>' + sb_('The cart is currently empty.') + '</p>') + '</div>';
                    if (response['orders'].length) {
                        code += `<div class="sb-title">${sb_('Orders')}</div><div class="sb-list-items sb-woocommerce-orders sb-accordion">`;
                        for (var i = 0; i < response['orders'].length; i++) {
                            let order = response['orders'][i];
                            let id = order['id'];
                            code += `<div data-id="${id}"><span><span>#${id}</span> <span>${SBF.beautifyTime(order['date'], true)}</span><a href="${SITE_URL}/wp-admin/post.php?post=${id}&action=edit" target="_blank" class="sb-icon-next"></a></span><div></div></div>`;
                        }
                        code += '</div>';
                    }
                    $(this.panel).html(code).sbLoading(false);
                    collapse(this.panel, 160);
                });
            },


            // Conversation panel order details
            conversationPanelOrder: function (order_id) {
                let accordion = this.panel.find(`[data-id="${order_id}"] > div`);
                accordion.html('');
                SBF.ajax({
                    function: 'woocommerce-get-order',
                    order_id: order_id
                }, (response) => {
                    let code = '';
                    let collapse = this.panel.find('.sb-collapse-btn:not(.sb-active)');
                    if (response) {
                        let products = response['products'];
                        code += `<div class="sb-title">${sb_('Order total')}: <span>${response['currency_symbol']}${response['total']}<span></div><div class="sb-title">${sb_('Order status')}: <span>${SBF.slugToString(response['status'].replace('wc-', ''))}<span></div><div class="sb-title">${sb_('Date')}: <span>${SBF.beautifyTime(response['date'], true)}<span></div><div class="sb-title">${sb_('Products')}</div>`;
                        for (var i = 0; i < products.length; i++) {
                            code += `<a href="${SITE_URL}?p=${products[i]['id']}" target="_blank"><span>#${products[i]['id']}</span> <span>${products[i]['quantity']} x</span> <span>${products[i]['name']}</span></a>`;
                        }
                        for (var i = 0; i < 2; i++) {
                            let key = i == 0 ? 'shipping' : 'billing';
                            if (response[key + '_address']) {
                                code += `<div class="sb-title">${sb_((i == 0 ? 'Shipping' : 'Billing') + ' address')}</div><div class="sb-multiline">${response[key + '_address'].replace(/\\n/g, '<br>')}</div>`;
                            }
                        }
                    }
                    if (collapse.length) {
                        collapse.click();
                    }
                    accordion.html(code);
                });
            },

            conversationPanelUpdate: function (product_id, action = 'added') {
                let busy = false;
                let count = 0;
                this.timeout = setInterval(() => {
                    if (!busy) {
                        SBF.ajax({
                            function: 'woocommerce-get-conversation-details'
                        }, (response) => {
                            let removed = true;
                            for (var i = 0; i < response['cart'].length; i++) {
                                if (response['cart'][i]['id'] == product_id) {
                                    if (action == 'added') count = 61; else removed = false;
                                }
                            }
                            if (count > 60 || removed) {
                                this.conversationPanel();
                                conversations_area.find('.sb-add-cart-btn,.sb-woocommerce-cart > a i').sbLoading(false);
                                clearInterval(this.timeout);
                            }
                            count++;
                            busy = false;
                        });
                        busy = true;
                    }
                }, 1000);
            }
        },

        wordpress: {
            ajax: function (action, data, onSuccess) {
                $.ajax({
                    method: 'POST',
                    url: SB_WP_AJAX_URL,
                    data: $.extend({ action: 'sb_wp_ajax', type: action }, data)
                }).done((response) => {
                    if (onSuccess !== false) {
                        onSuccess(response);
                    }
                });
            }
        },

        is: function (name) {
            if (typeof SB_VERSIONS == ND) return false;
            switch (name) {
                case 'telegram':
                case 'armember':
                case 'aecommerce':
                case 'whmcs':
                case 'perfex':
                case 'ump':
                case 'messenger':
                case 'whatsapp':
                case 'woocommerce':
                case 'dialogflow':
                case 'slack':
                case 'tickets': return typeof SB_VERSIONS[name] != ND && SB_VERSIONS[name] != -1;
                case 'wordpress': return typeof SB_WP != ND;
                case 'sb': return true;
            }
            return false;
        },
    }

    /*
    * ----------------------------------------------------------
    * # Settings
    * ----------------------------------------------------------
    */

    var SBSettings = {
        init: false,

        save: function (btn) {
            if (loading(btn)) return;
            let external_settings = {};
            let settings = {};
            let tab = settings_area.find(' > .sb-tab > .sb-nav .sb-active').attr('id');
            switch (tab) {
                case 'tab-articles':
                    this.articles.save((response) => {
                        showResponse(response === true ? 'Articles and categories saved' : response);
                        $(btn).sbLoading(false);
                    });
                    break;
                case 'tab-automations':
                    let active = automations_area_nav.find('.sb-active').attr('data-id');
                    SBSettings.automations.save((response) => {
                        showResponse(response === true ? 'Automations saved' : response);
                        SBSettings.automations.populate();
                        automations_area_nav.find(`[data-id="${active}"]`).click();
                        $(btn).sbLoading(false);
                    });
                    break;
                case 'tab-translations':
                    this.translations.updateActive();
                    SBF.ajax({
                        function: 'save-translations',
                        translations: JSON.stringify(this.translations.to_update)
                    }, () => {
                        showResponse('Translations saved');
                        $(btn).sbLoading(false);
                    });
                    break;
                default:
                    settings_area.find('.sb-setting').each((i, element) => {
                        let setting = this.get(element);
                        let setting_id = $(element).data('setting');
                        if (setting[0]) {
                            if (typeof setting_id != ND) {
                                let originals = false;
                                if ($(element).find('[data-language]').length) {
                                    let language = $(element).find('[data-language].sb-active');
                                    originals = setting[0] in this.translations.originals ? this.translations.originals[setting[0]] : false;
                                    this.translations.save(element, language.length ? language.attr('data-language') : false);
                                    if (originals) {
                                        if (typeof originals != 'string') {
                                            for (var key in originals) {
                                                originals[key] = [originals[key], setting[1][key][1]]
                                            }
                                        }
                                    }
                                }
                                if (!(setting_id in external_settings)) external_settings[setting_id] = {};
                                external_settings[setting_id][setting[0]] = [originals ? originals : setting[1], setting[2]];
                            } else {
                                settings[setting[0]] = [setting[1], setting[2]];
                            }
                        }
                    });
                    SBF.ajax({
                        function: 'save-settings',
                        settings: settings,
                        external_settings: external_settings,
                        external_settings_translations: this.translations.translations
                    }, () => {
                        showResponse('Settings saved');
                        $(btn).sbLoading(false);
                    });
                    break;
            }
        },

        initPlugins: function () {
            settings_area.find('textarea').each(function () {
                $(this).autoExpandTextarea();
                $(this).manualExpandTextarea();
            });
            settings_area.find('[data-setting] .sb-language-switcher-cnt').each(function () {
                $(this).sbLanguageSwitcher(SBSettings.translations.getLanguageCodes($(this).closest('[data-setting]').attr('id')), 'settings');
            });
        },

        initColorPicker: function (area = false) {
            $(area ? area : settings_area).find('.sb-type-color input').colorPicker({
                renderCallback: function (t, toggled) {
                    $(t.context).closest('.input').find('input').css('background-color', t.text);
                }
            });
        },

        initHTML: function (response) {
            if ('slack-agents' in response) {
                let code = '';
                for (var key in response['slack-agents'][0]) {
                    code += `<div data-id="${key}"><select><option value="${response['slack-agents'][0][key]}"></option></select></div>`;
                }
                settings_area.find('#slack-agents .input').html(code);
            }
        },

        get: function (item) {
            item = $(item);
            let id = item.attr('id');
            let type = item.data('type');
            switch (type) {
                case 'upload':
                case 'range':
                case 'number':
                case 'text':
                case 'password':
                case 'color':
                    return [id, item.find('input').val(), type];
                    break;
                case 'textarea':
                    return [id, item.find('textarea').val(), type];
                    break;
                case 'select':
                    return [id, item.find('select').val(), type];
                    break;
                case 'checkbox':
                    return [id, item.find('input').is(':checked'), type];
                    break;
                case 'radio':
                    let value = item.find('input:checked').val();
                    if (SBF.null(value)) value = '';
                    return [id, value, type];
                    break;
                case 'upload-image':
                    let url = item.find('.image').attr('data-value');
                    if (SBF.null(url)) url = '';
                    return [id, url, type];
                    break;
                case 'multi-input':
                    let multi_inputs = {};
                    item.find('.input > div').each((i, element) => {
                        let setting = this.get(element);
                        if (setting[0]) {
                            multi_inputs[setting[0]] = [setting[1], setting[2]];
                        }
                    });
                    return [id, multi_inputs, type];
                    break;
                case 'select-images':
                    return [id, item.find('.input > .sb-active').data('value'), type];
                    break;
                case 'repeater':
                    return [id, this.repeater('get', item.find('.repeater-item'), ''), type];
                    break;
                case 'double-select':
                    let selects = {};
                    item.find('.input > div').each(function () {
                        let value = $(this).find('select').val();
                        if (value != -1) {
                            selects[$(this).attr('data-id')] = [value];
                        }
                    });
                    return [id, selects, type];
                    break;
                case 'timetable':
                    let times = {};
                    item.find('.sb-timetable > [data-day]').each(function () {
                        let day = $(this).attr('data-day');
                        let hours = [];
                        $(this).find('> div > div').each(function () {
                            let name = $(this).html()
                            let value = $(this).attr('data-value');
                            if (SBF.null(value)) {
                                hours.push(['', '']);
                            } else if (value == 'closed') {
                                hours.push(['closed', 'Closed']);
                            } else {
                                hours.push([value, name]);
                            }
                        });
                        times[day] = hours;
                    });
                    return [id, times, type];
                    break;
                case 'color-palette':
                    return [id, item.attr('data-value'), type];
                    break;

            }
            return ['', '', ''];
        },

        set: function (id, setting) {
            let type = $(setting)[1];
            let value = $(setting)[0];
            id = `#${id}`;
            switch (type) {
                case 'color':
                case 'upload':
                case 'number':
                case 'text':
                case 'password':
                    settings_area.find(`${id} input`).val(SBF.restoreJson(value));
                    break;
                case 'textarea':
                    settings_area.find(`${id} textarea`).val(SBF.restoreJson(value));
                    break;
                case 'select':
                    settings_area.find(`${id} select`).val(SBF.restoreJson(value));
                    break;
                case 'checkbox':
                    settings_area.find(`${id} input`).prop('checked', (value == 'false' ? false : value));
                    break;
                case 'radio':
                    settings_area.find(`${id} input[value="${SBF.restoreJson(value)}"]`).prop('checked', true);
                    break;
                case 'upload-image':
                    if (value) {
                        settings_area.find(id + ' .image').attr('data-value', SBF.restoreJson(value)).css('background-image', `url("${SBF.restoreJson(value)}")`);
                    }
                    break;
                case 'multi-input':
                    for (var key in value) {
                        this.set(key, value[key]);
                    }
                    break;
                case 'range':
                    let range_value = SBF.restoreJson(value);
                    settings_area.find(id + ' input').val(range_value);
                    settings_area.find(id + ' .range-value').html(range_value);
                    break;
                case 'select-images':
                    settings_area.find(id + ' .input > div').sbActivate(false);
                    settings_area.find(id + ` .input > [data-value="${SBF.restoreJson(value)}"]`).sbActivate();
                    break;
                case 'repeater':
                    let content = this.repeater('set', value, settings_area.find(id + ' .repeater-item:last-child'));
                    if (content) {
                        settings_area.find(id + ' .sb-repeater').html(content);
                    }
                    break;
                case 'double-select':
                    for (var key in value) {
                        settings_area.find(`${id} .input > [data-id="${key}"] select`).val(value[key]);
                    }
                    break;
                case 'timetable':
                    for (var key in value) {
                        let hours = settings_area.find(`${id} [data-day="${key}"] > div > div`);
                        for (var i = 0; i < hours.length; i++) {
                            $(hours[i]).attr('data-value', value[key][i][0]).html(value[key][i][1]);
                        }
                    }
                    break;
                case 'color-palette':
                    if (value) {
                        settings_area.find(id).attr('data-value', value);
                    }
                    break;
            }
        },

        repeater: function (action, items, content) {
            $(content).find('.sb-icon-close').remove();
            content = $(content).html();
            if (action == 'set') {
                var html = '';
                if (items.length > 0) {
                    for (var i = 0; i < items.length; i++) {
                        let item = $($.parseHTML(`<div>${content}</div>`));
                        for (var key in items[i]) {
                            this.setInput(item.find(`[data-id="${key}"]`), items[i][key]);
                        }
                        html += `<div class="repeater-item">${item.html()}<i class="sb-icon-close"></i></div>`;
                    }
                }
                return html;
            }
            if (action == 'get') {
                let items_array = [];
                let me = this;
                $(items).each(function () {
                    let item = {};
                    let empty = true;
                    $(this).find('[data-id]').each(function () {
                        let value = me.getInput(this);
                        if (empty && value && $(this).attr('type') != 'hidden' && $(this).attr('data-type') != 'auto-id') {
                            empty = false;
                        }
                        item[$(this).attr('data-id')] = value;
                    });
                    if (!empty) {
                        items_array.push(item);
                    }
                });
                return items_array;
            }
        },

        repeaterAdd: function (item) {
            let parent = $(item).parent();
            item = $($.parseHTML(`<div>${parent.find('.repeater-item:last-child').html()}</div>`));
            item.find('[data-id]').each(function () {
                SBSettings.resetInput(this);
                if ($(this).data('type') == 'auto-id') {
                    let larger = 1;
                    parent.find('[data-type="auto-id"]').each(function () {
                        let index = parseInt($(this).val());
                        if (index > larger) {
                            larger = index;
                        }
                    });
                    $(this).attr('value', larger + 1);
                }
            });
            parent.find('.sb-repeater').append(`<div class="repeater-item">${item.html()}</div>`);
        },

        repeaterDelete: function (item) {
            let parent = $(item).parent();
            if (parent.parent().find('.repeater-item').length > 1) {
                parent.remove();
            } else {
                parent.find('[data-id]').each((e, element) => {
                    this.resetInput(element);
                });
            }
        },

        setInput: function (input, value) {
            value = $.trim(value);
            input = $(input);
            if (input.is('select')) {
                input.find(`option[value="${value}"]`).attr('selected', '');
            } else {
                if (input.is(':checkbox') && value && value != 'false') {
                    input.attr('checked', '');
                } else {
                    if (input.is('textarea')) {
                        input.html(value);
                    } else {
                        let div = input.is('div');
                        if (div || input.is('i') || input.is('li')) {
                            input.attr('data-value', value);
                            if (div && input.hasClass('image')) {
                                input.css('background-image', `url("${value}")`);
                            }
                        } else {
                            input.attr('value', value);
                        }
                    }
                }
            }
        },

        getInput: function (input) {
            input = $(input);
            if (input.is(':checkbox')) {
                return input.is(':checked');
            } else {
                if (input.is("div") || input.is("i") || input.is("li")) {
                    let value = input.attr('data-value');
                    return SBF.null(value) ? '' : value;
                } else {
                    return input.val();
                }
            }
            return '';
        },

        resetInput: function (input) {
            input = $(input);
            if (input.is("select")) {
                input.val('').find('[selected]').removeAttr('selected');
            } else {
                if (input.is("checkbox") && value) {
                    input.removeAttr('checked').prop('checked', false);
                } else {
                    if (input.is("textarea")) {
                        input.html('');
                    } else {
                        input.removeAttr('value').removeAttr('style').removeAttr('data-value').val('');
                    }
                }
            }
        },

        getSettingObject: function (setting) {
            return $(setting)[0].hasAttribute('data-setting') ? $(setting) : $(setting).closest('[data-setting]');
        },

        articles: {
            categories: [],
            articles: [],
            translations: {},

            get: function (onSuccess, categories = false, full = true) {
                SBF.ajax({
                    function: 'get-articles',
                    categories: categories,
                    articles_language: 'all',
                    full: full
                }, (response) => {
                    onSuccess(response);
                });
            },

            save: function (onSuccess = false) {
                this.updateActiveArticle();
                articles_area.find('.sb-new-category-cnt input').each((i, element) => {
                    let value = $.trim($(element).val());
                    if (value) this.categories.push({ id: SBF.random(), title: value });
                    $(element).parents().eq(1).remove();
                });
                if (this.categories.length) {
                    this.categories.sort(function (a, b) {
                        return a.title.localeCompare(b.title);
                    });
                }
                SBF.ajax({
                    function: 'save-articles',
                    articles: this.articles,
                    translations: this.translations,
                    categories: this.categories.length ? this.categories : 'delete_all'
                }, (response) => {
                    articles_area.find('.sb-menu-wide .sb-active').click();
                    articles_area.find(`.sb-nav [data-id="${this.activeID()}"]`).click();
                    this.updateSelect();
                    if (onSuccess) onSuccess(response);
                });
                if (SBApps.is('dialogflow')) SBF.ajax({ function: 'dialogflow-knowledge', articles: this.articles });
            },

            show: function (article_id = false, element = false, language = false) {
                let contents = [-1, '', '', '', ''];
                this.updateActiveArticle();
                this.hide(false);
                let articles = language ? (language in this.translations ? this.translations[language] : []) : this.articles;
                if (article_id === false) article_id = this.activeID();
                for (var i = 0; i < articles.length; i++) {
                    if (articles[i]['id'] == article_id) {
                        contents = [article_id, articles[i]['title'], articles[i]['content'], articles[i]['link'], SBF.null(articles[i]['categories']) ? [''] : articles[i]['categories'], SBF.null(articles[i]['parent_category']) ? '' : articles[i]['parent_category']];
                        if (element) {
                            $(element).siblings().sbActivate(false);
                            $(element).sbActivate();
                        }
                        break;
                    }
                }
                articles_category_selects.val('');
                articles_category_parent_select.val(contents[5]);
                for (var i = 0; i < contents[4].length; i++) {
                    articles_category_selects.eq(i).val(contents[4][i]);
                }
                articles_area.sbLanguageSwitcher(this.getTranslations(article_id), 'articles', language);
                articles_area.find('.sb-content').attr('data-id', contents[0]);
                articles_area.find('.sb-article-title input').val(contents[1]);
                articles_area.find('.sb-article-content textarea').val(contents[2]);
                articles_area.find('.sb-article-link input').val(contents[3]);
                articles_area.find('#sb-article-id').html(`ID <span>${contents[0]}</span>`);
            },

            add: function () {
                let nav = articles_area.find('.sb-nav > ul');
                let id = SBF.random();
                this.updateActiveArticle();
                this.articles.push({ id: id, title: '', content: '', link: '', categories: [] });
                this.hide(false);
                nav.find('.sb-active').sbActivate(false);
                nav.find('.sb-no-results').remove();
                nav.append(`<li class="sb-active" data-id="${id}">${sb_('Article')} ${nav.find('li').length + 1}<i class="sb-icon-delete"></i></li>`);
                articles_area.find('input, textarea, select').val('');
                articles_area.find('.sb-content').attr('data-id', id);
                articles_area.sbLanguageSwitcher([], 'articles');
            },

            addCategory: function () {
                articles_area.find('[data-type="categories"] .sb-no-results').remove();
                articles_area.find('.sb-new-category-cnt').append('<div class="sb-input-setting sb-type-text"><div><input type="text"></div></div>');
            },

            delete: function (element, category = false) {
                let nav = $(element).closest('.sb-nav').find(' > ul');
                this[category ? 'categories' : 'articles'].splice($(element).parent().index(), 1);
                this.hide();
                if (nav.find('li').length > 1) {
                    $(element).parent().remove();
                } else {
                    nav.html(`<li class="sb-no-results">${sb_('No results found.')}</li>`);
                }
            },

            populate: function (items = false, category = false) {
                if (items === false) items = category ? this.categories : this.articles;
                if (Array.isArray(items)) {
                    let code = '';
                    if (category) {
                        this.categories = items;
                    } else {
                        this.articles = items;
                    }
                    if (items.length) {
                        for (var i = 0; i < items.length; i++) {
                            code += `<li data-id="${items[i]['id']}">${category ? '<span>' + items[i]['id'] + '</span>' : ''}${items[i]['title']}<i class="sb-icon-delete${category ? ' sb-category' : ''}"></i></li>`;
                        }
                    } else {
                        code = `<li class="sb-no-results">${sb_('No results found.')}</li>`;
                    }
                    articles_area.find('.sb-add-category,.sb-new-category-cnt').sbActivate(category);
                    articles_area.find('.sb-add-article').sbActivate(!category);
                    articles_area.find('.sb-nav').attr('data-type', category ? 'categories' : 'articles');
                    articles_area.find('.sb-nav > ul').html(code);
                    this.hide();
                } else {
                    SBF.error(items, 'SBSettings.articles.populate');
                }
            },

            updateActiveArticle: function () {
                let id = this.activeID();
                if (id != -1) {
                    let language = articles_area.find(`.sb-language-switcher [data-language].sb-active`).attr('data-language');
                    let articles = language ? (language in this.translations ? this.translations[language] : []) : this.articles;
                    let categories = [];
                    articles_category_selects.each(function () {
                        if ($(this).val()) categories.push($(this).val());
                    });
                    for (var i = 0; i < articles.length; i++) {
                        if (articles[i]['id'] == id) {
                            articles[i] = { id: id, title: articles_area.find('.sb-article-title input').val(), content: articles_area.find('.sb-article-content textarea').val(), link: articles_area.find('.sb-article-link input').val(), categories: categories, parent_category: articles_category_parent_select.val() };
                            if (SBF.null(articles[i].title)) this.delete(articles_area.find(`.sb-nav [data-id="${id}"] i`));
                            break;
                        }
                    }
                }
            },

            updateSelect: function () {
                let select_values = [];
                let select_parent_value = articles_category_parent_select.val();
                let code = '<option value=""></option>';
                articles_category_selects.each(function () {
                    select_values.push($(this).val());
                });
                for (var i = 0; i < this.categories.length; i++) {
                    code += `<option value="${this.categories[i]['id']}">${this.categories[i]['title']}</option>`;
                }
                articles_category_selects.html(code);
                articles_category_parent_select.html(code);
                articles_category_parent_select.val(select_parent_value);
                for (var i = 0; i < select_values.length; i++) {
                    articles_category_selects.eq(i).val(select_values[i]);
                }
            },

            addTranslation: function (article_id = false, language) {
                if (article_id === false) article_id = this.activeID();
                if (this.getTranslations(article_id).includes(article_id)) {
                    return console.warn('Article translation already in array.');
                }
                if (!(language in this.translations)) this.translations[language] = [];
                this.translations[language].push({ id: article_id, title: '', content: '', link: '', categories: [] });
            },

            getTranslations: function (article_id = false) {
                let translations = [];
                if (article_id === false) article_id = this.activeID();
                for (var key in this.translations) {
                    let articles = this.translations[key];
                    for (var i = 0; i < articles.length; i++) {
                        if (articles[i]['id'] == article_id) {
                            translations.push(key);
                            break;
                        }
                    }
                }
                return translations;
            },

            deleteTranslation: function (article_id = false, language) {
                if (article_id === false) article_id = this.activeID();
                if (language in this.translations) {
                    let articles = this.translations[language];
                    for (var i = 0; i < articles.length; i++) {
                        if (articles[i]['id'] == article_id) {
                            this.translations[language].splice(i, 1);
                            return true;
                        }
                    }
                }
                return false;
            },

            activeID: function () {
                return articles_area.find('.sb-content').attr('data-id');
            },

            hide: function (hide = true) {
                articles_area.find('.sb-content').setClass('sb-hide', hide);
            }
        },

        automations: {
            items: { messages: [], emails: [], sms: [], popups: [], design: [] },
            translations: {},
            conditions: {
                datetime: ['Date time', ['Is between', 'Is exactly'], 'dd/mm/yyy hh:mm - dd/mm/yyy hh:mm'],
                repeat: ['Repeat', ['Every day', 'Every week', 'Every month', 'Every year']],
                browsing_time: ['Browsing time', [], 'seconds'],
                scroll_position: ['Scroll position', [], 'px'],
                include_urls: ['Include URLs', ['Contains', 'Does not contain', 'Is exactly', 'Is not'], 'URLs parts separated by commas'],
                exclude_urls: ['Exclude URLs', ['Contains', 'Does not contain', 'Is exactly', 'Is not'], 'URLs parts separated by commas'],
                referring: ['Referring URLs', ['Contains', 'Does not contain', 'Is exactly', 'Is not'], 'URLs parts separated by commas'],
                user_type: ['User type', ['Is visitor', 'Is lead', 'Is user', 'Is not visitor', 'Is not lead', 'Is not user']],
                returning_visitor: ['Returning visitor', ['First time visitor', 'Returning visitor']],
                countries: ['Countries', [], 'Country codes separated by commas'],
                languages: ['Languages', [], 'Language codes separated by commas'],
                cities: ['Cities', [], 'Cities separated by commas'],
                custom_variable: ['Custom variable', [], 'variable=value']
            },

            get: function (onSuccess) {
                SBF.ajax({
                    function: 'automations-get'
                }, (response) => {
                    this.items = response[0];
                    this.translations = Array.isArray(response[1]) && !response[1].length ? {} : response[1];
                    onSuccess(response);
                });
            },

            save: function (onSuccess = false) {
                this.updateActiveItem();
                SBF.ajax({
                    function: 'automations-save',
                    automations: this.items,
                    translations: this.translations
                }, (response) => {
                    if (onSuccess) onSuccess(response);
                });
            },

            show: function (id = false, language = false) {
                this.updateActiveItem();
                let items = language ? (language in this.translations ? this.translations[language] : []) : this.items;
                let area = automations_area.find(' > .sb-tab > .sb-content');
                if (id === false) id = this.activeID();
                this.hide(false);
                for (var key in items) {
                    for (var i = 0; i < items[key].length; i++) {
                        let item = items[key][i];
                        let conditions = item['conditions'];
                        if (item['id'] == id) {
                            conditions_area.html('');
                            for (var key in item) {
                                let element = area.find(`[data-id="${key}"]`);
                                if (element.hasClass('image')) {
                                    element.css('background-image', `url(${item[key]})`).attr('data-value', item[key]);
                                    if (item[key] == '') element.removeAttr('data-value');
                                } else if (element.attr('type') == 'checkbox') {
                                    element.prop('checked', item[key]);
                                } else element.val(item[key]);
                            }
                            if (conditions) {
                                for (var key in conditions) {
                                    this.addCondition();
                                    let condition = conditions_area.find(' > div:last-child');
                                    condition.find('select').val(conditions[key][0]);
                                    this.updateCondition(condition.find('select'));
                                    condition.find(' > div').eq(1).find('select,input').val(conditions[key][1]);
                                    if (conditions[key].length > 2) {
                                        condition.find(' > div').eq(2).find('input').val(conditions[key][2]);
                                    }
                                }
                            }
                            conditions_area.parent().setClass('sb-hide', language);
                            area.sbLanguageSwitcher(this.getTranslations(id), 'automations', language);
                            return true;
                        }
                    }
                }
                return false;
            },

            add: function () {
                let id = SBF.random();
                let name = `${sb_('Item')} ${automations_area_nav.find('li:not(.sb-no-results)').length + 1}`;
                this.updateActiveItem();
                this.items[this.activeType()].push(this.itemArray(this.activeType(), id, name));
                this.hide(false);
                automations_area_nav.find('.sb-active').sbActivate(false);
                automations_area_nav.find('.sb-no-results').remove();
                automations_area_nav.append(`<li class="sb-active" data-id="${id}">${name}<i class="sb-icon-delete"></i></li>`);
                automations_area.find('.sb-automation-values').find('input, textarea').val('');
                automations_area.sbLanguageSwitcher([], 'automations');
                conditions_area.html('');
            },

            delete: function (element) {
                this.items[this.activeType()].splice($(element).parent().index(), 1);
                $(element).parent().remove();
                this.hide();
                if (this.items[this.activeType()].length == 0) automations_area_nav.html(`<li class="sb-no-results">${sb_('No results found.')}</li>`);
            },

            populate: function (type = false) {
                if (type === false) type = this.activeType();
                let code = '';
                let items = this.items[type];
                this.updateActiveItem();
                if (items.length) {
                    for (var i = 0; i < items.length; i++) {
                        code += `<li data-id="${items[i]['id']}">${items[i]['name']}<i class="sb-icon-delete"></i></li>`;
                    }
                } else {
                    code = `<li class="sb-no-results">${sb_('No results found.')}</li>`;
                }
                automations_area_nav.html(code);
                code = '';
                switch (type) {
                    case 'emails':
                        code = `<h2>${sb_('Subject')}</h2><div class="sb-input-setting sb-type-text"><div><input data-id="subject" type="text"></div></div>`;
                        break;
                    case 'popups':
                        code = `<h2>${sb_('Title')}</h2><div class="sb-input-setting sb-type-text"><div><input data-id="title" type="text"></div></div><h2>${sb_('Profile image')}</h2><div data-type="upload-image" class="sb-input-setting sb-type-upload-image"><div class="input"><div data-id="profile_image" class="image"><i class="sb-icon-close"></i></div></div></div><h2>${sb_('Message fallback')}</h2><div class="sb-input-setting sb-type-checkbox"><div><input data-id="fallback" type="checkbox"></div></div>`;
                        break;
                    case 'design':
                        code = `<h2>${sb_('Header title')}</h2><div class="sb-input-setting sb-type-text"><div><input data-id="title" type="text"></div></div>`;
                        for (var i = 1; i < 4; i++) {
                            code += `<h2>${sb_((i == 1 ? 'Primary' : (i == 2 ? 'Secondary' : 'Tertiary')) + ' color')}</h2><div data-type="color" class="sb-input-setting sb-type-color"><div class="input"><input data-id="color_${i}" type="text"><i class="sb-close sb-icon-close"></i></div></div>`;
                        }
                        for (var i = 1; i < 4; i++) {
                            code += `<h2>${sb_(i == 1 ? 'Header background image' : (i == 2 ? 'Header brand image' : 'Chat button icon'))}</h2><div data-type="upload-image" class="sb-input-setting sb-type-upload-image"><div class="input"><div data-id="${i == 1 ? 'background' : (i == 2 ? 'brand' : 'icon')}" class="image"><i class="sb-icon-close"></i></div></div></div>`;
                        }
                        break;
                }
                automations_area.find('.sb-automation-extra').html(code);
                SBSettings.initColorPicker(automations_area);
                this.hide();
            },

            updateActiveItem: function () {
                let id = this.activeID();
                if (id) {
                    let language = automations_area.find(`.sb-language-switcher [data-language].sb-active`).attr('data-language');
                    let type = this.activeType();
                    let items = language ? (language in this.translations ? this.translations[language][type] : []) : this.items[type];
                    let conditions = conditions_area.find(' > div');
                    for (var i = 0; i < items.length; i++) {
                        if (items[i]['id'] == id) {
                            items[i] = { id: id, conditions: [] };
                            automations_area.find('.sb-automation-values').find('input,textarea,[data-type="upload-image"] .image').each(function () {
                                items[i][$(this).attr('data-id')] = $(this).hasClass('image') && $(this)[0].hasAttribute('data-value') ? $(this).attr('data-value') : ($(this).attr('type') == 'checkbox' ? $(this).is(':checked') : $(this).val());
                            });
                            conditions.each(function () {
                                let condition = [];
                                $(this).find('input,select').each(function () {
                                    condition.push($(this).val());
                                });
                                if (condition[0] && condition[1] && (condition.length == 2 || condition[2])) {
                                    items[i]['conditions'].push(condition);
                                }
                            });
                            if (SBF.null(items[i].name)) {
                                this.delete(automations_area_nav.find(`[data-id="${id}"] i`));
                            }
                            break;
                        }
                    }
                }
            },

            addCondition: function () {
                conditions_area.append(`<div><div class="sb-input-setting sb-type-select sb-condition-1"><select>${this.getAvailableConditions()}</select></div></div>`);
            },

            updateCondition: function (element) {
                $(element).parent().siblings().remove();
                let parent = $(element).parents().eq(1);
                if ($(element).val()) {
                    let condition = this.conditions[$(element).val()];
                    let code = '';
                    if (condition[1].length) {
                        code = '<div class="sb-input-setting sb-type-select sb-condition-2"><select>';
                        for (var i = 0; i < condition[1].length; i++) {
                            code += `<option value="${SBF.stringToSlug(condition[1][i])}">${sb_(condition[1][i])}</option>`;
                        }
                        code += '</select></div>';
                    }
                    parent.append(code + (condition.length > 2 ? `<div class="sb-input-setting sb-type-text"><input placeholder="${sb_(condition[2])}" type="text"></div>` : ''));
                    parent.siblings().find('.sb-condition-1 select').each(function () {
                        let value = $(this).val();
                        $(this).html(SBSettings.automations.getAvailableConditions(value));
                        $(this).val(value);
                    });
                } else {
                    parent.remove();
                }
            },

            getAvailableConditions: function (include = '') {
                let code = '<option value=""></option>';
                let existing_conditions = [];
                conditions_area.find('.sb-condition-1 select').each(function () {
                    existing_conditions.push($(this).val());
                });
                for (var key in this.conditions) {
                    if (!existing_conditions.includes(key) || key == include) {
                        code += `<option value="${key}">${sb_(this.conditions[key][0])}</option>`;
                    }
                }
                return code;
            },

            addTranslation: function (id = false, type = false, language) {
                if (id === false) id = this.activeID();
                if (type === false) type = this.activeType();
                if (this.getTranslations(id).includes(id)) {
                    return console.warn('Automation translation already in array.');
                }
                if (!(language in this.translations)) this.translations[language] = { messages: [], emails: [], sms: [], popups: [], design: [] };
                if (!(type in this.translations[language])) this.translations[language][type] = [];
                this.translations[language][type].push(this.itemArray(type, id));
            },

            getTranslations: function (id = false) {
                let translations = [];
                if (id === false) id = this.activeID();
                for (var key in this.translations) {
                    let types = this.translations[key];
                    for (var key2 in types) {
                        let items = types[key2];
                        for (var i = 0; i < items.length; i++) {
                            if (items[i]['id'] == id) {
                                translations.push(key);
                                break;
                            }
                        }
                    }
                }
                return translations;
            },

            deleteTranslation: function (id = false, language) {
                if (id === false) id = this.activeID();
                if (language in this.translations) {
                    let types = this.translations[language];
                    for (var key in types) {
                        let items = types[key];
                        for (var i = 0; i < items.length; i++) {
                            if (items[i]['id'] == id) {
                                this.translations[language][key].splice(i, 1);
                                return true;
                            }
                        }
                    }
                }
                return false;
            },

            activeID: function () {
                let item = automations_area_nav.find('.sb-active');
                return item.length ? item.attr('data-id') : false;
            },

            activeType: function () {
                return automations_area_select.find('li.sb-active').data('value');
            },

            itemArray: function (type, id, name = '', message = '') {
                return $.extend({ id: id, name: name, message: message }, type == 'emails' ? { subject: '' } : (type == 'popups' ? { title: '', profile_image: '' } : (type == 'design' ? { title: '', color_1: '', color_2: '', color_3: '', background: '', brand: '', icon: '' } : {})));
            },

            hide: function (hide = true) {
                automations_area.find(' > .sb-tab > .sb-content').setClass('sb-hide', hide);
            }
        },

        translations: {
            translations: {},
            originals: {},
            to_update: {},

            add: function (language) {
                let setting = SBSettings.getSettingObject(language_switcher_target);
                let setting_id = setting.attr('id');
                let active_language = language_switcher_target.find('[data-language].sb-active');
                this.save(setting, active_language.length ? active_language.attr('data-language') : false);
                setting.find('textarea,input[type="text"]').val('');
                this.save(setting, language);
                language_switcher_target.remove();
                setting.sbLanguageSwitcher(this.getLanguageCodes(setting_id), 'settings', language);
            },

            delete: function (setting, language) {
                setting = SBSettings.getSettingObject(setting);
                let setting_id = setting.attr('id');
                delete this.translations[language][setting_id];
                setting.find(`.sb-language-switcher [data-language="${language}"]`).remove();
                this.activate(setting);
            },

            activate: function (setting, language = false) {
                setting = SBSettings.getSettingObject(setting);
                let setting_id = setting.attr('id');
                let values = language ? this.translations[language][setting_id] : this.originals[setting_id];
                if (typeof values == 'string') {
                    setting.find('input, textarea').val(values);
                } else {
                    for (var key in values) {
                        setting.find('#' + key).find('input, textarea').val(typeof values[key] == 'string' ? values[key] : values[key][0]);
                    }
                }
            },

            updateActive: function () {
                let area = settings_area.find('.sb-translations-list')
                let translations = { 'front': {}, 'admin': {}, 'admin/js': {}, 'admin/settings': {} };
                let language_code = area.attr('data-value');
                if (SBF.null(language_code)) return;
                for (var key in translations) {
                    area.find(' > [data-area="' + key + '"] .sb-input-setting:not(.sb-new-translation)').each(function () {
                        translations[key][$(this).find('label').html()] = $(this).find('input').val();
                    });
                    area.find('> [data-area="' + key + '"] .sb-new-translation').each(function () {
                        let original = $(this).find('input:first-child').val();
                        let value = $(this).find('input:last-child').val();
                        if (original && value) {
                            translations[key][original] = value;
                        }
                    });
                }
                this.to_update[language_code] = translations;
            },

            save: function (setting, language = false) {
                setting = SBSettings.getSettingObject(setting);
                let values = {};
                let setting_id = $(setting).attr('id');
                if (setting.data('type') == 'multi-input') {
                    setting.find('.multi-input-textarea,.multi-input-text').each(function () {
                        values[$(this).attr('id')] = $(this).find('input, textarea').val();
                    });
                } else {
                    values = setting.find('input, textarea').val();
                }
                if (language) {
                    if (!(language in this.translations)) {
                        this.translations[language] = {};
                    }
                    this.translations[language][setting_id] = values;
                } else {
                    this.originals[setting_id] = values;
                }
            },

            load: function (language_code) {
                let area = settings_area.find('.sb-translations > .sb-content');
                area.find(' > .sb-hide').removeClass('sb-hide');
                this.updateActive();
                SBF.ajax({
                    function: 'get-translation',
                    language_code: language_code
                }, (translations) => {
                    if (language_code in this.to_update) translations = this.to_update[language_code];
                    let code = '';
                    let areas = ['front', 'admin', 'admin/js', 'admin/settings'];
                    for (var i = 0; i < areas.length; i++) {
                        let translations_area = translations[areas[i]];
                        code += `<div class="sb-active" data-area="${areas[i]}">`;
                        for (var key in translations_area) {
                            code += `<div class="sb-input-setting sb-type-text"><label>${key}</label><div><input type="text" value="${translations_area[key]}"></div></div>`;
                        }
                        code += '</div>';
                    }
                    area.find('.sb-translations-list').attr('data-value', language_code).html(code);
                    area.find('.sb-menu-wide li').sbActivate(false).eq(0).sbActivate(true);
                    area.sbLoading(false);
                });
                area.sbLoading(true);
            },

            getLanguageCodes: function (setting_id) {
                let languages = [];
                for (var key in this.translations) {
                    if (setting_id in this.translations[key]) {
                        languages.push(key);
                    }
                }
                return languages;
            }
        }
    }

    /*
    * ----------------------------------------------------------
    * # Reports
    * ----------------------------------------------------------
    */

    var SBReports = {
        chart: false,
        active_report: false,

        initChart: function (data, type = 'line', label_type = 1) {
            let values = [];
            let labels = [];
            let blues = ['#049CFF', '#74C4F7', '#B9E5FF', '#0562A0', '#003B62', '#1F74C4', '#436786'];
            for (var key in data) {
                values.push(data[key][0]);
                labels.push(key);
            }
            if (type != 'line' && values.length > 6) {
                for (var i = 0; i < values.length; i++) {
                    blues.push('hsl(' + 210 + ', ' + Math.floor(Math.random() * 100) + '%, ' + Math.floor(Math.random() * 100) + '%)');
                }
            }
            if (this.chart) this.chart.destroy();
            this.chart = new Chart(reports_area.find('canvas'), {
                type: type,
                data: {
                    labels: labels,
                    datasets: [{
                        data: values,
                        backgroundColor: type == 'line' ? '#028be530' : blues,
                        borderColor: type == 'line' ? '#049CFF' : '#FFFFFF',
                        borderWidth: 0
                    }],
                },
                options: {
                    legend: {
                        display: false
                    },
                    scales: {
                        yAxes: [{
                            ticks: {
                                callback: function (tickValue, index, ticks) {
                                    return label_type == 1 ? tickValue : (label_type == 2 ? new Date(tickValue * 1000).toISOString().substr(11, 8) : tickValue);
                                },
                                beginAtZero: true
                            }
                        }],
                        xAxes: [{
                            ticks: {
                                beginAtZero: true
                            }
                        }],
                    },
                    tooltips: {
                        callbacks: {
                            label: function (tooltipItem, chartData) {
                                let index = tooltipItem['index'];
                                let value = chartData['datasets'][0]['data'][index];
                                switch (label_type) {
                                    case 1: return value;
                                    case 2: return new Date(values[index] * 1000).toISOString().substr(11, 8);
                                    case 3: return value + '%';
                                    case 4: let tds = reports_area.find('.sb-table tbody tr').eq(index).find('td'); return tds.eq(0).text() + ' ' + tds.eq(1).text();
                                }
                            },
                        },
                        displayColors: false
                    }
                }
            });
        },

        initTable: function (header, data, inverse = false) {
            let code = '<thead><tr>';
            let index = data[Object.keys(data)[0]].length - 1;
            let list = [];
            for (var i = 0; i < header.length; i++) {
                code += `<th>${header[i]}</th>`;
            }
            code += '</tr></thead><tbody>';
            for (var key in data) {
                if (data[key][index] != 0) {
                    list.push([key, data[key][index]]);
                }
            }
            if (inverse) {
                list.reverse();
            }
            for (var i = 0; i < list.length; i++) {
                code += `<tr><td><div>${list[i][0]}</div></td><td>${list[i][1]}</td></tr>`;
            }
            code += '</tbody>';
            reports_area.find('table').html(code);
        },

        initReport: function (name = false, date_range = false) {
            let area = reports_area.find('.sb-tab > .sb-content');
            date_range = SBF.null(date_range) ? [false, false] : date_range.split(' - ');
            area.sbLoading(true);
            if (name) this.active_report = name;
            if (!this.active_report) return;
            this.getData(this.active_report, date_range[0], date_range[1], (response) => {
                if (response == false) {
                    area.addClass('sb-no-results-active');
                } else {
                    area.removeClass('sb-no-results-active');
                    this.initChart(response['data'], response['chart_type'], response['label_type']);
                    this.initTable(response['table'], response['data'], response['table-inverse']);
                    reports_area.find('.sb-reports-title').html(response['title']);
                    reports_area.find('.sb-reports-text').html(response['description']);
                    reports_area.find('.sb-collapse-btn').remove();
                    if (!responsive) collapse(reports_area.find('.sb-collapse'), reports_area.find('canvas').outerHeight() - 135);
                }
                area.sbLoading(false);
            });
        },

        getData: function (name, date_start = false, date_end = false, onSuccess) {
            SBF.ajax({
                function: 'reports',
                name: name,
                date_start: date_start,
                date_end: date_end
            }, (response) => {
                onSuccess(response);
            });
        },

        initDatePicker: function () {
            let settings = {
                ranges: {},
                locale: {
                    'format': 'DD/MM/YYYY',
                    'separator': ' - ',
                    'applyLabel': sb_('Apply'),
                    'cancelLabel': sb_('Cancel'),
                    'fromLabel': sb_('From'),
                    'toLabel': sb_('To'),
                    'customRangeLabel': sb_('Custom'),
                    'weekLabel': sb_('W'),
                    'daysOfWeek': [
                        sb_('Su'),
                        sb_('Mo'),
                        sb_('Tu'),
                        sb_('We'),
                        sb_('Th'),
                        sb_('Fr'),
                        sb_('Sa')
                    ],
                    'monthNames': [
                        sb_('January'),
                        sb_('February'),
                        sb_('March'),
                        sb_('April'),
                        sb_('May'),
                        sb_('June'),
                        sb_('July'),
                        sb_('August'),
                        sb_('September'),
                        sb_('October'),
                        sb_('November'),
                        sb_('December')
                    ],
                    'firstDay': 1
                },
                showCustomRangeLabel: true,
                alwaysShowCalendars: true,
                autoApply: true
            };
            settings['ranges'][sb_('Today')] = [moment(), moment()];
            settings['ranges'][sb_('Yesterday')] = [moment().subtract(1, 'days'), moment().subtract(1, 'days')];
            settings['ranges'][sb_('Last 7 Days')] = [moment().subtract(6, 'days'), moment()];
            settings['ranges'][sb_('Last 30 Days')] = [moment().subtract(29, 'days'), moment()];
            settings['ranges'][sb_('This Month')] = [moment().startOf('month'), moment().endOf('month')];
            settings['ranges'][sb_('Last Month')] = [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')];
            reports_area.find('#sb-date-picker').daterangepicker(settings).val('');
        }
    }

    /*
    * ----------------------------------------------------------
    * # Users
    * ----------------------------------------------------------
    */

    var SBUsers = {
        real_time: null,
        datetime_last_user: '2000-01-01 00:00:00',
        sorting: ['creation_time', 'DESC'],
        user_types: ['visitor', 'lead', 'user'],
        user_main_fields: ['id', 'first_name', 'last_name', 'email', 'password', 'profile_image', 'user_type', 'creation_time', 'token', 'last_activity', 'department'],
        search_query: '',
        init: false,
        busy: false,
        table_extra: false,

        // Table menu filter
        filter: function (type) {
            if (type == 'all') {
                type = ['visitor', 'lead', 'user'];
            } else if (type == 'agent') {
                type = ['agent', 'admin'];
            } else {
                type = [type];
            }
            this.user_types = type;
            this.loading();
            users_pagination = 1;
            users_pagination_count = 1;
            let settings = type[0] == 'online' ? ['get-online-users', SB_ACTIVE_AGENT['id'], this.sorting[0]] : ['get-users', -1, this.sorting];
            SBF.ajax({
                function: settings[0],
                sorting: settings[2],
                user_types: type,
                search: this.search_query,
                extra: this.table_extra
            }, (response) => {
                this.populate(response);
                this.loading(false);
            });
        },

        // Table menu sort
        sort: function (field, direction = 'DESC') {
            this.sorting = [field, direction];
            this.loading();
            users_pagination = 1;
            users_pagination_count = 1;
            SBF.ajax({
                function: 'get-users',
                sorting: this.sorting,
                user_types: this.user_types,
                search: this.search_query,
                extra: this.table_extra
            }, (response) => {
                this.populate(response);
                this.loading(false);
            });
        },

        // Search users
        search: function (input) {
            searchInput(input, (search, icon) => {
                users_pagination = 1;
                users_pagination_count = 1;
                SBF.ajax({
                    function: search.length > 1 ? 'search-users' : 'get-users',
                    search: search,
                    user_types: this.user_types,
                    sorting: this.sorting,
                    extra: this.table_extra
                }, (response) => {
                    this.user_types = ['visitor', 'lead', 'user'];
                    this.populate(response);
                    this.search_query = search;
                    $(icon).sbLoading(false);
                    users_table_menu.find('li').sbActivate(false).eq(0).sbActivate();
                });
            });
        },

        // Populate the table
        populate: function (response) {
            let code = '';
            let count = response.length;
            if (count) {
                for (var i = 0; i < count; i++) {
                    code += this.getRow(new SBUser(response[i], response[i].extra));
                }
            } else {
                code = `<p class="sb-no-results">${sb_('No users found.')}</p>`;
            }
            users_table.parent().scrollTop(0);
            users_table.find('tbody').html(code);
            if (this.user_types.includes('agent')) {
                SBF.ajax({
                    function: 'get-online-users',
                    agents: true
                }, (response) => {
                    let ids = [];
                    for (var i = 0; i < response.length; i++) {
                        ids.push(response[i].id);
                    }
                    users_table.find('[data-user-id]').each(function () {
                        $(this).find('.sb-td-profile').addClass('sb-' + (ids.includes($(this).attr('data-user-id')) ? 'online' : 'offline'));
                    });
                });
            }
        },

        // Update users and table with new users
        update: function () {
            if (!this.busy) {
                let checks = ['user', 'visitor', 'lead', 'agent'];
                let populate = checks.includes(this.user_types[0]) && this.search_query == '';
                let filter = users_table_menu.find('.sb-active').data('type');
                if (filter == 'online') {
                    this.filter(filter);
                } else {
                    this.busy = true;
                    SBF.ajax({
                        function: 'get-new-users',
                        datetime: this.datetime_last_user
                    }, (response) => {
                        let count = response.length;
                        this.busy = false;
                        if (count > 0) {
                            let code = '';
                            for (var i = 0; i < count; i++) {
                                let user = new SBUser(response[i]);
                                users[user.id] = user;
                                this.updateMenu('add', user.type);
                                if (populate) {
                                    code += this.getRow(user);
                                }
                            }
                            if (populate) {
                                users_table.find('tbody').prepend(code);
                                if (checks.includes(filter)) {
                                    let selector = '';
                                    for (var i = 0; i < checks.length; i++) {
                                        selector += checks[i] == filter ? '' : `[data-user-type="${checks[i]}"],`;
                                    }
                                    users_table.find(selector.slice(0, -1)).remove();
                                }
                            }
                            this.datetime_last_user = response[0]['creation_time'];
                        }
                    });
                }
            }
        },

        // Get a user row code
        getRow: function (user) {
            if (user instanceof SBUser) {
                let code = '';
                for (var i = 0; i < this.table_extra.length; i++) {
                    let slug = this.table_extra[i];
                    code += `<td class="sb-td-${slug}">${this.user_main_fields.includes(slug) ? user.get(slug) : user.getExtra(slug)}</td>`;
                }
                return `<tr data-user-id="${user.id}" data-user-type="${user.type}"><td><input type="checkbox" /></td><td class="sb-td-profile"><a class="sb-profile"><img src="${user.image}" /><span>${user.name}</span></a></td>${code}<td class="sb-td-email">${user.get('email')}</td><td class="sb-td-ut">${user.type}</td><td>${SBF.beautifyTime(user.get('last_activity'), true)}</td><td>${user.get('creation_time')}</td></tr>`;
            } else {
                SBF.error('User not of type SBUser', 'SBUsers.getRow');
                return false;
            }
        },

        // Update a user row
        updateRow: function (user) {
            let row = users_table.find(`[data-user-id="${user.id}"]`);
            if (row.length) {
                let menu_active = users_table_menu.find('.sb-active').data('type');
                if ((user.type != menu_active) && !(user.type == 'admin' && menu_active == 'agent') && menu_active != 'all') {
                    let counter = admin.find(`[data-type="${user.type == 'admin' ? 'agent' : user.type}"] span`);
                    let count = parseInt(counter.attr('data-count'));
                    counter.html(count + 1).attr('data-count', count + 1);
                    row.remove();
                } else {
                    row.replaceWith(this.getRow(user));
                }
            } else {
                users_table.find('tbody').append(this.getRow(user));
            }
        },

        // Update users table menu
        updateMenu: function (action = 'all', type = false) {
            let user_types = ['all', 'user', 'lead', 'visitor'];
            if (action == 'all') {
                SBF.ajax({
                    function: 'count-users'
                }, (response) => {
                    for (var i = 0; i < user_types.length; i++) {
                        this.updateMenuItem('set', user_types[i], response[user_types[i]]);
                    }
                });
            } else {
                this.updateMenuItem(action, type);
            }
        },

        updateMenuItem: function (action = 'set', type = false, count = 1) {
            let item = users_table_menu.find(`[data-type="${type}"] span`);
            let user_types = ['user', 'lead', 'visitor'];
            if (action != 'set') {
                count = parseInt(item.attr('data-count')) + (1 * (action == 'add' ? 1 : -1));
            }
            item.html(`(${count})`).attr('data-count', count);
            count = 0;
            for (var i = 0; i < user_types.length; i++) {
                count += parseInt(users_table_menu.find(`[data-type="${user_types[i]}"] span`).attr('data-count'));
            }
            users_table_menu.find(`[data-type="all"] span`).html(`(${count})`).attr('data-count', count);
        },

        // Delete a user
        delete: function (user_ids) {
            this.loading();
            if (Array.isArray(user_ids)) {
                if (SB_ADMIN_SETTINGS.cloud) {
                    user_ids = SBCloud.removeAdminID(user_ids);
                    if (!user_ids.length) return;
                }
                SBF.ajax({
                    function: 'delete-users',
                    user_ids: user_ids
                }, () => {
                    for (var i = 0; i < user_ids.length; i++) {
                        delete users[user_ids[i]];
                        users_table.find(`[data-user-id="${user_ids[i]}"]`).remove();
                        conversations_admin_list_ul.find(`[data-user-id="${user_ids[i]}"]`).remove();
                    }
                    if (users_table.find('[data-user-id]').length == 0) {
                        this.filter(users_table_menu.find('.sb-active').data('type'));
                    }
                    showResponse('Users deleted');
                    this.updateMenu();
                    this.loading(false);
                });
            } else {
                users[user_ids].delete(() => {
                    let conversation = conversations_admin_list_ul.find(`[data-user-id="${user_ids}"]`);
                    if (activeUser().id == user_ids) {
                        activeUser(false);
                    }
                    if (conversation.sbActive()) {
                        SBChat.conversation = false;
                        setTimeout(() => { SBConversations.clickFirst() }, 300);
                    }
                    delete users[user_ids];
                    users_table.find(`[data-user-id="${user_ids}"]`).remove();
                    conversation.remove();
                    admin.sbHideLightbox();
                    showResponse('User deleted');
                    this.updateMenu();
                    this.loading(false);
                });
            }
        },

        // Start or stop the real time update of the users and table
        startRealTime: function () {
            if (SBPusher.active) return;
            this.stopRealTime();
            this.real_time = setInterval(() => {
                this.update();
            }, 1000);
        },

        stopRealTime: function () {
            clearInterval(this.real_time);
        },

        // Table loading
        loading: function (show = true) {
            let loading = users_area.find('.sb-loading-table');
            if (show) loading.sbActivate();
            else loading.sbActivate(false);
        },

        // CSV generation and download
        csv: function () {
            SBF.ajax({ function: 'csv-users' }, (response) => window.open(response));
        },

        // Update user and agent activity status
        updateUsersActivity: function () {
            SBF.updateUsersActivity(agent_online ? SB_ACTIVE_AGENT['id'] : -1, activeUser() ? activeUser().id : -1, function (response) {
                SBUsers.setActiveUserStatus(response == 'online');
            });
        },

        // Set active agent status
        setActiveAgentStatus: function (online = true) {
            agent_online = online;
            header.find('[data-value="status"]').html(sb_(online ? 'Online' : 'Offline')).attr('class', online ? 'sb-online' : 'sb-offline');
            if (SBPusher.active) {
                if (online) {
                    SBPusher.presence();
                } else {
                    SBPusher.presenceUnsubscribe();
                }
            }
        },

        // Set active user status
        setActiveUserStatus: function (online = true) {
            let labels = conversations_area.find('.sb-conversation .sb-top > .sb-labels');
            labels.find('.sb-status-online').remove();
            if (online) labels.prepend(`<span class="sb-status-online">${sb_('Online')}</span>`);
            SBChat.user_online = online;
        }
    }

    /*
    * ----------------------------------------------------------
    * # Conversations 
    * ----------------------------------------------------------
    */

    var SBConversations = {
        real_time: null,
        datetime_last_conversation: '2000-01-01 00:00:00',
        user_typing: false,
        desktop_notifications: false,
        flash_notifications: false,
        busy: false,
        is_search: false,
        menu_count_ajax: false,

        // Open the conversations tab
        open: function (conversation_id = -1, user_id) {
            if (conversation_id != -1) {
                this.openConversation(conversation_id, user_id);
            }
            admin.sbHideLightbox();
            header.find('.sb-admin-nav a').sbActivate(false).parent().find('#sb-conversations').sbActivate();
            admin.find(' > main > div').sbActivate(false);
            conversations_area.sbActivate().find('.sb-board').removeClass('sb-no-conversation');
            this.startRealTime();
        },

        // Open a single conversation
        openConversation: function (conversation_id, user_id = false, scroll = true) {
            if (user_id === false && conversation_id) {
                SBF.ajax({
                    function: 'get-user-from-conversation',
                    conversation_id: conversation_id
                }, (response) => {
                    if (!SBF.null(response['id'])) {
                        this.openConversation(conversation_id, response['id'], scroll);
                    } else SBF.error('User not found', 'SBAdmin.openConversation');
                });
            } else {
                let area = conversations_area.find('.sb-conversation .sb-list');
                let new_user = SBF.null(users[user_id]) || !('email' in users[user_id].details);
                let conversation = conversations_area.find(`[data-conversation-id="${conversation_id}"]`);
                area.html('');
                area.sbLoading(true);

                // Init the user
                if (new_user) {
                    activeUser(new SBUser({ 'id': user_id }));
                    activeUser().update(() => {
                        users[user_id] = activeUser();
                        this.updateUserDetails();
                    });
                } else {
                    activeUser(users[user_id]);
                }
                if (SBPusher.active) {
                    SBPusher.event('client-typing', (response) => {
                        if (response.user_id == activeUser().id) {
                            SBConversations.typing(true);
                            clearTimeout(pusher_timeout);
                            pusher_timeout = setTimeout(() => { SBConversations.typing(false) }, 1000);
                        }
                    });
                    SBPusher.event('new-message', () => {
                        SBChat.update();
                    });
                    SBPusher.event('agent-active-conversation-changed', (response) => {
                        if (response.previous_conversation_id == conversation_id) {
                            conversations_area.find('.sb-conversation-busy').remove();
                        }
                    }, 'agents');
                    SBPusher.event('init', () => {
                        SBConversations.updateCurrentURL();
                    });
                }
                if (SB_ADMIN_SETTINGS['smart-reply']) suggestions_area.html('');

                // Open the conversation
                conversations_admin_list_ul.find('li').sbActivate(false);
                conversation.sbActivate();
                if (conversation_id != -1) {
                    activeUser().getFullConversation(conversation_id, (response) => {

                        let conversation_status_code = response.get('conversation_status_code');
                        let select = conversations_admin_list.find('.sb-select');
                        let select_status_code = select.find('.sb-active').attr('data-value');

                        SBChat.setConversation(response);
                        SBChat.populate();
                        conversations_area.find('.sb-top > a').html(response.get('title'));
                        conversations_area.find('.sb-top [data-value="read"]').sbActivate(conversation_status_code == 2);
                        conversations_area.find('.sb-conversation-busy').remove();
                        this.updateUserDetails();

                        // Automatic translation
                        SBAdmin.must_translate = SB_ADMIN_SETTINGS['translation'] && activeUser().language && SB_ADMIN_SETTINGS['active-agent-language'] != activeUser().language;
                        if (SBAdmin.must_translate) {
                            let strings = [];
                            let message_ids = [];
                            let message_user_types = [];
                            for (var i = 0; i < response.messages.length; i++) {
                                let message = response.messages[i];
                                if (message.get('user_type') != 'bot') {
                                    strings.push(message.message);
                                    message_ids.push(message.id);
                                    message_user_types.push(message.get('user_type'));
                                }
                            }
                            SBApps.dialogflow.translate(strings, SB_ADMIN_SETTINGS['active-agent-language'], (response) => {
                                if (response) {
                                    for (var i = 0; i < response.length; i++) {
                                        let message = SBChat.conversation.getMessage(message_ids[i]);
                                        area.find(`[data-id="${message_ids[i]}"] .sb-message`).html(response[i].translatedText);
                                        area.find(`[data-id="${message_ids[i]}"] .sb-menu`).prepend(`<li data-value="original">${sb_(SBF.isAgent(message_user_types[i]) ? 'View translation' : 'View original message')}</li>`);
                                        if (message) message.set('translation', response[i].translatedText);
                                    }
                                }
                            });
                        }

                        // Departments
                        let select_departments = conversations_area.find('#conversation-department');
                        if (select_departments.length) {
                            let item = select_departments.find(`[data-id="${response.get('department')}"]`);
                            select_departments.find(' > p').attr('data-value', item.data('value')).html(item.html());
                        }

                        // Agent assignment
                        let select_agents = conversations_area.find('#conversation-agent');
                        if (select_agents.length) {
                            let item = select_agents.find(`[data-id="${response.get('agent_id')}"]`);
                            select_agents.find(' > p').attr('data-value', item.data('id')).html(item.html());
                        }

                        // Activate conversation
                        if ([1, 2].includes(conversation_status_code)) {
                            conversation_status_code = 0;
                        }
                        if (select_status_code != conversation_status_code && !$(conversations_admin_list).find('.sb-search-btn').sbActive()) {
                            select.find(`[data-value="${conversation_status_code}"]`).click();
                            select.find('ul').sbActivate(false);
                        }
                        if (responsive) {
                            this.mobileOpenConversation();
                        }
                        if (!conversation.length && select_status_code == conversation_status_code) {
                            conversations_admin_list_ul.prepend(SBConversations.getListCode(response).replace('<li', '<li class="sb-active"'));
                        }
                        conversation.sbActivate();
                        if (scroll) {
                            this.scrollTo();
                        }

                        // Check if another agent has the conversation open
                        if (response.get('busy')) {
                            conversations_area.find('.sb-editor > .sb-labels').prepend(`<span data-agent="${response.get('busy')}" class="sb-status-warning sb-conversation-busy">${sb_('Another agent is replying to this conversation')}</span>`);
                        }

                        // Woocommerce
                        if (SBApps.is('woocommerce')) {
                            SBApps.woocommerce.conversationPanel();
                        }

                        // UMP
                        if (SBApps.is('ump')) {
                            SBApps.ump.conversationPanel();
                        }

                        // Perfex
                        if (SBApps.is('perfex')) {
                            SBApps.perfex.conversationPanel();
                        }

                        // WHMCS
                        if (SBApps.is('whmcs')) {
                            SBApps.whmcs.conversationPanel();
                        }

                        // Active eCommerce
                        if (SBApps.is('aecommerce')) {
                            SBApps.aecommerce.conversationPanel();
                        }

                        // ARMember
                        if (SBApps.is('armember')) {
                            SBApps.armember.conversationPanel();
                        }

                        // Notes
                        this.notes.update(response['details']['notes']);

                        // Attachments
                        this.attachments();

                        // Suggestions
                        if (SB_ADMIN_SETTINGS['smart-reply']) {
                            let message = response.getLastUserMessage();
                            suggestions_area.html('');
                            if (message && message.payload('sb-human-takeover')) {
                                message = response.getLastUserMessage(message.get('index'));
                            }
                            if (message) {
                                SBApps.dialogflow.smart_reply_data = false;
                                SBApps.dialogflow.smartReply(message.message);
                            }
                        }

                        // Rating
                        for (var i = response.messages.length - 1; i > 0; i--) {
                            let payload = response.messages[i].get('payload');
                            let break_loop = false;
                            if (payload && 'rich-messages' in payload) {
                                for (var rich_message_id in payload['rich-messages']) {
                                    let rich_message = payload['rich-messages'][rich_message_id];
                                    if (rich_message.type == 'rating') {
                                        conversations_area.find('.sb-profile-list > ul').append(`<li data-id="rating"><i class="sb-icon sb-icon-${rich_message.result.rating == 1 ? 'like' : 'dislike'}"></i><span>${sb_('User rating')}</span><label>${sb_(rich_message.result.rating == 1 ? 'Helpful' : 'Not helpful')}</label></li>`);
                                        break_loop = true;
                                        break;
                                    }
                                }
                            }
                            if (break_loop) break;
                        }

                        // Populate user conversations on the bottom right area
                        activeUser().getConversations(function (response) {
                            conversations_area.find('.sb-user-conversations').html(activeUser().getConversationsCode(response));
                        });

                        area.sbLoading(false);
                    });
                } else {
                    SBChat.clear();
                    conversations_admin_list_ul.find('li').sbActivate(false);
                    area.sbLoading(false);
                }

                // User details
                if (!new_user) {
                    this.updateUserDetails();
                }

                // More settings
                conversations_area.find('.sb-board').removeClass('sb-no-conversation');
                SBUsers.updateUsersActivity();
                this.startRealTime();
                if (SBF.getURL('conversation') != conversation_id) pushState('?conversation=' + conversation_id);
            }
        },

        // [Deprecated] this method is obsolete and it will be removed soon
        populate: function (conversation_id, user_id, scroll) {
            this.openConversation(conversation_id, user_id, scroll);
        },

        // Populate conversations
        populateList: function (response) {
            let code = '';
            conversations = [];
            for (var i = 0; i < response.length; i++) {
                code += this.getListCode(response[i]);
                conversations.push(response[i]);
            }
            if (code == '') {
                code = `<p class="sb-no-results">${sb_('No conversations found.')}</p>`;
            }
            conversations_admin_list_ul.html(code);
            this.updateMenu();
            SBF.event('SBAdminConversationsLoaded', { conversations: response });
        },

        // Update the left conversations list with new conversations or messages 
        update: function () {
            if (!this.busy) {
                this.busy = true;
                SBF.ajax({
                    function: 'get-new-conversations',
                    datetime: this.datetime_last_conversation,
                    routing: SB_ADMIN_SETTINGS['routing'],
                    routing_unassigned: SB_ADMIN_SETTINGS['assign-conversation-to-agent']
                }, (response) => {
                    this.busy = false;
                    if (response.length) {
                        let code_pending = '';
                        let code_not_pending = '';
                        let active_conversation_id = SBChat.conversation ? SBChat.conversation.id : -1;
                        let item_not_pending;
                        let scroll_to_conversation = false;
                        let id_check = [];
                        this.datetime_last_conversation = response[0]['creation_time'];

                        for (var i = 0; i < response.length; i++) {
                            if (!id_check.includes(response[i]['conversation_id'])) {
                                let item = response[i];
                                let status = item['conversation_status_code'];
                                let user_id = item['user_id'];
                                let conversation_id = item['conversation_id'];
                                let active_conversation = active_conversation_id == conversation_id;
                                let conversation_code = this.getListCode(item, null);
                                let conversation_li = conversations_admin_list_ul.find(`[data-conversation-id="${conversation_id}"]`);
                                let conversation_index = conversation_li.index();
                                let conversation = conversation_li.length;
                                let payload = SBF.null(response[i]['payload']) ? {} : JSON.parse(response[i]['payload']);

                                // Active conversation
                                if (active_conversation) {
                                    conversation_code = conversation_code.replace('<li', '<li class="sb-active"');
                                    if (conversation) {
                                        if (item['message']) {
                                            conversation_li.replaceWith(conversation_code);
                                        }
                                        conversations[conversation_index]['conversation_status_code'] = status;
                                        conversations_area.find('.sb-top [data-value="read"]').sbActivate(status == 2);
                                    } else {
                                        scroll_to_conversation = true;
                                    }
                                } else if (conversation) {

                                    // Conversation already in list but not active
                                    conversations[conversation_index] = item;
                                    conversations_admin_list_ul.find(`[data-conversation-id="${conversation_id}"]`).remove();
                                }

                                // Add the user to the global users array if it doesn't exists
                                if (!(user_id in users)) {
                                    users[user_id] = new SBUser({ 'id': user_id, 'first_name': item['first_name'], 'last_name': item['last_name'], 'profile_image': item['profile_image'], 'user_type': item['user_type'] });
                                }

                                // New conversation 
                                if (!active_conversation || !conversation) {
                                    if (status == 2) {
                                        code_pending += conversation_code;
                                        conversations.unshift(item);
                                    } else if (status == 0 || status == 1) {
                                        item_not_pending = conversations_admin_list_ul.find('[data-conversation-status="2"]').last();
                                        if (item_not_pending.length == 0) {
                                            code_pending += conversation_code;
                                        } else {
                                            conversations.splice(item_not_pending.index() + 1, 0, item);
                                            code_not_pending += conversation_code;
                                        }
                                    }
                                    if (user_id == activeUser().id) {
                                        activeUser().getConversations(function (response) {
                                            conversations_area.find('.sb-user-conversations').html(activeUser().getConversationsCode(response));
                                        });
                                    }
                                    SBF.event('SBAdminNewConversation', { conversation: item });
                                }

                                // Update user
                                if (activeUser() && (('event' in payload && payload['event'] == 'update-user') || (users[user_id].type != item['user_type']))) {
                                    activeUser().update(() => {
                                        this.updateUserDetails();
                                        users[activeUser().id] = activeUser();
                                    });
                                }

                                // Desktop, flash, sounds notifications
                                if (!SBChat.tab_active && item['conversation_status_code'] == 2 && (!SBF.isAgent(item['message_user_type']) || 'preview' in payload) && !(SBF.null(item.message) && SBF.null(item.attachments))) {
                                    if (this.desktop_notifications) {
                                        let user_details = [item['first_name'] + ' ' + item['last_name'], (item['profile_image'].indexOf('user.svg') > 0 ? SB_ADMIN_SETTINGS['notifications-icon'] : item['profile_image'])];
                                        SBChat.desktopNotification(user_details[0], 'preview' in payload ? payload.preview : item.message, user_details[1], conversation_id, user_id);
                                    }
                                    if (this.flash_notifications) {
                                        SBChat.flashNotification();
                                    }
                                    if (SBChat.audio && ['a', 'c', 'ic'].includes(SB_ADMIN_SETTINGS['sounds'])) {
                                        SBChat.audio.play();
                                    }
                                }
                                id_check.push(conversation_id);
                            }
                        }
                        if (code_pending) {
                            conversations_admin_list_ul.prepend(code_pending);
                        }
                        if (code_not_pending) {
                            $(code_not_pending).insertAfter(item_not_pending);
                        }
                        if (scroll_to_conversation) {
                            this.scrollTo();
                        }
                        this.updateMenu();
                    }
                });
                if (SB_ADMIN_SETTINGS['assign-conversation-to-agent'] || SB_ACTIVE_AGENT['department']) {
                    let ids = conversations_admin_list_ul.find(' > li').map(function () { return $(this).attr('data-conversation-id') }).get();
                    if (ids.length) {
                        SBF.ajax({
                            function: 'check-conversations-assignment',
                            conversations_ids: ids,
                            agent_id: SB_ADMIN_SETTINGS['assign-conversation-to-agent'] ? SB_ACTIVE_AGENT['id'] : false,
                            department: SB_ACTIVE_AGENT['department']
                        }, (response) => {
                            if (response) {
                                for (var i = 0; i < response.length; i++) {
                                    conversations_admin_list_ul.find(`[data-conversation-id="${response[i]}"]`).remove();
                                }
                            }
                        });
                    }
                }
            }
        },

        // Update the top left filter
        updateMenu: function () {
            let count = conversations_admin_list_ul.find('[data-conversation-status="2"]').length;
            let item = conversations_admin_list.find('.sb-select');
            let span = item.find(' > p span');
            if (count == 100 || this.menu_count_ajax) {
                let status = item.find('li.sb-active').data('value');
                this.menu_count_ajax = true;
                SBF.ajax({
                    function: 'count-conversations',
                    status_code: status == 0 ? 2 : status
                }, (response) => {
                    span.html(`(${response})`);
                });
            } else {
                span.html(`(${count})`);
            }
        },

        // Return the code of the message menu
        messageMenu: function (agent) {
            return `<i class="sb-menu-btn sb-icon-menu"></i><ul class="sb-menu">${SBApps.is('dialogflow') ? `<li data-value="bot">${sb_('Send to Dialogflow')}</li>` : ''}${agent ? `<li data-value="delete">${sb_('Delete')}</li>` : ''}</ul>`;
        },

        // Update the users details of the conversations area
        updateUserDetails() {
            if (!activeUser()) return;
            conversations_area.find(`[data-user-id="${activeUser().id}"] .sb-name,.sb-top > a`).html(activeUser().name);
            conversations_area.find('.sb-user-details .sb-profile').setProfile();
            SBProfile.populate(activeUser(), conversations_area.find('.sb-profile-list'));
        },

        // Return the conversation code of the left conversations list
        getListCode: function (conversation, status) {
            if (conversation instanceof SBConversation) {
                conversation = {
                    message: conversation.getLastMessage().message,
                    attachments: conversation.getLastMessage().attachments,
                    user_id: conversation.get('user_id'),
                    conversation_id: conversation.id,
                    conversation_status_code: conversation.get('conversation_status_code'),
                    conversation_source: conversation.get('source'),
                    profile_image: conversation.get('profile_image'),
                    first_name: conversation.get('first_name'),
                    last_name: conversation.get('last_name'),
                    creation_time: conversation.get('creation_time'),
                    payload: conversation.get('payload')
                };
            }
            let message = conversation['message'];
            if (conversation['payload'].includes('preview')) {
                let payload = JSON.parse(conversation['payload']);
                if (payload && 'preview' in payload) message = payload.preview;
            }
            if (SBF.null(status)) status = conversation['conversation_status_code'];
            if (message == '' && !SBF.null(conversation['attachments'])) {
                let files = JSON.parse(conversation['attachments']);
                if (Array.isArray(files)) {
                    for (var i = 0; i < files.length; i++) {
                        message += files[i][0] + ' ';
                    }
                    if (message.length > 114) {
                        message = message.substr(0, 114) + ' ...';
                    }
                }
            }
            if (message.length > 110) {
                message = message.substr(0, 110) + ' ...';
            }
            return `<li data-user-id="${conversation['user_id']}" data-conversation-id="${conversation['conversation_id']}" data-conversation-status="${status}"${!SBF.null(conversation['conversation_source']) ? ` data-conversation-source="${conversation['conversation_source']}"` : ''}><div class="sb-profile"><img src="${conversation['profile_image']}"><span class="sb-name">${conversation['first_name']} ${conversation['last_name']}</span><span class="sb-time">${SBF.beautifyTime(conversation['creation_time'])}</span></div><p>${message}</p></li>`;
        },

        // Start or stop the real time update of left conversations list and chat 
        startRealTime: function () {
            if (SBPusher.active) return;
            this.stopRealTime();
            this.real_time = setInterval(() => {
                this.update();
                this.updateCurrentURL();
            }, 10000);
            SBChat.startRealTime();
        },
        stopRealTime: function () {
            clearInterval(this.real_time);
            SBChat.stopRealTime();
        },

        // Transcript generation and download
        transcript: function (conversation_id, action = false) {
            if (action == 'email' && (!activeUser() || !activeUser().get('email'))) return false;
            SBF.ajax({
                function: 'transcript',
                conversation_id: conversation_id
            }, (response) => {
                if (action == 'email') SBChat.sendEmail(SB_ADMIN_SETTINGS['transcript-message'], [[response, response]], true);
                else window.open(response);
            });
        },

        // Set the typing status
        typing: function (typing) {
            if (typing) {
                if (SBChat.user_online && !this.user_typing) {
                    conversations_area.find('.sb-conversation .sb-top > .sb-labels').append('<span class="sb-status-typing">' + sb_('Typing') + '</span>');
                    this.user_typing = true;
                }
            } else if (this.user_typing) {
                conversations_area.find('.sb-conversation .sb-top .sb-status-typing').remove();
                this.user_typing = false;
            }
        },

        // Scroll the left conversations list to the active conversation
        scrollTo: function () {
            let active = conversations_admin_list_ul.find('.sb-active');
            let offset = active.length ? active[0].offsetTop : 0;
            conversations_admin_list_ul.parent().scrollTop(offset - (responsive ? 120 : 70));
        },

        // Search conversations
        search: function (input) {
            searchInput(input, (search, icon) => {
                pagination_count = 1;
                if (search.length > 1) {
                    SBF.ajax({
                        function: 'search-conversations',
                        search: search,
                        routing: SB_ADMIN_SETTINGS['routing']
                    }, (response) => {
                        SBConversations.populateList(response);
                        $(icon).sbLoading(false);
                        this.scrollTo();
                        this.is_search = true;
                    });
                } else {
                    pagination = 1;
                    SBF.ajax({
                        function: 'get-conversations',
                        status_code: conversations_admin_list.find('.sb-select li.sb-active').data('value'),
                        routing: SB_ADMIN_SETTINGS['routing']
                    }, (response) => {
                        SBConversations.populateList(response);
                        $(icon).sbLoading(false);
                        this.is_search = false;
                    });
                }
            });
        },

        // Get the page url of the user
        updateCurrentURL: function () {
            if (SBChat.user_online && activeUser() != false) {
                let url = conversations_area.find('.sb-profile-list [data-id="current_url"] label');
                if (url.length) {
                    SBF.ajax({
                        function: 'current-url'
                    }, (response) => {
                        if (response != false) {
                            url.attr('data-value', response).html(response.replace('https://', '').replace('http://', '').replace(/\/$/, ''));
                        }
                    });
                }
            }
        },

        // [Deprecated] this method is obsolete and it will be removed soon
        showDialogflowIntent: function (message_id) {
            SBApps.dialogflow.showCreateIntentBox(message_id);
        },

        // [Deprecated] this method is obsolete and it will be removed soon
        sendDialogflowIntent: function (button) {
            SBApps.dialogflow.submitIntent(button);
        },

        // Update the department of a conversation
        assignDepartment: function (conversation_id, department, onSuccess) {
            SBF.ajax({
                function: 'update-conversation-department',
                conversation_id: conversation_id,
                department: department,
                message: SBChat.conversation.getLastMessage().message
            }, (response) => {
                onSuccess(response);
            });
        },

        // Update the agent assignged to a conversation
        assignAgent: function (conversation_id, agent_id, onSuccess = false) {
            SBF.ajax({
                function: 'update-conversation-agent',
                conversation_id: conversation_id,
                agent_id: agent_id,
                message: SBChat.conversation.getLastMessage().message
            }, (response) => {
                if (onSuccess) onSuccess(response);
            });
        },

        // Update the UI to display the active department of the conversation
        setActiveDepartment: function (department_id) {
            let select = conversations_area.find('#conversation-department');
            let li = select.find(`[data-id="${department_id}"]`);
            select.find(' > p').attr('data-value', li.data('value')).html(li.html()).next().sbActivate(false);
            if (SB_ACTIVE_AGENT['user_type'] == 'agent' && SB_ACTIVE_AGENT['department'] && SB_ACTIVE_AGENT['department'] != department_id) {
                conversations_admin_list_ul.find(`[data-conversation-id="${SBChat.conversation.id}"]`).remove();
                SBConversations.clickFirst();
            }
            showResponse('Department updated. The agents have been notified.');
        },

        // Update the UI to display the active agent of the conversation
        setActiveAgent: function (agent_id) {
            let select = conversations_area.find('#conversation-agent');
            let li = select.find(`[data-id="${agent_id}"]`);
            SBChat.conversation.set('agent_id', agent_id);
            select.find(' > p').attr('data-value', li.data('value')).html(li.html()).next().sbActivate(false);
            if (SB_ACTIVE_AGENT['user_type'] == 'agent' && (!SB_ADMIN_SETTINGS['assign-conversation-to-agent'] || agent_id)) {
                conversations_admin_list_ul.find(`[data-conversation-id="${SBChat.conversation.id}"]`).remove();
                SBConversations.clickFirst();
            }
            if (agent_id) showResponse('Agent assigned. The agent has been notified.');
        },

        // Mobile conversations menu
        mobileOpenConversation: function () {
            conversations_area.find('.sb-admin-list').sbActivate(false);
            conversations_area.find('.sb-conversation').sbActivate();
            header.addClass('sb-hide');
        },

        mobileCloseConversation: function () {
            conversations_admin_list_ul.find('li.sb-active').sbActivate(false);
            conversations_area.find('.sb-admin-list').sbActivate();
            conversations_area.find('.sb-conversation').sbActivate(false);
            header.removeClass('sb-hide');
            window.history.replaceState({}, document.title, window.location.href.substr(0, window.location.href.indexOf('?')));
        },

        // Trigger the click event of the first conversation
        clickFirst: function () {
            let conversations = conversations_admin_list_ul.find('li:first-child');
            if (conversations.length) {
                conversations_admin_list_ul.find('li:first-child').click();
                SBConversations.scrollTo();
            } else conversations_area.find('.sb-board').addClass('sb-no-conversation');
        },

        // Saved replies
        savedReplies: function (textarea, value) {
            let last_char = value.charAt(textarea.selectionStart - 1);
            if (last_char == '#') {
                SBChat.editor_listening = true;
            }
            if (SBChat.editor_listening && last_char == ' ') {
                let keyword = value.substr(value.lastIndexOf('#') + 1).replace(' ', '');
                SBChat.editor_listening = false;
                for (var i = 0; i < saved_replies_list.length; i++) {
                    if (saved_replies_list[i]['reply-name'] == keyword) {
                        $(textarea).val(value.substr(0, value.lastIndexOf('#')) + saved_replies_list[i]['reply-text']);
                        return;
                    }
                }
            }
        },

        // Conversation attachments panel
        attachments: function () {
            if (attachments_panel.length) {
                let attachments = SBChat.conversation.getAttachments();
                let code = '';
                for (var i = 0; i < attachments.length; i++) {
                    code += `<a href="${attachments[i][1]}" target="_blank"><i class="sb-icon sb-icon-download"></i>${attachments[i][0]}</a>`;
                }
                $(attachments_panel).html(code == '' ? '' : `<h3>${sb_('Attachments')}</h3><div class="sb-list-items sb-list-links sb-list-icon">${code}</div>`);
                collapse(attachments_panel, 160);
            }
        },

        // Notes
        notes: {
            busy: false,

            add: function (conversation_id, user_id, name, message, onSuccess = false) {
                SBF.ajax({
                    function: 'add-note',
                    conversation_id: conversation_id,
                    user_id: user_id,
                    name: name,
                    message: message
                }, (response) => {
                    if (onSuccess) onSuccess(response);
                });
            },

            update: function (notes, add = false) {
                if (notes_panel.length) {
                    let code = '';
                    let div = notes_panel.find(' > div');
                    for (var i = 0; i < notes.length; i++) {
                        let note = notes[i];
                        code += `<div data-id="${note['id']}"><span>${note['name']}${SB_ACTIVE_AGENT['id'] == note['user_id'] ? '<i class="sb-delete-note sb-icon-close"></i>' : ''}</span><span>${note['message']}</span></div>`;
                    }
                    if (add) {
                        div.append(code);
                    } else {
                        div.html(code);
                    }
                    div.attr('style', '');
                    notes_panel.find('.sb-collapse-btn').remove();
                    collapse(notes_panel, 155);
                    this.busy = false;
                }
            },

            delete: function (conversation_id, note_id, onSuccess = false) {
                if (this.busy) return;
                this.busy = true;
                SBF.ajax({
                    function: 'delete-note',
                    conversation_id: conversation_id,
                    note_id: note_id
                }, (response) => {
                    this.busy = false;
                    if (onSuccess) onSuccess(response);
                });
            }
        },

        // Direct message
        showDirectMessageBox: function (type, user_ids = []) {
            let email = type == 'email';
            SBForm.clear(direct_message_box);
            direct_message_box.find('.sb-direct-message-users').val(user_ids.length ? user_ids.join(',') : 'all');
            direct_message_box.find('.sb-bottom > div').html('');
            direct_message_box.find('.sb-top-bar > div:first-child').html(sb_(`Send ${type == 'sms' ? 'text message' : type}`));
            direct_message_box.find('.sb-loading').sbLoading(false);
            direct_message_box.find('.sb-direct-message-subject').sbActivate(email).find('input').attr('required', email);
            direct_message_box.attr('data-type', type);
            direct_message_box.sbShowLightbox();
        }
    }

    /* 
    * ----------------------------------------------------------
    * # Profile
    * ----------------------------------------------------------
    */

    var SBProfile = {

        // Get all profile settings
        getAll: function (profile_area) {
            return SBForm.getAll(profile_area);
        },

        // Get a single setting
        get: function (input) {
            return SBForm.get(input);
        },

        // Set a single setting
        set: function (item, value) {
            return SBForm.set(item, value);
        },

        // Display the user box
        show: function (user_id) {
            loadingGlobal();
            activeUser(new SBUser({ 'id': user_id }));
            activeUser().update(() => {
                this.populate(activeUser(), profile_box.find('.sb-profile-list'));
                profile_box.find('.sb-profile').setProfile();
                activeUser().getConversations((response) => {
                    let user_type = activeUser().type;
                    if (SBF.isAgent(user_type)) {
                        this.agentData();
                    }
                    profile_box.find('.sb-user-conversations').html(activeUser().getConversationsCode(response));
                    profile_box.find('.sb-top-bar [data-value]').sbActivate(false);
                    if (!SBF.null(activeUser().get('email'))) {
                        profile_box.find('.sb-top-bar [data-value=email]').sbActivate();
                    }
                    if (activeUser().getExtra('phone') && SB_ADMIN_SETTINGS['sms']) {
                        profile_box.find('.sb-top-bar [data-value=sms]').sbActivate();
                    }
                    this.boxClasses(profile_box, user_type);
                    profile_box.attr('data-user-id', activeUser().id).sbShowLightbox();
                    loadingGlobal(false, false);
                    SBF.event('SBProfileBoxOpened', { user_id: user_id });
                });
                users[user_id] = activeUser();
                if (SBF.getURL('user') != user_id) pushState('?user=' + user_id);
            });
        },

        showEdit: function (user) {
            if (user instanceof SBUser) {
                let password = profile_edit_box.find('#password input');
                let current_user_type = user.type;
                let select = profile_edit_box.find('#user_type select');
                let email = profile_edit_box.find('#email input');

                profile_edit_box.removeClass('sb-user-new').attr('data-user-id', user.id);
                profile_edit_box.find('.sb-top-bar .sb-save').html(`<i class="sb-icon-check"></i>${sb_('Save changes')}`);
                profile_edit_box.find('.sb-profile').setProfile();
                profile_edit_box.find('.sb-custom-detail').remove();
                profile_edit_box.find('input,select,textara').removeClass('sb-error');

                // Custom details
                let code = '';
                let default_ids = profile_edit_box.find('.sb-additional-details [id]').map(function () { return this.id; }).get().concat(['wp-id', 'perfex-id', 'whmcs-id', 'aecommerce-id', 'facebook-id', 'ip', 'os', 'current_url', 'country_code', 'browser_language', 'browser']);
                for (var id in user.extra) {
                    if (!default_ids.includes(id)) {
                        code += `<div id="${id}" data-type="text" class="sb-input sb-custom-detail"><span>${sb_(user.extra[id].name)}</span><input type="text"></div>`;
                    }
                }
                profile_edit_box.find('.sb-additional-details .sb-edit-box').append(code);

                // Set values
                this.populateEdit(user, profile_edit_box);
                if (SBF.isAgent(current_user_type)) {
                    email.prop('required', true);
                    password.prop('required', true);
                } else {
                    email.removeAttr('required');
                    password.removeAttr('required');
                }

                // User type select
                if (SB_ACTIVE_AGENT['user_type'] == 'admin' && SBF.isAgent(current_user_type)) {
                    select.html('<option value="agent">Agent</option><option value="admin"' + (current_user_type == 'admin' ? ' selected' : '') + '>Admin</option>');
                }

                // Password
                if (password.val()) {
                    password.val('********');
                }

                // Cloud
                if (SB_ADMIN_SETTINGS.cloud) {
                    profile_edit_box.setClass('sb-cloud-admin', SB_ADMIN_SETTINGS.cloud.id == user.id);
                }

                // Show the edit box
                this.boxClasses(profile_edit_box, current_user_type);
                profile_edit_box.sbShowLightbox();
                SBF.event('SBProfileEditBoxOpened', { user_id: user.id });
            } else {
                SBF.error('User not of type SBUser', 'SBUsers.showEdit');
                return false;
            }
        },

        // Populate profile
        populate: function (user, profile_area) {
            let exclude = ['first_name', 'last_name', 'password', 'profile_image'];
            let code = '';
            if (profile_area.hasClass('sb-profile-list-conversation') && SBChat.conversation) {
                let source = SBChat.conversation.get('source');
                code = this.profileRow('conversation-id', SBChat.conversation.id, sb_('Conversation ID'));
                if (!SBF.null(source)) {
                    code += this.profileRow('conversation-source', source == 'fb' ? 'Facebook' : (source == 'wa' ? 'WhatsApp' : (source == 'tm' ? 'Text message' : (source == 'ig' ? 'Instagram' : (source == 'tg' ? 'Telegram' : source)))), sb_('Source'));
                }
            }
            if (SB_ACTIVE_AGENT['user_type'] != 'admin') {
                exclude.push('token');
            }
            for (var key in user.details) {
                if (!exclude.includes(key)) {
                    code += this.profileRow(key, user.get(key));
                }
            }
            if (user.isExtraEmpty()) {
                SBF.ajax({
                    function: 'get-user-extra',
                    user_id: user.id
                }, (response) => {
                    for (var i = 0; i < response.length; i++) {
                        let slug = response[i]['slug'];
                        user.setExtra(slug, response[i]);
                        code += this.profileRow(slug, response[i]['value'], response[i]['name']);
                    }
                    profile_area.html(`<ul>${code}</ul>`);
                    collapse(profile_area, 145);
                });
            } else {
                for (var key in user.extra) {
                    let info = user.getExtra(key);
                    code += this.profileRow(key, info['value'], info['name']);
                }
                profile_area.html(`<ul>${code}</ul>`);
                collapse(profile_area, 145);
            }
        },

        profileRow: function (key, value, name = key) {
            if (value == '') return '';
            let icons = { 'id': 'padlock', 'conversation-id': 'padlock', 'full_name': 'user', 'email': 'envelope', 'phone': 'phone', 'user_type': 'user', 'last_activity': 'calendar', 'creation_time': 'calendar', 'token': 'shuffle', 'currency': 'currency', 'location': 'marker', 'country': 'marker', 'address': 'marker', 'city': 'marker', 'postal_code': 'marker', 'os': 'desktop', 'current_url': 'next', 'timezone': 'clock' };
            let icon = `<i class="sb-icon sb-icon-${key in icons ? icons[key] : 'plane'}"></i>`;
            let lowercase;
            let image = false;
            switch (key) {
                case 'last_activity':
                case 'creation_time':
                    value = SBF.beautifyTime(value);
                    break;
                case 'user_type':
                    value = SBF.slugToString(value);
                    break;
                case 'country_code':
                case 'language':
                case 'browser_language':
                    icon = `<img src="${SB_URL}/media/flags/${value.toLowerCase()}.png" />`;
                    break;
                case 'browser':
                    lowercase = value.toLowerCase();
                    if (lowercase.includes('chrome')) {
                        image = 'chrome';
                    } else if (lowercase.includes('edge')) {
                        image = 'edge';
                    } else if (lowercase.includes('firefox')) {
                        image = 'firefox';
                    } else if (lowercase.includes('opera')) {
                        image = 'opera';
                    } else if (lowercase.includes('safari')) {
                        image = 'safari';
                    }
                    break;
                case 'os':
                    lowercase = value.toLowerCase();
                    if (lowercase.includes('windows')) {
                        image = 'windows';
                    } else if (lowercase.includes('mac') || lowercase.includes('apple') || lowercase.includes('ipad') || lowercase.includes('iphone')) {
                        image = 'apple';
                    } else if (lowercase.includes('android')) {
                        image = 'android';
                    } else if (lowercase.includes('linux')) {
                        image = 'linux';
                    } else if (lowercase.includes('ubuntu')) {
                        image = 'ubuntu';
                    }
                    break;
                case 'conversation-source':
                    image = value.toLowerCase();
                case 'browser':
                case 'os':
                case 'conversation-source':
                    if (image) {
                        icon = `<img src="${SB_URL}/media/devices/${image}.svg" />`;
                    }
                    break;

            }
            return `<li data-id="${key}">${icon}<span>${sb_(SBF.slugToString(name))}</span><label>${value}</label></li>`;
        },

        // Populate profile edit box
        populateEdit: function (user, profile_edit_area) {
            profile_edit_area.find('.sb-details .sb-input').each((i, element) => {
                this.set(element, user.details[$(element).attr('id')]);
            });
            profile_edit_area.find('.sb-additional-details .sb-input').each((i, element) => {
                let key = $(element).attr('id');
                if (key in user.extra) {
                    this.set(element, user.extra[key]['value']);
                } else {
                    this.set(element, '');
                }
            });
        },

        // Clear the profile edit area
        clear: function (profile_edit_area) {
            SBForm.clear(profile_edit_area);
        },

        // Check for errors on user input
        errors: function (profile_edit_area) {
            return SBForm.errors(profile_edit_area.find('.sb-details'));
        },

        // Display a error message
        showErrorMessage: function (profile_edit_area, message) {
            SBForm.showErrorMessage(profile_edit_area, message);
        },

        // Agents data area
        agentData: function () {
            let code = `<div class="sb-title">${sb_('Feedback rating')}</div><div class="sb-rating-area sb-loading"></div>`;
            let area = profile_box.find('.sb-agent-area');
            area.html(code);
            SBF.ajax({
                function: 'get-rating'
            }, (response) => {
                if (response[0] == 0 && response[1] == 0) {
                    code = `<p class="sb-no-results">${sb_('No ratings yet.')}</p>`;
                } else {
                    let total = response[0] + response[1];
                    let positive = response[0] * 100 / total;
                    let negative = response[1] * 100 / total;
                    code = `<div><div>${sb_('Helpful')}</div><span data-count="${response[0]}" style="width: ${Math.round(positive * 2)}px"></span><div>${positive.toFixed(2)} %</div></div><div><div>${sb_('Not helpful')}</div><span data-count="${response[1]}" style="width: ${Math.round(negative * 2)}px"></span><div>${negative.toFixed(2)} %</div></div><p class="sb-rating-count">${total} ${sb_('Ratings')}</p>`;
                }
                area.find('.sb-rating-area').html(code).sbLoading(false);
            });
        },

        boxClasses: function (box, user_type = false) {
            $(box).removeClass('sb-type-admin sb-type-agent sb-type-lead sb-type-user sb-type-visitor').addClass(`${user_type != false ? `sb-type-${user_type}` : ''} sb-agent-${SB_ACTIVE_AGENT['user_type']}`);
        }
    }

    /*
    * ----------------------------------------------------------
    * # Init
    * ----------------------------------------------------------
    */

    var SBAdmin = {
        dialog: dialog,
        open_popup: false,
        must_translate: false,
        is_logout: false,
        conversations: SBConversations,
        users: SBUsers,
        settings: SBSettings,
        profile: SBProfile,
        apps: SBApps
    }
    window.SBAdmin = SBAdmin;

    $(document).ready(function () {

        admin = $('.sb-admin');
        header = admin.find('> .sb-header');
        conversations_area = admin.find('.sb-area-conversations');
        conversations_admin_list = conversations_area.find('.sb-admin-list');
        conversations_admin_list_ul = conversations_admin_list.find('.sb-scroll-area ul');
        users_area = admin.find('.sb-area-users');
        users_table = users_area.find('.sb-table-users');
        users_table_menu = users_area.find('.sb-menu-users');
        profile_box = admin.find('.sb-profile-box');
        profile_edit_box = admin.find('.sb-profile-edit-box');
        settings_area = admin.find('.sb-area-settings');
        automations_area = settings_area.find('.sb-automations-area');
        conditions_area = automations_area.find('.sb-conditions');
        automations_area_select = automations_area.find(' > .sb-select');
        automations_area_nav = automations_area.find(' > .sb-tab > .sb-nav > ul');
        reports_area = admin.find('.sb-area-reports');
        articles_area = settings_area.find('.sb-articles-area');
        articles_category_selects = articles_area.find('.sb-article-categories select');
        articles_category_parent_select = articles_area.find('.sb-article-parent-category select');
        saved_replies = conversations_area.find('.sb-replies');
        overlay = admin.find('.sb-lightbox-overlay');
        SITE_URL = typeof SB_URL != ND ? SB_URL.substr(0, SB_URL.indexOf('-content') - 3) : '';
        woocommerce_products_box = conversations_area.find('.sb-woocommerce-products');
        woocommerce_products_box_ul = woocommerce_products_box.find(' > div > ul');
        notes_panel = conversations_area.find('.sb-panel-notes');
        attachments_panel = conversations_area.find('.sb-panel-attachments');
        direct_message_box = admin.find('.sb-direct-message-box');
        wp_admin = SBApps.is('wordpress') && $('.wp-admin').length;
        dialogflow_intent_box = admin.find('.sb-dialogflow-intent-box');
        suggestions_area = conversations_area.find('.sb-editor > .sb-suggestions');

        // Browser history
        window.onpopstate = function () {
            if (SBF.getURL('user')) {
                if (!users_area.sbActive()) header.find('.sb-admin-nav #sb-users').click();
                SBProfile.show(SBF.getURL('user'));
            } else if (SBF.getURL('area')) {
                header.find('.sb-admin-nav #sb-' + SBF.getURL('area')).click();
            } else if (SBF.getURL('conversation')) {
                if (!conversations_area.sbActive()) header.find('.sb-admin-nav #sb-conversations').click();
                SBConversations.openConversation(SBF.getURL('conversation'));
            } else if (SBF.getURL('setting')) {
                if (!settings_area.sbActive()) header.find('.sb-admin-nav #sb-settings').click();
                settings_area.find('#tab-' + SBF.getURL('setting')).click();
            } else if (SBF.getURL('report')) {
                if (!reports_area.sbActive()) header.find('.sb-admin-nav #sb-reports').click();
                reports_area.find('#' + SBF.getURL('report')).click();
            }
        };

        if (SBF.getURL('area')) {
            setTimeout(() => { header.find('.sb-admin-nav #sb-' + SBF.getURL('area')).click() }, 300);
        }

        // Installation
        if (typeof SB_ADMIN_SETTINGS == ND) {
            let area = admin.find('.sb-intall');
            $(admin).on('click', '.sb-submit-installation', function () {
                if (loading(this)) return;
                let message = false;
                let account = area.find('#first-name').length;
                if (SBForm.errors(area)) {
                    message = account ? 'All fields are required. Minimum password length is 8 characters. Be sure you\'ve entered a valid email.' : 'All fields are required.';
                } else {
                    if (account && area.find('#password input').val() != area.find('#password-check input').val()) {
                        message = 'The passwords do not match.';
                    } else {
                        let url = window.location.href.replace('/admin', '').replace('.php', '').replace(/#$|\/$/, '').replace(/#$|\/$/, '');
                        if (url.includes('?')) url = url.substr(0, url.indexOf('?'));
                        $.ajax({
                            method: 'POST',
                            url: url + '/include/ajax.php',
                            data: {
                                function: 'installation',
                                details: $.extend(SBForm.getAll(area), { url: url })
                            }
                        }).done((response) => {
                            response = JSON.parse(response);
                            if (response != false) {
                                response = response[1];
                                if (response === true) {
                                    setTimeout(() => {
                                        window.location.href = url + '/admin.php?refresh=true';
                                    }, 1000);
                                    return;
                                } else {
                                    switch (response) {
                                        case 'connection-error':
                                            message = 'Support Board cannot connect to the database. Please check the database information and try again.';
                                            break;
                                        case 'missing-details':
                                            message = 'Missing database details! Please check the database information and try again.';
                                            break;
                                        case 'missing-url':
                                            message = 'Support Board cannot get the plugin URL.';
                                            break;
                                        default:
                                            message = response;
                                    }
                                }
                            } else {
                                message = response;
                            }
                            if (message !== false) {
                                SBForm.showErrorMessage(area, message);
                                $('html, body').animate({ scrollTop: 0 }, 500);
                            }
                            $(this).sbLoading(false);
                        });
                    }
                }
                if (message !== false) {
                    SBForm.showErrorMessage(area, message);
                    $('html, body').animate({ scrollTop: 0 }, 500);
                    $(this).sbLoading(false);
                }
            });
            return;
        }

        // Initialization
        if (!admin.length) return;
        loadingGlobal();
        admin.removeAttr('style');
        if (isPWA()) {
            admin.addClass('sb-pwa');
        }
        if (SBApps.is('woocommerce')) {
            woocommerce_products_box = conversations_area.find('.sb-woocommerce-products');
            woocommerce_products_box_ul = woocommerce_products_box.find(' > div > ul');
        }
        if (localhost) {
            clearCache();
        }
        if (admin.find(' > .sb-rich-login').length) {
            return;
        }
        if (SB_ADMIN_SETTINGS['pusher']) {
            SBPusher.active = true;
            SBPusher.init(() => {
                SBPusher.presence(1, () => {
                    SBUsers.updateUsersActivity();
                });
                SBPusher.event('update-conversations', () => {
                    SBConversations.update();
                }, 'agents');
                SBPusher.event('set-agent-status', (response) => {
                    if (response.agent_id == SB_ACTIVE_AGENT['id']) {
                        SBUsers.setActiveAgentStatus(response.status == 'online');
                    }
                }, 'agents');
                initialization();
            });
        } else {
            initialization();
            setInterval(function () {
                SBUsers.updateUsersActivity();
            }, 10000);
        }
        SBUsers.table_extra = users_table.find('th[data-extra]').map(function () { return $(this).attr('data-field') }).get();

        // On Support Board close
        $(window).on('beforeunload', function () {
            SBF.ajax({ function: 'on-close' });
        });

        // Keyboard shortcuts
        $(window).keydown(function (e) {
            let code = e.which;
            let valid = false;
            if ([13, 27, 37, 38, 39, 40, 46].includes(code)) {
                if (admin.find('.sb-dialog-box').sbActive()) {
                    let target = admin.find('.sb-dialog-box');
                    switch (code) {
                        case 46:
                        case 27:
                            target.find('.sb-cancel').click();
                            break;
                        case 13:
                            target.find(target.attr('data-type') != 'info' ? '.sb-confirm' : '.sb-close').click();
                            break;
                    }
                    valid = true;
                } else if ([38, 40, 46].includes(code) && conversations_area.sbActive()) {
                    if (code == 46) {
                        if (conversations_area.find('.sb-editor textarea').is(':focus')) return;
                        let target = conversations_area.find(' > div > .sb-conversation');
                        target.find('.sb-top [data-value="' + (target.attr('data-conversation-status') == 3 ? 'delete' : 'archive') + '"]').click();
                    } else if (e.ctrlKey) {
                        let target = conversations_admin_list_ul.find('.sb-active');
                        if (code == 40) {
                            target.next().click();
                        } else {
                            target.prev().click();
                        }
                        SBConversations.scrollTo();
                    }
                    valid = true;
                } else if ([37, 39].includes(code) && users_area.sbActive() && admin.find('.sb-lightbox').sbActive()) {
                    let target = users_table.find(`[data-user-id="${activeUser().id}"]`);
                    target = code == 39 ? target.next() : target.prev();
                    if (target.length) {
                        admin.sbHideLightbox();
                        SBProfile.show(target.attr('data-user-id'));
                    }
                    valid = true;
                } else if ([46, 27].includes(code)) {
                    if (admin.find('.sb-lightbox').sbActive()) {
                        admin.sbHideLightbox();
                        valid = true;
                    } else {
                        let target = admin.find('.sb-search-btn.sb-active');
                        if (target.length) {
                            target.find('i').click();
                            valid = true;
                        }
                    }
                }
                if (valid) {
                    e.preventDefault();
                }
            }
        });

        // Check if the admin is active
        $(document).on('click keydown mousemove', function () {
            SBF.debounce(function () {
                if (!SBChat.tab_active) {
                    SBF.visibilityChange();
                }
                SBChat.tab_active = true;
                clearTimeout(active_interval);
                active_interval = setTimeout(() => { SBChat.tab_active = false }, 10000);
            }, '#3', 8000);
        });

        // Updates 
        $(header).on('click', '.sb-version', function () {
            let box = admin.find('.sb-updates-box');
            SBF.ajax({
                function: 'get-versions'
            }, (response) => {
                let code = '';
                let names = { 'sb': 'Support Board', 'slack': 'Slack', 'dialogflow': 'Dialogflow', 'tickets': 'Tickets', 'woocommerce': 'Woocommerce', 'ump': 'Ultimate Membership Pro', 'perfex': 'Perfex', 'whmcs': 'WHMCS', 'aecommerce': 'Active eCommerce', 'messenger': 'Messenger', 'whatsapp': 'WhatsApp', 'armember': 'ARMember', 'telegram': 'Telegram' };
                let updates = false;
                for (var key in response) {
                    if (SBApps.is(key)) {
                        let updated = SB_VERSIONS[key] == response[key];
                        if (!updated) {
                            updates = true;
                        }
                        code += `<div class="sb-input"><span>${names[key]}</span><div${updated ? ' class="sb-green"' : ''}>${updated ? sb_('You are running the latest version.') : sb_('Update available! Please update now.')} ${sb_('Your version is')} V ${SB_VERSIONS[key]}.</div></div>`;
                    }
                }
                if (updates) {
                    box.find('.sb-update').removeClass('sb-hide');
                } else {
                    box.find('.sb-update').addClass('sb-hide');
                }
                loadingGlobal(false);
                box.find('.sb-main').prepend(code);
                box.sbShowLightbox();
            });
            loadingGlobal(true);
            box.sbActivate(false);
            box.find('.sb-input').remove();
        });

        $(admin).on('click', '.sb-updates-box .sb-update', function () {
            if (loading(this)) return;
            let box = admin.find('.sb-updates-box');
            SBF.ajax({
                function: 'update',
                domain: SB_URL
            }, (response) => {
                let error = '';
                if (SBF.errorValidation(response, 'envato-purchase-code-not-found')) {
                    error = 'Please go to Settings > Miscellaneous and insert the Envato Purchase Code of Support Board.'
                } else if (SBF.errorValidation(response)) {
                    error = SBF.slugToString(response[1]);
                } else {
                    let success = true;
                    for (var key in response) {
                        if (response[key] != 'success') {
                            success = false;
                            break;
                        }
                    }
                    if (!success) {
                        error = JSON.stringify(response);
                    }
                }
                if (error == '') {
                    clearCache();
                    showResponse('Update completed.');
                    location.reload();
                } else {
                    SBForm.showErrorMessage(box, error);
                }
                $(this).sbLoading(false);
            });
        });

        setTimeout(function () {
            let last = SBF.storage('last-update-check');
            let today_arr = [today.getMonth(), today.getDate()];
            if (SB_ADMIN_SETTINGS.cloud) return;
            if (last == false || today_arr[0] != last[0] || (today_arr[1] > (last[1] + 10))) {
                SBF.storage('last-update-check', today_arr);
                if (SB_ADMIN_SETTINGS['auto-updates']) {
                    SBF.ajax({
                        function: 'update',
                        domain: SB_URL
                    }, (response) => {
                        if (typeof response !== 'string' && !Array.isArray(response)) {
                            showResponse('Automatic update completed. Reload the admin area to apply the update.');
                            clearCache();
                        }
                    });
                } else if (SB_ACTIVE_AGENT['user_type'] == 'admin') {
                    SBF.ajax({
                        function: 'updates-available'
                    }, (response) => {
                        if (response === true) {
                            showResponse(`${sb_('Update available.')} <span onclick="$(\'.sb-version\').click()">${sb_('Click here to update now')}</span>`, 'info');
                        }
                    });
                }
            }
        }, 1000);

        // Apps
        $(admin).on('click', '.sb-apps > div', function () {
            let box = admin.find('.sb-app-box');
            let app_name = $(this).data('app');
            let ga = '?utm_source=plugin&utm_medium=admin_area&utm_campaign=plugin';
            SBF.ajax({
                function: 'app-get-key',
                app_name: app_name
            }, (response) => {
                box.find('input').val(response);
            });
            box.find('input').val('');
            box.find('.sb-top-bar > div:first-child').html($(this).find('h2').html());
            box.find('p').html($(this).find('p').html());
            box.attr('data-app', app_name);
            box.find('.sb-btn-app-setting').sbActivate(SBApps.is(app_name));
            box.find('.sb-btn-app-puchase').attr('href', 'https://board.support/shop/' + app_name + ga);
            box.find('.sb-btn-app-details').attr('href', 'https://board.support/' + app_name + ga);
            box.sbShowLightbox();
        });

        $(admin).on('click', '.sb-app-box .sb-activate', function () {
            let box = admin.find('.sb-app-box');
            let key = box.find('input').val();
            let app_name = box.attr('data-app');
            if (key) {
                if (loading(this)) return;
                SBF.ajax({
                    function: 'app-activation',
                    app_name: app_name,
                    key: key
                }, (response) => {
                    if (SBF.errorValidation(response)) {
                        let error = '';
                        response = response[1];
                        if (response == 'envato-purchase-code-not-found') {
                            error = 'Please go to Settings > Miscellaneous and insert the Envato Purchase Code of Support Board.';
                        } else if (response == 'invalid-key') {
                            error = 'It looks like your license key is invalid. If you believe this is an error, please contact support.';
                        } else if (response == 'expired') {
                            error = `Your license key is expired. Please purchase a new license <a href="https://board.support/shop/${app_name}" target="_blank"> here</a>.`;
                        } else {
                            error = 'Error: ' + response;
                        }
                        SBForm.showErrorMessage(box, error);
                        $(this).sbLoading(false);
                    } else {
                        showResponse('Activation complete! Page reload in progress...');
                        setTimeout(function () {
                            location.reload();
                        }, 1000);
                    }
                });
            } else {
                SBForm.showErrorMessage(box, 'Please insert the license key.');
            }
        });

        $(admin).on('click', '.sb-app-box .sb-btn-app-setting', function () {
            settings_area.find('#tab-' + $(this).closest('[data-app]').attr('data-app')).click();
            admin.sbHideLightbox();
        });

        // Desktop and flash notifications
        if (typeof Notification !== ND && (SB_ADMIN_SETTINGS['desktop-notifications'] == 'all' || SB_ADMIN_SETTINGS['desktop-notifications'] == 'agents') && !SB_ADMIN_SETTINGS['push-notifications']) {
            SBConversations.desktop_notifications = true;
        }

        if (SB_ADMIN_SETTINGS['flash-notifications'] == 'all' || SB_ADMIN_SETTINGS['flash-notifications'] == 'agents') {
            SBConversations.flash_notifications = true;
        }

        // Cron jobs
        if (today.getDate() != SBF.storage('admin-clean')) {
            setTimeout(function () {
                SBF.ajax({ function: 'cron-jobs' });
                SBF.storage('admin-clean', today.getDate());
            }, 10000);
        }

        // Collapse button
        $(admin).on('click', '.sb-collapse-btn', function () {
            let active = $(this).sbActive();
            let height = active ? $(this).parent().data('height') + 'px' : '';
            $(this).html(sb_(active ? 'View more' : 'Close'));
            $(this).parent().find(' > div, > ul').css({ 'height': height, 'max-height': height });
            $(this).sbActivate(!active);
        });

        // Close lightbox popup
        $(admin).on('click', '.sb-popup-close', function () {
            admin.sbHideLightbox();
        });

        /*
        * ----------------------------------------------------------
        * # Responsive and mobile
        * ----------------------------------------------------------
        */

        if (responsive) {
            $(admin).on('click', '.sb-menu-mobile > i', function () {
                $(this).toggleClass('sb-active');
                SBAdmin.open_popup = $(this).parent();
            });

            $(admin).on('click', '.sb-menu-mobile a', function () {
                $(this).closest('.sb-menu-mobile').find(' > i').sbActivate(false);
            });

            $(admin).on('click', '.sb-menu-wide,.sb-nav', function () {
                $(this).toggleClass('sb-active');
            });

            $(admin).on('click', '.sb-menu-wide > ul > li, .sb-nav > ul > li', function (e) {
                let menu = $(this).parent().parent();
                menu.find('li').sbActivate(false);
                menu.find('> div:not(.sb-menu-wide):not(.sb-btn)').html($(this).html());
                menu.sbActivate(false);
                if (menu.find('> .sb-menu-wide').length) {
                    menu.closest('.sb-scroll-area').scrollTop(menu.next()[0].offsetTop - (admin.hasClass('sb-header-hidden') ? 70 : 130));
                }
                e.preventDefault();
                return false;
            });

            $(admin).find('.sb-admin-list .sb-scroll-area, main > div > .sb-scroll-area,.sb-area-settings > .sb-tab > .sb-scroll-area,.sb-area-reports > .sb-tab > .sb-scroll-area').on('scroll', function () {
                let scroll = $(this).scrollTop();
                if (scrolls['last'] < (scroll - 10) && scrolls['header']) {
                    admin.addClass('sb-header-hidden');
                    scrolls['header'] = false;
                } else if (scrolls['last'] > (scroll + 10) && !scrolls['header'] && !scrolls['always_hidden']) {
                    admin.removeClass('sb-header-hidden');
                    scrolls['header'] = true;
                }
                scrolls['last'] = scroll;
            });

            $(admin).on('click', '.sb-search-btn i', function () {
                if ($(this).parent().sbActive()) {
                    admin.addClass('sb-header-hidden');
                    scrolls['always_hidden'] = true;
                } else {
                    scrolls['always_hidden'] = false;
                    if (conversations_admin_list_ul.parent().scrollTop() < 10) {
                        admin.removeClass('sb-header-hidden');
                    }
                }
            });

            $(admin).on('click', '.sb-top .sb-btn-back', function () {
                SBConversations.mobileCloseConversation();
            });

            $(users_table).find('th:first-child').html(sb_('Order by'));

            $(users_table).on('click', 'th:first-child', function () {
                $(this).parent().toggleClass('sb-active');
            });
        }

        /*
        * ----------------------------------------------------------
        * # Left nav
        * ----------------------------------------------------------
        */

        $(header).on('click', ' .sb-admin-nav a', function () {
            let id = $(this).attr('id');
            header.find('.sb-admin-nav a').sbActivate(false);
            admin.find(' > main > div').sbActivate(false).eq($(this).index()).sbActivate();
            $(this).sbActivate();
            SBF.deactivateAll();

            switch (id) {
                case 'sb-conversations':
                    if (!responsive && !SBF.getURL('conversation')) {
                        SBConversations.clickFirst();
                    }
                    SBConversations.update();
                    SBConversations.startRealTime();
                    SBUsers.stopRealTime();
                    break;
                case 'sb-users':
                    SBUsers.startRealTime();
                    SBConversations.stopRealTime();
                    if (!SBUsers.init) {
                        loadingGlobal();
                        users_pagination = 1;
                        users_pagination_count = 1;
                        SBF.ajax({
                            function: 'get-users',
                            user_types: ['user', 'visitor', 'lead'],
                            extra: SBUsers.table_extra
                        }, (response) => {
                            SBUsers.populate(response);
                            SBUsers.updateMenu();
                            SBUsers.init = true;
                            SBUsers.datetime_last_user = SBF.dateDB('now');
                            loadingGlobal(false);
                        });
                    }
                    break;
                case 'sb-settings':
                    if (!SBSettings.init) {
                        loadingGlobal();
                        SBF.ajax({
                            function: 'get-all-settings'
                        }, (response) => {
                            let translations = response['external-settings-translations'];
                            SBSettings.initHTML(response);
                            SBSettings.translations.translations = Array.isArray(translations) && !translations.length ? {} : translations;
                            delete response['external-settings-translations'];
                            for (var key in response) {
                                SBSettings.set(key, response[key]);
                            }
                            SBSettings.initPlugins();
                            SBSettings.init = true;
                            loadingGlobal(false);
                        });
                    }
                    SBUsers.stopRealTime();
                    SBConversations.stopRealTime();
                    break;
                case 'sb-reports':
                    if (reports_area.sbLoading()) {
                        $.getScript(SB_URL + '/vendor/moment.min.js', () => {
                            $.getScript(SB_URL + '/vendor/daterangepicker.min.js', () => {
                                $.getScript(SB_URL + '/vendor/chart.min.js', () => {
                                    SBReports.initDatePicker();
                                    SBReports.initReport('conversations');
                                    reports_area.sbLoading(false);
                                });
                            });
                        });
                    }
                    SBUsers.stopRealTime();
                    SBConversations.stopRealTime();
                    break;
            }
            let slug = id.substr(3);
            let url_area = SBF.getURL('area');
            if (url_area != slug && ((slug == 'conversations' && !SBF.getURL('conversation')) || (slug == 'users' && !SBF.getURL('user')) || (slug == 'settings' && !SBF.getURL('setting')) || (slug == 'reports' && !SBF.getURL('report')))) pushState('?area=' + slug);
        });

        $(header).on('click', '.sb-profile', function () {
            $(this).next().toggleClass('sb-active');
        });

        $(header).on('click', '[data-value="logout"],.logout', function () {
            SBAdmin.is_logout = true;
            SBF.ajax({ function: 'on-close' });
            SBUsers.stopRealTime();
            SBConversations.stopRealTime();
            SBF.logout();
        });

        $(header).on('click', '[data-value="edit-profile"],.edit-profile', function () {
            loadingGlobal();
            let user = new SBUser({ 'id': SB_ACTIVE_AGENT['id'] });
            user.update(() => {
                activeUser(user);
                conversations_area.find('.sb-board').addClass('sb-no-conversation');
                conversations_admin_list_ul.find('.sb-active').sbActivate(false);
                SBProfile.showEdit(user);
            });
        });

        $(header).on('click', '[data-value="status"]', function () {
            SBUsers.setActiveAgentStatus(!$(this).hasClass('sb-online'));
        });

        $(header).find('.sb-account').setProfile(SB_ACTIVE_AGENT['full_name'], SB_ACTIVE_AGENT['profile_image']);

        /*
        * ----------------------------------------------------------
        * # Conversations area
        * ----------------------------------------------------------
        */

        // Open the conversation clicked on the left menu
        $(conversations_admin_list_ul).on('click', 'li', function () {
            SBConversations.openConversation($(this).attr('data-conversation-id'), $(this).attr('data-user-id'), false);
            SBF.deactivateAll();
        });

        // Open the user conversation clicked on the bottom right area or user profile box
        $(admin).on('click', '.sb-user-conversations li', function () {
            SBConversations.openConversation($(this).attr('data-conversation-id'), activeUser().id, $(this).attr('data-conversation-status'));

        });

        // Archive, delete or restore conversations
        $(conversations_area).on('click', '.sb-top ul a', function () {
            let status_code = -1;
            let message = 'The conversation will be ';
            let value = $(this).attr('data-value');
            let conversation_id = SBChat.conversation.id;
            switch (value) {
                case 'inbox':
                    status_code = 0;
                    message += 'restored.';
                    break;
                case 'archive':
                    message += 'archived.';
                    status_code = 3;
                    break;
                case 'delete':
                    message += 'deleted.';
                    status_code = 4;
                    break;
                case 'empty-trash':
                    status_code = 5;
                    message = 'All conversations in the trash (including their messages) will be deleted permanently.'
                    break;
                case 'transcript':
                    SBConversations.transcript(conversation_id, $(this).attr('data-action'));
                    break;
                case 'read':
                    status_code = 0;
                    message += 'marked as read.';
                    break;
            }
            if (status_code != -1) {
                dialog(message, 'alert', function () {
                    SBF.ajax({
                        function: 'update-conversation-status',
                        conversation_id: conversation_id,
                        status_code: status_code
                    }, () => {
                        if ([0, 3, 4].includes(status_code)) {
                            for (var i = 0; i < conversations.length; i++) {
                                if (conversations[i]['conversation_id'] == conversation_id) {
                                    conversations[i]['conversation_status_code'] = status_code;
                                    break;
                                }
                            }
                        }
                        if (SB_ADMIN_SETTINGS['close-message'] && status_code == 3) {
                            SBF.ajax({ function: 'close-message', conversation_id: conversation_id, bot_id: SB_ADMIN_SETTINGS['bot-id'] });
                            if (SB_ADMIN_SETTINGS['close-message-transcript']) SBConversations.transcript(conversation_id, 'email');
                        }
                        if (value == 'read') {
                            conversations_admin_list_ul.find('.sb-active').attr('data-conversation-status', 0);
                            conversations_area.find('.sb-top [data-value="read"]').sbActivate(false);
                        } else {
                            conversations_admin_list.find('.sb-select li.sb-active').click();
                            conversations_admin_list.find('.sb-select ul').sbActivate(false);
                        }
                    });
                    if (SBChat.conversation && SBChat.conversation.id == conversation_id) SBChat.conversation.set('conversation_status_code', status_code);
                });
            }
        });

        // Saved replies
        SBF.ajax({
            function: 'saved-replies'
        }, (response) => {
            let code = `<p class="sb-no-results">${sb_('No saved replies found. Add new saved replies via Settings > Miscellaneous.')}</p>`;
            if (Array.isArray(response)) {
                if (response.length > 0 && response[0]['reply-name']) {
                    code = '';
                    saved_replies_list = response;
                    for (var i = 0; i < response.length; i++) {
                        code += `<li><div>${response[i]['reply-name']}</div><div>${response[i]['reply-text']}</div></li>`;
                    }
                }
            }
            saved_replies.find('.sb-replies-list > ul').html(code).sbLoading(false);
        });

        $(conversations_area).on('click', '.sb-btn-saved-replies', function () {
            saved_replies.sbTogglePopup(this);
        });

        $(saved_replies).on('click', '.sb-replies-list li', function () {
            SBChat.insertText($(this).find('div:last-child').html());
            SBF.deactivateAll();
            admin.removeClass('sb-popup-active');
        });

        $(saved_replies).on('input', '.sb-search-btn input', function () {
            let search = $(this).val().toLowerCase();
            SBF.search(search, () => {
                let code = '';
                let all = search.length > 1 ? false : true;
                for (var i = 0; i < saved_replies_list.length; i++) {
                    if (all || saved_replies_list[i]['reply-name'].toLowerCase().includes(search) || saved_replies_list[i]['reply-text'].toLowerCase().includes(search)) {
                        code += `<li><div>${saved_replies_list[i]['reply-name']}</div><div>${saved_replies_list[i]['reply-text']}</div></li>`;
                    }
                }
                saved_replies.find('.sb-replies-list > ul').html(code);
            });
        });

        // Pagination for conversations
        $(conversations_admin_list).find('.sb-scroll-area').on('scroll', function () {
            if (!is_busy && !SBConversations.is_search && scrollPagination(this, true) && pagination_count) {
                let parent = conversations_area.find('.sb-admin-list');
                is_busy = true;
                parent.append('<div class="sb-loading-global sb-loading"></div>');
                SBF.ajax({
                    function: 'get-conversations',
                    pagination: pagination,
                    status_code: parent.find(' > .sb-top > .sb-select p').attr('data-value'),
                    routing: SB_ADMIN_SETTINGS['routing'],
                    routing_unassigned: SB_ADMIN_SETTINGS['assign-conversation-to-agent']
                }, (response) => {
                    setTimeout(() => { is_busy = false }, 500);
                    pagination_count = response.length;
                    if (pagination_count) {
                        let code = '';
                        for (var i = 0; i < pagination_count; i++) {
                            code += SBConversations.getListCode(response[i]);
                            conversations.push(response[i]);
                        }
                        pagination++;
                        conversations_admin_list_ul.append(code);
                        scrollPagination(this, false, 1000);
                    }
                    parent.find(' > .sb-loading').remove();
                    SBF.event('SBAdminConversationsLoaded', { conversations: response });
                });
            }
        });

        // Event: message deleted
        $(document).on('SBMessageDeleted', function () {
            let last_message = SBChat.conversation.getLastMessage();
            if (last_message != false) {
                conversations_admin_list_ul.find('li.sb-active p').html(last_message.message);
            } else {
                conversations_admin_list_ul.find('li.sb-active').remove();
                SBConversations.clickFirst();
                SBConversations.scrollTo();
            }
        });

        // Event: message sent
        $(document).on('SBMessageSent', function (e, response) {
            let conversation_id = response['conversation_id'];
            let item = conversations_admin_list_ul.find(`[data-conversation-id="${conversation_id}"]`);
            if (response['message']) {
                item.find('p').html(response['message']);
            }
            if (response['conversation_status_code'] != -1) {
                item.attr('data-conversation-status', response['conversation_status_code']);
                SBConversations.updateMenu();
            }
            if (SBApps.messenger.check(SBChat.conversation)) {
                SBApps.messenger.send(activeUser().getExtra('facebook-id').value, SBChat.conversation.get('extra'), response.message, response.attachments, response.message_id, (response) => {
                    if (response && 'error' in response) {
                        dialog('Error. Message not sent to Messenger. Error message: ' + response.error.message, 'info');
                    }
                });
            }
            if (SBApps.whatsapp.check(SBChat.conversation)) {
                SBApps.whatsapp.send(SBApps.whatsapp.activeUserPhone(), response['message'], response['attachments'], (response) => {
                    if ('ErrorCode' in response) {
                        dialog('Error. Message not sent to WhatsApp. Error message: ' + response.errorMessage, 'info');
                    }
                });
            }
            if (SBApps.telegram.check(SBChat.conversation)) {
                SBApps.telegram.send(SBChat.conversation.get('extra'), response['message'], response['attachments'], (response) => {
                    if (!('ok' in response) || !response.ok) {
                        dialog('Error. Message not sent to Telegram. Error message: ' + JSON.stringify(response), 'info');
                    }
                });
            }
            if (SB_ADMIN_SETTINGS['smart-reply']) {
                suggestions_area.html('');
            }
            if (SB_ADMIN_SETTINGS['assign-conversation-to-agent'] && SBChat.conversation && SBChat.conversation.id == conversation_id && SBF.null(SBChat.conversation.get('agent_id'))) {
                SBConversations.assignAgent(conversation_id, SB_ACTIVE_AGENT['id'], () => {
                    SBChat.conversation.set('agent_id', SB_ACTIVE_AGENT['id']);
                    $(conversations_area).find('#conversation-agent > p').attr('data-value', SB_ACTIVE_AGENT['id']).html(SB_ACTIVE_AGENT['full_name']);
                });
            }
        });

        // Event: new message of active chat conversation received
        $(document).on('SBNewMessagesReceived', function (e, response) {
            let payload = response.get('payload');
            let area = conversations_area.find('.sb-conversation');
            let agent = SBF.isAgent(response.get('user_type'));
            setTimeout(function () {
                area.find('.sb-top .sb-status-typing').remove();
            }, 300);
            if (SB_ADMIN_SETTINGS['smart-reply']) {
                if (agent) {
                    if (SB_ADMIN_SETTINGS['smart-reply-agent-assistant']) SBApps.dialogflow.smartReplyUpdate(response.message);
                } else {
                    SBApps.dialogflow.smartReply(response.message);
                }
            }
            if (SBAdmin.must_translate) {
                let message = area.find(`[data-id="${response.id}"] .sb-message`);
                let message_menu = area.find(`[data-id="${response.id}"] .sb-menu`);
                if ('original-message' in payload) {
                    message.html(payload['original-message']);
                    message_menu.prepend(`<li data-value="original">${sb_('View translation')}</li>`);
                    SBChat.conversation.getMessage(response.id).set('translation', payload['original-message']);
                } else {
                    SBApps.dialogflow.translate([response.message], SB_ADMIN_SETTINGS['active-agent-language'], (response_2) => {
                        if (response_2) {
                            message.html(response_2[0].translatedText);
                            message_menu.prepend(`<li data-value="original">${sb_('View original message')}</li>`);
                            SBChat.conversation.getMessage(response.id).set('translation', response_2[0].translatedText);
                        }
                    });
                }
            }
            if ('queryResult' in payload && 'fulfillmentMessages' in payload.queryResult) {
                let messages = payload.queryResult.fulfillmentMessages;
                for (var i = 0; i < messages.length; i++) {
                    if ('payload' in messages[i]) {
                        let message_payload = messages[i].payload;
                        if ('department' in message_payload) {
                            SBConversations.setActiveDepartment(message_payload.department);
                            break;
                        }
                        if ('agent' in message_payload) {
                            SBConversations.setActiveAgent(message_payload.agent);
                            break;
                        }
                    }
                }
            }
            if ('ErrorCode' in payload) {
                dialog('Error. Message not sent to WhatsApp. Error message: ' + payload['ErrorMessage'], 'info');
            }
            if ('whatsapp-fallback' in payload) {
                showResponse(`Message sent as text message.${'whatsapp-template-fallback' in payload ? ' The user has been notified via WhatsApp Template notification.' : ''}`);
            }
            if ('whatsapp-template-fallback' in payload && !('whatsapp-fallback' in payload)) {
                showResponse('The user has been notified via WhatsApp Template notification.');
            }
            if (!agent && SBChat.conversation.id == response.get('conversation_id') && !SBChat.user_online) {
                SBUsers.setActiveUserStatus();
            }
            SBConversations.update();
        });

        // Event: new conversation created 
        $(document).on('SBNewConversationCreated', function () {
            SBConversations.update();
        });

        // Event: email notification sent
        $(document).on('SBEmailSent', function () {
            showResponse(`The user has been notified by email.`);
        });

        // Event: SMS notification sent
        $(document).on('SBSMSSent', function () {
            showResponse('The user has been notified by text message.');
        });

        // Event: Message notifications
        $(document).on('SBNotificationsSent', function (e, response) {
            showResponse(`The user has been notified by email${response.includes('sms') ? ' and text message' : ''}.`);
        });

        // Event: user typing status change
        $(document).on('SBTyping', function (e, response) {
            SBConversations.typing(response);
        });

        // Conversations search
        $(conversations_admin_list).on('input', '.sb-search-btn input', function () {
            SBConversations.search(this);
        });

        $(conversations_area).on('click', '.sb-admin-list .sb-search-btn i', function () {
            SBF.searchClear(this, () => { SBConversations.search($(this).next()) });
        });

        // Conversations filter
        $(conversations_area).on('click', '.sb-admin-list .sb-select li', function () {
            let parent = conversations_admin_list_ul.parent();
            let status_code = $(this).data('value');
            if (loading(parent)) return;
            pagination = 1;
            pagination_count = 1;
            SBF.ajax({
                function: 'get-conversations',
                status_code: status_code,
                routing: SB_ADMIN_SETTINGS['routing'],
                routing_unassigned: SB_ADMIN_SETTINGS['assign-conversation-to-agent']
            }, (response) => {
                SBConversations.populateList(response);
                conversations_area.find('.sb-conversation').attr('data-conversation-status', status_code);
                if (response.length) {
                    if (!responsive) {
                        if (SBChat.conversation != false) {
                            let conversation = conversations_admin_list_ul.find(`[data-conversation-id="${SBChat.conversation.id}"]`);
                            if (conversation.length) conversation.sbActivate();
                            else if (status_code == SBChat.conversation.get('conversation_status_code')) conversations_admin_list_ul.prepend(SBConversations.getListCode(SBChat.conversation).replace('<li', '<li class="sb-active"'));
                            else SBConversations.clickFirst();
                        } else SBConversations.clickFirst();
                        SBConversations.scrollTo();
                    }
                } else {
                    conversations_area.find('.sb-board').addClass('sb-no-conversation');
                    SBChat.conversation = false;
                }
                parent.sbLoading(false);
            });
        });

        // Display the user details box
        $(conversations_area).on('click', '.sb-user-details .sb-scroll-area > .sb-profile,.sb-top > a', function () {
            let user_id = conversations_admin_list_ul.find('.sb-active').attr('data-user-id');
            if (activeUser().id != user_id) {
                activeUser(users[user_id]);
            }
            SBProfile.show(activeUser().id);
        });

        // Right profile list methods
        $(admin).on('click', '.sb-profile-list [data-id="location"]', function () {
            let location = $(this).find('label').html().replace(', ', '+');
            dialog('<iframe src="https://maps.google.com/maps?q=' + location + '&output=embed"></iframe>', 'map');
        });

        $(admin).on('click', '.sb-profile-list [data-id="timezone"]', function () {
            SBF.getLocationTimeString(activeUser().extra, (response) => {
                loadingGlobal(false);
                dialog(response, 'info');
            });
        });

        $(admin).on('click', '.sb-profile-list [data-id="current_url"]', function () {
            let label = $(this).find('label');
            window.open(SBF.null(label.attr('data-value')) ? label.html() : label.attr('data-value'));
        });

        $(admin).on('click', '.sb-profile-list [data-id="conversation-source"]', function () {
            let source = $(this).find('label').html().toLowerCase();
            if (source == 'whatsapp' && activeUser().getExtra('phone')) {
                window.open('https://wa.me/' + SBApps.whatsapp.activeUserPhone());
            } else if (source == 'facebook') {
                window.open('https://www.facebook.com/messages/t/' + SBChat.conversation.get('extra'));
            } else if (source == 'instagram') {
                window.open('https://www.instagram.com/direct/inbox/');
            } else if (source == 'telegram') {
                window.open('https://t.me/' + activeUser().getExtra('telegram-id').value);
            }
        });

        $(admin).on('click', '.sb-profile-list [data-id="wp-id"]', function () {
            window.open(window.location.href.substr(0, window.location.href.lastIndexOf('/')) + '/user-edit.php?user_id=' + activeUser().getExtra('wp-id').value);
        });

        // Dialogflow
        $(conversations_area).on('click', '.sb-menu [data-value="bot"]', function () {
            SBApps.dialogflow.showCreateIntentBox($(this).closest('[data-id]').attr('data-id'));
        });

        $(dialogflow_intent_box).on('click', '.sb-intent-add [data-value="add"]', function () {
            dialogflow_intent_box.find('> div > .sb-type-text').last().after('<div class="sb-input-setting sb-type-text"><input type="text"></div>');
        });

        $(dialogflow_intent_box).on('click', '.sb-intent-add [data-value="previous"],.sb-intent-add [data-value="next"]', function () {
            let input = dialogflow_intent_box.find('.sb-first input');
            let message = input.val();
            let next = $(this).attr('data-value') == 'next';
            let messages = SBChat.conversation.getUserMessages();
            let messages_length = messages.length;
            for (var i = 0; i < messages_length; i++) {
                if (messages[i].message == message && ((next && i < (messages_length - 1)) || (!next && i > 0))) {
                    i = i + (next ? 1 : -1);
                    input.val(messages[i].message);
                    dialogflow_intent_box.attr('data-message-id', messages[i].id);
                    break;
                }
            }
        });

        $(dialogflow_intent_box).on('click', '.sb-send', function () {
            SBApps.dialogflow.submitIntent(this);
        });

        $(dialogflow_intent_box).on('input', '.sb-search-btn input', function () {
            SBApps.dialogflow.searchIntents($(this).val());
        });

        $(dialogflow_intent_box).on('click', '.sb-search-btn i', function () {
            SBF.searchClear(this, () => { SBApps.dialogflow.searchIntents($(this).val()) });
        });

        $(dialogflow_intent_box).on('click', '#sb-intent-preview', function () {
            SBApps.dialogflow.previewIntent(dialogflow_intent_box.find('#sb-intents-select').val());
        });

        $(dialogflow_intent_box).on('change', '#sb-intents-select', function () {
            dialogflow_intent_box.find('.sb-bot-response').css('opacity', $(this).val() ? .5 : 1);
        }); 

        // Departments
        $(conversations_area).on('click', '#conversation-department li', function (e) {
            let select = $(this).parent().parent();
            if ($(this).data('value') == select.find(' > p').attr('data-value')) return true;
            if (SBChat.conversation == false) {
                $(this).parent().sbActivate(false);
                e.preventDefault();
                return false;
            }
            if (!select.sbLoading()) dialog(`${sb_('All agents assigned to the new department will be notified. The new department will be')} ${$(this).html()}.`, 'alert', () => {
                select.sbLoading(true);
                SBConversations.assignDepartment(SBChat.conversation.id, $(this).data('id'), () => {
                    SBConversations.setActiveDepartment($(this).data('id'));
                    select.sbLoading(false);
                });
            });
            e.preventDefault();
            return false;
        });

        // Agent assignment
        $(conversations_area).on('click', '#conversation-agent li', function (e) {
            let select = $(this).parent().parent();
            let agent_id = $(this).data('id');
            if (agent_id == select.find(' > p').attr('data-value') || agent_id == SB_ACTIVE_AGENT['id']) return true;
            if (!SBChat.conversation) {
                $(this).parent().sbActivate(false);
                e.preventDefault();
                return false;
            }
            if (!select.sbLoading()) {
                dialog(`${sb_('The new agent will be')} ${$(this).html()}.`, 'alert', () => {
                    select.sbLoading(true);
                    SBConversations.assignAgent(SBChat.conversation.id, agent_id, () => {
                        SBConversations.setActiveAgent(agent_id);
                        select.sbLoading(false);
                    });
                });
            }
            e.preventDefault();
            return false;
        });

        // Notes 
        notes_panel.on('click', '> i', function (e) {
            admin.find('.sb-notes-box').sbShowLightbox();
            e.preventDefault();
            return false;
        });

        notes_panel.on('click', '.sb-delete-note', function () {
            let item = $(this).parents().eq(1);
            SBConversations.notes.delete(SBChat.conversation.id, item.attr('data-id'), (response) => {
                if (response === true) item.remove(); else SBF.error(response);
            });
        });

        $(admin).on('click', '.sb-add-note', function () {
            let textarea = $(this).parent().parents().eq(1).find('textarea');
            let message = textarea.val();
            if (message.length == 0) {
                SBForm.showErrorMessage(admin.find('.sb-notes-box'), 'Please write something...');
            } else {
                if (loading(this)) return;
                SBConversations.notes.add(SBChat.conversation.id, SB_ACTIVE_AGENT['id'], SB_ACTIVE_AGENT['full_name'], message, (response) => {
                    if (Number.isInteger(response)) {
                        $(this).sbLoading(false);
                        admin.sbHideLightbox();
                        SBConversations.notes.update([{ 'id': response, 'conversation_id': SBChat.conversation.id, 'user_id': SB_ACTIVE_AGENT['id'], 'name': SB_ACTIVE_AGENT['full_name'], 'message': message }], true);
                        textarea.val('');
                        showResponse('New note successfully added.');
                    } else {
                        SBForm.showErrorMessage(response);
                    }
                });
            }
        });

        // Suggestions
        $(suggestions_area).on('click', 'span', function () {
            SBChat.insertText($(this).html());
            suggestions_area.html('');
        });

        // Message menu
        $(conversations_area).on('click', '.sb-list .sb-menu > li', function () {
            let message = $(this).closest('[data-id]');
            let message_id = message.attr('data-id');
            let message_user_type = SBChat.conversation.getMessage(message_id).get('user_type');
            switch ($(this).attr('data-value')) {
                case 'delete':
                    if (SBChat.user_online) {
                        SBF.ajax({
                            function: 'update-message',
                            message_id: message_id,
                            message: '',
                            attachments: [],
                            payload: { 'event': 'delete-message' }
                        }, () => {
                            SBChat.conversation.deleteMessage(message_id);
                            message.remove();
                        });
                    } else {
                        SBChat.deleteMessage(message_id);
                    }
                    break;
                case 'original':
                    message.find('.sb-message').html(SBChat.conversation.getMessage(message_id).message);
                    $(this).attr('data-value', 'translation').html(sb_(SBF.isAgent(message_user_type) ? 'View original message' : 'View translation'));
                    break;
                case 'translation':
                    message.find('.sb-message').html(SBChat.conversation.getMessage(message_id).get('translation'));
                    $(this).attr('data-value', 'original').html(sb_(SBF.isAgent(message_user_type) ? 'View translation' : 'View original message'));
                    break;
            }
        });

        /*
        * ----------------------------------------------------------
        * # Users area
        * ----------------------------------------------------------
        */

        // Open user box by URL
        if (SBF.getURL('user')) {
            header.find('.sb-admin-nav #sb-users').click();
            setTimeout(() => { SBProfile.show(SBF.getURL('user')) }, 500);
        }

        // Checkbox selector
        $(users_table).on('click', 'th :checkbox', function () {
            users_table.find('td :checkbox').prop('checked', $(this).prop('checked'));
        });

        $(users_table).on('click', ':checkbox', function () {
            let button = users_area.find('[data-value="delete"]');
            if (users_table.find('td input:checked').length) {
                button.removeAttr('style');
            } else {
                button.hide();
            }
        });

        // Table menu filter
        $(users_table_menu).on('click', 'li', function () {
            SBUsers.filter($(this).data('type'));
        });

        // Search users
        $(users_area).on('input', '.sb-search-btn input', function () {
            SBUsers.search(this);
        });

        $(users_area).on('click', '.sb-search-btn i', function () {
            SBF.searchClear(this, () => { SBUsers.search($(this).next()) });
        });

        // Sorting
        $(users_table).on('click', 'th:not(:first-child)', function () {
            let direction = $(this).hasClass('sb-order-asc') ? 'DESC' : 'ASC';
            $(this).toggleClass('sb-order-asc');
            $(this).siblings().sbActivate(false);
            $(this).sbActivate();
            SBUsers.sort($(this).data('field'), direction);
        });

        // Pagination for users
        $(users_table).parent().on('scroll', function () {
            if (!is_busy && SBUsers.search_query == '' && scrollPagination(this, true) && users_pagination_count) {
                is_busy = true;
                users_area.append('<div class="sb-loading-global sb-loading sb-loading-pagination"></div>');
                SBF.ajax({
                    function: 'get-users',
                    pagination: users_pagination,
                    sorting: SBUsers.sorting,
                    user_types: SBUsers.user_types,
                    search: SBUsers.search_query,
                    extra: SBUsers.table_extra
                }, (response) => {
                    setTimeout(() => { is_busy = false }, 500);
                    users_pagination_count = response.length;
                    if (users_pagination_count) {
                        let code = '';
                        for (var i = 0; i < users_pagination_count; i++) {
                            let user = new SBUser(response[i], response[i].extra);
                            code += SBUsers.getRow(user);
                            users[user.id] = user;
                        }
                        users_pagination++;
                        users_table.find('tbody').append(code);
                        scrollPagination(this);
                    }
                    users_area.find(' > .sb-loading-pagination').remove();
                });
            }
        });

        // Delete user button
        $(profile_edit_box).on('click', '.sb-delete', function () {
            dialog('This user will be deleted permanently including all linked data, conversations, and messages.', 'alert', function () {
                SBUsers.delete(activeUser().id);
            });
        });

        // Display user box
        $(users_table).on('click', 'td:not(:first-child)', function () {
            SBProfile.show($(this).parent().attr('data-user-id'));
        });

        // Display edit box
        $(profile_box).on('click', '.sb-top-bar .sb-edit', function () {
            SBProfile.showEdit(activeUser());
        });

        // Display new user box
        $(users_area).on('click', '.sb-new-user', function () {
            profile_edit_box.addClass('sb-user-new');
            profile_edit_box.find('.sb-top-bar .sb-profile span').html(sb_('Add new user'));
            profile_edit_box.find('.sb-top-bar .sb-save').html(`<i class="sb-icon-check"></i>${sb_('Add user')}`);
            profile_edit_box.find('#email input').prop('required', true);
            profile_edit_box.find('input,select,textara').removeClass('sb-error');
            if (SB_ACTIVE_AGENT['user_type'] == 'admin') {
                profile_edit_box.find('#user_type').find('select').html('<option value="user">User</option><option value="agent">Agent</option><option value="admin">Admin</option>');
            }
            SBProfile.clear(profile_edit_box);
            SBProfile.boxClasses(profile_edit_box);
            profile_edit_box.sbShowLightbox();
        });

        // Add or update user
        $(profile_edit_box).on('click', '.sb-save', function () {
            if (loading(this)) return;
            let new_user = (profile_edit_box.hasClass('sb-user-new') ? true : false);
            let user_id = profile_edit_box.attr('data-user-id');

            // Get settings
            let settings = SBProfile.getAll(profile_edit_box.find('.sb-details'));
            let settings_extra = SBProfile.getAll(profile_edit_box.find('.sb-additional-details'));

            // Errors check
            if (SBProfile.errors(profile_edit_box)) {
                SBProfile.showErrorMessage(profile_edit_box, ['agent', 'admin'].includes(profile_edit_box.find('#user_type :selected').val()) || profile_edit_box.hasClass('sb-user-new') ? 'First name, last name, and a valid email are required.' : 'First name and last name are required.');
                $(this).sbLoading(false);
                return;
            }

            // Save the settings
            SBF.ajax({
                function: (new_user ? 'add-user' : 'update-user'),
                user_id: user_id,
                settings: settings,
                settings_extra: settings_extra
            }, (response) => {
                if (SBF.errorValidation(response, 'duplicate-email') || SBF.errorValidation(response, 'duplicate-phone')) {
                    SBProfile.showErrorMessage(profile_edit_box, `This ${SBF.errorValidation(response, 'duplicate-email') ? 'email' : 'phone number'} is already in use.`);
                    $(this).sbLoading(false);
                    return;
                }
                if (new_user) {
                    user_id = response;
                    activeUser(new SBUser({ 'id': user_id }));
                }
                activeUser().update(() => {
                    users[user_id] = activeUser();
                    if (new_user) {
                        SBProfile.clear(profile_edit_box);
                        SBUsers.update();
                    } else {
                        SBUsers.updateRow(activeUser());
                        if (conversations_area.sbActive()) {
                            SBConversations.updateUserDetails();
                        }
                        if (user_id == SB_ACTIVE_AGENT['id']) {
                            SBF.loginCookie(response[1]);
                            SB_ACTIVE_AGENT['full_name'] = activeUser().name;
                            SB_ACTIVE_AGENT['profile_image'] = activeUser().image;
                            header.find('.sb-account').setProfile();
                        }
                    }
                    $(this).sbLoading(false);
                    profile_edit_box.find('.sb-profile').setProfile();
                    showResponse(new_user ? 'New user added' : 'User updated');
                });
                SBF.event('SBUserUpdated', { new_user: new_user, user_id: user_id });
            });
        });

        // Set and unset required visitor fields
        $(profile_edit_box).on('change', '#user_type', function () {
            SBProfile.boxClasses(profile_edit_box, $(this).find("option:selected").val());
        });

        // Open a user conversation
        $(profile_box).on('click', '.sb-user-conversations li', function () {
            SBConversations.open($(this).attr('data-conversation-id'), activeUser().id);
        });

        // Start a new user conversation
        $(profile_box).on('click', '.sb-start-conversation', function () {
            SBConversations.open(-1, activeUser().id);
            SBConversations.openConversation(-1, activeUser().id);
            if (responsive) SBConversations.mobileOpenConversation();
        });

        // Show direct message box from user profile
        $(profile_box).on('click', '.sb-top-bar [data-value]', function () {
            SBConversations.showDirectMessageBox($(this).attr('data-value'), [activeUser().id]);
        });

        // Top icons menu
        $(users_area).on('click', '.sb-top-bar [data-value]', function () {
            let value = $(this).data('value');
            let user_ids = [];
            users_table.find('tr').each(function () {
                if ($(this).find('td input[type="checkbox"]').is(':checked')) {
                    user_ids.push($(this).attr('data-user-id'));
                }
            });
            switch (value) {
                case 'message':
                case 'email':
                case 'sms':
                    SBConversations.showDirectMessageBox(value, user_ids);
                    break;
                case 'csv':
                    SBUsers.csv();
                    break;
                case 'delete':
                    dialog('All selected users will be deleted permanently including all linked data, conversations, and messages.', 'alert', () => {
                        SBUsers.delete(user_ids);
                        $(this).hide();
                        users_table.find('th:first-child input').prop('checked', false);
                    });
                    break;
            }
        });

        // Direct message
        $(admin).on('click', '.sb-send-direct-message', function () {
            let type = direct_message_box.attr('data-type');
            let subject = direct_message_box.find('.sb-direct-message-subject input').val();
            let message = direct_message_box.find('textarea').val();
            let user_ids = direct_message_box.find('.sb-direct-message-users').val().replace(/ /g, '');
            if (SBForm.errors(direct_message_box)) {
                SBForm.showErrorMessage(direct_message_box, 'All fields are required.');
            } else {
                if (loading(this)) return;
                if (type == 'message') {
                    SBF.ajax({
                        function: 'direct-message',
                        user_ids: user_ids,
                        message: message
                    }, (response) => {
                        $(this).sbLoading(false);
                        let send_email = SB_ADMIN_SETTINGS['notify-user-email'];
                        let send_sms = SB_ADMIN_SETTINGS['sms-active-users'];
                        if (SBF.errorValidation(response)) {
                            return SBForm.showErrorMessage(direct_message_box, 'An error has occurred. Please make sure all user ids are correct.');
                        }
                        if (send_email || send_sms) {
                            SBF.ajax({
                                function: 'get-users-with-details',
                                user_ids: user_ids,
                                details: send_email && send_sms ? ['email', 'phone'] : [send_email ? 'email' : 'phone']
                            }, (response) => {
                                if (send_email && response['email'].length) {
                                    recursiveSending(response['email'], message, 0, send_sms ? response['phone'] : [], 'email', subject);
                                } else if (send_sms && response['phone'].length) {
                                    recursiveSending(response['phone'], message, 0, [], 'sms');
                                } else {
                                    admin.sbHideLightbox();
                                }
                            });
                        }
                        showResponse(`${SBF.slugToString(type)} sent to all users.`);
                    });
                } else {
                    let slug = type == 'email' ? 'email' : 'phone';
                    SBF.ajax({
                        function: 'get-users-with-details',
                        user_ids: user_ids,
                        details: [slug]
                    }, (response) => {
                        if (response[slug].length) {
                            recursiveSending(response[slug], message, 0, [], type == 'email' ? 'custom-email' : 'sms', subject);
                        } else {
                            return SBForm.showErrorMessage(direct_message_box, 'No users found.');
                        }
                    });
                }
            }
        });

        function recursiveSending(user_ids, message, i = 0, user_ids_sms = [], type, subject = false) {
            let settings = type == 'custom-email' ? ['send-custom-email', 'emails', ' users with an email', 'direct-emails'] : (type == 'sms' ? ['send-sms', 'text messages', ' with a phone number', 'direct-sms'] : ['create-email', 'emails', ' with an email', false]);
            SBF.ajax({
                function: settings[0],
                to: user_ids[i]['value'],
                recipient_id: user_ids[i]['id'],
                sender_name: SB_ACTIVE_AGENT['full_name'],
                sender_profile_image: SB_ACTIVE_AGENT['profile_image'],
                subject: subject,
                message: message,
                template: false
            }, (response) => {
                let user_ids_length = user_ids.length;
                direct_message_box.find('.sb-bottom > div').html(`${sb_('Sending')} ${settings[1]}... ${i + 1} / ${user_ids_length}`);
                if (!response) console.warn(response);
                if (response !== true && 'status' in response && response.status == 400) {
                    dialog(`${response.message}. Details at ${response.more_info}`, 'info');
                    console.warn(response);
                    return;
                }
                if (i < user_ids_length - 1) {
                    return recursiveSending(user_ids, message, i + 1, user_ids_sms, type, subject);
                } else {
                    if (user_ids_sms.length) {
                        recursiveSending(user_ids_sms, message, 0, [], 'sms', false);
                    } else {
                        admin.sbHideLightbox();
                        if (settings[3]) SBF.ajax({ function: 'reports-update', name: settings[3], value: message.substr(0, 18) + ' | ' + user_ids_length });
                    }
                    showResponse(user_ids_length == 1 ? 'Message sent' : `${SBF.slugToString(settings[1])} sent to all users${settings[2]}.`);
                }
            });
        }

        /*
        * ----------------------------------------------------------
        * # Settings area
        * ----------------------------------------------------------
        */

        // Open settings area by URL
        if (SBF.getURL('setting')) {
            header.find('.sb-admin-nav #sb-settings').click();
            setTimeout(() => { settings_area.find('#tab-' + SBF.getURL('setting')).click() }, 300);
        }

        // Settings history
        $(settings_area).on('click', ' > .sb-tab > .sb-nav [id]', function () {
            let id = $(this).attr('id').substr(4);
            if (SBF.getURL('setting') != id) pushState('?setting=' + id);
        });

        // Upload image
        $(settings_area).on('click', '[data-type="upload-image"] .image', function () {
            upload_target = this;
            admin.find('.sb-upload-form-admin .sb-upload-files').click();
        });

        $(settings_area).on('click', '[data-type="upload-image"] .image > i', function (e) {
            $(this).parent().removeAttr('data-value').css('background-image', '');
            e.preventDefault();
            return false;
        });

        // Repeater
        $(settings_area).on('click', '.sb-repeater-add', function () {
            SBSettings.repeaterAdd(this);
        });

        $(settings_area).on('click', '.repeater-item > i', function () {
            SBSettings.repeaterDelete(this);
        });

        // Color picker
        SBSettings.initColorPicker();

        $(settings_area).find('[data-type="color"]').focusout(function () {
            let t = $(this).closest('.input-color');
            let color = t.find('input').val();
            setTimeout(function () { t.find('input').val(''); t.find('.color-preview').css('background-color', color); }, 300);
            SBSettings.set($(this).attr('id'), color);
        });

        $(settings_area).on('click', '.sb-type-color .input i', function (e) {
            $(this).parent().find('input').removeAttr('style').val('');
        });

        // Color palette
        $(settings_area).on('click', '.sb-color-palette span', function () {
            let active = $(this).hasClass('sb-active');
            $(this).closest('.sb-repeater').find('.sb-active').sbActivate(false);
            $(this).sbActivate(!active);
        });

        $(settings_area).on('click', '.sb-color-palette ul li', function () {
            $(this).parent().parent().attr('data-value', $(this).data('value')).find('span').sbActivate(false);
        });

        // Select images
        $(settings_area).on('click', '[data-type="select-images"] .input > div', function () {
            $(this).siblings().sbActivate(false);
            $(this).sbActivate();
        });

        // Save
        $(settings_area).on('click', '.sb-save-changes', function () {
            SBSettings.save(this);
        });

        // Miscellaneous
        $(settings_area).on('change', '#user-additional-fields [data-id="extra-field-slug"], #saved-replies [data-id="reply-name"], [data-id="rich-message-name"]', function () {
            $(this).val(SBF.stringToSlug($(this).val()));
        });

        $(settings_area).on('click', '#timetable-utc input', function () {
            if ($(this).val() == '') {
                $(this).val(Math.round(today.getTimezoneOffset() / 60));
            }
        });

        $(settings_area).on('click', '#dialogflow-button .sb-btn', function (e) {
            let client_id = settings_area.find('#google-client-id input').val();
            if (client_id) {
                window.open(`https://accounts.google.com/o/oauth2/auth?scope=https%3A%2F%2Fwww.googleapis.com/auth/dialogflow%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-translation&response_type=code&access_type=offline&redirect_uri=${SB_URL}/include/google.php&client_id=${client_id}&prompt=consent`);
            } else window.open('https://board.support/synch/?service=dialogflow&plugin_url=' + SB_URL + cloudURL());
            e.preventDefault();
            return false;
        });

        $(settings_area).on('click', '#google-domain-information .sb-btn', function (e) {
            let uri = SB_URL.substr(0, SB_URL.replace('//', '').indexOf('/') + 2);
            dialog(`Authorised JavaScript origins URI: ${uri}<br><br>Authorised redirect URI: ${SB_URL}/include/google.php`, 'info');
            e.preventDefault();
            return false;
        });

        $(settings_area).on('click', '#test-email-user .sb-btn, #test-email-agent .sb-btn', function () {
            let email = $(this).parent().find('input').val();
            if (email && email.indexOf('@') > 0 && !loading(this)) {
                SBF.ajax({
                    function: 'send-test-email',
                    to: email,
                    email_type: $(this).parent().parent().attr('id') == 'test-email-user' ? 'user' : 'agent'
                }, () => {
                    dialog('Email successfully sent. Check your emails!', 'info');
                    $(this).sbLoading(false);
                });
            }
        });

        $(settings_area).on('click', '.sb-timetable > div > div > div', function () {
            let timetable = $(this).closest('.sb-timetable');
            let active = $(this).sbActive();
            $(timetable).find('.sb-active').sbActivate(false);
            if (active) {
                $(this).sbActivate(false).find('.sb-custom-select').remove();
            } else {
                let select = $(timetable).find('> .sb-custom-select').html();
                $(timetable).find(' > div .sb-custom-select').remove();
                $(this).append(`<div class="sb-custom-select">${select}</div>`).sbActivate();
            }
        });

        $(settings_area).on('click', '.sb-timetable .sb-custom-select span', function () {
            let value = [$(this).html(), $(this).attr('data-value')];
            $(this).closest('.sb-timetable').find('> div > div > .sb-active').html(value[0]).attr('data-value', value[1]);
            $(this).parent().sbActivate(false);
        });

        $(settings_area).on('click', '#system-requirements a', function (e) {
            let box = admin.find('.sb-requirements-box');
            let code = '';
            SBF.ajax({
                function: 'system-requirements'
            }, (response) => {
                for (var key in response) {
                    code += `<div class="sb-input"><span>${sb_(SBF.slugToString(key))}</span><div${response[key] ? ' class="sb-green"' : ''}>${response[key] ? sb_('Success') : sb_('Error')}</div></div>`;
                }
                loadingGlobal(false);
                box.find('.sb-main').html(code);
                box.sbShowLightbox();
            });
            box.sbActivate(false);
            loadingGlobal(true);
            e.preventDefault();
            return false;
        });

        $(settings_area).on('click', '#sb-path a', function (e) {
            SBF.ajax({
                function: 'path'
            }, (response) => {
                dialog(response, 'info');
            });
            e.preventDefault();
            return false;
        });

        $(settings_area).on('click', '#delete-leads a', function (e) {
            if (!$(this).sbLoading()) {
                dialog('All leads, including all the linked conversations and messages, will be deleted permanently.', 'alert', () => {
                    $(this).sbLoading(true);
                    SBF.ajax({
                        function: 'delete-leads'
                    }, () => {
                        dialog('Leads and conversations successfully deleted.', 'info');
                        $(this).sbLoading(false);
                    });
                });
            }
            e.preventDefault();
            return false;
        });

        $(settings_area).on('click', '#dialogflow-smart-reply-generate a', function (e) {
            if (loading(this)) return;
            SBF.ajax({
                function: 'dialogflow-smart-reply-generate-conversations-data'
            }, (response) => {
                dialog('Conversations data successfully generated. Folder: ' + response, 'info');
                $(this).sbLoading(false);
            });
            e.preventDefault();
            return false;
        });

        $(settings_area).on('click', '#sb-export-settings a', function (e) {
            if (loading(this)) return;
            SBF.ajax({
                function: 'export-settings'
            }, (response) => {
                window.open(response);
                dialog(`${sb_('For security reasons, delete the settings file after downloading it. Close this window to automatically delete it. File location:')}<pre>${response}</pre>`, 'info', false, 'sb-export-settings-close', 'Settings exported');
                $(this).sbLoading(false);
            });
            e.preventDefault();
            return false;
        });

        $(settings_area).on('click', '#sb-import-settings a', function (e) {
            if (loading(this)) return;
            upload_target = this;
            upload_on_success = (response) => {
                SBF.ajax({
                    function: 'import-settings',
                    file_url: response
                }, (response) => {
                    if (response) showResponse('Settings successfully imported. Reload the admin area to apply the new settings.');
                    else dialog(response, 'info');
                    $(this).sbLoading(false);
                });
                upload_on_success = false;
            }
            admin.find('.sb-upload-form-admin .sb-upload-files').click();
            e.preventDefault();
            return false;
        });

        $(admin).on('click', '#sb-export-settings-close', function () {
            SBF.ajax({ function: 'delete-file', path: admin.find('.sb-dialog-box p pre').html() });
        });


        // Slack  
        $(settings_area).find('#slack-button .sb-btn').attr('href', 'https://board.support/synch/?service=slack&plugin_url=' + SB_URL + cloudURL());

        $(settings_area).on('click', '#slack-test .sb-btn', function (e) {
            if (loading(this)) return;
            SBF.ajax({
                function: 'send-slack-message',
                user_id: -1,
                full_name: SB_ACTIVE_AGENT['full_name'],
                profile_image: SB_ACTIVE_AGENT['profile_image'],
                message: 'Lorem ipsum dolor sit amete consectetur adipiscing elite incidido labore et dolore magna aliqua.',
                attachments: [['Example link', SB_URL + '/media/user.svg'], ['Example link two', SB_URL + '/media/user.svg']]
            }, (response) => {
                if (SBF.errorValidation(response)) {
                    if (response[1] == 'slack-not-active') {
                        dialog('Please first activate Slack, then save the settings and reload the admin area.', 'info');
                    } else {
                        dialog('Error. Response: ' + JSON.stringify(response), 'info');
                    }
                } else {
                    dialog(response[0] == 'success' ? 'Slack message successfully sent. Check your Slack app!' : JSON.stringify(response), 'info');
                }
                $(this).sbLoading(false);
            });
            e.preventDefault();
            return false;
        });

        $(settings_area).on('click', '#tab-slack', function () {
            let input = settings_area.find('#slack-agents .input');
            input.html('<div class="sb-loading"></div>');
            SBF.ajax({
                function: 'slack-users'
            }, (response) => {
                let code = '';
                if (SBF.errorValidation(response, 'slack-token-not-found')) {
                    code = `<p>${sb_('Synchronize Slack and save changes before linking agents.')}</p>`;
                } else {
                    let select = '<option value="-1"></option>';
                    for (var i = 0; i < response['agents'].length; i++) {
                        select += `<option value="${response['agents'][i]['id']}">${response['agents'][i]['name']}</option>`;
                    }
                    for (var i = 0; i < response['slack_users'].length; i++) {
                        code += `<div data-id="${response['slack_users'][i]['id']}"><label>${response['slack_users'][i]['name']}</label><select>${select}</select></div>`;
                    }
                }
                input.html(code);
                SBSettings.set('slack-agents', [response['saved'], 'double-select']);
            });
        });

        $(settings_area).on('click', '#slack-archive-channels .sb-btn', function (e) {
            e.preventDefault();
            if (loading(this)) return;
            SBF.ajax({
                function: 'archive-slack-channels'
            }, (response) => {
                if (response === true) {
                    dialog('Slack channels archived successfully!', 'info');
                }
                $(this).sbLoading(false);
            });
        });

        // Messenger
        $(settings_area).find('#messenger-button .sb-btn').attr('href', 'https://board.support/synch/?service=messenger&plugin_url=' + SB_URL + cloudURL());

        // WhatsApp
        $(settings_area).on('click', '#whatsapp-twilio-btn .sb-btn', function (e) {
            dialog(SB_URL + '/apps/whatsapp/post.php', 'info');
            return false;
            e.preventDefault();
        });

        // Telegram
        $(settings_area).on('click', '#telegram-button .sb-btn', function (e) {
            let token = settings_area.find('#telegram-token input').val().trim();
            e.preventDefault();
            if (!token || loading(this)) return false;
            SBF.ajax({
                function: 'telegram-synchronization',
                token: token
            }, () => {
                dialog('Synchronization completed.', 'info');
                $(this).sbLoading(false);
            });
            return false;
        });

        // WordPress
        $(settings_area).on('click', '#wp-sync .sb-btn', function (e) {
            e.preventDefault();
            if (loading(this)) return false;
            SBApps.wordpress.ajax('wp-sync', {}, (response) => {
                if (response === true || response === '1') {
                    SBUsers.update();
                    dialog('WordPress users successfully imported.', 'info');
                } else {
                    dialog('Error. Response: ' + JSON.stringify(response), 'info');
                }
                $(this).sbLoading(false);
            });
            return false;
        });

        $('body').on('click', '#wp-admin-bar-logout', function () {
            SBF.logout(false);
        });

        // Translations
        $(settings_area).on('click', '#tab-translations', function () {
            let nav = settings_area.find('.sb-translations > .sb-nav > ul');
            if (nav.html() == '') {
                let code = '';
                for (var key in SB_LANGUAGE_CODES) {
                    if (key == 'en') continue;
                    code += `<li data-code="${key}"><img src="${SB_URL}/media/flags/${key}.png" />${SB_LANGUAGE_CODES[key]}</li>`;
                }
                nav.html(code);
            }
        });

        $(settings_area).on('click', '.sb-translations .sb-nav li', function () {
            SBSettings.translations.load($(this).data('code'));
        });

        $(settings_area).on('click', '.sb-translations .sb-menu-wide li', function () {
            settings_area.find(`.sb-translations [data-area="${$(this).data('value')}"]`).sbActivate().siblings().sbActivate(false);
        });

        $(settings_area).on('click', '.sb-add-translation', function () {
            settings_area.find('.sb-translations-list > .sb-active').prepend(`<div class="sb-input-setting sb-type-text sb-new-translation"><input type="text" placeholder="${sb_('Enter original text...')}"><input type="text" placeholder="${sb_('Enter translation...')}"></div></div>`);
        });

        $(settings_area).on('input', '.sb-search-translation input', function () {
            let search = $(this).val().toLowerCase();
            SBF.search(search, () => {
                if (search.length > 1) {
                    settings_area.find('.sb-translations .sb-content > .sb-active label').each(function () {
                        let value = $(this).html().toLowerCase();
                        if (value.includes(search) && value != temp) {
                            let scroll_area = settings_area.find('.sb-scroll-area');
                            scroll_area[0].scrollTop = 0;
                            scroll_area[0].scrollTop = $(this).position().top - 80;
                            temp = value;
                            return false;
                        }
                    });
                }
            });
        });

        // Articles
        $(settings_area).on('click', '#tab-articles', function () {
            articles_area.find('.sb-menu-wide li').eq(0).sbActivate().next().sbActivate(false);
            SBSettings.articles.get((response) => {
                SBSettings.articles.populate(response[0]);
                SBSettings.articles.categories = response[1];
                SBSettings.articles.translations = Array.isArray(response[2]) && !response[2].length ? {} : response[2];
                SBSettings.articles.updateSelect();
                loadingGlobal(false);
            }, true);
            loadingGlobal();
        });

        $(articles_area).on('click', '.sb-nav:not([data-type="categories"]) li', function () {
            SBSettings.articles.show($(this).attr('data-id'), this);
        });

        $(articles_area).on('click', '.sb-add-article', function () {
            SBSettings.articles.add();
        });

        $(articles_area).on('click', '.sb-add-category', function () {
            SBSettings.articles.addCategory(false, $(this).data('type') == 'categories');
        });

        $(articles_area).on('click', '.sb-nav i', function () {
            let category = $(this).hasClass('sb-category');
            dialog(`The ${category ? 'category' : 'article'} will be deleted permanently.`, 'alert', () => {
                SBSettings.articles.delete(this, category);
            });
        });

        $(articles_area).on('click', '.sb-menu-wide li', function () {
            SBSettings.articles.populate(false, $(this).data('type') == 'categories');
        });

        // Email piping manual sync
        $(settings_area).on('click', '#email-piping-sync a', function (e) {
            if (loading(this)) return;
            SBF.ajax({
                function: 'email-piping',
                force: true
            }, (response) => {
                dialog(response === true ? 'Syncronization completed.' : response, 'info');
                $(this).sbLoading(false);
            });
            e.preventDefault();
        });

        // Automations
        $(settings_area).on('click', '#tab-automations', function () {
            SBSettings.automations.get(() => {
                SBSettings.automations.populate();
                loadingGlobal(false);
            }, true);
            loadingGlobal();
        });

        $(automations_area).on('click', '.sb-add-condition', function () {
            SBSettings.automations.addCondition();
        });

        $(automations_area).on('change', '.sb-condition-1 select', function () {
            SBSettings.automations.updateCondition(this);
        });

        $(automations_area_select).on('click', 'li', function () {
            SBSettings.automations.populate($(this).data('value'));
        });

        $(automations_area_nav).on('click', 'li', function () {
            SBSettings.automations.show($(this).attr('data-id'));
        });

        $(automations_area).on('click', '.sb-add-automation', function () {
            SBSettings.automations.add();
        });

        $(automations_area_nav).on('click', 'li i', function () {
            dialog(`The automation will be deleted permanently.`, 'alert', () => {
                SBSettings.automations.delete(this);
            });
        });

        /*
        * ----------------------------------------------------------
        * # Reports area
        * ----------------------------------------------------------
        */

        $(reports_area).on('click', '.sb-nav [id]', function () {
            let id = $(this).attr('id');
            SBReports.active_report = false;
            reports_area.find('#sb-date-picker').val('');
            reports_area.attr('class', 'sb-area-reports sb-active sb-report-' + id);
            SBReports.initReport($(this).attr('id'));
            if (SBF.getURL('report') != id) pushState('?report=' + id);
        });

        $(reports_area).on('change', '#sb-date-picker', function () {
            SBReports.initReport(false, $(this).val());
        });

        if (SBF.getURL('report')) {
            if (!reports_area.sbActive()) header.find('.sb-admin-nav #sb-reports').click();
            setTimeout(() => { reports_area.find('#' + SBF.getURL('report')).click() }, 500);
        }

        /*
        * ----------------------------------------------------------
        * # Woocommerce
        * ----------------------------------------------------------
        */

        // Panel reload button
        $(conversations_area).on('click', '.sb-panel-woocommerce > i', function () {
            SBApps.woocommerce.conversationPanel();
        });

        // Get order details
        $(conversations_area).on('click', '.sb-woocommerce-orders > div > span', function (e) {
            let parent = $(this).parent();
            if (!$(e.target).is('span')) return;
            if (!parent.sbActive()) {
                SBApps.woocommerce.conversationPanelOrder(parent.attr('data-id'));
            }
        });

        // Products popup 
        $(conversations_area).on('click', '.sb-btn-woocommerce', function () {
            if (woocommerce_products_box_ul.sbLoading() || (activeUser() != false && activeUser().language != SBApps.woocommerce.popupLanguage)) {
                SBApps.woocommerce.popupPopulate();
            }
            woocommerce_products_box.sbTogglePopup(this);
        });

        // Products popup pagination
        $(woocommerce_products_box).find('.sb-woocommerce-products-list').on('scroll', function () {
            if (scrollPagination(this, true)) {
                SBApps.woocommerce.popupPagination(this);
            }
        });

        // Products popup filter
        $(woocommerce_products_box).on('click', '.sb-select li', function () {
            SBApps.woocommerce.popupFilter(this);
        });

        // Products popup search
        $(woocommerce_products_box).on('input', '.sb-search-btn input', function () {
            SBApps.woocommerce.popupSearch(this);
        });

        $(woocommerce_products_box).on('click', '.sb-search-btn i', function () {
            SBF.searchClear(this, () => { SBApps.woocommerce.popupSearch($(this).next()) });
        });

        // Cart popup insert product
        $(woocommerce_products_box).on('click', '.sb-woocommerce-products-list li', function () {
            let action = woocommerce_products_box.attr('data-action');
            let id = $(this).data('id');
            if (SBF.null(action)) {
                SBChat.insertText(`{product_card id="${id}"}`);
            } else {
                woocommerce_products_box_ul.sbLoading(true);
                conversations_area.find('.sb-add-cart-btn').sbLoading(true);
                SBChat.sendMessage(-1, '', [], (response) => {
                    if (response) {
                        SBApps.woocommerce.conversationPanelUpdate(id);
                        admin.sbHideLightbox();
                    }
                }, { 'event': 'woocommerce-update-cart', 'action': 'cart-add', 'id': id });
            }
            SBF.deactivateAll();
            admin.removeClass('sb-popup-active');
        });

        // Cart add product
        $(conversations_area).on('click', '.sb-panel-woocommerce .sb-add-cart-btn', function () {
            if ($(this).sbLoading()) return;
            if (SBChat.user_online) {
                SBApps.woocommerce.popupPopulate();
                woocommerce_products_box.sbShowLightbox(true, 'cart-add');
            } else {
                dialog('The user is offline. Only the carts of online users can be updated.', 'info');
            }
        });

        // Cart remove product
        $(conversations_area).on('click', '.sb-panel-woocommerce .sb-list-items > a > i', function (e) {
            let id = $(this).parent().attr('data-id');
            SBChat.sendMessage(-1, '', [], () => {
                SBApps.woocommerce.conversationPanelUpdate(id, 'removed');
            }, { 'event': 'woocommerce-update-cart', 'action': 'cart-remove', 'id': id });
            $(this).sbLoading(true);
            e.preventDefault();
            return false;
        });

        // Settings
        $(settings_area).on('click', '#wc-dialogflow-synch a, #wc-dialogflow-create-intents a', function (e) {
            if (SBApps.is('dialogflow')) {
                if (loading(this)) return;
                let id = $(this).parent().attr('id');
                SBF.ajax({
                    function: 'woocommerce-dialogflow-' + (id == 'wc-dialogflow-synch' ? 'entities' : 'intents')
                }, (response) => {
                    $(this).sbLoading(false);
                    dialog(response ? 'Synchronization completed.' : 'Error. Something went wrong.', 'info');
                });
            } else {
                dialog('This feature requires the Dialogflow App. Get it from the apps area.', 'info');
            }
            e.preventDefault();
            return false;
        });

        /*
        * ----------------------------------------------------------
        * # Apps area
        * ----------------------------------------------------------
        */

        // Ump
        $(conversations_area).on('click', '.sb-panel-ump > i', function () {
            SBApps.ump.conversationPanel();
        });

        // ARMember
        $(conversations_area).on('click', '.sb-panel-armember > i', function () {
            SBApps.armember.conversationPanel();
        });

        // Perfex, whmcs, aecommerce
        $(settings_area).on('click', '#perfex-sync .sb-btn, #whmcs-sync .sb-btn,#perfex-articles-sync .sb-btn, #whmcs-articles-sync .sb-btn, #aecommerce-sync .sb-btn, #aecommerce-sync-admins .sb-btn, #aecommerce-sync-sellers .sb-btn', function (e) {
            if (loading(this)) return;
            let function_name = $(this).closest('[id]').attr('id');
            let articles = function_name.indexOf('article') > 0;
            SBF.ajax({
                function: function_name
            }, (response) => {
                if (response === true) {
                    if (!articles) {
                        SBUsers.update();
                    }
                    dialog(articles ? 'Knowledge base articles successfully imported.' : 'Users successfully imported.', 'info');
                } else {
                    dialog('Error. Response: ' + JSON.stringify(response), 'info');
                }
                $(this).sbLoading(false);
            });
            e.preventDefault();
        });

        /*
        * ----------------------------------------------------------
        * # Components
        * ----------------------------------------------------------
        */

        // Language switcher
        $(admin).on('click', '.sb-language-switcher > i', function () {
            let switcher = $(this).parent();
            let active_languages = switcher.find('[data-language]').map(function () { return $(this).attr('data-language') }).get();
            let box = admin.find('.sb-languages-box');
            let code = '';
            active_languages.push('en');
            for (var key in SB_LANGUAGE_CODES) {
                if (!active_languages.includes(key)) {
                    code += `<div data-language="${key}"><img src="${SB_URL}/media/flags/${key}.png" />${sb_(SB_LANGUAGE_CODES[key])}</div>`;
                }
            }
            language_switcher_target = switcher;
            box.attr('data-source', switcher.attr('data-source'));
            box.find('.sb-main').html(code);
            box.sbShowLightbox();
        });

        $(admin).on('click', '.sb-language-switcher img', function () {
            let item = $(this).parent();
            let active = item.sbActive();
            let language = active ? false : item.attr('data-language');
            switch (item.parent().attr('data-source')) {
                case 'articles':
                    SBSettings.articles.show(false, false, language);
                    break;
                case 'automations':
                    SBSettings.automations.show(false, language);
                    break;
                case 'settings':
                    let active_language = item.parent().find('[data-language].sb-active');
                    SBSettings.translations.save(item, active ? item.attr('data-language') : (active_language.length ? active_language.attr('data-language') : false));
                    SBSettings.translations.activate(item, language);
                    break;
            }
            item.siblings().sbActivate(false);
            item.sbActivate(!active);
        });

        $(admin).on('click', '.sb-language-switcher span > i', function () {
            let item = $(this).parent();
            let language = item.attr('data-language');
            dialog(sb_('The {T} translation will be deleted.').replace('{T}', sb_(SB_LANGUAGE_CODES[language])), 'alert', () => {
                switch (item.parent().attr('data-source')) {
                    case 'articles':
                        SBSettings.articles.deleteTranslation(false, language);
                        SBSettings.articles.show();
                        break;
                    case 'automations':
                        SBSettings.automations.deleteTranslation(false, language);
                        SBSettings.automations.show();
                        break;
                    case 'settings':
                        SBSettings.translations.delete(item, language);
                        break;
                }
                item.remove();
            });
        });

        $(admin).on('click', '.sb-languages-box [data-language]', function () {
            let box = $(this).parents().eq(1);
            let language = $(this).attr('data-language');
            switch (box.attr('data-source')) {
                case 'articles':
                    SBSettings.articles.addTranslation(false, language);
                    SBSettings.articles.show(false, false, language);
                    break;
                case 'automations':
                    SBSettings.automations.addTranslation(false, false, language);
                    SBSettings.automations.show(false, language);
                    break;
                case 'settings':
                    SBSettings.translations.add(language);
                    break;
            }
            admin.sbHideLightbox();
        });

        // Lightbox
        $(admin).on('click', '.sb-lightbox .sb-top-bar .sb-close', function () {
            admin.sbHideLightbox();
        });

        $(admin).on('click', '.sb-lightbox .sb-info', function () {
            $(this).sbActivate(false);
        });

        // Alert and information box
        $(admin).on('click', '.sb-dialog-box a', function () {
            let lightbox = $(this).closest('.sb-lightbox');
            if ($(this).hasClass('sb-confirm')) {
                alertOnConfirmation();
            }
            if (admin.find('.sb-lightbox.sb-active').length == 1) {
                overlay.sbActivate(false);
            }
            SBAdmin.open_popup = false;
            lightbox.sbActivate(false);
        });

        /*
       * ----------------------------------------------------------
       * # Miscellaneous
       * ----------------------------------------------------------
       */

        $(admin).on('click', '.sb-menu-wide li, .sb-nav li', function () {
            $(this).siblings().sbActivate(false);
            $(this).sbActivate();
        });

        $(admin).on('click', '.sb-nav:not(.sb-nav-only) li:not(.sb-tab-nav-title)', function () {
            let area = $(this).closest('.sb-tab');
            let tab = $(area).find(' > .sb-content > div').sbActivate(false).eq($(this).parent().find('li:not(.sb-tab-nav-title)').index(this));
            tab.sbActivate();
            tab.find('textarea').each(function () {
                $(this).autoExpandTextarea();
                $(this).manualExpandTextarea();
            });
            area.find('.sb-scroll-area').scrollTop(0);
        });

        $(admin).sbInitTooltips();

        $(admin).on('click', '[data-button="toggle"]', function () {
            let show = admin.find('.' + $(this).data('show'));
            let hide = admin.find('.' + $(this).data('hide'));
            show.addClass('sb-show-animation').show();
            hide.hide();
            SBAdmin.open_popup = show.hasClass('sb-lightbox') || show.hasClass('sb-popup') ? show : false;
        });

        $(admin).on('click', '.sb-info-card', function () {
            $(this).sbActivate(false);
        });

        $(admin).on('change', '.sb-upload-form-admin .sb-upload-files', function (data) {
            $(this).sbUploadFiles(function (response) {
                response = JSON.parse(response);
                if (response[0] == 'success') {
                    let type = $(upload_target).closest('[data-type]').data('type');
                    if (type == 'upload-image') {
                        $(upload_target).attr('data-value', response[1]).css('background-image', `url("${response[1]}")`);
                    }
                    if (upload_on_success) upload_on_success(response[1]);
                } else {
                    console.log(response[1]);
                }
            });
        });

        $(admin).on('click', '.sb-accordion > div > span', function (e) {
            let parent = $(this).parent();
            let active = $(parent).sbActive();
            if (!$(e.target).is('span')) return;
            parent.siblings().sbActivate(false);
            parent.sbActivate(!active);
        });

        $(admin).on('mousedown', function (e) {
            if ($(SBAdmin.open_popup).length) {
                let popup = $(SBAdmin.open_popup);
                if (!popup.is(e.target) && popup.has(e.target).length === 0 && !['sb-btn-saved-replies', 'sb-btn-emoji'].includes($(e.target).attr('class'))) {
                    if (popup.hasClass('sb-popup')) popup.sbTogglePopup();
                    else if (popup.hasClass('sb-select')) popup.find('ul').sbActivate(false);
                    else if (popup.hasClass('sb-menu-mobile')) popup.find('i').sbActivate(false);
                    else if (popup.hasClass('sb-menu')) popup.sbActivate(false);
                    else admin.sbHideLightbox();
                    SBAdmin.open_popup = false;
                }
            }
        });
    });

    function initialization() {
        SBF.ajax({
            function: 'get-conversations',
            routing: SB_ADMIN_SETTINGS['routing'],
            routing_unassigned: SB_ADMIN_SETTINGS['assign-conversation-to-agent']
        }, (response) => {
            if (response.length == 0) {
                conversations_area.find('.sb-board').addClass('sb-no-conversation');
            }
            SBConversations.populateList(response);
            if (responsive) {
                conversations_area.find('.sb-admin-list').sbActivate();
            }
            if (SBF.getURL('conversation')) {
                if (!conversations_area.sbActive()) header.find('.sb-admin-nav #sb-conversations').click();
                SBConversations.openConversation(SBF.getURL('conversation'));
            } else if (!responsive && !SBF.getURL('user') && !SBF.getURL('setting') && !SBF.getURL('report') && (!SBF.getURL('area') || SBF.getURL('area') == 'conversations')) {
                SBConversations.clickFirst();
            }
            SBConversations.startRealTime();
            SBConversations.datetime_last_conversation = SB_ADMIN_SETTINGS['now-db'];
            loadingGlobal(false);
        });
        SBPusher.initServiceWorker();
        if (SB_ADMIN_SETTINGS['push-notifications']) {
            SBPusher.initPushNotifications();
        }
    }

}(jQuery));

// tinyColorPicker v1.1.1 2016-08-30 

!function (a, b) { "object" == typeof exports ? module.exports = b(a) : "function" == typeof define && define.amd ? define("colors", [], function () { return b(a) }) : a.Colors = b(a) }(this, function (a, b) { "use strict"; function c(a, c, d, f, g) { if ("string" == typeof c) { var c = v.txt2color(c); d = c.type, p[d] = c[d], g = g !== b ? g : c.alpha } else if (c) for (var h in c) a[d][h] = k(c[h] / l[d][h][1], 0, 1); return g !== b && (a.alpha = k(+g, 0, 1)), e(d, f ? a : b) } function d(a, b, c) { var d = o.options.grey, e = {}; return e.RGB = { r: a.r, g: a.g, b: a.b }, e.rgb = { r: b.r, g: b.g, b: b.b }, e.alpha = c, e.equivalentGrey = n(d.r * a.r + d.g * a.g + d.b * a.b), e.rgbaMixBlack = i(b, { r: 0, g: 0, b: 0 }, c, 1), e.rgbaMixWhite = i(b, { r: 1, g: 1, b: 1 }, c, 1), e.rgbaMixBlack.luminance = h(e.rgbaMixBlack, !0), e.rgbaMixWhite.luminance = h(e.rgbaMixWhite, !0), o.options.customBG && (e.rgbaMixCustom = i(b, o.options.customBG, c, 1), e.rgbaMixCustom.luminance = h(e.rgbaMixCustom, !0), o.options.customBG.luminance = h(o.options.customBG, !0)), e } function e(a, b) { var c, e, k, q = b || p, r = v, s = o.options, t = l, u = q.RND, w = "", x = "", y = { hsl: "hsv", rgb: a }, z = u.rgb; if ("alpha" !== a) { for (var A in t) if (!t[A][A]) { a !== A && (x = y[A] || "rgb", q[A] = r[x + "2" + A](q[x])), u[A] || (u[A] = {}), c = q[A]; for (w in c) u[A][w] = n(c[w] * t[A][w][1]) } z = u.rgb, q.HEX = r.RGB2HEX(z), q.equivalentGrey = s.grey.r * q.rgb.r + s.grey.g * q.rgb.g + s.grey.b * q.rgb.b, q.webSave = e = f(z, 51), q.webSmart = k = f(z, 17), q.saveColor = z.r === e.r && z.g === e.g && z.b === e.b ? "web save" : z.r === k.r && z.g === k.g && z.b === k.b ? "web smart" : "", q.hueRGB = v.hue2RGB(q.hsv.h), b && (q.background = d(z, q.rgb, q.alpha)) } var B, C, D, E = q.rgb, F = q.alpha, G = "luminance", H = q.background; return B = i(E, { r: 0, g: 0, b: 0 }, F, 1), B[G] = h(B, !0), q.rgbaMixBlack = B, C = i(E, { r: 1, g: 1, b: 1 }, F, 1), C[G] = h(C, !0), q.rgbaMixWhite = C, s.customBG && (D = i(E, H.rgbaMixCustom, F, 1), D[G] = h(D, !0), D.WCAG2Ratio = j(D[G], H.rgbaMixCustom[G]), q.rgbaMixBGMixCustom = D, D.luminanceDelta = m.abs(D[G] - H.rgbaMixCustom[G]), D.hueDelta = g(H.rgbaMixCustom, D, !0)), q.RGBLuminance = h(z), q.HUELuminance = h(q.hueRGB), s.convertCallback && s.convertCallback(q, a), q } function f(a, b) { var c = {}, d = 0, e = b / 2; for (var f in a) d = a[f] % b, c[f] = a[f] + (d > e ? b - d : -d); return c } function g(a, b, c) { return (m.max(a.r - b.r, b.r - a.r) + m.max(a.g - b.g, b.g - a.g) + m.max(a.b - b.b, b.b - a.b)) * (c ? 255 : 1) / 765 } function h(a, b) { for (var c = b ? 1 : 255, d = [a.r / c, a.g / c, a.b / c], e = o.options.luminance, f = d.length; f--;)d[f] = d[f] <= .03928 ? d[f] / 12.92 : m.pow((d[f] + .055) / 1.055, 2.4); return e.r * d[0] + e.g * d[1] + e.b * d[2] } function i(a, c, d, e) { var f = {}, g = d !== b ? d : 1, h = e !== b ? e : 1, i = g + h * (1 - g); for (var j in a) f[j] = (a[j] * g + c[j] * h * (1 - g)) / i; return f.a = i, f } function j(a, b) { var c = 1; return c = a >= b ? (a + .05) / (b + .05) : (b + .05) / (a + .05), n(100 * c) / 100 } function k(a, b, c) { return a > c ? c : b > a ? b : a } var l = { rgb: { r: [0, 255], g: [0, 255], b: [0, 255] }, hsv: { h: [0, 360], s: [0, 100], v: [0, 100] }, hsl: { h: [0, 360], s: [0, 100], l: [0, 100] }, alpha: { alpha: [0, 1] }, HEX: { HEX: [0, 16777215] } }, m = a.Math, n = m.round, o = {}, p = {}, q = { r: .298954, g: .586434, b: .114612 }, r = { r: .2126, g: .7152, b: .0722 }, s = function (a) { this.colors = { RND: {} }, this.options = { color: "rgba(0,0,0,0)", grey: q, luminance: r, valueRanges: l }, t(this, a || {}) }, t = function (a, d) { var e, f = a.options; u(a); for (var g in d) d[g] !== b && (f[g] = d[g]); e = f.customBG, f.customBG = "string" == typeof e ? v.txt2color(e).rgb : e, p = c(a.colors, f.color, b, !0) }, u = function (a) { o !== a && (o = a, p = a.colors) }; s.prototype.setColor = function (a, d, f) { return u(this), a ? c(this.colors, a, d, b, f) : (f !== b && (this.colors.alpha = k(f, 0, 1)), e(d)) }, s.prototype.setCustomBackground = function (a) { return u(this), this.options.customBG = "string" == typeof a ? v.txt2color(a).rgb : a, c(this.colors, b, "rgb") }, s.prototype.saveAsBackground = function () { return u(this), c(this.colors, b, "rgb", !0) }, s.prototype.toString = function (a, b) { return v.color2text((a || "rgb").toLowerCase(), this.colors, b) }; var v = { txt2color: function (a) { var b = {}, c = a.replace(/(?:#|\)|%)/g, "").split("("), d = (c[1] || "").split(/,\s*/), e = c[1] ? c[0].substr(0, 3) : "rgb", f = ""; if (b.type = e, b[e] = {}, c[1]) for (var g = 3; g--;)f = e[g] || e.charAt(g), b[e][f] = +d[g] / l[e][f][1]; else b.rgb = v.HEX2rgb(c[0]); return b.alpha = d[3] ? +d[3] : 1, b }, color2text: function (a, b, c) { var d = c !== !1 && n(100 * b.alpha) / 100, e = "number" == typeof d && c !== !1 && (c || 1 !== d), f = b.RND.rgb, g = b.RND.hsl, h = "hex" === a && e, i = "hex" === a && !h, j = "rgb" === a || h, k = j ? f.r + ", " + f.g + ", " + f.b : i ? "#" + b.HEX : g.h + ", " + g.s + "%, " + g.l + "%"; return i ? k : (h ? "rgb" : a) + (e ? "a" : "") + "(" + k + (e ? ", " + d : "") + ")" }, RGB2HEX: function (a) { return ((a.r < 16 ? "0" : "") + a.r.toString(16) + (a.g < 16 ? "0" : "") + a.g.toString(16) + (a.b < 16 ? "0" : "") + a.b.toString(16)).toUpperCase() }, HEX2rgb: function (a) { return a = a.split(""), { r: +("0x" + a[0] + a[a[3] ? 1 : 0]) / 255, g: +("0x" + a[a[3] ? 2 : 1] + (a[3] || a[1])) / 255, b: +("0x" + (a[4] || a[2]) + (a[5] || a[2])) / 255 } }, hue2RGB: function (a) { var b = 6 * a, c = ~~b % 6, d = 6 === b ? 0 : b - c; return { r: n(255 * [1, 1 - d, 0, 0, d, 1][c]), g: n(255 * [d, 1, 1, 1 - d, 0, 0][c]), b: n(255 * [0, 0, d, 1, 1, 1 - d][c]) } }, rgb2hsv: function (a) { var b, c, d, e = a.r, f = a.g, g = a.b, h = 0; return g > f && (f = g + (g = f, 0), h = -1), c = g, f > e && (e = f + (f = e, 0), h = -2 / 6 - h, c = m.min(f, g)), b = e - c, d = e ? b / e : 0, { h: 1e-15 > d ? p && p.hsl && p.hsl.h || 0 : b ? m.abs(h + (f - g) / (6 * b)) : 0, s: e ? b / e : p && p.hsv && p.hsv.s || 0, v: e } }, hsv2rgb: function (a) { var b = 6 * a.h, c = a.s, d = a.v, e = ~~b, f = b - e, g = d * (1 - c), h = d * (1 - f * c), i = d * (1 - (1 - f) * c), j = e % 6; return { r: [d, h, g, g, i, d][j], g: [i, d, d, h, g, g][j], b: [g, g, i, d, d, h][j] } }, hsv2hsl: function (a) { var b = (2 - a.s) * a.v, c = a.s * a.v; return c = a.s ? 1 > b ? b ? c / b : 0 : c / (2 - b) : 0, { h: a.h, s: a.v || c ? c : p && p.hsl && p.hsl.s || 0, l: b / 2 } }, rgb2hsl: function (a, b) { var c = v.rgb2hsv(a); return v.hsv2hsl(b ? c : p.hsv = c) }, hsl2rgb: function (a) { var b = 6 * a.h, c = a.s, d = a.l, e = .5 > d ? d * (1 + c) : d + c - c * d, f = d + d - e, g = e ? (e - f) / e : 0, h = ~~b, i = b - h, j = e * g * i, k = f + j, l = e - j, m = h % 6; return { r: [e, l, f, f, k, e][m], g: [k, e, e, l, f, f][m], b: [f, f, k, e, e, l][m] } } }; return s }), function (a, b) { "object" == typeof exports ? module.exports = b(a, require("jquery"), require("colors")) : "function" == typeof define && define.amd ? define(["jquery", "colors"], function (c, d) { return b(a, c, d) }) : b(a, a.jQuery, a.Colors) }(this, function (a, b, c, d) { "use strict"; function e(a) { return a.value || a.getAttribute("value") || b(a).css("background-color") || "#FFF" } function f(a) { return a = a.originalEvent && a.originalEvent.touches ? a.originalEvent.touches[0] : a, a.originalEvent ? a.originalEvent : a } function g(a) { return b(a.find(r.doRender)[0] || a[0]) } function h(c) { var d = b(this), f = d.offset(), h = b(a), k = r.gap; c ? (s = g(d), s._colorMode = s.data("colorMode"), p.$trigger = d, (t || i()).css(r.positionCallback.call(p, d) || { left: (t._left = f.left) - ((t._left += t._width - (h.scrollLeft() + h.width())) + k > 0 ? t._left + k : 0), top: (t._top = f.top + d.outerHeight()) - ((t._top += t._height - (h.scrollTop() + h.height())) + k > 0 ? t._top + k : 0) }).show(r.animationSpeed, function () { c !== !0 && (y.toggle(!!r.opacity)._width = y.width(), v._width = v.width(), v._height = v.height(), u._height = u.height(), q.setColor(e(s[0])), n(!0)) }).off(".tcp").on(D, ".cp-xy-slider,.cp-z-slider,.cp-alpha", j)) : p.$trigger && b(t).hide(r.animationSpeed, function () { n(!1), p.$trigger = null }).off(".tcp") } function i() { return b("head")[r.cssPrepend ? "prepend" : "append"]('<style type="text/css" id="tinyColorPickerStyles">' + (r.css || I) + (r.cssAddon || "") + "</style>"), b(H).css({ margin: r.margin }).appendTo("body").show(0, function () { p.$UI = t = b(this), F = r.GPU && t.css("perspective") !== d, u = b(".cp-z-slider", this), v = b(".cp-xy-slider", this), w = b(".cp-xy-cursor", this), x = b(".cp-z-cursor", this), y = b(".cp-alpha", this), z = b(".cp-alpha-cursor", this), r.buildCallback.call(p, t), t.prepend("<div>").children().eq(0).css("width", t.children().eq(0).width()), t._width = this.offsetWidth, t._height = this.offsetHeight }).hide() } function j(a) { var c = this.className.replace(/cp-(.*?)(?:\s*|$)/, "$1").replace("-", "_"); (a.button || a.which) > 1 || (a.preventDefault && a.preventDefault(), a.returnValue = !1, s._offset = b(this).offset(), (c = "xy_slider" === c ? k : "z_slider" === c ? l : m)(a), n(), A.on(E, function () { A.off(".tcp") }).on(C, function (a) { c(a), n() })) } function k(a) { var b = f(a), c = b.pageX - s._offset.left, d = b.pageY - s._offset.top; q.setColor({ s: c / v._width * 100, v: 100 - d / v._height * 100 }, "hsv") } function l(a) { var b = f(a).pageY - s._offset.top; q.setColor({ h: 360 - b / u._height * 360 }, "hsv") } function m(a) { var b = f(a).pageX - s._offset.left, c = b / y._width; q.setColor({}, "rgb", c) } function n(a) { var b = q.colors, c = b.hueRGB, e = (b.RND.rgb, b.RND.hsl, r.dark), f = r.light, g = q.toString(s._colorMode, r.forceAlpha), h = b.HUELuminance > .22 ? e : f, i = b.rgbaMixBlack.luminance > .22 ? e : f, j = (1 - b.hsv.h) * u._height, k = b.hsv.s * v._width, l = (1 - b.hsv.v) * v._height, m = b.alpha * y._width, n = F ? "translate3d" : "", p = s[0].value, t = s[0].hasAttribute("value") && "" === p && a !== d; v._css = { backgroundColor: "rgb(" + c.r + "," + c.g + "," + c.b + ")" }, w._css = { transform: n + "(" + k + "px, " + l + "px, 0)", left: F ? "" : k, top: F ? "" : l, borderColor: b.RGBLuminance > .22 ? e : f }, x._css = { transform: n + "(0, " + j + "px, 0)", top: F ? "" : j, borderColor: "transparent " + h }, y._css = { backgroundColor: "#" + b.HEX }, z._css = { transform: n + "(" + m + "px, 0, 0)", left: F ? "" : m, borderColor: i + " transparent" }, s._css = { backgroundColor: t ? "" : g, color: t ? "" : b.rgbaMixBGMixCustom.luminance > .22 ? e : f }, s.text = t ? "" : p !== g ? g : "", a !== d ? o(a) : G(o) } function o(a) { v.css(v._css), w.css(w._css), x.css(x._css), y.css(y._css), z.css(z._css), r.doRender && s.css(s._css), s.text && s.val(s.text), r.renderCallback.call(p, s, "boolean" == typeof a ? a : d) } var p, q, r, s, t, u, v, w, x, y, z, A = b(document), B = b(), C = "touchmove.tcp mousemove.tcp pointermove.tcp", D = "touchstart.tcp mousedown.tcp pointerdown.tcp", E = "touchend.tcp mouseup.tcp pointerup.tcp", F = !1, G = a.requestAnimationFrame || a.webkitRequestAnimationFrame || function (a) { a() }, H = '<div class="cp-color-picker"><div class="cp-z-slider"><div class="cp-z-cursor"></div></div><div class="cp-xy-slider"><div class="cp-white"></div><div class="cp-xy-cursor"></div></div><div class="cp-alpha"><div class="cp-alpha-cursor"></div></div></div>', I = ".cp-color-picker{position:absolute;overflow:hidden;padding:6px 6px 0;background-color:#444;color:#bbb;font-family:Arial,Helvetica,sans-serif;font-size:12px;font-weight:400;cursor:default;border-radius:5px}.cp-color-picker>div{position:relative;overflow:hidden}.cp-xy-slider{float:left;height:128px;width:128px;margin-bottom:6px;background:linear-gradient(to right,#FFF,rgba(255,255,255,0))}.cp-white{height:100%;width:100%;background:linear-gradient(rgba(0,0,0,0),#000)}.cp-xy-cursor{position:absolute;top:0;width:10px;height:10px;margin:-5px;border:1px solid #fff;border-radius:100%;box-sizing:border-box}.cp-z-slider{float:right;margin-left:6px;height:128px;width:20px;background:linear-gradient(red 0,#f0f 17%,#00f 33%,#0ff 50%,#0f0 67%,#ff0 83%,red 100%)}.cp-z-cursor{position:absolute;margin-top:-4px;width:100%;border:4px solid #fff;border-color:transparent #fff;box-sizing:border-box}.cp-alpha{clear:both;width:100%;height:16px;margin:6px 0;background:linear-gradient(to right,#444,rgba(0,0,0,0))}.cp-alpha-cursor{position:absolute;margin-left:-4px;height:100%;border:4px solid #fff;border-color:#fff transparent;box-sizing:border-box}", J = function (a) { q = this.color = new c(a), r = q.options, p = this }; J.prototype = { render: n, toggle: h }, b.fn.colorPicker = function (c) { var d = this, f = function () { }; return c = b.extend({ animationSpeed: 150, GPU: !0, doRender: !0, customBG: "#FFF", opacity: !0, renderCallback: f, buildCallback: f, positionCallback: f, body: document.body, scrollResize: !0, gap: 4, dark: "#222", light: "#DDD" }, c), !p && c.scrollResize && b(a).on("resize.tcp scroll.tcp", function () { p.$trigger && p.toggle.call(p.$trigger[0], !0) }), B = B.add(this), this.colorPicker = p || new J(c), this.options = c, b(c.body).off(".tcp").on(D, function (a) { -1 === B.add(t).add(b(t).find(a.target)).index(a.target) && h() }), this.on("focusin.tcp click.tcp", function (a) { p.color.options = b.extend(p.color.options, r = d.options), h.call(this, a) }).on("change.tcp", function () { q.setColor(this.value || "#FFF"), d.colorPicker.render(!0) }).each(function () { var a = e(this), d = a.split("("), f = g(b(this)); f.data("colorMode", d[1] ? d[0].substr(0, 3) : "HEX").attr("readonly", r.preventFocus), c.doRender && f.css({ "background-color": a, color: function () { return q.setColor(a).rgbaMixBGMixCustom.luminance > .22 ? c.dark : c.light } }) }) }, b.fn.colorPicker.destroy = function () { b("*").off(".tcp"), p.toggle(!1), B = b() } });

Youez - 2016 - github.com/yon3zu
LinuXploit