NewOperatorProfileDialog = function( options ) { let instance = this; instance.oneFSSearchEnabled = true; instance.oprParentCo = null; instance.onReturn = null; instance.distrib1 = null; instance.distrib2 = null; instance.from1FSId = null; instance.showCountryField = false; instance.defaultCountryId = 0; instance.territoryId = null; instance.defaultTerritoryId = null; let countryIds = Fse.Portal.getConfiguration( "CRM.countryIdList" ).split(","); let countryCount = 0; let uniqueCountryIds = {} countryIds.forEach( function( cid ) { if( ! instance.defaultCountryId ) { instance.defaultCountryId = parseInt( cid ) ; } if( uniqueCountryIds[cid] ) return; countryCount++; uniqueCountryIds[cid] = cid; }) if( ! instance.defaultCountryId ) { instance.defaultCountryId = 27; } else if( countryCount > 1 ) { instance.showCountryField = true; } instance.defaultStateLabel = "State"; instance.defaultStatePlaceholder = "state"; if( instance.defaultCountryId == 5 ) { instance.defaultStateLabel = "Prov."; instance.defaultStatePlaceholder = "prov"; } // let oprProfileRequired = Fse.Portal.getConfiguration( "OPR.profile.required" ); // console.log( oprProfileConfig ); instance.requiredFields = { distrib1 : Fse.Portal.getConfiguration( "OPR.profile.REQUIRED.PREFDISTRIBUTOR" ) == "true" ? true : false, oprSegment : Fse.Portal.getConfiguration( "OPR.profile.REQUIRED.PRIMARYSEGMENT" ) == "true" ? true : false, phone : Fse.Portal.getConfiguration( "OPR.profile.REQUIRED.MAINPHONE" ) == "true" ? true : false, address : Fse.Portal.getConfiguration( "OPR.profile.REQUIRED.STREET" ) == "true" ? true : false, city : Fse.Portal.getConfiguration( "OPR.profile.REQUIRED.CITYSTATE" ) == "true" ? true : false, state : Fse.Portal.getConfiguration( "OPR.profile.REQUIRED.CITYSTATE" ) == "true" ? true : false, zipCode : Fse.Portal.getConfiguration( "OPR.profile.REQUIRED.ZIPCODE" ) == "true" ? true : false }; instance.initial1FSSearchTypes = { "O" : true, "I" : true, "U" : false, "G" : false, "C" : false }; instance.contactDefaults = { countryId : instance.defaultCountryId, preferredLanguage : "EN", contactDecisionMaker : false, officeAddrSame : true, primaryContact : true }; if( options ) { if( options.onReturn ) { instance.onReturn = options.onReturn; } if( options.oprParentCo ) { instance.oprParentCo = options.oprParentCo; } if( options.distrib1 ) { instance.distrib1 = options.distrib1; } if( options.distrib2 ) { instance.distrib2 = options.distrib2; } if( options.initial1FSSearchTypes ) { let initialChoTypes = options.initial1FSSearchTypes; if( !Array.isArray( initialChoTypes ) ) { initialChoTypes = initialChoTypes.split( "," ); } for( ct in instance.initial1FSSearchTypes ) { let ctOn = false; initialChoTypes.forEach( function( ict ) { if( ict == ct ) { ctOn = true; } }) instance.initial1FSSearchTypes[ct] = ctOn; } } if( options.territoryId ) { instance.territoryId = options.territoryId } if( options.defaultTerritoryId ) { instance.defaultTerritoryId = options.defaultTerritoryId } if( options.from1FSId ) { instance.oneFSSearchEnabled = false; instance.from1FSId = options.from1FSId; } } } NewOperatorProfileDialog.prototype.constructor = NewOperatorProfileDialog; NewOperatorProfileDialog.prototype.show = function() { let instance = this; instance.popup = $("
").dxPopup( { title : `New ${getText( 'OPERATOR' )}`, width : 800, contentTemplate : function() { let multiViewItems = []; let addOperatorToolbarItems = []; if( instance.oneFSSearchEnabled ) { instance.search1FSFormTabIndex = multiViewItems.length; multiViewItems.push( { id :"search1FSForm", template : function() { return instance.search1FSTemplate() }, toolbarItems : [ { toolbar : "bottom", location : "after", template : function() { instance.skip1FSSearchButton = $("
").dxButton( { text : "Add manually", visible : false, stylingMode : "text", disabled : true, onClick : function( e ) { instance.skip1FSSearch(); } }).dxButton( "instance" ); return instance.skip1FSSearchButton.element(); } }, { toolbar : "bottom", location : "after", template : function() { instance.search1FSButton = $("
").dxButton( { text : "Search 1FS", type : "default", onClick : function( e ) { instance.search1FS(); } }).dxButton( "instance"); return instance.search1FSButton.element(); } } ] }) addOperatorToolbarItems.push( { toolbar : "bottom", location : "after", widget : "dxButton", options : { text : "back to 1FS search", type : "default", stylingMode : "text", onClick : function( e ) { instance.backTo1FSSearch(); } } }) } addOperatorToolbarItems.push( { toolbar : "bottom", location : "after", widget : "dxButton", options : { text : `Add ${getText( 'OPERATOR' )}`, type : "default", onClick : function( e ) { instance.addOperator(); } } }); instance.addOperatorFormTabIndex = multiViewItems.length; multiViewItems.push( { id : "addOperatorForm", template : function() { return instance.addOperatorTemplate() }, toolbarItems : addOperatorToolbarItems }); instance.matchedOperatorFormTabIndex = multiViewItems.length; multiViewItems.push( { id : "matchedOperatorForm", template : function() { return instance.matchedOperatorTemplate() }, toolbarItems : [ { toolbar : "bottom", location : "after", widget : "dxButton", options : { text : "Submit", type : "default", onClick : function( e ) { let vr = instance.dupActionForm.validate(); if( vr.isValid ) { let dupActionData = instance.dupActionForm.option( "formData" ); if( dupActionData.dupAction == "allowDup" ) { instance.addOperator( dupActionData ); } else if( dupActionData.dupDaction = "useThisOne" ) { instance.returnOperator( dupActionData.matchOperatorId, "goto" ); } } } } } ] }); instance.multiView = $("
").dxMultiView( { swipeEnabled : false, selectedIndex : 0, deferRendering : false, // this is so that all view are rendered before they are needed, so that one can reference the other items : multiViewItems, onContentReady : function( e ) { let item = e.component.option( "selectedItem" ); instance.popup.option( "toolbarItems", item.toolbarItems ); }, onSelectionChanged : function( e ) { let item = e.component.option( "selectedItem" ); instance.popup.option( "toolbarItems", item.toolbarItems ); } }).dxMultiView( "instance" ); instance.multiView.option( "selectedIndex", 0 ); return instance.multiView.element(); }, hideOnOutsideClick : false, onHidden : function( e ) { e.component.element().remove(); e.component.dispose(); }, onShown : function( e ) { let item = instance.multiView.option( "selectedItem" ); if( item.id == "search1FSForm" ) { instance.search1FSForm.getEditor("cho_name").focus(); } else { } if( instance.from1FSId ) { let ds = Fse.Data.newDataSource( { object : "OPR.1fsOperators", keyField : "cho_id" } ).store(); ds.byKey( instance.from1FSId).done( function( data ) { if( data ) { instance.initiateAddFrom1FS( data ); } // console.log( "1FS Data", data ); }) } } }).dxPopup("instance"); instance.popup.element().appendTo( "body" ); instance.popup.show(); return instance.savePromise; } NewOperatorProfileDialog.prototype.search1FS = function() { let instance = this; let vr = instance.search1FSForm.validate(); if( ! vr.isValid ) { return; } let searchData = instance.search1FSForm.option( "formData" ); let ds = []; let filter = []; if( searchData.cho_name) { if( filter.length ) { filter.push( "and" ); } filter.push( [ "cho_name", "contains", searchData.cho_name ] ) } if( searchData.cho_address ) { if( filter.length ) { filter.push( "and" ); } filter.push( [ "cho_address", "contains", searchData.cho_address ] ) } if( searchData.cho_city ) { if( filter.length ) { filter.push( "and" ); } filter.push( [ "cho_city", "contains", searchData.cho_city ] ) } if( searchData.cho_state ) { if( filter.length ) { filter.push( "and" ); } filter.push( [ "cho_state", "=", searchData.cho_state ] ) } if( searchData.cho_zipCode ) { if( filter.length ) { filter.push( "and" ); } filter.push( [ "cho_zipCode", "startswith", searchData.cho_zipCode ] ) } if( searchData.cho_countryId ) { if( filter.length ) { filter.push( "and" ); } filter.push( [ "cho_countryId", "=", searchData.cho_countryId ] ); } else { if( filter.length ) { filter.push( "and" ); } filter.push( [ "cho_countryId", "=", instance.defaultCountryId ] ); } if( searchData.cho_type ) { let typeFilter = []; searchData.cho_type.forEach( function( cho_type ) { if( typeFilter.length ) { typeFilter.push( "or" ) } typeFilter.push( [ "cho_type", "=", cho_type ]); }) if( filter.length ) { filter.push( "and" ); } filter.push( typeFilter ); } else { if( filter.length ) { filter.push( "and" ); } filter.push( [ "cho_type", "=", "X" ] ); // no types, return nothing } if( filter.length ) { ds = Fse.Data.newDataSource( { object : "OPR.1fsOperators", keyField : "cho_id", paginate : true, pageSize : 25 } ); ds.filter( filter ); ds.on( "loadingChanged", function( isLoading ) { if( isLoading ) { instance.search1FSButton.option( "disabled", true ); instance.skip1FSSearchButton.option( "disabled", true ); } else { instance.skip1FSSearchButton.option( { "visible" : true, "disabled" : false } ); instance.search1FSButton.option( "disabled", false ); } }) } instance.search1FSResultList.option( "dataSource", ds ); } NewOperatorProfileDialog.prototype.skip1FSSearch = function() { let instance = this; let search1FSData = instance.search1FSForm.option( "formData" ); let initialData = { companyName : search1FSData.cho_name, address : search1FSData.cho_address, city : search1FSData.cho_city, state : search1FSData.cho_state, zipCode : search1FSData.cho_zipCode, countryId : search1FSData.cho_countryId ? search1FSData.cho_countryId : instance.defaultCountryId }; instance.setAddOperatorFormData( initialData ); instance.multiView.option( "selectedIndex", instance.addOperatorFormTabIndex ); } NewOperatorProfileDialog.prototype.setAddOperatorFormData = function( data ) { let instance = this; let defaults = { priority : "C", numUnits_TY : 1, numUnits_LY : 1, numUnits_NY : 1, countryId : instance.defaultCountryId, addContact : false, contact : $.extend( true, {}, instance.contactDefaults ) } let formData = $.extend( true, {}, defaults ); if( ! formData.distrib1 && instance.distrib1 ) { formData.distrib1 = instance.distrib1; } if( ! formData.distrib2 && instance.distrib2 ) { formData.distrib2 = instance.distrib2; } let validURLProtocol = /^https?:\/\//i; // cleanup urls ["url","linkedIn"].forEach( function( dataField ) { if( ! formData[dataField] ) return; if( formData[dataField].search( validURLProtocol ) < 0 ) formData[dataField] = `https://${formData[dataField]}`; }) formData = $.extend( true, formData, data ); instance.addOperatorForm.option( "formData", formData ); } NewOperatorProfileDialog.prototype.backTo1FSSearch = function() { let instance = this; instance.multiView.option( "selectedIndex", instance.search1FSFormTabIndex ); instance.skip1FSSearchButton.option( { "visible" : true, "disabled" : false } ) } NewOperatorProfileDialog.prototype.backToOperatorAdd = function() { let instance = this; let items = instance.multiView.option( "items" ); // instance.multiView.option( "selectedIndex", items.length - 2 ); instance.multiView.option( "selectedIndex", instance.addOperatorFormTabIndex ); } NewOperatorProfileDialog.prototype.showMatchedOperator = function( operatorId ) { let instance = this; let items = instance.multiView.option( "items" ); // let matchingOperatorIndex = items.length - 1; let matchingOperatorIndex = instance.matchedOperatorFormTabIndex; let operatorDataStore = Fse.Data.newDataSource( { object : "OPR.operatorDetails", paginate : false, keyField : "operatorId", objectParams : { operatorId : instance.operatorId } }).store(); operatorDataStore.byKey( operatorId ).done( function( data ) { instance.matchedOperatorForm.option( "formData", data ); instance.dupActionForm.option( "formData", { matchOperatorId : operatorId, dupAction : "useThisOne" }); instance.multiView.option( "selectedIndex", matchingOperatorIndex ); }) } NewOperatorProfileDialog.prototype.initiateAddFrom1FS = function( data ) { let instance = this; let addOperatorData = { companyName : data.cho_name, address : data.cho_address, address2 : null, city : data.cho_city, state : data.cho_state, zipCode : data.cho_zipCode, fsl_choId : data.cho_id, countryId : data.cho_countryId, oprSegment : data.clientSegId, url : data.cho_url, phone : data.cho_phone } instance.setAddOperatorFormData( addOperatorData ); // instance.multiView.option( "selectedIndex", 1 ); instance.multiView.option( "selectedIndex", instance.addOperatorFormTabIndex ); } NewOperatorProfileDialog.prototype.addOperator = function( dupActionData) { let instance = this; let vr = DevExpress.validationEngine.validateGroup( "addOperatorForm" ); if( vr.isValid ) { // TODO - get this to protect the page until the load operation is complete let loadPanel = $("
").dxLoadPanel( { message : "Working...", deplay : 0, hideOnOutsideClick : false, hideOnParentScroll : false, container : instance.popup.element(), onHidden : function( e ) { e.component.element().remove(); e.component.dispose(); } }).appendTo( $("body") ).dxLoadPanel( "instance" ); let dataToSend = $.extend( true, {}, instance.addOperatorForm.option( "formData" ) ); if( instance.oprParentCo ) { dataToSend.oprParentCo = instance.oprParentCo; } // if any of the contact fields have been added, then we are going to add a contact dataToSend.addContact = false; for( contactField in dataToSend.contact ) { if( dataToSend.contact[contactField] ) { if( instance.contactDefaults[contactField] && instance.contactDefaults[contactField] === dataToSend.contact[contactField] ) continue; dataToSend.addContact = true; break; } } if( dupActionData ) { dataToSend = $.extend( true, dataToSend, dupActionData ); } loadPanel.show(); Fse.Ajax.performAction( { object : "OPR.addOperator", data : dataToSend }).done( function( addOperatorResult ) { if( addOperatorResult.operatorId ) { instance.returnOperator( addOperatorResult.operatorId ); } else if ( addOperatorResult.status == "duplicate" ) { // already exists, // select an option - dupAction = useThisOne or allowDup // allowDup - require a reason instance.showMatchedOperator( addOperatorResult.matchingOperatorId ); } }).then( function() { loadPanel.hide(); }) } else { let message = vr.brokenRules[0].message; if( vr.brokenRules.length > 1 ) { message = `'${message}' plus ${vr.brokenRules.length-1} more`; } DevExpress.ui.notify( message, "warning", 1000 ); vr.brokenRules[0].validator.focus(); } } NewOperatorProfileDialog.prototype.returnOperator = function( operatorId, additionalData ) { let instance = this; let operatorDataStore = Fse.Data.newDataSource( { object : "OPR.operatorDetails", paginate : false, keyField : "operatorId", objectParams : { operatorId : instance.operatorId } }).store(); operatorDataStore.byKey( operatorId ).done( function( data ) { if( data.crmActive != 'Y' ) { let loadPanel = $("
").dxLoadPanel( { message : "Activating Operator...", hideOnOutsideClick : false, onHidden : function( e ) { e.component.element().remove(); e.component.dispose(); } }).appendTo( $("body") ).dxLoadPanel( "instance" ); loadPanel.show(); // activate Fse.Ajax.performAction( { object : "OPR.activateOperator", data : { operatorId : operatorId } }).done( function( activeOperatorResult ) { // and return if( instance.onReturn ) { operatorDataStore.byKey( operatorId ).done( function( data ) { instance.onReturn( data, additionalData ) }) } }).then( function( ) { loadPanel.hide(); }) } else { if( instance.onReturn ) { instance.onReturn( data, additionalData ) } } }) instance.popup.hide(); } NewOperatorProfileDialog.prototype.search1FSTemplate = function() { let instance = this; let content = $("
"); let search1FSFormItems = []; search1FSFormItems.push( { label : { text : "Company", location : "left" }, dataField : "cho_name", isRequired : true } ); if( instance.showCountryField ) { search1FSFormItems.push( { dataField : "cho_countryId", label : { text : "Country" }, editorType : "dxSelectBox", editorOptions : { dataSource : Fse.Data.newDataSource( { object : "UT.countries", keyField : "countryId" } ), value : instance.defaultCountryId, displayExpr : "countryAbbrev", valueExpr : "countryId", width : 80 } } ) }; search1FSFormItems.push( { label : { text : "Address", location : "left" }, dataField : "cho_address" }, { label : { location : "left", text : "Location" }, template : function( options, itemElement ) { let cityTextBox = $("
").dxTextBox( { width : 150, placeholder : "city", onValueChanged : function( e ) { options.component.updateData( "cho_city", e.value ); } , onEnterKey : function( e ) { instance.search1FS(); } }).css( { "display" : "inline-block" } ); /* cityTextBox.dxValidator( { validationGroup : options.component.option( "validationGroup" ), validationRules : [ { type : "required", message : "City is required" } ] }) */ let stateSelectBox = $("
").dxSelectBox( { width : 80, dataSource : Fse.Data.newDataSource( { object : "UT.states", keyField : "state", objectParams : { countryId : instance.defaultCountryId } } ), placeholder : instance.defaultStatePlaceholder, displayExpr : "state", valueExpr : "state", searchEnabled : true, searchExpr : "state", searchMethod : "startswith", showClearButton : true, validationGroup : options.component.option( "validationGroup" ), onValueChanged : function( e ) { options.component.updateData( "cho_state", e.value ); } , onEnterKey : function( e ) { instance.search1FS(); } }).css( { "display" : "inline-block", "margin-left" : "8px" } ); let zipCodeTextBox = $("
").dxTextBox( { width : 80, placeholder : "postal code", validationGroup : options.component.option( "validationGroup" ), onValueChanged : function( e ) { options.component.updateData( "cho_zipCode", e.value ); } , onEnterKey : function( e ) { instance.search1FS(); } }).css( { "display" : "inline-block", "margin-left" : "8px" } ); itemElement.append( cityTextBox ).append( "," ).append( stateSelectBox ).append( zipCodeTextBox ) let customEditors = options.component.option( "customEditors" ); if( ! customEditors ) { customEditors = {}; } customEditors.state = stateSelectBox.dxSelectBox( "instance"); customEditors.city = cityTextBox.dxTextBox( "instance"); customEditors.zipCode = zipCodeTextBox.dxTextBox( "instance" ); options.component.option( "customEditors", customEditors ); } }, { label : { text : "Type", location : "left" }, dataField : "cho_type", template : function( options, itemElement ) { let checkboxes = []; let updateFormValue = function() { let formValue = []; checkboxes.forEach( function( cbe ) { let cb = cbe.dxCheckBox( "instance" ); if( cb.option( "value" )) { formValue.push( cb.option( "cho_type" ) ) } }) if( formValue.length ) { options.component.updateData( options.dataField, formValue ); } else { options.component.updateData( options.dataField, null ); } } checkboxes.push( $("
").dxCheckBox( { cho_type : "O", text : "Chain HQ", value : instance.initial1FSSearchTypes["O"] ? true : false, onValueChanged : function( e ) { updateFormValue(); } }).css( { "display" : "inline-block", "margin-right" : "16px" } ) ); checkboxes.push( $("
").dxCheckBox( { cho_type : "I", text : "Independent", value : instance.initial1FSSearchTypes["I"] ? true : false, onValueChanged : function( e ) { updateFormValue(); } }).css( { "display" : "inline-block", "margin-right" : "16px" } ) ); checkboxes.push( $("
").dxCheckBox( { cho_type : "U", text : "Unit", value : instance.initial1FSSearchTypes["U"] ? true : false, onValueChanged : function( e ) { updateFormValue(); } }).css( { "display" : "inline-block", "margin-right" : "16px" } ) ); checkboxes.push( $("
").dxCheckBox( { cho_type : "G", text : "GPO", value : instance.initial1FSSearchTypes["G"] ? true : false, onValueChanged : function( e ) { updateFormValue(); } }).css( { "display" : "inline-block", "margin-right" : "16px" } ) ); checkboxes.push( $("
").dxCheckBox( { cho_type : "C", text : "CMC", value : instance.initial1FSSearchTypes["C"] ? true : false, onValueChanged : function( e ) { updateFormValue(); } }).css( { "display" : "inline-block", "margin-right" : "16px" } ) ); checkboxes.forEach( function( cb ) { itemElement.append( cb ); }) // this call is here to put the initial values on the formdata updateFormValue(); } } ); instance.search1FSForm = $("
").dxForm( { validationGroup : "search1FSForm", items : search1FSFormItems, onEditorEnterKey : function( e ) { instance.search1FS(); }, onFieldDataChanged : function( e ) { if( e.dataField == "cho_countryId" ) { let stateEditor = null; let customEditors = e.component.option( "customEditors" ); if( customEditors ) { stateEditor = customEditors.state; } if( stateEditor ) { let countryId = e.value; if( ! countryId ) { countryId = 0; } let placeholder = "state"; if( countryId == 5 ) { placeholder = "prov"; } let stateDataSource = Fse.Data.newDataSource( { object : "UT.states", keyField : "state", objectParams : { countryId : countryId } } ) stateEditor.option( { dataSource : stateDataSource, value : null, placeholder : placeholder }); stateEditor.repaint(); } } } }).dxForm( "instance" ); instance.search1FSForm.element().appendTo( content ); instance.search1FSResultList = $("
").dxDataGrid( { width : "100%", height : 365, remoteOperations : { paging : true, filtering : true, sorting : true }, scrolling : { mode : "virtual" }, showBorders : 1, columns : [ { dataField : "cho_type", caption : "Type", width : 90, allowSorting : false, calculateDisplayValue : function( rowData ){ let displayValue = null; if( rowData && rowData.cho_type ) { displayValue = rowData.cho_type; switch ( rowData.cho_type ) { case "I" : displayValue = "Independent"; break; case "O" : displayValue = "Chain HQ"; break; case "U" : displayValue = "Unit"; break; case "G" : displayValue = "GPO"; break; case "C" : displayValue = "CMC"; break; } } return displayValue; } }, { dataField : "cho_name", caption : "Company/Address", cellTemplate : function( container, options ) { if( options.rowType != "data" ) { return; } container.append( $("
").text( options.data.cho_name ) ); container.append( $("
").text( options.data.cho_address ).css( { "font-size" : "smaller" } )); } }, { dataField : "territoryName", caption : "Territory/Location", cellTemplate : function( container, options ) { if( options.rowType != "data" ) { return; } if( options.data.territoryName ) { container.append( $("
").text( options.data.territoryName ) ); } else { container.append( $("
").html( " " ) ); } container.append( $("
").text( `${options.data.cho_city}, ${options.data.cho_state} ${options.data.cho_zipCode }` ).css( { "font-size" : "smaller" } )); } }, { width : 80, cellTemplate : function( container, options ) { if( options.rowType != "data" ) { return; } let button = null; if( options.data.operatorId ) { button = $("
").dxButton( { text : "Go to", width : 55, onClick : function( ee ) { instance.returnOperator( options.data.operatorId, "goto" ); } }) } else { button = $("
").dxButton( { width : 55, text : "Add", onClick : function( e ) { instance.initiateAddFrom1FS( options.data ); } }) } container.append( button ); } } ] }).dxDataGrid( "instance" ); instance.search1FSResultList.element().css( { "margin-top" : "15px" } ).appendTo( content ); return content; } NewOperatorProfileDialog.prototype.addOperatorTemplate = function() { let instance = this; let crmItems = [ { dataField : "territoryId", label : { text : "Sales Territory", location : "left" }, isRequired : true, editorType : "dxSelectBox", editorOptions : { valueExpr : "TerritoryID", displayExpr : "territoryName", // dataSource : Fse.Data.newDataSource( { object : "TER.salesTerritories", keyField : "TerritoryID" }), dataSource : Fse.Data.getLocalDataSource( "$.salesTerritories" ), searchEnabled : true, searchExpr : "territoryName", searchMode : "contains" } }, { dataField : "salesRepId", label : { text : "Sales Rep", location : "left" }, editorType : "dxSelectBox", editorOptions : { valueExpr : "fspro_userId", displayExpr : "fullName", // dataSource : Fse.Data.newDataSource( { dataURL : instance.dataURL, object : "CRM.salesRepList", keyField : "fspro_userId" } ), dataSource : Fse.Data.getLocalDataSource( "$.salesRepList" ), searchEnabled : true, searchExpr : "fullName", searchMode : "contains" } }, { dataField : "priority", label : { text : "Priority", location : "left" }, editorType : "dxSelectBox", editorOptions : { dataSource : [ { text : "A+", value : "*" }, { text : "A", value : "A" }, { text : "B", value : "B" }, { text : "C", value : "C" }, { text : "D", value : "D" } ], displayExpr : "text", valueExpr : "value", value : "C", width : 75 } }, { dataField : "classificationId", label : { location : "left", text : "Classification" }, editorType : "dxSelectBox", editorOptions : { // dataSource : Fse.Data.newDataSource( { dataURL : instance.dataURL, object : "OPR.classifications", keyField : "classificationId" } ), dataSource : Fse.Data.getLocalDataSource( "$.operatorClassifications" ), searchExpr : "name", searchMode : "contains", displayExpr : "name", valueExpr : "classificationId" } } ] let internetItems = []; let validURLPattern = Fse.CRM.socialMediaPlatforms.other.urlRegEx; /* let validURLPattern = /^https?:\/\/([-\w\.]+)+(:\d+)?(:\w+)?(@\d+)?(@\w+)?([-\w\.]+)(\/([\w\/_\.]*(\?\S+)?)?)?/i; */ let internetLocations = [ { dataField : "url", label : "Website", placeholder : "Website URL", maxLength : 150, type : "url" }, { dataField : "companyEmail", label : "Email", placeholder : "email address", maxLength : 150, validationRules : [ { type : "email", message : "Invalid Email" } ] }, { dataField : "facebook", label : "Facebook", placeholder : "Facebook URL or ID", type : "url", socialMediaPlatform : "facebook" }, { dataField : "instagram", label : "Instagram", placeholder : "Instagram URL or ID", type : "url", socialMediaPlatform : "instagram" }, { dataField : "twitter", label : "\"X\"", placeholder : "\"X\" URL or ID (1-15 char)", type : "url", socialMediaPlatform : "twitter" }, { dataField : "tiktok", label : "TikTok",placeholder : "TikTok URL or ID", type : "url", socialMediaPlatform : "tiktok", }, { dataField : "youtube", label : "YouTube", placeholder : "YouTube URL or ID (10 char)", type : "url", socialMediaPlatform : "youtube" }, { dataField : "linkedIn", label : "LinkedIn", placeholder : "LinkedIn URL", maxLength : 150, type : "url", socialMediaPlatform : "linkedin" } ]; /* let internetLocations = [ { type : "url", dataField : "url", label : "Website", maxLength : 150, placeholder : "url", validationRules : [ { type : "pattern", message : "Invalid URL", pattern : validURLPattern }] }, { dataField : "companyEmail", label : "Email", maxLength : 150, placeholder : "email address", validationRules : [ { type : "email" } ] }, { dataField : "facebook", label : "Facebook", prefix : "facebook.com/" }, { dataField : "instagram", label : "Instagram", prefix : "instagram.com/" }, { dataField : "twitter", label : "Twitter (X)", prefix : "twitter.com/" }, { dataField : "tiktok", label : "TikTok", prefix : "tiktok.com/@" }, { dataField : "youtube", label : "YouTube", prefix : "youtube.com/@" }, { type : "url", dataField : "linkedIn", label : "LinkedIn", maxLength : 150, placeholder : "url", validationRules : [ { type : "pattern", message : "Invalid URL", pattern : validURLPattern }] } ]; */ internetLocations.forEach( function( il ) { let item = { dataField : il.dataField, label : { text : il.label }, template : function( options, itemElement ) { let customEditors = options.component.option( "customEditors" ); if( ! customEditors ) { customEditors = {}; } let textBoxConfig = { maxLength : il.maxLength ? il.maxLength : null, placeholder : il.placeholder ? il.placeholder : null, onValueChanged : function( e ) { options.component.updateData( options.dataField, e.value ); } } if( il.type == "url" ) { textBoxConfig.onOptionChanged = function( e ) { if( e.name == "validationErrors" ) { let validationErrors = e.value; if( validationErrors ) { let errorHandled = false; validationErrors.forEach( function( ve ) { if( errorHandled ) return; if( ve.type == "pattern" ) { if( ve.socialMediaPlatform ) { let value = ve.value; if( ! value.match( validURLPattern ) ) { value = ve.urlTransform( value ); if( value.match( validURLPattern ) && value.match( ve.pattern ) ) { errorHandled = true; setTimeout( function() { e.component.option( "value", value ) }, 10 ); } } } else { let value = ve.value; if( ! value.match( /^https+:\/\//i) ) { value = value.replace( /^.*:/i, '' ).replace( /^\/\//, '' ); value = `https://${value}` errorHandled = true; setTimeout( function() { e.component.option( "value", value ) }, 10 ); } } } }) } } /* if( e.name == "validationErrors" ) { let validationErrors = e.value; if( validationErrors ) { validationErrors.forEach( function( ve ) { if( ve.type == "pattern" ) { let value = ve.value; if( ! value.match( /^https+:\/\//i) ) { value = value.replace( /^.*:/i, '' ).replace( /^\/\//, '' ); value = `https://${value}` console.log( `revised value ${value}` ) setTimeout( function() { e.component.option( "value", value ) }, 10 ); } } }) } } */ } } let textBox = $("
").dxTextBox( textBoxConfig ).dxTextBox( "instance" ); let validationRules = il.validationRules ? il.validationRules : null; if( ! validationRules && il.type == "url" ) { validationRules = []; let message = "Invalid URL"; if( il.socialMediaPlatform && Fse.CRM.socialMediaPlatforms[il.socialMediaPlatform] ) { let pattern = Fse.CRM.socialMediaPlatforms[il.socialMediaPlatform].urlRegEx; let urlTransform = Fse.CRM.socialMediaPlatforms[il.socialMediaPlatform].urlTransform; urlTransform ? urlTransform : function( v ) { return v }; message = `Invalid ${il.placeholder}`; validationRules.push( { type : "pattern", socialMediaPlatform : il.socialMediaPlatform, message : message, pattern : pattern, urlTransform : urlTransform } ) } validationRules.push( { type : "pattern", message : message, pattern : validURLPattern } ); } textBox.element().dxValidator( { validationGroup : options.component.option( "validationGroup" ), validationRules : validationRules }) /* textBox.element().dxValidator( { validationGroup : options.component.option( "validationGroup" ), validationRules : il.validationRules ? il.validationRules : null }) let prefix = null; if( il.prefix ) { prefix = $("
").css( { "font-style" : "italic", "display" : "inline-block", "margin-right" : "5px", "width" : "95px", "text-align" : "right" } ).text( il.prefix ); textBox.element().css( { "display" : "inline-block" } ); } */ let editorContainer = $("
"); /* if( prefix ) { editorContainer.append( prefix ); } */ editorContainer.append( textBox.element() ); itemElement.append( editorContainer ); customEditors[il.dataField] = textBox; options.component.option( "customEditors", customEditors ); } } internetItems.push( item ); }); let countyDS = Fse.Data.getLocalDataSource( "$.counties" ); countyDS.filter( [ [ "state", "=", '?' ], "and", [ "countryId", "=", 0 ] ] ); let companyItems = []; companyItems.push( { dataField : "companyName", isRequired : true, editorType : "dxTextBox", editorOptions : { maxLength : 150, xwidth : 200 } }, { dataField : "address", label : { text : "Address Line 1" }, isRequired : instance.requiredFields.address, editorType : "dxTextBox", editorOptions : { maxLength : 75, xwidth : 200 } }, { dataField : "address2", label : { location : "left", text : "Address Line 2" }, editorType : "dxTextBox", editorOptions : { maxLength : 75, xwidth : 200 } } ) if( instance.showCountryField ) { companyItems.push( { dataField : "countryId", label : { text : "Country" }, editorType : "dxSelectBox", editorOptions : { dataSource : Fse.Data.newDataSource( { object : "UT.countries", keyField : "countryId" } ), value : instance.defaultCountryId, displayExpr : "countryAbbrev", valueExpr : "countryId", width : 100 } } ); } companyItems.push( { label : { text : "Location", location : "left"}, template : function( options, itemElement ) { let cityTextBox = $("
").dxTextBox( { width : 150, placeholder : "city", onValueChanged : function( e ) { options.component.updateData( "city", e.value ); } }).css( { "display" : "inline-block" } ); if( instance.requiredFields.city ) { cityTextBox.dxValidator( { validationGroup : options.component.option( "validationGroup" ), validationRules : [ { type : "required", message : "City is required" } ] }) } let stateSelectBox = $("
").dxSelectBox( { width : 80, dataSource : Fse.Data.newDataSource( { object : "UT.states", keyField : "state", objectParams : { countryId : instance.defaultCountryId } } ), placeholder : instance.defaultStatePlaceholder, displayExpr : "state", valueExpr : "state", searchEnabled : true, searchExpr : "state", searchMethod : "startswith", showClearButton : true, validationGroup : options.component.option( "validationGroup" ), onValueChanged : function( e ) { options.component.updateData( "state", e.value ); } }).css( { "display" : "inline-block", "margin-left" : "8px" } ); if( instance.requiredFields.state ) { stateSelectBox.dxValidator( { validationGroup : options.component.option( "validationGroup" ), validationRules : [ { type : "required", message : "State is required" } ] }) } let zipCodeTextBox = $("
").dxTextBox( { width : 90, placeholder : "postal code", validationGroup : options.component.option( "validationGroup" ), onValueChanged : function( e ) { options.component.updateData( "zipCode", e.value ); } }).css( { "display" : "inline-block", "margin-left" : "8px" } ); if( instance.requiredFields.zipCode ) { zipCodeTextBox.dxValidator( { validationGroup : options.component.option( "validationGroup" ), validationRules : [ { type : "required", message : "Postal code is required" } ] }) } // add the editors to the component's options so we can find them later let customEditors = options.component.option( "customEditors" ); if( ! customEditors ) { customEditors = {}; } customEditors.zipCode = zipCodeTextBox.dxTextBox( "instance" ); customEditors.city = cityTextBox.dxTextBox( "instance" ); customEditors.state = stateSelectBox.dxSelectBox( "instance" ); options.component.option( "customEditors", customEditors ); itemElement.append( cityTextBox ) .append( stateSelectBox ) .append( zipCodeTextBox ) } }, /* { dataField : "county", label : { text : "County" }, editorType : "dxTextBox", editorOptions : { maxLength : 50, width : 100 } }, */ { dataField : "county", label : { text : "County" }, editorType : "dxAutocomplete", editorOptions : { width : 100, dataSource : countyDS, valueExpr : "county" } }, { label : { text : "Main Phone" }, isRequired : instance.requiredFields.phone, template : function( options, itemElement ) { let customEditors = options.component.option( "customEditors" ); if( ! customEditors ) { customEditors = {}; } let phoneValidationRules = [] if( false ) { phoneValidationRules.push( { ignoreEmptyValue : true, type: 'pattern', pattern: /^\d{3}-\d{3}-\d{4}$/, message: 'The phone must have a correct phone format', }) } if( instance.requiredFields.phone ) { phoneValidationRules.push( { type : "custom", message : "The phone is required", reevaluate : true, ignoreEmptyValue : false, validationCallback : function( options ) { let result = false; if( options.value ) { result = true; } return result; } }) } let phoneTextBox = $("
").dxTextBox( { width : 100, maxLength : 30, /* mask: '000-000-0000', maskChar : ' ', useMaskedValue : true, onValueChanged : function( e ) { if( e.value ) { if( e.value.replace( /\s|-/g, '' ) == '' ) { e.component.option( "value", null ); } else { options.component.updateData( "phone", e.value ); } } else { options.component.updateData( "phone", e.value ); } } */ onValueChanged : function( e ) { let theValue = e.value; if( e.component.option( "fseReformatted") ) { e.component.option( "fseReformatted", false ); options.component.updateData( "phone", e.value ); } else { let formatted = Fse.UI.reformatPhone( e.value ); if( formatted != e.value ) { e.component.option( { "fseReformatted" : true, value : formatted } ) } else { options.component.updateData( "phone", e.value ); } } } }).css( { "display" : "inline-block" } ).dxTextBox( "instance" ); if( phoneValidationRules.length ) { phoneTextBox.element().dxValidator( { validationGroup : options.component.option( "validationGroup" ), validationRules : phoneValidationRules }) } customEditors.phone = phoneTextBox; itemElement.append( phoneTextBox.element() ) let phoneExtTextBox = $("
").dxTextBox( { width : 50, maxLength : 10, onValueChanged : function( e ) { options.component.updateData( "phoneExt", e.value ); } }).css( { "display" : "inline-block" } ).dxTextBox( "instance" ); customEditors.phoneExt = phoneExtTextBox; itemElement .append( $("").text( "Ext." ).css( { "padding-left" : "8px", "padding-right" : "8px" }) ) .append( phoneExtTextBox.element() ); options.component.option( "customEditors", customEditors ); } } // 1. Sales Territory+ // 1. Sales Rep // 1. Priority+ // Classification+ // County // Main Phone // Extension // website URL // Email Address // instagram, facebook, x(Twitter), TikTok, YouTube // LinkedIn // 1. Preferred Distributor // Secondary Distributor // 1. Acct Nbr (Preferred Distributor) // Number of Units // Food Mgmt Co / ID / Since // Buying Group/GPO / ID / Since // 1. Primary Segment // Cuisine ); let distributionItems = [ { colSpan : 2, dataField : "distrib1", label : { location : "left", text : `Preferred ${getText( 'DISTRIBUTOR' )}` }, isRequired : instance.requiredFields.distrib1, editorType : "dxSelectBox", editorOptions : { showClearButton : true, searchEnabled : true, dataSource : Fse.Data.newDataSource( { dataURL : instance.dataURL, object : "CDR.distributorsLight", keyField : "cdr_recordId" } ), searchExpr : "cdr_dstName", searchMode : "contains", displayExpr : "cdr_dstName", valueExpr : "cdr_recordId", } }, { dataField : "distrib1_acctNbr", label : { location : "left", text : "Acct. Nbr" }, editorType : "dxTextBox", editorOptions : { maxLength : 50, disabled : true } }, { colSpan : 2, dataField : "distrib2", label : { location : "left", text : `Secondary ${getText( 'DISTRIBUTOR' )}` }, editorType : "dxSelectBox", editorOptions : { showClearButton : true, searchEnabled : true, dataSource : Fse.Data.newDataSource( { dataURL : instance.dataURL, object : "CDR.distributorsLight", keyField : "cdr_recordId" } ), searchExpr : "cdr_dstName", searchMode : "contains", displayExpr : "cdr_dstName", valueExpr : "cdr_recordId", } }, { dataField : "distrib2_acctNbr", label : { location : "left", text : "Acct. Nbr" }, editorType : "dxTextBox", editorOptions : { maxLength : 50, disabled : true } } ]; let numUnitsItems = [ { label : { location : "left", text : "Num. Units" }, template : function( options, itemElement ) { let customEditors = options.component.option( "customEditors" ); if( ! customEditors ) { customEditors = {}; } let currentYear = ( new Date() ).getFullYear(); let fieldDefs = [ { label : currentYear - 1, dataField : "numUnit_LY" }, { label : currentYear, dataField : "numUnit_TY" }, { label : currentYear + 1, dataField : "numUnit_NY" }, ]; fieldDefs.forEach( function( fd ) { let editor = $("
").dxTextBox( { width : 50, value : 1, onValueChanged : function( e ) { options.component.updateData( fd.dataField, e.value ); } }).dxTextBox( "instance" ); editor.element().dxValidator( { validationGroup : options.component.option( "validationGroup" ), validationRules : [ { type : "required", message : "A number zero or greater is required" }, { type : "numeric", message : "A number zero or greater is required" }, { type : "range", message : "A number zero or greater is required", min : 0 } ] }) let label = $("").text( fd.label ); label.css( { "padding-right" : "8px" }) editor.element().css( { "display" : "inline-block", "margin-right" : "10px" } ) itemElement.append( label ).append( editor.element() ) customEditors[fd.dataField] = editor; }) options.component.option( "customEditors", customEditors ); } } ]; let memberGroupItems = [ { colSpan : 2, label : { text : "Food Mgmt. Co" }, dataField : "cmc_operatorId", editorType : "dxSelectBox", editorOptions : { placeholder : "self managed", dataSource : Fse.Data.newDataSource( { object : "OPR.cmcs", keyField : "operatorId" }), searchEnabled : true, searchExpr : "companyName", searchMode : "contains", valueExpr : "operatorId", displayExpr : "companyName", showClearButton : true, } }, { label : { text : "ID" }, dataField : "cmc_memberNbr", editorType : "dxTextBox", editorOptions : { maxLength : 50, disabled : true } }, { label : { text : "Since" }, dataField : "cmc_affiliationDate", editorType : "dxDateBox", editorOptions : { disabled : true } }, { colSpan : 2, label : { text : "GPO/Buying Group" }, dataField : "gpo_operatorId", editorType : "dxSelectBox", editorOptions : { placeholder : "none", dataSource : Fse.Data.newDataSource( { object : "OPR.gpos", keyField : "operatorId" }), searchEnabled : true, searchExpr : "companyName", searchMode : "contains", valueExpr : "operatorId", displayExpr : "companyName", showClearButton : true, } }, { label : { text : "ID" }, dataField : "gpo_memberNbr", editorType : "dxTextBox", editorOptions : { maxLength : 50, disabled : true } }, { label : { text : "Since" }, dataField : "gpo_affiliationDate", editorType : "dxDateBox", editorOptions : { disabled : true } } ]; let otherItems = [ { dataField : "oprSegment", label : { location : "left", text : "Segment" }, isRequired : instance.requiredFields.oprSegment, editorType : "dxSelectBox", editorOptions : { showClearButton : true, dataSource : Fse.Data.newDataSource( { object : "OPR.segments", key : "clientSegId", map : function( dataItem ) { return { clientSegId : dataItem.clientSegId, segmentPath : dataItem.segmentPath, disabled : dataItem.hasChildSegments ? true : false, hierarchyLevel : dataItem.hierarchyLevel } } } ), itemTemplate : function( item ) { let itemText = item.segmentPath; let itemElement = $("
").attr( { "title" : itemText } ).text( itemText ); if( item.hierarchyLevel == 1 ) { itemTextParsed = itemText.split( "/" ); itemTextParsed.shift(); itemElement.css( { "padding-left" : "15px" } ).text( itemTextParsed.join( "/" ) ); } return itemElement; }, searchExpr : "segmentPath", searchMode : "contains", searchEnabled : true, displayExpr : "segmentPath", valueExpr : "clientSegId" } }, { dataField : "cuisineId", label : { location : "left", text : "Cuisine" }, editorType : "dxSelectBox", editorOptions : { showClearButton : true, dataSource : Fse.Data.newDataSource( { object : "OPR.cuisines", keyField : "cuisineId" } ), searchExpr : "cuisine", searchEnabled : true, searchMode : "contains", displayExpr : "cuisine", valueExpr : "cuisineId" } } ] let contactItems = instance.addOperatorTemplateContactItems(); instance.addOperatorForm = $("
").dxForm( { validationGroup : "addOperatorForm", items : [ { itemType : "tabbed", tabPanelOptions : { deferRendering : false }, // this is so all of the fields are rendered at the start tabs : [ { title : "Company", items : [ { itemType : "group", items : crmItems, }, { itemType: "group", items : companyItems }, { itemType : "group", items : internetItems }, { itemType : "group", colCount : 3, items : distributionItems }, { itemType : "group", items : numUnitsItems }, { itemType : "group", colCount : 4, items : memberGroupItems, }, { itemType : "group", items : otherItems, } ] }, { title : "Contact", items : contactItems } ] } ], onFieldDataChanged : function( e ) { let customEditors = e.component.option( "customEditors" ); if( customEditors && customEditors[e.dataField] ) { // push the data into the custom editor customEditors[e.dataField].option( "value", e.value ); } // handle object value for contact v. qualified field names if( e.dataField == "contact" && e.value ) { let customEditors = e.component.option( "customEditors" ); if( customEditors ) { for( contactField in e.value ) { let qualifiedContactField = `${e.dataField}.${contactField}`; if( customEditors && customEditors[qualifiedContactField] ) { // push the data into the custom editor customEditors[qualifiedContactField].option( "value", e.value[contactField] ); } } } } if( e.dataField == "gpo_operatorId" || e.dataField == "cmc_operatorId" ) { let fieldPrefix = e.dataField.split( "_" )[0]; let memberNbrEditor = e.component.getEditor( `${fieldPrefix}_memberNbr` ); let affiliationDateEditor = e.component.getEditor( `${fieldPrefix}_affiliationDate` ); let editorOptions = { disabled : e.value ? false : true } if( editorOptions.disabled ) { editorOptions.value = null; } memberNbrEditor.option( editorOptions ); affiliationDateEditor.option( editorOptions ); } if( e.dataField == "zipCode" && e.value ) { let territoryId = e.component.option( "formData").territoryId; if( ! territoryId ) { let salesTerritoryDS = Fse.Data.newDataSource( { object : "TER.salesTerritories", keyField : "territoryId", objectParams : { byZipCode : e.value } }); salesTerritoryDS.load().done( function( data ) { if( data.length == 1 ) { e.component.updateData( { territoryId : data[0].TerritoryID } ); } }) } } if( e.dataField == "territoryId" ) { let distrib1Editor = e.component.getEditor( "distrib1" ); let distrib2Editor = e.component.getEditor( "distrib2" ); let filter = []; if( e.value ) { filter.push( "relatedTerritoryIds", "contains", `#${e.value};` ); } else { filter.push( "territoryId", "=", -1 ); } let ds1 = distrib1Editor.getDataSource(); ds1.filter( filter ); ds1.load(); let ds2 = distrib2Editor.getDataSource(); ds2.filter( filter ); ds2.load(); let salesRepFilter = []; if( e.value ) { salesRepFilter.push( "territoryIdList", "contains", `#${e.value};` ); } let salesRepEditor = e.component.getEditor( "salesRepId" ); let salesRepDataSource = salesRepEditor.getDataSource(); salesRepDataSource.filter( salesRepFilter ); salesRepDataSource.load(); e.component.updateData( { "distrib1" : null, "distrib2" : null, "salesRepId" : null }); } if( e.dataField == "distrib1" || e.dataField == "distrib2" ) { let fieldOptions = { disabled : e.value ? false : true }; if( fieldOptions.disabled ) { fieldOptions.value = null; } e.component.getEditor( `${e.dataField}_acctNbr` ).option( fieldOptions ); } /* if( e.dataField == "addContact" ) { instance.enableAddOperatorContactFields( e.value ? true : false ); } */ if( e.dataField == "countryId" ) { let editor = null; let customEditors = e.component.option( "customEditors" ); if( customEditors ) { editor = customEditors.state; } if( editor ) { // let formData = e.component.option( "formData" ); let countryId = e.value; if( ! countryId ) { countryId = 0; } let stateDataSource = Fse.Data.newDataSource( { object : "UT.states", keyField : "state", objectParams : { countryId : countryId } } ); let placeholder = "state"; if( countryId == 5 ) { placeholder = "prov"; } editor.option( { dataSource : stateDataSource, "value" : null, placeholder : placeholder } ); editor.repaint(); } } if( e.dataField == "state" ) { let editor = e.component.getEditor( "county" ); if( editor ) { let formData = e.component.option( "formData" ); let countyDataSource = editor.getDataSource(); let countyFilter = []; if( formData.countryId ) { countyFilter.push( [ "countryId", "=", formData.countryId ] ) } else { countyFilter.push( [ "countryId", "=", 0 ] ) } countyFilter.push( "and" ); if( formData.state ) { countyFilter.push( [ "state", "=", formData.state ] ); } else { countyFilter.push( ["state", "=", "?" ]); } countyDataSource.filter( countyFilter ); editor.option( "value", null ); } } /* if( e.dataField.substring( 0, 8 ) == "contact." ) { console.log( "Contact Field Changed", e.dataField ); let editor = customEditors["contact.jobFunction"]; editor = e.component.getEditor( "contact.jobFunction" ); let validator = editor.element().dxValidator( "instance" ); console.log( validator ); } */ if( e.dataField == "contact.countryId" ) { let stateEditor = e.component.getEditor( "contact.state" ); if( stateEditor ) { let countryId = e.value; if( ! countryId ) { countryId = 0; } let placeholder = "state"; if( countryId == 5 ) { placeholder = "prov"; } let stateDataSource = Fse.Data.newDataSource( { object : "UT.states", keyField : "state", objectParams : { countryId : countryId } } ); stateEditor.option( { dataSource : stateDataSource, value : null, placeholder : placeholder }); stateEditor.repaint(); } } if( e.dataField == "contact.officeAddrSame" ) { let disabled = e.value ? true : false; ["contact.address1","contact.address2","contact.countryId","contact.city","contact.state","contact.zipCode"].forEach( function( f ) { let contactAddressEditor = e.component.getEditor( f ); if( contactAddressEditor ) { contactAddressEditor.option( "disabled", disabled ); } }) } } }).dxForm( "instance" ); return instance.addOperatorForm.element(); } NewOperatorProfileDialog.prototype.contactFieldValidationCallback = function( v ) { let instance = this; let valid = true; let isRequired = false; let formData = instance.addOperatorForm.option( "formData" ); for( contactField in formData.contact ) { if( formData.contact[contactField] ) { if( instance.contactDefaults[contactField] && instance.contactDefaults[contactField] === formData.contact[contactField] ) continue; isRequired = true; break; } } if( isRequired && ! v.value ) { valid = false; } return valid; } NewOperatorProfileDialog.prototype.addOperatorTemplateContactItems = function() { let instance = this; let contactItems = []; // the addContact value is determined by the presence of data // contactItems.push( { label : { text : "Add Contact" }, dataField : "addContact", editorType : "dxCheckBox" }); contactItems.push ( { label : { text : "Contact Name" }, template : function( options, itemElement ) { /* let salutationSelectBox = $("
").dxSelectBox( { width : 90, showClearButton : true, hint : "salutation", placeholder : null, dataSource: [ { text : "Mr." }, { text : "Ms." }, { text : "Miss" }, { text : "Dr." }, { text : "Chef" } ], displayExpr: "text", valueExpr : "text", onValueChanged : function( e ) { options.component.updateData( { "contact.salutation" : e.value } ); } }).dxSelectBox("instance" ) salutationSelectBox.element().dxValidator( { validationGroup : options.component.option( "validationGroup" ) }) */ let firstNameTextBox = $("
").dxTextBox( { width : 150, //maxLength : 50, placeholder : "first name", onValueChanged : function( e ) { options.component.updateData( { "contact.firstName" : e.value } ); } }).dxTextBox( "instance"); firstNameTextBox.element().dxValidator( { validationGroup : options.component.option( "validationGroup" ), validationRules : [ { type : "custom", reevaluate : true, message : "First Name is required", validationCallback : function( v ) { return instance.contactFieldValidationCallback( v ); } } ] }) let lastNameTextBox = $("
").dxTextBox( { width : 150, //maxLength : 50, placeholder : "last name", onValueChanged : function( e ) { options.component.updateData( { "contact.lastName" : e.value } ); } }).dxTextBox( "instance" ) lastNameTextBox.element().dxValidator( { validationGroup : options.component.option( "validationGroup" ) }) let primaryContactCheckBox = $("
").dxCheckBox( { text: "Primary Contact", onValueChanged: function (e) { options.component.updateData( "contact.primaryContact", e.value ); } }).dxCheckBox( "instance" ) let decisionMakerCheckBox = $("
").dxCheckBox( { text: "Decision maker", onValueChanged: function (e) { options.component.updateData( "contact.contactDecisionMaker", e.value ); } }).dxCheckBox( "instance" ) itemElement // .append( salutationSelectBox.element().css( { "display" : "inline-block" } )) .append( firstNameTextBox.element().css( { "display" : "inline-block" } )) .append( lastNameTextBox.element().css( { "display" : "inline-block", "margin-left" : "8px" } )) .append( $("
").append( primaryContactCheckBox.element() )) .append( $("
").append( decisionMakerCheckBox.element() )) let customEditors = options.component.option( "customEditors" ); if( ! customEditors ) { customEditors = {}; } customEditors["contact.firstName"] = firstNameTextBox; customEditors["contact.lastName"] = lastNameTextBox; // customEditors["contact.salutation"] = salutationSelectBox; customEditors["contact.contactDecisionMaker"] = decisionMakerCheckBox; customEditors["contact.primaryContact"] = primaryContactCheckBox; options.component.option( "customEditors", customEditors ); } }) contactItems.push( { dataField : "contact.caRelationshipRank", label : { text : "Relationship Rank" }, editorType : "dxSelectBox", editorOptions : { dataSource : Fse.Data.getLocalDataSource( "$.contactRelationshipRanks"), displayExpr : "caRelationshipRankText", valueExpr : "caRelationshipRank", searchEnabled : true, searchExpr : "caRelationshipRankText", searchMethod : "startswith", showClearButton : true, width : 150 } } ); contactItems.push( { dataField: "contact.email", label : { text : "Contact Email" }, editorType : "dxTextBox", editorOptions : { maxLength : 75, width : 200 }, validationRules : [ { type : "email" } ] }, { dataField: "contact.title", label : { text : "Contact Title" }, editorType : "dxTextBox", editorOptions : { maxLength : 75, width : 200, } }, { dataField : "contact.jobFunction", label : { text : "Job Function" }, visible : Fse.Portal.getConfiguration( "CRM.OPR.hasJobFunctions" ), editorType : "dxSelectBox", editorOptions : { dataSource : Fse.Data.getLocalDataSource( "$.operatorContactJobFunctions"), displayExpr : "caJobFunctionText", valueExpr : "caJobFunction", searchEnabled : true, searchExpr : "caJobFunctionText", searchMethod : "startswith", showClearButton : true, width : 150 }, validationRules : [ { type : "custom", reevaluate : true, message : "Job Function is required", validationCallback : function( v ) { if( ! Fse.Portal.getConfiguration( "CRM.OPR.hasJobFunctions" ) ) { return true; } return instance.contactFieldValidationCallback( v ); } } ] }, { dataField : "contact.preferredCommunication", label : { text : "Communication Pref." }, editorType: 'dxSelectBox', editorOptions: { width : 150, dataSource: [ { "dispValue": "Text" , "value": "T"}, { "dispValue": "Email" ,"value": "E"}, { "dispValue": "Phone", "value": "P"}, { "dispValue": "Cell", "value": "C"} ], showClearButton : true, displayExpr: "dispValue", valueExpr : "value", placeholder : "no preference", searchEnabled: true } }, { label : { text : "Contact Phone" }, template : function( options, itemElement ) { let phoneTextBox = $("
").dxTextBox( { width : 150, maxLength : 30, /* mask: '000-000-0000', maskChar : ' ', onValueChanged : function( e ) { options.component.updateData( "contact.phone", e.value ); } */ onValueChanged : function( e ) { console.log( e ); if( e.component.option( "fseReformatted") ) { console.log( "fseReformatted = false") e.component.option( "fseReformatted", false ); } else { let formatted = Fse.UI.reformatPhone( e.value ); if( formatted != e.value ) { e.component.option( { "fseReformatted" : true, value : formatted } ) console.log( "fseReformatted = true") } else { options.component.updateData( "contact.phone", e.value ); } } } }).dxTextBox( "instance"); let phoneExtTextBox = $("
").dxTextBox( { width : 60, maxLength : 10, onValueChanged : function( e ) { options.component.updateData( "contact.phoneExt", e.value ); } }).dxTextBox( "instance" ); itemElement .append( phoneTextBox.element().css( { "display" : "inline-block" } ) ) .append( $("").text( "Ext." ).css( { "padding-left" : "8px", "padding-right" : "8px" }) ) .append( phoneExtTextBox.element().css( { "display" : "inline-block" } ) ); let customEditors = options.component.option( "customEditors" ); if( ! customEditors ) { customEditors = {}; } customEditors["contact.phone"] = phoneTextBox; customEditors["contact.phoneExt"] = phoneExtTextBox; options.component.option( "customEditors", customEditors ); } }, { dataField: "contact.cell", label : { text : "Contact Mobile" }, editorType : "dxTextBox", editorOptions : { maxLength : 30, width : 150, // mask: '000-000-0000', maskChar : ' ' //, useMaskedValue : true onValueChanged : function( e ) { if( e.component.option( "fseReformatted") ) { e.component.option( "fseReformatted", false ); } else { let formatted = Fse.UI.reformatPhone( e.value ); if( formatted != e.value ) { e.component.option( { "fseReformatted" : true, value : formatted } ) } } } } }, ) let validURLPattern = Fse.CRM.socialMediaPlatforms.other.urlRegEx; /* let validURLPattern = /^https?:\/\/([-\w\.]+)+(:\d+)?(:\w+)?(@\d+)?(@\w+)?([-\w\.]+)(\/([\w\/_\.]*(\?\S+)?)?)?/i; */ let internetLocations = [ { dataField : "contact.linkedIn", label : "LinkedIn", placeholder : "LinkedIn URL", maxLength : 150, width : 300, type : "url", socialMediaPlatform : "linkedin" }, { dataField : "contact.facebook", label : "Facebook", placeholder : "Facebook URL or ID", type : "url", socialMediaPlatform : "facebook" }, { dataField : "contact.instagram", label : "Instagram", placeholder : "Instagram URL or ID", type : "url", socialMediaPlatform : "instagram" }, { dataField : "contact.twitter", label : "\"X\"", placeholder : "\"X\" URL or ID (1-15 char)", type : "url", socialMediaPlatform : "twitter" }, { dataField : "contact.tiktok", label : "TikTok",placeholder : "TikTok URL or ID", type : "url", socialMediaPlatform : "tiktok", }, { dataField : "contact.youtube", label : "YouTube", placeholder : "YouTube URL or ID (10 char)", type : "url", socialMediaPlatform : "youtube" }, ]; internetLocations.forEach( function( il ) { let item = { dataField : il.dataField, label : { text : il.label }, template : function( options, itemElement ) { let customEditors = options.component.option( "customEditors" ); if( ! customEditors ) { customEditors = {}; } let textBoxConfig = { maxLength : il.maxLength ? il.maxLength : null, placeholder : il.placeholder ? il.placeholder : null, width : il.width ? il.width : null, onValueChanged : function( e ) { options.component.updateData( options.dataField, e.value ); } }; if( il.type == "url" ) { textBoxConfig.onOptionChanged = function( e ) { if( e.name == "validationErrors" ) { let validationErrors = e.value; if( validationErrors ) { let errorHandled = false; validationErrors.forEach( function( ve ) { if( errorHandled ) return; if( ve.type == "pattern" ) { if( ve.socialMediaPlatform ) { let value = ve.value; if( ! value.match( validURLPattern ) ) { value = ve.urlTransform( value ); if( value.match( validURLPattern ) && value.match( ve.pattern ) ) { errorHandled = true; setTimeout( function() { e.component.option( "value", value ) }, 10 ); } } } else { let value = ve.value; if( ! value.match( /^https+:\/\//i) ) { value = value.replace( /^.*:/i, '' ).replace( /^\/\//, '' ); value = `https://${value}` errorHandled = true; setTimeout( function() { e.component.option( "value", value ) }, 10 ); } } } }) } } } } let textBox = $("
").dxTextBox( textBoxConfig ).dxTextBox( "instance" ); let validationRules = il.validationRules ? il.validationRules : null; if( ! validationRules && il.type == "url" ) { validationRules = []; let message = "Invalid URL"; if( il.socialMediaPlatform && Fse.CRM.socialMediaPlatforms[il.socialMediaPlatform] ) { let pattern = Fse.CRM.socialMediaPlatforms[il.socialMediaPlatform].urlRegEx; let urlTransform = Fse.CRM.socialMediaPlatforms[il.socialMediaPlatform].urlTransform; urlTransform ? urlTransform : function( v ) { return v }; message = `Invalid ${il.placeholder}`; validationRules.push( { type : "pattern", socialMediaPlatform : il.socialMediaPlatform, message : message, pattern : pattern, urlTransform : urlTransform } ) } validationRules.push( { type : "pattern", message : message, pattern : validURLPattern } ); } textBox.element().dxValidator( { validationGroup : options.component.option( "validationGroup" ), validationRules : validationRules }) let editorContainer = $("
"); editorContainer.append( textBox.element() ); itemElement.append( editorContainer ); customEditors[il.dataField] = textBox; options.component.option( "customEditors", customEditors ); } } contactItems.push( item ); }); contactItems.push( { dataField : "contact.preferredLanguage", label : { text : "Preferred Language" }, editorType: 'dxSelectBox', editorOptions: { width : 150, // dataSource : Fse.Data.newDataSource( { object : "CRM.languages", keyField : "languageCode" } ), dataSource : Fse.Data.getLocalDataSource( "$.languages"), displayExpr : "languageName", valueExpr : "languageCode", searchEnabled : true, searchExpr : "languageName", searchMethod : "startswith", showClearButton : true, placeholder : "" } } ) contactItems.push( { dataField : "contact.officeAddrSame", label : { text : "Location" }, editorType : "dxCheckBox", editorOptions : { text : "same as Company", onValueChanged : function( e ) { if( e.value ) { } else { } } } }, { dataField : "contact.address1", label : { text : "Address" }, isRequired : true, editorOptions : { maxLength : 75, xwidth : 150, disabled : true } }, { dataField : "contact.address2", label : { text : "Line 2" }, editorOptions : { maxLength : 75, xwidth : 150, disabled : true } } ); if( instance.showCountryField ) { contactItems.push( { dataField : "contact.countryId", label : { text : "Country" }, editorType : "dxSelectBox", editorOptions : { disabled : true, dataSource : Fse.Data.newDataSource( { object : "UT.countries", keyField : "countryId" } ), value : instance.defaultCountryId, displayExpr : "countryAbbrev", valueExpr : "countryId", width : 100 } }) } contactItems.push( { dataField : "contact.city", label : { text : "City" }, isRequired : true, editorOptions : { maxLength : 75, xwidth : 100, disabled : true } }, { dataField : "contact.state", label : { text : instance.defaultStateLabel }, isRequired : true, editorType : "dxSelectBox", editorOptions : { disabled : true, width : 80, dataSource : Fse.Data.newDataSource( { object : "UT.states", keyField : "state", objectParams : { countryId : instance.defaultCountryId } } ), placeholder : instance.defaultStatePlaceholder, displayExpr : "state", valueExpr : "state", searchEnabled : true, searchExpr : "state", searchMethod : "startswith", showClearButton : true } }, { dataField : "contact.zipCode", label : { text : "Postal Code" }, isRequired : true, editorOptions : { maxLength : 10, width : 80, disabled : true } } ) return contactItems; } NewOperatorProfileDialog.prototype.matchedOperatorTemplate = function() { let instance = this; let content = $("
"); content.append( $("

" ).css( "font-size", "larger" ).text( `The ${getText( 'OPERATOR' ).toLowerCase()} profile you are attempting to add already exists. Below is a brief view of the existing ${getText( 'OPERATOR' ).toLowerCase()} profile.` )); instance.matchedOperatorForm = $("

").dxForm( { readOnly : true, items : [ "territoryName", { itemType : "group", colCount : 3, items : [ { dataField : "accountOwnerFullName", label : { text : "Account Owner "} }, { dataField : "accountOwnerTitle", label : { text : "Title" }}, { dataField : "accountOwnerEmail", label : { text : "Email"}} ], }, "companyName", "address", "address2", "city", "state", "zipCode", { dataField : "recordSource", label : { text : "Source" } } ] }).dxForm( "instance" ); content.append( instance.matchedOperatorForm.element() ); content.append( $("

").css( "font-size", "larger" ).text( `You can either use the existing ${getText( 'OPERATOR' ).toLowerCase()} profile, revise your profile and try again, or add your ${getText( 'OPERATOR' ).toLowerCase()} as a duplicate.` )); instance.dupActionForm = $("

").dxForm( { items : [ { dataField : "dupAction", label : { text : "Duplicate Action" }, isRequired : true, editorType : "dxSelectBox", editorOptions : { placeholder : "select action", dataSource : [ { text : `Use Existing & Go to ${getText( 'OPERATOR' )}`, value : "useThisOne" }, { text : "Revise and try again", value : "revise" }, { text : "Add as a duplicate", value : "allowDup" } ], displayExpr : "text", valueExpr : "value" } }, { dataField : "allowDupReason", label : { text : "Reason for Duplicate" }, isRequired : true, editorType : "dxTextBox", editorOptions : { maxLength : 200, disabled : true } } ], onFieldDataChanged : function( e ) { if( e.dataField == "dupAction" ) { let reasonOptions = { disabled : true } if( e.value == "allowDup" ) { reasonOptions.disabled = false; reasonOptions.value = null; } e.component.getEditor( "allowDupReason" ).option( reasonOptions ); if( e.value == "revise" ) { instance.backToOperatorAdd(); } } } }).dxForm( "instance" ); content.append( instance.dupActionForm.element() ) return content; }