/* Solaron Omnichannel — O2 Inbox (native grid) & Conversation JS. * The inbox is a native list_fields grid; reload re-posts the paging/sort/search * form to omnichannel_getInbox. Conversation detail opens in a dynamic window * (the sdesk/ccenter pattern). Posts go to the relative 'action.php' (a module * .js.php is served without a session — never reference $_SESSION here unguarded). */ var omni_csrf = (typeof omni_csrf !== 'undefined') ? omni_csrf : ''; var omni_form_name = (typeof omni_form_name !== 'undefined') ? omni_form_name : 'form_omni_inbox'; var omni_current_cid = 0; function omnichannel_region() { return 'ui-layout-center'; } /* ---- native grid reload ---- */ function omnichannel_inboxParams(action) { var par = 'action=' + action; var fields = ['page_selected', 'page_limit', 'page_sort', 'page_sort_desc', 'page_search_string', 'page_filter_id', 'page_filter_field', 'omni_view', 'f_channel', 'f_department', 'f_employee', 'f_customer', 'f_sale', 'f_status', 'f_participant']; for (var i = 0; i < fields.length; i++) { var sel = 'form[name=' + omni_form_name + '] input#' + fields[i]; if ($(sel).length) { par += '&' + fields[i] + '=' + encodeURIComponent($(sel).val()); } } return par; } /* Landing = the Dashboard (primary start page). Called by the module menu + reused as the Dashboard nav button. */ function omnichannel_getList() { actionController('action=omnichannel_getDashboard', omnichannel_region()); } /* Open the Inbox fresh (from the Dashboard / nav) — resets view, filter, search, page, and advanced filters. */ function omnichannel_openInbox() { actionController('action=omnichannel_getInbox&omni_view=all&page_filter_field=&page_filter_id=0&page_search_string=&page_selected=1&omni_reset=1', omnichannel_region()); } /* Open the Inbox on a specific quick-view (all/mine/unassigned/unread). */ function omnichannel_openInboxView(v) { actionController('action=omnichannel_getInbox&omni_view=' + encodeURIComponent(v) + '&page_filter_field=&page_filter_id=0&page_search_string=&page_selected=1', omnichannel_region()); } /* Open the Inbox filtered by a conversation status code (native column filter). */ function omnichannel_openInboxStatus(code) { actionController('action=omnichannel_getInbox&omni_view=all&page_filter_field=omnichannel_status&page_filter_id=' + encodeURIComponent(code) + '&page_search_string=&page_selected=1', omnichannel_region()); } /* Inbox grid reload (sort/filter/search/paging round-trip). */ function omnichannel_reloadInbox() { actionController(omnichannel_inboxParams('omnichannel_getInbox'), omnichannel_region()); } /* O1 foundation status page (still available, technical). */ function omnichannel_getFoundation() { actionController('action=omnichannel_getList', omnichannel_region()); } /* Inbox quick-view filters (All/Mine/Unassigned/Unread) — stay in the Inbox. */ function omnichannel_setView(v) { var f = 'form[name=' + omni_form_name + '] input#'; $(f + 'omni_view').val(v); $(f + 'page_selected').val('1'); omnichannel_reloadInbox(); } function omnichannel_resetInbox() { var f = 'form[name=' + omni_form_name + '] input#'; $(f + 'omni_view').val('all'); $(f + 'page_search_string').val(''); $(f + 'page_filter_id').val('0'); $(f + 'page_filter_field').val(''); $(f + 'page_selected').val('1'); ['f_channel', 'f_department', 'f_employee', 'f_customer', 'f_sale', 'f_status', 'f_participant'].forEach(function (n) { $(f + n).val(''); }); omnichannel_reloadInbox(); } /* Reload whichever primary screen is currently shown (Inbox grid vs Dashboard). */ function omnichannel_refreshCurrent() { if ($('form[name=form_omni_inbox]').length) { omnichannel_reloadInbox(); } else { omnichannel_getList(); } } /* ---- O7.1.5 Inbox advanced filters (native, server-side, combinable) ---- All six controls are native ChosenSelects (Channel/Status/Department/Employee = local option sets; Customer/Sale = REMOTE searchable selects, options fetched on typing and scoped to the user's CRM visibility + the dependency chain). On change each control's value is mirrored into the hidden f_* field and the grid reloads (omnichannel_inboxParams serialises them → one server query; paging/sort/ open-close preserve them). The value is always a real id (or 'unassigned'), never free text. */ function omnichannel_setHidden(name, val) { $('form[name=' + omni_form_name + '] input#' + name).val(val == null ? '' : val); } function omnichannel_selVal(id) { var v = $('#' + id).val(); return (v == null) ? '' : ('' + v); } function omnichannel_applyInboxFilters() { omnichannel_setHidden('f_channel', omnichannel_selVal('omni-f-channel')); omnichannel_setHidden('f_status', omnichannel_selVal('omni-f-status')); omnichannel_setHidden('f_department', omnichannel_selVal('omni-f-department')); omnichannel_setHidden('f_employee', omnichannel_selVal('omni-f-employee')); omnichannel_setHidden('f_customer', omnichannel_selVal('omni-f-customer')); omnichannel_setHidden('f_sale', omnichannel_selVal('omni-f-sale')); omnichannel_setHidden('f_participant', $('#omni-f-participant').val() || ''); omnichannel_setHidden('page_selected', '1'); // filters changed materially → back to page 1 (§12) omnichannel_reloadInbox(); } function omnichannel_clearInboxFilters() { // clear the visible Chosen selects + the participant text + the hidden ids; keep grid prefs + view (§8) $('#omni-f-channel,#omni-f-status,#omni-f-department,#omni-f-employee,#omni-f-customer,#omni-f-sale').val('').trigger('chosen:updated'); $('#omni-f-participant').val(''); ['f_channel', 'f_status', 'f_department', 'f_employee', 'f_customer', 'f_sale', 'f_participant'].forEach(function (n) { omnichannel_setHidden(n, ''); }); omnichannel_setHidden('page_selected', '1'); omnichannel_reloadInbox(); } // current numeric value of a visible filter select ('unassigned'/'' → 0) function omnichannel_selInt(id) { return parseInt($('#' + id).val() || '0', 10) || 0; } /* Wire a native Chosen single-select to a REMOTE, CRM-scoped, dependency-scoped source (searchLinkTarget). Typing in the Chosen search box fetches a bounded result set (never the whole table) and rebuilds the options, preserving the current selection. scopeFn() adds the dependency params (employee→customer, customer→sale); scope:'crm' makes the server restrict to the user's CRM visibility. */ function omnichannel_initFilterRemoteChosen(selectId, type, scopeFn) { var $sel = $('#' + selectId); if (!$sel.length || $sel.data('omni-remote')) { return; } $sel.data('omni-remote', 1); var $container = $sel.next('.chosen-container'); if (!$container.length) { return; } var $search = $container.find('.chosen-search input, .chosen-search-input').first(); if (!$search.length) { $search = $container.find('input[type=text]').first(); } var timer = null; $search.on('keyup.omnifilter', function () { var term = $.trim($(this).val()); clearTimeout(timer); if (term.length < 2) { return; } timer = setTimeout(function () { var data = { action: 'omnichannel_searchLinkTarget', target: type, q: term, scope: 'crm' }; var scope = scopeFn() || {}; for (var k in scope) { if (scope.hasOwnProperty(k)) { data[k] = scope[k]; } } $.post('action.php', data, function (r) { var j; try { j = (typeof r === 'string') ? JSON.parse(r) : r; } catch (e) { return; } var curVal = String($sel.val() || ''); var curText = curVal ? $sel.find('option[value="' + curVal + '"]').text() : ''; var opts = ''; if (curVal) { opts += '