EmailCampaignEditor = function( campaignData, options ) { let instance = this; instance.height = 550; instance.readOnly = false; instance.cancelButton = null; instance.saveButton = null; instance.designButton = null; instance.executeNowButton = null; instance.sendTestEmailButton = null; instance.changes = null; instance.changeCount = 0; instance.intervalId = 0; instance.rootElement = $("
").addClass( "EmailCampaignEditor"); if( ! options ) { options = {}; } instance.options = $.extend( true, {}, { tabIndex : 0 }, options ); instance.campaignId = 0; if( campaignData && campaignData.campaignId ) { instance.campaignId = campaignData.campaignId; } instance.campaignData = null; instance.creatingNewCampaign = false; instance.tabPanel = null; if( instance.campaignId ) { instance.refreshEditor(); } else { let d = $.Deferred(); let waiting = false; instance.campaignData = { campaignId : 0, campaignType : campaignData.campaignType, emailFrom : Fse.Portal.appConfiguration.STP.userEmailAddress, emailFromDisplay : Fse.Portal.appConfiguration.STP.userFullName, emailSubject : null, useInternalContact : false, includeUnsubscribe : false, campaignName : null, gtmCampaignId : null } if( campaignData.gtmCampaignId ) { instance.campaignData.gtmCampaignId = campaignData.gtmCampaignId; instance.campaignData.emailFrom = campaignData.emailFrom; instance.campaignData.emailFromDisplay = campaignData.emailFromDisplay; instance.campaignData.emailSubject = campaignData.campaignName; instance.campaignData.campaignName = campaignData.campaignName; instance.getDataForGTMCampaign( campaignData.gtmCampaignId ).done( function( gtmCampaignData ) { if( Array.isArray( gtmCampaignData ) && gtmCampaignData.length ) { gtmCampaignData = gtmCampaignData[0]; } instance.campaignData.gtmCampaignName = gtmCampaignData.campaignName, instance.campaignData.gtmCampaignDescription = gtmCampaignData.campaignDescription, instance.campaignData.gtmCampaignManagerDisplay = gtmCampaignData.campaignManagerDisplay, instance.campaignData.gtmSalesManagerDisplay = gtmCampaignData.salesManagerDisplay, instance.campaignData.gtmLeadType = gtmCampaignData.leadType, instance.campaignData.gtmTargetPartnerType = gtmCampaignData.targetPartnerType, instance.campaignData.gtmTerritoryName = gtmCampaignData.territoryName d.resolve(); }) waiting = true; } if( campaignData.campaignName ) { instance.campaignData.campaignName = campaignData.campaignName; } instance.creatingNewCampaign = true; if( ! waiting ) { d.resolve(); } d.done( function() { instance.createUI( instance.campaignData, instance.options.tabIndex ); if( instance.creatingNewCampaign ) { instance.changes.insert( "newCampaign" ); } }) } } EmailCampaignEditor.prototype.gotoTab = function( tabTitle ) { let tabIndex = -1; let tabItems = this.tabPanel.option( "items" ); for( let ti = 0; ti < tabItems.length; ti++ ) { if( tabItems[ti].title === tabTitle ) { tabIndex = ti; break; } } if( tabIndex != -1 ) { this.tabPanel.option( "selectedIndex", tabIndex ); } } EmailCampaignEditor.prototype.constructor = EmailCampaignEditor; EmailCampaignEditor.prototype.prepareChanges = function() { let d = $.Deferred(); return d; } EmailCampaignEditor.prototype.saveChanges = function() { let instance = this; let saving = $.Deferred(); instance.changes.load().done( function( data ) { let changedTabs = {}; data.forEach( function( c ) { changedTabs[c.split(".")[0]] = true; }) let campaignData = { campaignId : instance.campaignData.campaignId, campaignType : instance.campaignData.campaignType, lastUpdatedDate : instance.campaignData.lastUpdatedDate }; let performSave = true; let partsToSave = []; let showSavingMessage = false; let changesReady = $.Deferred(); changesReady.progress( function( notify ) { changedTabs[notify.tab] = true; if( ! notify.data ) { performSave = false; } else { $.extend( campaignData, notify.data ); } let allTabsReady = true; for( let t in changedTabs ) { if( ! changedTabs[t] ) { allTabsReady = false; break; } } if( allTabsReady ) { changesReady.resolve( changedTabs ); } }); for( let t in changedTabs ) { let data = null; partsToSave.push( t ); switch ( t ) { case "details" : instance.getDetailsTabData().done( function( data ) { changesReady.notify( { tab : t, data : data } ); }); break; case "crmRecipients" : showSavingMessage = true; data = instance.getCRMRecipientsTabData(); changesReady.notify( { tab : t, data : data } ); break; case "stdRecipients" : data = instance.getStandardRecipientsTabData(); changesReady.notify( { tab : t, data : data } ); break; case "hyperlinks" : data = instance.getHyperlinksTabData(); changesReady.notify( { tab : t, data : data } ); break; case "defaults" : data = instance.getDefaultsTabData(); changesReady.notify( { tab : t, data : data } ); break; } } changesReady.done( function() { if( performSave ) { // show the wait box let savePanel = null; if( showSavingMessage ) { savePanel = $("
").dxLoadPanel( { message : "Saving...", shading : true, container : "body", onHidden : function( e ) { e.component.element().remove(); e.component.dispose(); } }).appendTo( $("body") ).dxLoadPanel("instance"); savePanel.show(); } let d = $.Deferred() .done( function( response ) { // close the wait box if( savePanel ) { savePanel.hide(); } if( ! response.success ) { instance.showSystemMessage( "warning", "Changes not saved. Probably due to a concurrent modification by another user or process. The Email campaign has been reloaded with fresh data." ); } instance.refreshEditor().done( function( refreshData ) { let campaignData = refreshData; if( campaignData.length ) { campaignData = campaignData[0]; } if( instance.options.campaignManager ) { if( instance.creatingNewCampaign ) { instance.creatingNewCampaign = false; instance.options.campaignManager.onCampaignCreated( campaignData ); } else { instance.options.campaignManager.onCampaignUpdated( campaignData ); } } }); saving.resolve(); }) .fail( function() { if( savePanel ) { savePanel.hide(); } instance.refreshEditor(); instance.showSystemMessage( "error", "An Error Occurred, Changes may not have saved. Please review and try again." ); saving.reject(); }) // do the save let saveURL = Fse.Util.updateURL2( $("link#appActionURL").attr( "href" ), { object : "GTM.saveEmailCampaign" } ); $.ajax( { url : saveURL, method : "post", data : { campaign : JSON.stringify( campaignData ), partsToSave : partsToSave.join( "," ) } }) .done( function( returnData ) { instance.campaignId = returnData.campaignId; d.resolve( returnData ); }) .fail( function() { d.reject(); }) } else { console.log( "Not Saving" ); saving.resolve(); } }) }) return saving; } EmailCampaignEditor.prototype.getDataForGTMCampaign = function( gtmCampaignId ) { // get the campaign data let campaignDataStore = Fse.Data.newDataSource( { object : "GTM.campaigns", keyField : "campaignId" }).store(); return campaignDataStore.byKey( gtmCampaignId ); } EmailCampaignEditor.prototype.resolveEmailSpoofing = function( data ) { let resolveEmailSpoofingURL = Fse.Util.updateURL2( $("link#appDataURL" ).attr( "href" ), { "object" : "GTM.resolveEmailSpoofing" }); return $.ajax( { url : resolveEmailSpoofingURL, method : "get", dataType : "json", data : { "emailFrom" : `${data.emailFromDisplay} <${data.emailFrom}>`, "emailSubject" : data.emailSubject } }).fail( function( x ) { console.log( "Fail X" ); console.log( x ) }) } EmailCampaignEditor.prototype.getDataForCampaign = function( campaignId ) { let instance = this; let data = null; let d = $.Deferred(); let waiting = 0; d.progress( function( notifyData ) { /* console.log( "PROGRESS" ); console.log( waiting ); console.log( notifyData ); */ if( data ) { // secondary data waiting--; if( notifyData.emailFrom ) { console.log( notifyData ); data.resolvedEmailFrom = notifyData.emailFrom; data.resolvedEmailSubject = notifyData.emailSubject; data.spoofingResolved = notifyData.status; } else { // this will be gtm campaign data as data is not null because we already have email campaign data if( notifyData.length ) { data.gtmCampaignName = notifyData[0].campaignName, data.gtmCampaignDescription = notifyData[0].campaignDescription, data.gtmCampaignManagerDisplay = notifyData[0].campaignManagerDisplay, data.gtmSalesManagerDisplay = notifyData[0].salesManagerDisplay, data.gtmLeadType = notifyData[0].leadType, data.gtmTargetPartnerType = notifyData[0].targetPartnerType, data.gtmTerritoryName = notifyData[0].territoryName } } } else { // main data waiting--; data = notifyData; waiting++; instance.resolveEmailSpoofing( data ).done( function( resolveEmailData ) { d.notify( resolveEmailData ); }); if( data.gtmCampaignId ) { // get the campaign data waiting++; instance.getDataForGTMCampaign( data.gtmCampaignId ).done( function( gtmCampaignData ) { d.notify( gtmCampaignData ); }) } } if( ! waiting ) { console.log( "RESOLVING" ); console.log( data ); d.resolve( data ); } }) waiting++; let dataStore = Fse.Data.newDataSource( { object : "GTM.emailCampaigns", keyField : "campaignId", objectParams : { includeMessageContent : true, includeStatColumns : true } } ).store(); dataStore.byKey( campaignId ) .done( function( campaignData ) { d.notify( campaignData ); }) .fail( function( err ) { console.log( "FAILING FAILING FAILING" ); console.log( err ); }) return d; } EmailCampaignEditor.prototype.refreshEditor = function() { let instance = this; let d = instance.getDataForCampaign( instance.campaignId ); d.done( function( data ) { let currentTabIndex = instance.getCurrentTabIndex(); /* if( data.length ) { data = data[0]; } */ instance.campaignData = data; instance.readOnly = instance.campaignData.statusCd != 'PEN'; instance.createUI( data, currentTabIndex ); }) return d; } EmailCampaignEditor.prototype.createUI = function( data, tabIndex ) { let instance = this; if( instance.intervalId ) { window.clearInterval( instance.intervalId ); instance.intervalId = 0; } if( instance.changes ) { instance.changes.off( "inserted" ); instance.changes = null; } instance.changeCount = 0; instance.changes = new DevExpress.data.ArrayStore( { data : [], onInserted : function( item ) { instance.changeCount++; if( instance.options.onChanged ) { instance.options.onChanged( item ); } else { instance.saveButton.option( { disabled : false } ); instance.cancelButton.option( { visible : true, disabled : false } ); } }}); // remove the old panels if they exist if( instance.tabPanel ) { tabIndex = instance.tabPanel.option( "selectedIndex" ); instance.tabPanel.element().remove(); instance.tabPanel.dispose(); instance.tabPanel = null; } instance.rootElement.empty(); if( data.length ) { data = data[0]; } let items = [] items.push( { title : "Details", template : function() { return instance.detailsTabTemplate( data ) } } ); if( data.campaignId ) { if( data.campaignType == "CRM" ) { items.push( // { title : "Defaults", template : function() { return instance.defaultsTabTemplate( data ) } }, { title : "Recipients", template : function() { return instance.crmRecipientsTabTemplate( data ) }} ); } else { items.push( { title : "Recipients", template : function() { return instance.standardRecipientsTabTemplate( data ) }} ); } items.push( { title : "Email Design", template : function() { return instance.designTabTemplate( data ) }}, { title : "Hyperlinks", template : function() { return instance.hyperlinksTabTemplate( data ) }}, { title : "Test", template : function() { return instance.testingTabTemplate( data ) }}, { title : "Summary", template : function() { return instance.summaryTabTemplate( data ) }} ); } instance.tabPanel = $("
").dxTabPanel( { items : items, selectedIndex : tabIndex }).dxTabPanel( "instance" ); instance.rootElement.append( instance.tabPanel.element() ); if( ! instance.options.onChanged ) { instance.cancelButton = $("
").dxButton( { text : "Cancel", visible : false, type : "normal", disabled : true, onClick : function( e ) { if( confirm( "Discard unsaved changes?" ) ) { instance.refreshEditor(); } } }).dxButton( "instance" ); instance.saveButton = $("
").dxButton( { text : "Save", type : "default", disabled : true, onClick : function( e ) { instance.saveChanges(); }}).dxButton( "instance" ); instance.rootElement.append( $("
").css( { "padding-top" : "5px", "padding-bottom" : "5px", "padding-right" : "10px" } ).dxToolbar( { items : [ { location : "after", template : function() { return instance.cancelButton.element() } }, { location : "after", template : function() { return instance.saveButton.element() } } ] }) ); } } EmailCampaignEditor.prototype.crmRecipientsTabTemplate = function( data ) { let instance = this; let template = $("
").css( "padding", "10px 10px 10px 10px" ); let partnerTypes = "OPR,CDR"; if( data.gtmCampaignId ) { partnerTypes = data.gtmTargetPartnerType; } console.log( data ); instance.listSelectBox = $("
").dxSelectBox( { dataSource : Fse.Data.newDataSource( { object : "LST.lists", keyField : "listId", objectParams : { includeStats : true, detailLists : true, partnerTypes : partnerTypes, listUses : "EMAIL" } }), displayExpr : function( rowData ) { if( ! rowData ) return; let listSizeText = DevExpress.localization.formatNumber( rowData.listSize, { type : "fixedPoint", precision : 0 } ); return `${rowData.listName} - (${listSizeText} contacts)`; }, searchEnabled : true, searchExpr : "listName", valueExpr : "listId", placeholder : "select recipient list", value : data.targetListId, disabled : instance.readOnly, required : true, onSelectionChanged : function( e ) { let value = e.selectedItem ? e.selectedItem.listId : null; if( value != data.targetListId ) { instance.changes.insert( "crmRecipients.targetListId" ); } } }).dxSelectBox( "instance" ); /* wait on the feature to add a new list let targetListNameTextBox = null; let listTypeRadioGroup = $("
").dxRadioGroup( { items : [ { text : "Use an existing list", newTargetList : false }, { text : "Create a new list", newTargetList : true } ], displayExpr : "text", valueExpr : "newTargetList", value : data.targetListId ? false : true, disabled : instance.readOnly, layout : "horizontal", onValueChanged : function( e ) { if( e.value ) { targetListNameTextBox.option( { required : true, disabled : false, visible : true } ); listSelectBox.option( { required : false, disabled : true, visible : false } ); } else { targetListNameTextBox.option( { required : false, disabled : true, visible : false } ) listSelectBox.option( { required : true, disabled : false, visible : true } ); } } }) .css( { "padding-top" : "10px" } ) .dxRadioGroup( "instance" ); targetListNameTextBox = $("
").dxTextBox( { maxLength : 50, disabled : true, required : false, value : null, placeholder : "name of new recipient list", visible : false }).dxTextBox( "instance" ); */ template.append( "

Target List

") let targetListLayout = $("
").css( { "display" : "grid", "grid-template-columns" : "100px auto" }) let listFields = $("
") .append( instance.listSelectBox.element() ) /* wait on the feature to add a new list .append( targetListNameTextBox.element() ); */ targetListLayout.append( "" ); targetListLayout.append( listFields ); /* wait on the feature to create a new list targetListLayout.append( "
" ); targetListLayout.append( listTypeRadioGroup.element() ); */ template.append( targetListLayout ); template.append( "

Contributors

" ); // let contributorList = null; // need to highlight non-staff in red let deleteContributor = function( fspro_userId ) { instance.changes.insert( "crmRecipients.contributorList" ); let contributors = instance.contributorList.getDataSource().items(); let deleted = false; let newContributors = []; contributors.forEach( function( c ) { if( c.fspro_userId != fspro_userId ) { newContributors.push( c ); } else { deleted = true; } }) if( deleted ) { instance.contributorList.option( "dataSource", { store : { type : "array", data : newContributors, key : "fspro_userId" } }) } } let addContributors = function( contributorsToAdd ) { let contributors = instance.contributorList.getDataSource().items(); let newContributors = []; let contributorIds = {}; contributors.forEach( function( c ) { newContributors.push( c ); contributorIds[c.fspro_userId] = true; }) let added = false; contributorsToAdd.forEach( function( a ) { if( ! contributorIds[a.fspro_userId] ) { newContributors.push( a ); contributorIds[a.fspro_userId] = true; added = true; } }) if( added ) { instance.contributorList.option( "dataSource", { store : { type : "array", data : newContributors, key : "fspro_userId" } }) instance.changes.insert( "crmRecipients.contributorList" ); } } let contributorPicker = new StaffPicker(); instance.contributorList = $("
").dxDataGrid( { scrolling : { mode : "virtual" }, height : 225, showBorders : true, columns : [ { name : "fullName", caption : "Full Name", allowSorting : true, calculateSortValue : function( rowData ) { if( rowData ) { return `${rowData.firstName} ${rowData.lastName}`; } }, calculateCellValue : function( rowData ) { if( rowData ) { return `${rowData.firstName} ${rowData.lastName}`; } } }, { dataField : "email", caption : "Email Address" }, { dataField : "staffMember", caption : "Staff Member", lookup : { dataSource : { store : { type : "array", key : "value", data : [ { value : 1, text :'Yes' }, { value : 0, text :'No' } ] } }, displayExpr : "text", valueExpr : "value" } }, { name : "junk", type : "buttons", width : 40, buttons : [ { icon : "trash", onClick: function( e ) { if( e.row.rowType == "data" ) { deleteContributor( e.row.data.fspro_userId ); } } } ] } ], onToolbarPreparing : function( e ) { if( ! e.toolbarOptions.items ) { e.toolbarOptions.items = []; } e.toolbarOptions.items.push ( { location : "after", widget : "dxButton", options : { text : "Add Contributors", icon : "add", disabled : instance.readOnly, onClick : function( e ) { contributorPicker.show( { onStaffPicked : addContributors } ) } } }); } }).dxDataGrid( "instance" ); template.append( instance.contributorList.element() ); let contributorDataStore = Fse.Data.newDataSource( { object : "GTM.emailCampaignListContributors", keyField : "fspro_userId", objectParams : { campaignId : data.campaignId } } ).store(); contributorDataStore.load().done( function( contributors ) { instance.contributorList.option( "dataSource", { store : { type : "array", data : contributors, key : "fspro_userId" } }) }) template.append( "

Note: All CRM internal contacts for Operators/Distributors in the identified list will be automatically added to the contributor list upon save.

" ); instance.sendNotificationCheckBox = null; instance.sendNotificationTextArea = null; if( ! instance.readOnly ) { template.append( "

Notify

" ); instance.sendNotificationTextArea = $("
").dxTextArea( { disabled : true, onValueChanged : function( e ) { instance.changes.insert( "crmRecipients.contributorNotificationText" ); } }).dxTextArea( "instance" ); instance.sendNotificationCheckBox = $("
").dxCheckBox( { value : false, text : "Send Notification", onValueChanged : function( e ) { if( e.value ) { instance.sendNotificationTextArea.option( { disabled : false, required : true } ) instance.sendNotificationTextArea.focus(); } else { instance.sendNotificationTextArea.option( { disabled : true, required : false, value : null } ) } instance.changes.insert( "crmRecipients.notififyContributors" ) } }).dxCheckBox( "instance" ) template.append( instance.sendNotificationCheckBox.element() ); template.append( $("

").append( $("").text( "When checked, and this page is saved, a notification will be sent to all contributors. The notification will include the details of the campaign and any note entered below." ) )); template.append( instance.sendNotificationTextArea.element() ); } return template; } EmailCampaignEditor.prototype.getCRMRecipientsTabData = function() { let instance = this; let data = { targetListId : instance.listSelectBox.option( "value" ), targetListContributors : null } if( instance.sendNotificationCheckBox ) { data.notifyContributors = instance.sendNotificationCheckBox.option( "value" ); data.contributorNotificationText = instance.sendNotificationTextArea.option( "value" ); } let contributors = instance.contributorList.getDataSource().items(); contributors.forEach( function( c ) { if( ! data.targetListContributors ) { data.targetListContributors = []; } data.targetListContributors.push( c.fspro_userId ); }) let valid = data.targetListId ? true : false; if( instance.sendNotificationCheckBox ) { valid = valid && ( ! data.notifyContributors || ( data.notifyContributors && data.contributorNotificationText != "" )); } if( valid ) { return data; } else { instance.gotoTab( "Recipients" ); return null; } } EmailCampaignEditor.prototype.showSystemMessage = function( messageType, message ) { let displayTime = 2000; if( messageType != "info" ) { displayTime = 5000; } $("

").dxToast( { displayTime : displayTime, type : messageType, // warning, or error, or info closeOnClick : true, hideOnOutsideClick : true, message : message, onHidden : function( e ) { e.component.element().remove(); e.component.dispose(); } }).appendTo( "body" ).dxToast( "show" ); } EmailCampaignEditor.prototype.standardRecipientsTabTemplate = function( data ) { let instance = this; let template = $("
").css( "padding", "10px 10px 10px 10px" ); instance.groupCheckBoxes = []; template.append( "

Custom Groups

" ); template.append( "

Select recipients for the Email Campaign by checking the appropriate Custom Groups from the list below:

" ); let groupSections = $("
"); let groupSectionScroll = $("
").append( groupSections ).dxScrollView( { height : 400 }); template.append( groupSectionScroll ); let campaignRecipientGroupsStore = Fse.Data.newDataSource( { object : 'GTM.emailCampaignRecipientGroups', objectParams : { campaignId : data.campaignId }, keyField : "groupId" }).store(); campaignRecipientGroupsStore.load().done( function( recipientGroupsUnsorted ) { let recipientGroups = DevExpress.data.query( recipientGroupsUnsorted ) .sortBy( "categorySort") .thenBy( "category" ) .thenBy( "groupName" ) .toArray(); let currentGroupCategoryId = -1; let groupGrid = null; recipientGroups.forEach( function( rg ) { if( ! groupGrid || currentGroupCategoryId != rg.categoryId ) { groupSections.append( $("

").text( rg.category ) ); groupGrid = $("
").css( { "display" : "grid", "gap" : "10px", "grid-template-columns" : "33% 33% 34%", "grid-auto-rows" : "auto" } ); groupSections.append( groupGrid ); } currentGroupCategoryId = rg.categoryId; let cbStyle = { "color" : rg.recipientGroup ? "blue" : "initial" }; let cb = $("
").css( cbStyle ).dxCheckBox( { groupId : rg.groupId, value : rg.recipientGroup, myInitialValue : rg.recipientGroup, text : rg.groupName, disabled : instance.readOnly, onValueChanged : function( e ) { if( e.value ) { e.component.element().css( "color", "blue" ); } else { e.component.element().css( "color", "initial" ); } if( e.value != e.component.option( "myInitialValue" )){ instance.changes.insert( "stdRecipients.groupIds" ); } } }).dxCheckBox( "instance" ); if( ! data.readOnly ) { // add this to the list of checkboxes used to update the campaign instance.groupCheckBoxes.push( cb ); } groupGrid.append( cb.element() ); }) }) return template; } EmailCampaignEditor.prototype.getStandardRecipientsTabData = function() { let instance = this; let groupIds = []; instance.groupCheckBoxes.forEach( function( cb ) { let cbo = cb.option(); if( cbo.value ) { groupIds.push( cbo.groupId ); } } ); if( groupIds.length ) { return { groupIds : groupIds }; } else { instance.gotoTab( "Recipients" ); return null; } } EmailCampaignEditor.prototype.designTabTemplate = function( data ) { let instance = this; let template = $("
").css( "padding", "10px 10px 10px 10px" ); let frameHeight = instance.height - 25; instance.designButton = $("
").dxButton( { icon : "edit", text : "Design", disabled : instance.readOnly, onClick : function( e ) { if( instance.changeCount ) { instance.alertSaveChanges() return; } let designer = new EmailCampaignDesigner(); designer.show( { campaignId : data.campaignId, campaignTk : data.campaignTk, onSave : function() { instance.refreshEditor(); } }); } }).dxButton( "instance" ); $("
").dxToolbar( { items : [ { location : "after", template : function() { return $("
").text( "Preview below, Click Design to Edit" ); } }, { location : "after", template : function() { return instance.designButton.element() }} ] }).appendTo( template ); let emailMessageViewer = $("