UpcomingTasksWidget = function( widgetOptions ) { let configDefaults = this.getDefaultConfig(); this.widgetOptions = widgetOptions; this.widgetOptions.config = $.extend( true, {}, configDefaults, this.widgetOptions.config ); this.dataGrid = null; this.preferencesPopup = null; // keeps track of the active filterPreferences this.activeFilterPreferences = {}; this.readyPromise = $.Deferred(); this.init( widgetOptions ); } UpcomingTasksWidget.prototype.constructor = UpcomingTasksWidget; UpcomingTasksWidget.prototype.element = function() { return this.dataGrid.element(); } UpcomingTasksWidget.prototype.ready = function() { return this.readyPromise; } UpcomingTasksWidget.prototype.init = function( widgetOptions ) { let widget = this; let filterUserIds = []; let userId = parseInt( Fse.Portal.appConfiguration.STP.userId ); filterUserIds.push( userId ); // create a copy of the config to use for the datasource creationg (scrum 46030) let configForDataSource = $.extend( true, {}, widget.widgetOptions.config ); if( configForDataSource.assignedTo ) { filterUserIds = []; filterUserIds.push( configForDataSource.assignedTo ) } //TSE 77 - if visibilityScope <> all then the list and grid will always scoped to themselves if(this.visibilityScope == "all"){ if( widgetOptions.filterPreferences.salesRepId != null){ filterUserIds = []; widgetOptions.filterPreferences.salesRepId.forEach( function( salesRepValue ) { filterUserIds.push( parseInt( salesRepValue ) ); widget.widgetOptions.config.assignedTo = filterUserIds }) widget.activeFilterPreferences["salesRepId"] = widget.widgetOptions.config.assignedTo; } } let filter = [] // upcoming tasks are those that are open or on-hold (maybe), the other dispositions don't matter filter.push( [[ "disposition", "=", "?" ], "or", ["disposition", "=", "H"]] ); filter.push( "and" ); let assignToFilter = []; if(this.visibilityScope == "all"){ filterUserIds.forEach( function( salesRepId ) { if( assignToFilter.length ) assignToFilter.push( "or" ); assignToFilter.push( [ [ "assignedTo", "=", salesRepId ] ] ); }) }else{ assignToFilter.push( [ [ "assignedTo", "=", parseInt( Fse.Portal.appConfiguration.STP.userId ) ] ] ); } if( filter.length ) filter.push( assignToFilter ); if(widgetOptions.config.createdBy != null){ widgetOptions.filterPreferences.createdBy = widgetOptions.config.createdBy; assignToFilter.push( [ [ "requestedBy", "=", widgetOptions.config.createdBy ], ] ); } if( configForDataSource.priority ) { if( filter.length ) { filter.push( "and" ) } let priority = configForDataSource.priority; if( ! Array.isArray( priority )) priority = [priority]; let priorityFilter = []; priority.forEach( function( priorityValue ) { if( priorityFilter.length ) priorityFilter.push( "or" ); priorityFilter.push( [ "priority", "=", priorityValue ]); }) filter.push( priorityFilter ); /* priority is an int if( configForDataSource.priority == "1" || configForDataSource.priority == "5" ){ filter.push([ "and",[["priority", "=", configForDataSource.priority]] ]) }else{ filter.push([ "and", [["priority", "=", 2], "or", ["priority", "=", 3], "or", ["priority", "=", 4]] ]) } */ } if( configForDataSource.dueDateStart ) { if( filter.length ) filter.push( "and" ); filter.push([ ["dueDate", ">=", configForDataSource.dueDateStart] ,"and", ["dueDate", "<=", configForDataSource.dueDateEnd] ]) } let dataSourceConfig = { object : "WRK.tasks", paginate : true, pageSize : 50, keyField : "taskId"} let dataSource = Fse.Data.newDataSource( dataSourceConfig ); if( filter.length > 0) { dataSource.filter( filter ); } dataSource.sort( { selector: "dueDate", desc: true } ); let columns = [ { dataField : "taskDescription", caption : "Task Name", width : 260,}, { dataField : "priority", caption : "Priority", width : 70, cellTemplate : function( container, options ) { let indicatorClass = [ "fx-priority-indicator"]; if( options.data.priority == 1 ) { indicatorClass.push( "high-priority" ); } else if( options.data.priority == 5 ) { indicatorClass.push( "low-priority" ); } else { indicatorClass.push( "medium-priority" ); } let indicator = $("").addClass( indicatorClass ); container.append( indicator ).css( { "text-align" : "center" } ); }}, { dataField : "dueDate", caption : "Due Date", dataType : "date", width : 100, cellTemplate : function( container, options ) { thisDate = new Date(options.text) if( thisDate < new Date() ){ container.addClass( "fse-alert" ).append( options.text ) }else{ container.append( options.text ) } }}, { dataField : "dueDateStart", visible : false}, { dataField : "dueDateEnd", visible : false}, { dataField : "disposition", caption : "Status", width : 80, lookup : { dataSource : { store : { type : "array", data : [ { value : "?", text : "Open" }, { value : "X", text : "Complete" }, { value : "Z", text : "Cancelled" }, { value : "H", text : "On Hold" } ], key : "value" }}, valueExpr : "value", displayExpr : "text" } }, ] widget.dataGrid = $("
").dxDataGrid( { dataSource: dataSource, scrolling : { mode : "virtual" }, columns : columns, onRowDblClick : function( rdce ) { if( rdce.rowType != "data" ) { return; } if( rdce.data.taskId ) { let te = new TaskEditorPopup( { taskId : rdce.data.taskId } ); te.show().done( function( doneData ) { rdce.component.refresh(); }) } }, }).dxDataGrid( "instance" ); widget.dataGrid.getDataSource().on( "loadingChanged", function( isLoading ) { if( ! isLoading ) { widget.readyPromise.resolve(); } }) } UpcomingTasksWidget.prototype.getDefaultConfig = function( ) { //TSE 77 - if visibilityScope <> all then the list and grid will always scoped to themselves let userPermissions = Fse.Portal._userPermissions; this.visibilityScope = "self"; if ( typeof userPermissions.TaskManagementAdmin !== 'undefined' && userPermissions.TaskManagementAdmin) this.visibilityScope = "all"; // if ( typeof userPermissions.TaskManagementReassign !== 'undefined' && userPermissions.TaskManagementReassign) // this.visibilityScope = "all"; return { assignedTo : parseInt( Fse.Portal.appConfiguration.STP.userId ), createdBy : null, priority : null, dueDate : null, dueDateStart : null, dueDateEnd : null, } } UpcomingTasksWidget.prototype.edit = function( applyFn) { let widget = this; const priorityTypes = [ {"priorityCode": 1,"desc":"High"}, {"priorityCode": 3,"desc":"Medium"}, {"priorityCode": 5,"desc":"Low"}, ]; if( ! this.preferencesPopup ) { let staffDatasource = Fse.Data.newDataSource( { dataURL : widget.dataURL, object : "CRM.salesRepList", keyField : "fspro_userId" } ) if( this.visibilityScope == 'self'){ let userId = parseInt( Fse.Portal.appConfiguration.STP.userId ) staffDatasource.filter( [ [ "fspro_userId", "=", userId] ] ); } const items = []; items.push( { dataField : "assignedTo", label : { location : "left", text : "Assigned To" }, editorType : "dxDropDownBox", cssClass : widget.widgetOptions.config.assignedTo ? 'fx-active-preference' : null, editorOptions : Fse.UI.multiSelectDropDownBoxEditorOptions({ dataSource : staffDatasource, searchExpr : "fullName", searchMode : "contains", displayExpr : "fullName", multipleSelectedDisplay : "Multiple Sales Reps Selected", keyExpr : "fspro_userId", title : "Select Assigned To" }) }, { dataField : "createdBy", label : { location : "left", text : "Creator" }, editorType : "dxSelectBox", cssClass : widget.widgetOptions.config.createdBy ? 'fx-active-preference' : null, editorOptions : { dataSource : staffDatasource, searchExpr : "fullName", searchMode : "contains", displayExpr : "fullName", valueExpr : "fspro_userId", title : "Select Creator", showClearButton : true, searchEnabled : true, } }, { dataField : "priority", label : { location : "left", text : "Priority" }, editorType : "dxDropDownBox", editorOptions : { placeholder : "Select Priority", dataSource : new DevExpress.data.ArrayStore({ data: priorityTypes, key: "priorityCode" }) , valueExpr : "priorityCode", displayExpr : "desc", contentTemplate : function( e ) { const v = e.component.option( "value" ); const $list = $("
").dxList( { dataSource : e.component.getDataSource(), displayExpr : "desc", valueExpr : "priorityCode", selectionMode: "multiple", showSelectionControls : true, selectedItemKeys : v, onSelectionChanged : function( sce ) { const keys = sce.component.option( "selectedItemKeys" ); e.component.option( "value", keys ); } }) list = $list.dxList('instance'); e.component.on('valueChanged', (args) => { const { value } = args; list.option( "selectedItemKeys", value ); }); return $list; } } }) items.push( { dataField : "dueDate", label : { location : "left", text : "Due Date" }, editorType : "dxDropDownBox", editorOptions : Fse.UI.dateRangePickerOptions( { dateRangeOptions : { periodTypes : { "Y" : true, "M" : true, "Q" : true, "H" : true, "W" : true }, rangeRelationships : { "T" : true, "L" : true, "N" : false }, calendarTypes : { "F" : true, "N" : true }, includeCustom : true }, //value : widget.widgetOptions.config.dueDate, applyCustomDateRange : function( startDate, endDate ) { widget.preferencesForm.updateData( { dueDateStart : startDate, dueDateEnd : endDate } ) } } ) } ) // annotate the preference editor to let user know there are active filter preferences - scrum 46030 if( Object.keys( widget.activeFilterPreferences ).length ) { items.push( { template : function() { let annotation = $("
").append( $("").addClass( "dx-field-item-label-text" ).append( "*filter preference active")).addClass( "fx-active-preference" ).css( { "cursor" : "pointer" } ); annotation.on( "click", function( e ) { // if the global filter preferences are applied, then close this popup let onSaveFilterPreferences = function() { widget.preferencesPopup.hide(); } widget.widgetOptions.dashboard.editFilterPreferences( onSaveFilterPreferences ); }) return annotation; } }) } const formData = { assignedTo : widget.widgetOptions.config.assignedTo, createdBy : widget.widgetOptions.config.createdBy, priority : widget.widgetOptions.config.priority, dueDate : widget.widgetOptions.config.dueDate, dueDateStart : widget.widgetOptions.config.dueDateStart, dueDateEnd : widget.widgetOptions.config.dueDateEnd, disposition : widget.widgetOptions.config.disposition, } this.preferencesPopup = $("
").dxPopup( { title : "Upcoming Task Preferences", width : 500, height : "auto", position : { my : "right top", at : "right top", of : widget.widgetOptions.portlet }, hideOnOutsideClick : true, contentTemplate : function() { widget.preferencesForm = $("
").dxForm( { formData : formData, colCount : 1, items : items, } ).dxForm("instance"); return widget.preferencesForm.element(); }, toolbarItems : [ { // scrum 49810.12 toolbar : "bottom", location : "after", widget : "dxButton", options : { text : "Use Defaults", type : "normal", onClick : function() { widget.preferencesPopup.hide(); applyFn( widget.getDefaultConfig() ); } } }, { toolbar : "bottom", location : "after", widget : "dxButton", options : { text : "Apply", type : "default", onClick : function() { widget.preferencesPopup.hide(); applyFn( widget.preferencesForm.option( "formData" ) ); } } } ] } ).dxPopup( "instance" ); this.preferencesPopup.element().appendTo( "body" ); } this.preferencesPopup.show(); } Fse.Portal.addWidgetFactory( "UpcomingTasksWidget", function( widgetDef ) { return new UpcomingTasksWidget( widgetDef ); })