////////////////////////////////////////////////// // Lists Submodule for Callflows // @copyright 2024 RuhNet https://ruhnet.co // @author Ruel Tmeizeh // // Derived from blacklist submodule. // cb_lists Crossbar module must be loaded: // sup crossbar_maintenance start_module cb_lists // ////////////////////////////////////////////////// define(function(require) { var $ = require('jquery'), _ = require('lodash'), monster = require('monster'); var app = { requests: {}, subscribe: { 'callflows.lists.edit': 'listsEdit', 'callflows.fetchActions': 'listsDefineActions' }, // Defines API requests not included in the SDK requests: { 'lists.list': { 'apiRoot': monster.config.api.default, 'url': 'accounts/{accountId}/lists', 'verb': 'GET' }, 'lists.get': { 'apiRoot': monster.config.api.default, 'url': 'accounts/{accountId}/lists/{listId}', 'verb': 'GET' }, 'lists.create': { 'apiRoot': monster.config.api.default, 'url': 'accounts/{accountId}/lists', 'verb': 'PUT' }, 'lists.delete': { 'apiRoot': monster.config.api.default, 'url': 'accounts/{accountId}/lists/{listId}', 'verb': 'DELETE' }, 'lists.getEntries': { 'apiRoot': monster.config.api.default, 'url': 'accounts/{accountId}/lists/{listId}/entries', 'verb': 'GET' }, 'lists.addEntry': { 'apiRoot': monster.config.api.default, 'url': 'accounts/{accountId}/lists/{listId}/entries', 'verb': 'PUT' }, 'lists.updateEntry': { 'apiRoot': monster.config.api.default, 'url': 'accounts/{accountId}/lists/{listId}/entries/{listEntryId}', 'verb': 'PATCH' }, 'lists.deleteEntry': { 'apiRoot': monster.config.api.default, 'url': 'accounts/{accountId}/lists/{listId}/entries/{listEntryId}', 'verb': 'DELETE' } }, listsDefineActions: function(args) { var self = this, callflow_nodes = args.actions; $.extend(callflow_nodes, { 'lists': { name: self.i18n.active().callflows.lists.title, module: 'lists', listEntities: function(callback) { monster.request({ resource: "lists.list", data: { accountId: self.accountId, }, success: function(res) { callback && callback(res.data); }, error: function(res) { if (res.status == 404) { callback([]); //Populate results with nothing } else if (res.status == 401) { monster.util.logoutAndReload(); } else { monster.ui.alert("ERROR: Failed to get lists: " + parsedError); callback([]); //Populate results with nothing } } }); }, editEntity: 'callflows.lists.edit' } }); }, // Added for the subscribed event to avoid refactoring conferenceEdit listsEdit: function(args) { //console.log(args); var self = this, afterGetData = function(data) { var template = $(self.getTemplate({ name: 'edit', data: data, submodule: 'lists' })), listsForm = template.find('#lists-form'), $listNumbers = template.find('.saved-numbers'); monster.ui.validate(listsForm, { rules: { 'name': { required: true } } }); _.each(data.entries, function(entry) { entry['state'] = 'saved'; $listNumbers.append($(self.getTemplate({ name: 'addNumber', data: entry, submodule: 'lists' }))); }); self.listsBindEvents(data, template, args.callbacks); (args.target) .empty() .append(template); }; if (args.data.id) { self.listsGet(args.data.id, function(data) { afterGetData(data); //data = {id: listid, name: listname, entries: [entry1,entry2,...]} }); } else { afterGetData({}); } }, listsBindEvents: function(data, template, callbacks) { var self = this, addNumber = function(e) { var number = template.find('#number_value').val(); var list_id = template.find('#active-list').attr('data-listid'); if (number) { var entryData = { number: number, }; $('.list-numbers .saved-numbers', template) .prepend($(self.getTemplate({ name: 'addNumber', data: { key: list_id ? list_id : null, id: null, state: 'pending-add', value: { number: number, }, }, submodule: 'lists' }))); $('#number_value', template).val(''); } }; $('.number-wrapper.placeholder:not(.active)', template).click(function() { var $this = $(this); $this.addClass('active'); $('#number_value', template).focus(); }); $('#add_number', template).click(function(e) { e.preventDefault(); addNumber(); }); $('.add-number', template).bind('keypress', function(e) { var code = e.keyCode || e.which; if (code === 13) { addNumber(e); } }); $(template).delegate('.delete-number', 'click', function(e) { if ($(this).parents('.number-wrapper').data('state') == 'pending-add') { //if this has just been added and not saved, remove it $(this).parents('.number-wrapper').remove(); } else { //toggle background red to signify that it will be deleted when save is clicked if ($(this).parents('.number-wrapper').hasClass('pending-delete')) { $(this).parents('.number-wrapper').removeClass('pending-delete'); $(this).parents('.number-wrapper').css('background-color',''); $(this).parents('.number-wrapper').attr('data-state', 'saved'); } else { $(this).parents('.number-wrapper').addClass('pending-delete'); $(this).parents('.number-wrapper').attr('data-state', 'pending-delete'); $(this).parents('.number-wrapper').css('background-color','#B91B0C'); } } }); $('#cancel_number', template).click(function(e) { e.stopPropagation(); $('.number-wrapper.placeholder.active', template).removeClass('active'); $('#number_value', template).val(''); }); $('.lists-save', template).click(function() { var formData = monster.ui.getFormData('blacklist-form'), cleanData = self.listsCleanFormData(formData), entries = []; $('.saved-numbers .number-wrapper', template).each(function(k, wrapper) { entry = { list_id: $(wrapper).attr('data-listid'), id: $(wrapper).attr('id'), number: $(wrapper).attr('data-number'), state: $(wrapper).attr('data-state'), } entries.push(entry); }); cleanData.entries = entries; if (data.id) { cleanData.id = data.id; } self.listsSave(cleanData, callbacks.save_success); }); $('.lists-delete', template).click(function() { monster.ui.confirm(self.i18n.active().callflows.lists.are_you_sure_you_want_to_delete, function() { self.listsDelete(data.id, callbacks.delete_success); }); }); }, listsCleanFormData: function(data) { delete data.extra; return data; }, listsSave: function(data, callback) { var self = this; if (data.id) { self.listsUpdate(data, callback); } else { var newListData = { name: data.name }; self.listsCreate(newListData, function(createdListData) { data.id = createdListData.id; self.listsUpdate(data, callback); }); } }, listsList: function(callback) { var self = this; monster.request({ resource: "lists.list", data: { accountId: self.accountId, }, success: function(res) { callback && callback(res.data); }, error: function(res) { if (res.status == 404) { callback([]); //Populate results with nothing } else if (res.status == 401) { monster.util.logoutAndReload(); } else { monster.ui.alert("ERROR: Failed to get lists: " + parsedError); callback([]); //Populate results with nothing } } }); }, listsGet: function(id, callback) { var self = this; monster.request({ resource: "lists.get", data: { accountId: self.accountId, listId: id, }, success: function(data) { listprops = data.data; monster.request({ resource: "lists.getEntries", data: { accountId: self.accountId, listId: id, }, success: function(res) { var listdata = { id: listprops.id, name: listprops.name, entries: res.data }; callback && callback(listdata); }, error: function(res) { if (res.status == 404) { callback([]); //Populate results with nothing } else if (res.status == 401) { monster.util.logoutAndReload(); } else { monster.ui.alert("ERROR: Failed to get list entries from list " + id + ": " + parsedError); callback([]); //Populate results with nothing } } }); }, error: function(res) { if (res.status == 404) { callback([]); //Populate results with nothing } else if (res.status == 401) { monster.util.logoutAndReload(); } else { monster.ui.alert("ERROR: Failed to get list " + id + ": " + parsedError); callback([]); //Populate results with nothing } } }); }, listsCreate: function(data, callback) { var self = this; monster.request({ resource: "lists.create", data: { accountId: self.accountId, data: data, }, success: function(res) { callback && callback(res.data); }, error: function(res) { if (res.status == 404) { callback([]); } else if (res.status == 401) { monster.util.logoutAndReload(); } else { monster.ui.alert("ERROR: Failed to create list: " + parsedError); callback([]); } } }); }, listsAddEntry: function(data, callback) { var self = this; monster.request({ resource: "lists.addEntry", data: { listId: data.list_id, accountId: self.accountId, data: { number: data.number, }, }, success: function(res) { callback && callback(res.data); }, error: function(res) { if (res.status == 404) { callback([]); } else if (res.status == 401) { monster.util.logoutAndReload(); } else { monster.ui.alert("ERROR: Failed to add number to list: " + parsedError); callback([]); } } }); }, listsUpdate: function(data, callback) { var self = this; var entrySaves = _.map(data.entries, function(entry) { if (!entry.list_id) entry.list_id = data.id; if (entry.state == 'pending-add') { self.listsAddEntry(entry, function(data) { //console.log("Added entry: "); console.log(data); }); entry.state = 'saved'; } else if ((entry.state == 'pending-delete') && entry.id) { self.listsDeleteEntry(entry, function(data) { //console.log("Deleted entry: "); console.log(data); }); entry.state = 'deleted'; } return entry; }); console.log(entrySaves); callback(entrySaves); }, listsDeleteEntry: function(data, callback) { var self = this; console.log("listsDeleteEntry input data:"); console.log(data); monster.request({ resource: "lists.deleteEntry", data: { accountId: self.accountId, listId: data.list_id, listEntryId: data.id, }, success: function(res) { callback && callback(res.data); }, error: function(res) { if (res.status == 404) { callback([]); } else if (res.status == 401) { monster.util.logoutAndReload(); } else { monster.ui.alert("ERROR: Failed to add number to list: " + parsedError); callback([]); } } }); }, listsDelete: function(id, callback) { var self = this; monster.request({ resource: "lists.delete", data: { accountId: self.accountId, listId: id, }, success: function(res) { callback && callback(res.data); }, error: function(res) { if (res.status == 404) { callback([]); } else if (res.status == 401) { monster.util.logoutAndReload(); } else { monster.ui.alert("ERROR: Failed to add number to list: " + parsedError); callback([]); } } }); } }; return app; });