{"version":3,"sources":["webpack://ncq-ipf-portal/./node_modules/moment/locale|sync|/^/.*$","webpack://ncq-ipf-portal/./src/EventConstants.ts","webpack://ncq-ipf-portal/./src/IpfApplication.ts","webpack://ncq-ipf-portal/./src/constants.generated.ts","webpack://ncq-ipf-portal/./src/enums.generated.ts","webpack://ncq-ipf-portal/./src/functions/append-tier-query-params.ts","webpack://ncq-ipf-portal/./src/functions/apply-enter-button-target.ts","webpack://ncq-ipf-portal/./src/functions/as-number-or-string.ts","webpack://ncq-ipf-portal/./src/functions/call-function.ts","webpack://ncq-ipf-portal/./src/functions/client-log.ts","webpack://ncq-ipf-portal/./src/functions/do-when.ts","webpack://ncq-ipf-portal/./src/functions/format-numeric-input.ts","webpack://ncq-ipf-portal/./src/functions/get-message-icon.ts","webpack://ncq-ipf-portal/./src/functions/get-property.ts","webpack://ncq-ipf-portal/./src/functions/get-validation-attributes.ts","webpack://ncq-ipf-portal/./src/functions/global.ts","webpack://ncq-ipf-portal/./src/functions/is-form-button.ts","webpack://ncq-ipf-portal/./src/functions/is-null-or-undefined.ts","webpack://ncq-ipf-portal/./src/functions/is-valid-date.ts","webpack://ncq-ipf-portal/./src/functions/on-brokerreport-grid-build-row-link-template.ts","webpack://ncq-ipf-portal/./src/functions/on-loan-status-build-row-link-template.ts","webpack://ncq-ipf-portal/./src/functions/parse-boolean.ts","webpack://ncq-ipf-portal/./src/functions/seconds-to-string.ts","webpack://ncq-ipf-portal/./src/functions/set-parameter-value.ts","webpack://ncq-ipf-portal/./src/functions/set-property.ts","webpack://ncq-ipf-portal/./src/functions/string.ts","webpack://ncq-ipf-portal/./src/ioc/container.config.ts","webpack://ncq-ipf-portal/./src/ioc/types.ts","webpack://ncq-ipf-portal/./src/main.ts","webpack://ncq-ipf-portal/./src/models/app.ts","webpack://ncq-ipf-portal/./src/models/http.ts","webpack://ncq-ipf-portal/./src/models/wizard.ts","webpack://ncq-ipf-portal/./src/react/AppTheme.ts","webpack://ncq-ipf-portal/./src/react/ReactDOMProxy.tsx","webpack://ncq-ipf-portal/./src/react/component-services/BootstrapMessageService.tsx","webpack://ncq-ipf-portal/./src/react/component-services/MaterialDataGridService.tsx","webpack://ncq-ipf-portal/./src/react/component-services/MaterialFormComponentService.tsx","webpack://ncq-ipf-portal/./src/react/component-services/MaterialLoaderService.tsx","webpack://ncq-ipf-portal/./src/react/component-services/MaterialStepperService.tsx","webpack://ncq-ipf-portal/./src/react/component-services/MaterialTierSelectorService.tsx","webpack://ncq-ipf-portal/./src/react/components/Alert.tsx","webpack://ncq-ipf-portal/./src/react/components/ConfirmationPrompt.tsx","webpack://ncq-ipf-portal/./src/react/components/DataGridComponent.tsx","webpack://ncq-ipf-portal/./src/react/components/DatePicker.tsx","webpack://ncq-ipf-portal/./src/react/components/ElementLoader.tsx","webpack://ncq-ipf-portal/./src/react/components/MessageList.tsx","webpack://ncq-ipf-portal/./src/react/components/MobileNumberInput.tsx","webpack://ncq-ipf-portal/./src/react/components/PageLoader.tsx","webpack://ncq-ipf-portal/./src/react/components/SelectTierButton.tsx","webpack://ncq-ipf-portal/./src/react/components/SelectTierDialog.tsx","webpack://ncq-ipf-portal/./src/react/components/SelectedTierComponent.tsx","webpack://ncq-ipf-portal/./src/react/components/SwitchControl.tsx","webpack://ncq-ipf-portal/./src/react/components/TextInputSearch.tsx","webpack://ncq-ipf-portal/./src/react/components/Toast.tsx","webpack://ncq-ipf-portal/./src/react/components/Wizard.tsx","webpack://ncq-ipf-portal/./src/react/hooks/useInject.ts","webpack://ncq-ipf-portal/./src/services/IpfFormService.ts","webpack://ncq-ipf-portal/./src/services/IpfPageService.ts","webpack://ncq-ipf-portal/./src/services/IpfScriptService.ts","webpack://ncq-ipf-portal/./src/services/IpfSearchFilterService.ts","webpack://ncq-ipf-portal/./src/services/IpfSessionValidationService.ts","webpack://ncq-ipf-portal/./src/services/IpfUrlService.ts","webpack://ncq-ipf-portal/./src/services/IpfUserTierService.ts","webpack://ncq-ipf-portal/./src/services/JQueryAjaxService.ts","webpack://ncq-ipf-portal/./src/services/JQueryValidationService.ts","webpack://ncq-ipf-portal/./src/services/ServiceBase.ts","webpack://ncq-ipf-portal/./src/util/DateFnsAdapterWrapper.ts","webpack://ncq-ipf-portal/./src/util/Guid.ts"],"names":["map","webpackContext","req","id","webpackContextResolve","__webpack_require__","o","e","Error","code","keys","Object","resolve","module","exports","blur","change","click","focus","input","keydown","none","blur_ipf","change_ipf","click_ipf","input_ipf","keydown_ipf","paste_ipf","change_ipfvalidator","change_ipffilter","input_ipfnumericformat","blur_ipfnumericformat","key_backspace","key_delete","key_enter","key_tab","EventConstants","_context","_ensuredActiveElement","_onReady","Array","_data","this","_page","res","Constants","LoanStatusBuildRowLinkTemplateFunction","onLoanStatusBuildRowLinkTemplate","BrokerReportGridBuildRowLinkTemplateFunction","onBrokerReportGridBuildRowLinkTemplate","element","addOnReady","handler","onReady","push","applyEffects","getService","TYPES","PageService","clearData","key","container","get","getData","registerPage","service","bind","to","setData","data","setContext","context","ClientContext","toConstantValue","SessionValidationService","setupSessionTimer","refreshSessionTimeout","refreshSessionTimer","injectable","IpfApplication","CssClassFinancial","DataKeyCurrentBroker","DataKeyMessages","DataKeyPrompt","EqualityRuleName","ExportQueryFieldName","HasNumericValueRuleName","LoaderSilentDisable","LoanStatusBuildRowLinkTemplateHandler","LogoutPageName","MinLoanAmount","NegativeValueRuleName","NewBusinessFormId","PositiveValueRuleName","TierKeyPageTier","WipType","TimeoutDuration","TierLevel","NewBusinessWizardStep","NewBusinessPoliciesStage","NcqLogLevel","MTAType","MessageType","LoanType","ListSortDirection","GlobalSearchFilterType","FilterType","EditBusinessPartnerType","DataSourceMode","DataGridColumnType","CustomerType","linkElement","pageTier","href","getAttribute","url","URL","baseURI","params","URLSearchParams","search","setParameterValue","group","branch","broker","toString","setAttribute","applyEnterButtonTarget","triggerSelector","targetSelector","validator","$","off","on","event","preventDefault","asNumberOrString","value","numValue","isNaN","parseInt","functionName","arg","lastDot","lastIndexOf","getProperty","window","path","substring","ipfModule","getIpfModule","IpfModule","addMessageToLog","message","messages","getGlobal","setGlobal","prefix","clientDebugEnabled","console","log","obj","JSON","stringify","error","doWhen","doHandler","whenHandler","maxIteration","timeout","delay","iteration","ensuredIteration","setTimeout","isOnInput","decimalIndex","stringValue","originalCaretPos","selectionStart","length","decimalsAttr","allowedDecimals","indexOf","segments","split","withoutDecs","join","slice","endsWith","parseFloat","replace","formatted","toLocaleString","undefined","minimumFractionDigits","newCaretPos","setSelectionRange","type","iconClass","Success","Warning","name","ref","items","inScope","i","item","err","apply","target","dataVal","atts","isFormButton","tagName","includes","date","Date","getTime","args","template","dataItem","mtaId","urlService","drawdown","options","rowLinkTemplate","urlDataFormat","wipType","MTA","agreementNumber","setLiveDate","lcase","toLowerCase","seconds","perHour","perMinute","hours","minutes","str","Math","floor","paramName","newValue","set","delete","lastIndex","parentName","forEach","formatString","outputString","matches","match","val","field","encodedValue","encodeURIComponent","cssClasses","cssClass","Container","AjaxService","JQueryAjaxService","inSingletonScope","FormComponentService","MaterialFormComponentService","FormService","IpfFormService","DataGridService","MaterialDataGridService","LoaderService","MaterialLoaderService","MessageService","BootstrapMessageService","IpfPageService","ScriptService","IpfScriptService","SearchFilterService","IpfSearchFilterService","IpfSessionValidationService","TierSelectorService","MaterialTierSelectorService","UrlService","IpfUrlService","UserTierService","IpfUserTierService","ValidationService","JQueryValidationService","WizardService","MaterialStepperService","IPF","document","addEventListener","ready","EnsureTierLevel","Get","Post","Put","Delete","HttpMethods","targetElement","steps","activeStepElement","_targetElement","_steps","_activeStepElement","WizardConfig","stepElement","title","index","content","guid","Guid","newGuid","visible","navigatable","completed","WizardStep","AppTheme","createTheme","palette","primary","main","secondary","typography","fontFamily","renderStyled","callback","styledElement","StyledEngineProvider","injectFirst","ThemeProvider","theme","render","createElement","classList","add","ReactDOMProxy","componentClassName","unmountAll","querySelectorAll","unmount","remove","unmountComponentAtNode","applyMessageEffects","applyToastEffects","showMessage","clearMessages","messageList","messageTarget","getElementById","MessageList","addMessage","each","jElement","duration","Fast","Standard","Slow","fadeOut","currentTarget","closest","inject","ServiceBase","LightTooltip","tooltip","backgroundColor","background","paper","color","text","boxShadow","shadows","fontSize","fontWeight","marginTop","Tooltip","ajaxService","formService","filterService","_urlService","applyAll","refresh","elementId","refresher","gridRefreshers","resetPageIndex","gridOptions","sortModel","convertSortModel","apiModel","sorts","fieldSorts","columns","keyField","DataGridComponent","convertColumns","apiUrl","state","onRendered","onRendering","redraw","tearDownFuncs","autoSizeColumns","sizeColumns","filterElementId","filtersElementId","filtersElement","setupFilters","gridElement","g","applyRowClass","applyFinancialColumnAlignment","applyDetailRow","applyActivateOnRowClick","hasPageHandlers","find","col","pageHandler","hasApiHandlers","apiHandler","form","applyPageHandlers","applyApiHandlers","handleRowLinkTemplateClick","parentElement","onBuildRowLinkTemplate","callFunction","location","removeEventListener","column","columnType","colDef","headerName","width","sortable","hideSortIcons","disableColumnMenu","renderHeader","getColumnSortHeader","getState","sortField","sortComparator","v1","v2","cellParams1","cellParams2","sortValue1","sortValue2","sortCol","c","formattedField","displayType","HyperLink","ConditionalClass","conditionalClassName","Formatted","renderer","cellRenderers","renderCell","headerClassName","formatter","cellFormatters","className","addClass","cellClassName","tWidth","colWidths","resizeTimeout","sizingMultiplier","clientWidth","clearTimeout","renderBool","getTypedProperty","row","renderNegativeBool","renderFormatted","renderHyperLink","linkInnerContent","linkTemplate","link","urlServiceStatic","linkCssClass","icon","ico","label","linkAny","dataFormat","role","tabIndex","apih","extend","k","urlField","Fragment","activateOnRowClick","renderTooltip","placement","renderMailTo","email","mailTo","renderConditionalClass","rule","renderBadge","badgeCssClass","badgeCssClassField","fullCssClass","renderHtml","dangerouslySetInnerHTML","__html","renderIcon","formatFinancial","formatIcon","iconCellClass","tooltipTitle","s","sortDir","sort","sortDirIcon","getColumn","direction","Descending","lowered","paging","page","pageSize","sortItem","Ascending","applyFilters","filters","request","method","financialCols","cell","innerText","valueElement","querySelector","innerHTML","style","appendChild","valueElementWidth","getBoundingClientRect","visibility","isNullOrUndefined","detailRowKey","detailRowElementId","rowElement","hasChildRow","detailRowContainer","after","renderingZone","removeProperty","gridViewPort","gridWindow","position","gridRoot","rowPageHandler","empty","open","conditionalRowClassName","Map","Boolean","NegativeBoolean","Html","Icon","MailTo","Badge","Financial","tierSelectorService","validationService","loaderService","applySwitchComponents","applyDatePickers","applyMobileInput","applyTextInputSearchComponents","applyConfirmationPromptComponents","applySubmitLoaders","renderSwitch","switchProps","checked","size","props","offLabel","onLabel","onChange","dispatchEvent","Event","insertBefore","SwitchControl","renderTextInputSearch","selected","self","valueField","setTextInputSearchValueField","TextInputSearch","inputField","hasAttribute","setTierSelectorValue","prompt","confirmOption","actionUrl","cancelOption","showConfirmationPrompt","renderButtonConfirmationPrompt","button","excludeCancelBtn","typeAttr","renderTextAsHtml","onclick","removeAttribute","ConfirmationPrompt","body","append","autoOpen","dialogContent","onOpen","applySubmitLoaderBehaviour","HTMLButtonElement","isValidForm","loaderTarget","dataSubmitLoaderValue","loadingContainer","contains","renderDatePicker","ipf","selectedDate","toDate","newInput","format","dateFormat","toUpperCase","display","minDate","maxDate","defaultCalendarDate","placeholder","isValidDate","setHours","toISOString","clear","IpfDatePicker","muiInput","applyDatePickerBehaviour","renderMobileInput","number","MobileNumberInput","pageLoader","getDefaultPageLoaderOptions","pageLoaderContainer","PageLoader","showPageLoader","show","hidePageLoader","hide","elementLoaderWrapper","ElementLoader","loaderWrapper","stepElements","wizardConfig","getSteps","Wizard","config","titleElement","parentNode","removeChild","userTierService","applyGlobalTierSelectors","renderGlobalTierSelector","applyInputTierSelectors","renderInputTierSelector","selectedTier","globalTierSelector","urlParams","getQueryParams","getPageTier","onCancel","SelectedTierComponent","requiresBroker","requiresGroup","onDialogCancel","inputGroup","inputGroupAppend","inputText","rootTier","subscribe","tier","parse","defaultText","getSelectedTierPath","isAllowedToChangeBroker","inputGroupPrepend","disabled","SelectTierButton","onSelect","getAlertCssClass","Alert","messageType","Info","getPromptCssClass","useState","setOpen","useInject","useEffect","handleConfirm","handleClose","reason","closeOnBackdropClick","close","getMessageIcon","confirmType","confirmElement","Button","onClick","formAction","variant","autoFocus","cancelElement","buttons","reverseButtons","reverse","buttonsElement","DialogActions","messageElements","DialogContent","textElement","DialogContentText","targetElementId","Dialog","onClose","maxWidth","closeAfterTransition","transitionDuration","DialogTitle","loading","dataMode","Server","totalRecords","apiBindingEnabled","autoBind","setState","refreshGrid","func","refreshState","apiResult","then","response","apiProperty","count","catch","onGridError","minPageSize","pageSizeSelectionEnabled","pageSizeOptions","hideFooterPagination","pageSizes","components","NoRowsOverlay","noResultsMessage","Pagination","rowsPerPage","apiRef","useGridApiContext","pageNumber","start","nextStart","end","selectedValue","selectedOptions","current","setPageSize","defaultValue","totalPages","ceil","navDisabled","pageSizeContainer","shape","setPage","CustomPagination","titleCssClass","hiddenUntilBound","onGridDataBound","rowSelected","onRowSelected","showGrid","DataGrid","autoHeight","disableSelectionOnClick","onPageChange","onPageSizeChange","onSortModelChange","paginationMode","rowCount","rows","rowsPerPageOptions","sortingMode","onRowClick","disableVirtualization","getRowId","minHeight","OpenCalendarIcon","isInputInvalid","resetValidation","handleBlur","dateAdapter","DatePicker","renderInput","inputProps","TextField","onBlur","OpenPickerIcon","inputFormat","OpenPickerButtonProps","PopperProps","defaultCalendarMonth","ignoreInvalidInputs","CircularProgress","dismissMessage","findIndex","m","splice","timeoutDuration","dismiss","Toast","gb","ie","originalValue","country","startsWith","defaultCssClass","newPrefix","pattern","RegExp","test","getValidationAttributes","notYetRendered","warn","useStyles","makeStyles","createStyles","backdrop","zIndex","drawer","classes","Backdrop","SelectTierDialog","formControl","spacing","minWidth","getGroups","getTiers","getBranches","groupId","getBrokers","branchId","action","apiAction","controller","userTier","groupOptions","branchOptions","brokerOptions","groupEnabled","branchEnabled","brokerEnabled","groupHidden","isAllowedToChangeGroup","branchHidden","isAllowedToChangeBranch","brokerHidden","groupLabel","branchLabel","brokerLabel","updateState","cancelHandler","setEnabledState","selectedGroup","selectedBranch","hasGroup","hasBranch","cancelButton","groupOpen","hidden","getOptionLabel","option","isValid","result","onInputChange","branchOpen","brokerOpen","selectedBroker","selectedElement","selectTierButton","currentTier","getCurrentTier","setSelectedTier","tierSelected","setPageTier","onPageTierChanged","getLink","level","Link","newSelectedTier","Group","Branch","getText","Typography","brokerElement","isFullyConstrained","groupElement","branchElement","Breadcrumbs","separator","isAllowedToChangePageTier","StyledSwitch","switchBase","track","Switch","setChecked","containerCss","containerVisibleCss","resultCss","focusedResultCss","searchResults","showResults","resultsGuid","selectedText","handleBodyClick","hideResults","resultElements","textFieldName","valueFieldName","containerClass","selectItem","onfocus","oninput","trim","responsePromise","onkeydown","resultsElement","newIndex","getToastCssClass","dismissButton","dismissible","stepIndex","getActiveStepIndex","componentDidMount","insertStepContent","setActiveStepElementValue","componentDidUpdate","navigate","step","currentIndex","jForm","validatorData","valid","cancelable","setActiveStep","isUpdate","stepsContainer","visibleIndex","contentTarget","btn","forward","backward","focusElement","HTMLElement","visibleSteps","filter","activeStepKey","reset","Stepper","activeStep","orientation","nonLinear","Step","StepButton","StepContent","Paper","square","elevation","Component","identifier","formComponentService","applyValidation","applyRateAmountToggle","applyFieldBehaviours","applyNumericInputFormatting","originalAction","HTMLInputElement","handlerUrl","getFormPageHandlerUrl","submitForm","HTMLSelectElement","isSubmitButton","isNonSubmitButton","setEnsuredActiveElement","isLinkButton","isDiv","stopPropagation","successCallback","handlerString","bindModel","modelAny","model","setFieldValue","dataBind","attr","not","prop","submit","pageHandlerString","query","queryIndex","hash","hashIndex","testPageHandlerString","setProperty","extractFieldValue","is","numberValue","booleanValue","fieldType","isString","parseBoolean","toggle","rateField","amountField","css","jinput","fieldWrap","trigger","trims","textBox","clipboard","originalEvent","clipboardData","inputs","formatNumericInput","activeElement","ensuredActiveElement","dataGridService","messageService","scriptService","wizardService","pageLoaderTimeout","register","unobstrusive","applySearch","run","onerror","source","lineno","colno","setupErrorHandling","applyTierLinks","logError","searchValue","clientLoggingDisabled","userId","msg","detail","stack","logErrorInternal","logType","scripts","executedScripts","copy","script","onChangeHandler","inputTimeout","submitHandler","changeArgs","elements","onInput","insertClearFilter","Element","onExport","export","submitElement","filterElement","minLength","exportButton","dateInput","handleInputFilterEnter","getFilterType","TierSelector","clearFilter","filterData","filterName","getFilterName","filterType","valueRetriever","filterValueRetrievers","filterValue","apiModels","origFormAction","getPageTierUrl","queryField","getTextBoxFilterValue","clearTextBoxFilterValue","getTierSelectorFilterValue","clearTierSelectorFilterValue","textInput","clearDateFilterValue","getDropDownFilterValue","select","clearDropDownFilterValue","selectedIndex","hasValue","filterValueClearers","filterTypeString","TextBox","DropDown","expirySeconds","promptVisible","expiryElement","tickerElement","sessionExpiry","json","localStorage","getItem","sessionExpiryLsKey","setItem","timerStartLsKey","removeItem","sessionExpiryWarningSeconds","startSessionExpiryTimer","checkSessionExpiry","sessionExpirySeconds","sessionTimeout","absoluteSessionExpirySeconds","timerStart","timeDiff","logExpirySeconds","logUserOut","secondsToString","serviceType","promptOptions","showExpiryTimer","isOpen","hideExpiryTimer","getSessionExpirySeconds","Number","MAX_VALUE","expirySecondsOffset","setExpirySeconds","logSetExpirySeconds","stopSessionExpiryTimer","intervalRef","setInterval","logStartSessionExpiryTimer","clearInterval","isFirstime","disableLogging","logInfo","returnUrl","pathname","queryData","getPathBaseEnsuredUrl","getQueryString","baseUrl","urlFragments","addQueryParam","queryString","paramValue","GroupId","tierParamPlaceholders","BranchId","BrokerId","queryParams","propertyName","hasOwnProperty","replaceTierParamValue","pathBase","getPathBase","_subscribers","getUserTier","sessionTierJson","sessionStorage","SelectedTierSessionKey","sesionTier","ensureSecureSessionTier","currentUserTier","subscriber","t","ensureTierQueryString","Broker","hasCurrentBroker","ensureTierQueryParam","paramString","userTierId","tierParamName","has","sessionTier","userBrokerId","userBranchId","userGroupId","appendTierQueryParams","settings","contentType","headers","authToken","token","dataType","Promise","reject","success","status","getResponseHeader","handleAjaxError","complete","ajax","setupAjaxForm","disableAjax","submitter","ajaxTimeout","ajaxBefore","FormData","processData","html","newForm","reapplyUnobtrusiveValidator","ajaxComplete","ajaxError","onError","always","reload","validationModifiers","applyEmailInputValidation","applyMinPasswordLength","applyNotEqual","applyNumericInputValidation","applyDateValidation","modifier","ignore","onkeyup","onfocusout","onInvalid","unobtrusive","removeData","methods","optional","addMethod","adapters","addBool","notEqualField","inputElement","fieldName","notEqualInputElement","param","minDateStr","maxDateStr","component","reactInput","getYearRange","startDate","startOfYear","years","endOfYear","isAfter","addYears","r","random"],"mappings":"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","file":"js/main.js","sourcesContent":["var map = {\n\t\"./af\": 42786,\n\t\"./af.js\": 42786,\n\t\"./ar\": 30867,\n\t\"./ar-dz\": 14130,\n\t\"./ar-dz.js\": 14130,\n\t\"./ar-kw\": 96135,\n\t\"./ar-kw.js\": 96135,\n\t\"./ar-ly\": 56440,\n\t\"./ar-ly.js\": 56440,\n\t\"./ar-ma\": 47702,\n\t\"./ar-ma.js\": 47702,\n\t\"./ar-sa\": 16040,\n\t\"./ar-sa.js\": 16040,\n\t\"./ar-tn\": 37100,\n\t\"./ar-tn.js\": 37100,\n\t\"./ar.js\": 30867,\n\t\"./az\": 31083,\n\t\"./az.js\": 31083,\n\t\"./be\": 9808,\n\t\"./be.js\": 9808,\n\t\"./bg\": 68338,\n\t\"./bg.js\": 68338,\n\t\"./bm\": 67438,\n\t\"./bm.js\": 67438,\n\t\"./bn\": 8905,\n\t\"./bn-bd\": 76225,\n\t\"./bn-bd.js\": 76225,\n\t\"./bn.js\": 8905,\n\t\"./bo\": 11560,\n\t\"./bo.js\": 11560,\n\t\"./br\": 1278,\n\t\"./br.js\": 1278,\n\t\"./bs\": 80622,\n\t\"./bs.js\": 80622,\n\t\"./ca\": 2468,\n\t\"./ca.js\": 2468,\n\t\"./cs\": 5822,\n\t\"./cs.js\": 5822,\n\t\"./cv\": 50877,\n\t\"./cv.js\": 50877,\n\t\"./cy\": 47373,\n\t\"./cy.js\": 47373,\n\t\"./da\": 24780,\n\t\"./da.js\": 24780,\n\t\"./de\": 59740,\n\t\"./de-at\": 60217,\n\t\"./de-at.js\": 60217,\n\t\"./de-ch\": 60894,\n\t\"./de-ch.js\": 60894,\n\t\"./de.js\": 59740,\n\t\"./dv\": 5300,\n\t\"./dv.js\": 5300,\n\t\"./el\": 50837,\n\t\"./el.js\": 50837,\n\t\"./en-au\": 78348,\n\t\"./en-au.js\": 78348,\n\t\"./en-ca\": 77925,\n\t\"./en-ca.js\": 77925,\n\t\"./en-gb\": 22243,\n\t\"./en-gb.js\": 22243,\n\t\"./en-ie\": 46436,\n\t\"./en-ie.js\": 46436,\n\t\"./en-il\": 47207,\n\t\"./en-il.js\": 47207,\n\t\"./en-in\": 44175,\n\t\"./en-in.js\": 44175,\n\t\"./en-nz\": 76319,\n\t\"./en-nz.js\": 76319,\n\t\"./en-sg\": 31662,\n\t\"./en-sg.js\": 31662,\n\t\"./eo\": 92915,\n\t\"./eo.js\": 92915,\n\t\"./es\": 55655,\n\t\"./es-do\": 55251,\n\t\"./es-do.js\": 55251,\n\t\"./es-mx\": 96112,\n\t\"./es-mx.js\": 96112,\n\t\"./es-us\": 71146,\n\t\"./es-us.js\": 71146,\n\t\"./es.js\": 55655,\n\t\"./et\": 5603,\n\t\"./et.js\": 5603,\n\t\"./eu\": 77763,\n\t\"./eu.js\": 77763,\n\t\"./fa\": 76959,\n\t\"./fa.js\": 76959,\n\t\"./fi\": 11897,\n\t\"./fi.js\": 11897,\n\t\"./fil\": 42549,\n\t\"./fil.js\": 42549,\n\t\"./fo\": 94694,\n\t\"./fo.js\": 94694,\n\t\"./fr\": 94470,\n\t\"./fr-ca\": 63049,\n\t\"./fr-ca.js\": 63049,\n\t\"./fr-ch\": 52330,\n\t\"./fr-ch.js\": 52330,\n\t\"./fr.js\": 94470,\n\t\"./fy\": 5044,\n\t\"./fy.js\": 5044,\n\t\"./ga\": 29295,\n\t\"./ga.js\": 29295,\n\t\"./gd\": 2101,\n\t\"./gd.js\": 2101,\n\t\"./gl\": 38794,\n\t\"./gl.js\": 38794,\n\t\"./gom-deva\": 27884,\n\t\"./gom-deva.js\": 27884,\n\t\"./gom-latn\": 23168,\n\t\"./gom-latn.js\": 23168,\n\t\"./gu\": 95349,\n\t\"./gu.js\": 95349,\n\t\"./he\": 24206,\n\t\"./he.js\": 24206,\n\t\"./hi\": 30094,\n\t\"./hi.js\": 30094,\n\t\"./hr\": 30316,\n\t\"./hr.js\": 30316,\n\t\"./hu\": 22138,\n\t\"./hu.js\": 22138,\n\t\"./hy-am\": 11423,\n\t\"./hy-am.js\": 11423,\n\t\"./id\": 29218,\n\t\"./id.js\": 29218,\n\t\"./is\": 90135,\n\t\"./is.js\": 90135,\n\t\"./it\": 90626,\n\t\"./it-ch\": 10150,\n\t\"./it-ch.js\": 10150,\n\t\"./it.js\": 90626,\n\t\"./ja\": 39183,\n\t\"./ja.js\": 39183,\n\t\"./jv\": 24286,\n\t\"./jv.js\": 24286,\n\t\"./ka\": 12105,\n\t\"./ka.js\": 12105,\n\t\"./kk\": 47772,\n\t\"./kk.js\": 47772,\n\t\"./km\": 18758,\n\t\"./km.js\": 18758,\n\t\"./kn\": 79282,\n\t\"./kn.js\": 79282,\n\t\"./ko\": 33730,\n\t\"./ko.js\": 33730,\n\t\"./ku\": 1408,\n\t\"./ku.js\": 1408,\n\t\"./ky\": 33291,\n\t\"./ky.js\": 33291,\n\t\"./lb\": 36841,\n\t\"./lb.js\": 36841,\n\t\"./lo\": 55466,\n\t\"./lo.js\": 55466,\n\t\"./lt\": 57010,\n\t\"./lt.js\": 57010,\n\t\"./lv\": 37595,\n\t\"./lv.js\": 37595,\n\t\"./me\": 39861,\n\t\"./me.js\": 39861,\n\t\"./mi\": 35493,\n\t\"./mi.js\": 35493,\n\t\"./mk\": 95966,\n\t\"./mk.js\": 95966,\n\t\"./ml\": 87341,\n\t\"./ml.js\": 87341,\n\t\"./mn\": 5115,\n\t\"./mn.js\": 5115,\n\t\"./mr\": 10370,\n\t\"./mr.js\": 10370,\n\t\"./ms\": 9847,\n\t\"./ms-my\": 41237,\n\t\"./ms-my.js\": 41237,\n\t\"./ms.js\": 9847,\n\t\"./mt\": 72126,\n\t\"./mt.js\": 72126,\n\t\"./my\": 56165,\n\t\"./my.js\": 56165,\n\t\"./nb\": 64924,\n\t\"./nb.js\": 64924,\n\t\"./ne\": 16744,\n\t\"./ne.js\": 16744,\n\t\"./nl\": 93901,\n\t\"./nl-be\": 59814,\n\t\"./nl-be.js\": 59814,\n\t\"./nl.js\": 93901,\n\t\"./nn\": 83877,\n\t\"./nn.js\": 83877,\n\t\"./oc-lnc\": 92135,\n\t\"./oc-lnc.js\": 92135,\n\t\"./pa-in\": 15858,\n\t\"./pa-in.js\": 15858,\n\t\"./pl\": 64495,\n\t\"./pl.js\": 64495,\n\t\"./pt\": 89520,\n\t\"./pt-br\": 57971,\n\t\"./pt-br.js\": 57971,\n\t\"./pt.js\": 89520,\n\t\"./ro\": 96459,\n\t\"./ro.js\": 96459,\n\t\"./ru\": 21793,\n\t\"./ru.js\": 21793,\n\t\"./sd\": 40950,\n\t\"./sd.js\": 40950,\n\t\"./se\": 10490,\n\t\"./se.js\": 10490,\n\t\"./si\": 90124,\n\t\"./si.js\": 90124,\n\t\"./sk\": 64249,\n\t\"./sk.js\": 64249,\n\t\"./sl\": 14985,\n\t\"./sl.js\": 14985,\n\t\"./sq\": 51104,\n\t\"./sq.js\": 51104,\n\t\"./sr\": 49131,\n\t\"./sr-cyrl\": 79915,\n\t\"./sr-cyrl.js\": 79915,\n\t\"./sr.js\": 49131,\n\t\"./ss\": 95606,\n\t\"./ss.js\": 95606,\n\t\"./sv\": 98760,\n\t\"./sv.js\": 98760,\n\t\"./sw\": 91172,\n\t\"./sw.js\": 91172,\n\t\"./ta\": 27333,\n\t\"./ta.js\": 27333,\n\t\"./te\": 23110,\n\t\"./te.js\": 23110,\n\t\"./tet\": 52095,\n\t\"./tet.js\": 52095,\n\t\"./tg\": 27321,\n\t\"./tg.js\": 27321,\n\t\"./th\": 9041,\n\t\"./th.js\": 9041,\n\t\"./tk\": 19005,\n\t\"./tk.js\": 19005,\n\t\"./tl-ph\": 75768,\n\t\"./tl-ph.js\": 75768,\n\t\"./tlh\": 89444,\n\t\"./tlh.js\": 89444,\n\t\"./tr\": 72397,\n\t\"./tr.js\": 72397,\n\t\"./tzl\": 28254,\n\t\"./tzl.js\": 28254,\n\t\"./tzm\": 51106,\n\t\"./tzm-latn\": 30699,\n\t\"./tzm-latn.js\": 30699,\n\t\"./tzm.js\": 51106,\n\t\"./ug-cn\": 9288,\n\t\"./ug-cn.js\": 9288,\n\t\"./uk\": 67691,\n\t\"./uk.js\": 67691,\n\t\"./ur\": 13795,\n\t\"./ur.js\": 13795,\n\t\"./uz\": 6791,\n\t\"./uz-latn\": 60588,\n\t\"./uz-latn.js\": 60588,\n\t\"./uz.js\": 6791,\n\t\"./vi\": 65666,\n\t\"./vi.js\": 65666,\n\t\"./x-pseudo\": 14378,\n\t\"./x-pseudo.js\": 14378,\n\t\"./yo\": 75805,\n\t\"./yo.js\": 75805,\n\t\"./zh-cn\": 83839,\n\t\"./zh-cn.js\": 83839,\n\t\"./zh-hk\": 55726,\n\t\"./zh-hk.js\": 55726,\n\t\"./zh-mo\": 99807,\n\t\"./zh-mo.js\": 99807,\n\t\"./zh-tw\": 74152,\n\t\"./zh-tw.js\": 74152\n};\n\n\nfunction webpackContext(req) {\n\tvar id = webpackContextResolve(req);\n\treturn __webpack_require__(id);\n}\nfunction webpackContextResolve(req) {\n\tif(!__webpack_require__.o(map, req)) {\n\t\tvar e = new Error(\"Cannot find module '\" + req + \"'\");\n\t\te.code = 'MODULE_NOT_FOUND';\n\t\tthrow e;\n\t}\n\treturn map[req];\n}\nwebpackContext.keys = function webpackContextKeys() {\n\treturn Object.keys(map);\n};\nwebpackContext.resolve = webpackContextResolve;\nmodule.exports = webpackContext;\nwebpackContext.id = 46700;","/**\r\n * Event constants class, contains event name strings and keyboard event key names.\r\n */\r\nexport abstract class EventConstants {\r\n\r\n\tpublic static readonly blur = \"blur\";\r\n\tpublic static readonly change = \"change\";\r\n\tpublic static readonly click = \"click\";\r\n\tpublic static readonly focus = \"focus\";\r\n\tpublic static readonly input = \"input\";\r\n\tpublic static readonly keydown = \"keydown\";\r\n\tpublic static readonly none = \"none\";\r\n\r\n\tpublic static readonly blur_ipf = \"blur.ipf\";\r\n\tpublic static readonly change_ipf = \"change.ipf\";\r\n\tpublic static readonly click_ipf = \"click.ipf\";\r\n\tpublic static readonly input_ipf = \"input.ipf\";\r\n\tpublic static readonly keydown_ipf = \"keydown.ipf\";\r\n\tpublic static readonly paste_ipf = \"paste.ipf\";\r\n\r\n\tpublic static readonly change_ipfvalidator = \"change.ipfvalidator\";\r\n\r\n\tpublic static readonly change_ipffilter = \"change.ipffilter\";\r\n\r\n\tpublic static readonly input_ipfnumericformat = \"input.ipfnumericformat\";\r\n\tpublic static readonly blur_ipfnumericformat = \"blur.ipfnumericformat\";\r\n\r\n\tpublic static readonly key_backspace = \"Backspace\";\r\n\tpublic static readonly key_delete = \"Delete\";\r\n\tpublic static readonly key_enter = \"Enter\";\r\n\tpublic static readonly key_tab = \"Tab\";\r\n}","import { injectable } from \"inversify\";\r\nimport { IpfModule } from \".\";\r\nimport { Constants } from \"./constants.generated\";\r\nimport { onLoanStatusBuildRowLinkTemplate } from \"./functions/on-loan-status-build-row-link-template\";\r\nimport { onBrokerReportGridBuildRowLinkTemplate } from \"./functions/on-brokerreport-grid-build-row-link-template\";\r\nimport { container } from \"./ioc/container.config\";\r\nimport { TYPES } from \"./ioc/types\";\r\nimport { ClientContext } from \"./models/app\";\r\nimport { PageInterface } from \"./pages\";\r\nimport { PageService, SessionValidationService } from \"./services\";\r\nimport { ServiceBase } from \"./services/ServiceBase\";\r\n\r\n@injectable()\r\nexport class IpfApplication implements IpfModule {\r\n\r\n\tprivate _context = {} as ClientContext;\r\n\tprivate _page?: PageInterface;\r\n\tprivate _ensuredActiveElement: HTMLElement | null = null;\r\n\tprivate readonly _onReady = new Array<() => void>();\r\n\tprivate readonly _data = {} as { [key: string]: any; };\r\n\r\n\tpublic get onReady(): Array<() => void> {\r\n\t\treturn this._onReady;\r\n\t}\r\n\r\n\tpublic get context(): ClientContext {\r\n\t\treturn this._context;\r\n\t}\r\n\r\n\tpublic get page() {\r\n\t\treturn this._page;\r\n\t}\r\n\r\n\tpublic get handlers() {\r\n\t\tconst res: Record = {};\r\n\t\tres[Constants.LoanStatusBuildRowLinkTemplateFunction] = onLoanStatusBuildRowLinkTemplate;\r\n\t\tres[Constants.BrokerReportGridBuildRowLinkTemplateFunction] = onBrokerReportGridBuildRowLinkTemplate;\r\n\t\treturn res;\r\n\t}\r\n\r\n\tpublic get ensuredActiveElement(): HTMLElement | null {\r\n\t\treturn this._ensuredActiveElement;\r\n\t}\r\n\r\n\tpublic set ensuredActiveElement(element: HTMLElement | null) {\r\n\t\tthis._ensuredActiveElement = element;\r\n\t}\r\n\r\n\tpublic addOnReady(handler: () => void) {\r\n\r\n\t\tthis.onReady.push(handler);\r\n\t}\r\n\r\n\tpublic applyEffects(element: Element) {\r\n\r\n\t\tthis.getService(TYPES.PageService).applyEffects(element);\r\n\t}\r\n\r\n\tpublic clearData(key: string) {\r\n\r\n\t\tdelete this._data[key];\r\n\t}\r\n\r\n\tpublic getService(key: string): TService {\r\n\r\n\t\treturn container.get(key);\r\n\t}\r\n\r\n\tpublic getData(key: string): TData {\r\n\t\treturn this._data[key] as TData;\r\n\t}\r\n\r\n\tpublic registerPage(service: { new(...args: any[]): TPage; }, id: string) {\r\n\t\tcontainer.bind(id).to(service);\r\n\t\tthis._page = container.get(id);\r\n\t\treturn this._page as TPage;\r\n\t}\r\n\r\n\tpublic setData(key: string, data: TData) {\r\n\t\tthis._data[key] = data;\r\n\t}\r\n\r\n\tpublic setContext(context: ClientContext) {\r\n\t\tthis._context = context;\r\n\t\tcontainer.bind(TYPES.ClientContext).toConstantValue(context);\r\n\r\n\t\tcontainer.get(TYPES.SessionValidationService).setupSessionTimer();\r\n\t}\r\n\r\n\tpublic refreshSessionTimeout() {\r\n\t\tthis.getService(TYPES.SessionValidationService).refreshSessionTimer();\r\n\t}\r\n}","export abstract class Constants {\r\n\tpublic static readonly BrokerReportGridBuildRowLinkTemplateFunction = \"onBrokerReportGridBuildRowLinkTemplate\";\r\n\tpublic static readonly CssClassFinancial = \"financial\";\r\n\tpublic static readonly DataKeyCurrentBroker = \"CurrentBroker\";\r\n\tpublic static readonly DataKeyMessages = \"Messages\";\r\n\tpublic static readonly DataKeyPrompt = \"Prompt\";\r\n\tpublic static readonly EqualityRuleName = \"Equality\";\r\n\tpublic static readonly ExportQueryFieldName = \"ExportQuery\";\r\n\tpublic static readonly HasNumericValueRuleName = \"HasNumericValue\";\r\n\tpublic static readonly LoaderSilentDisable = \"silent-disable\";\r\n\tpublic static readonly LoanStatusBuildRowLinkTemplateFunction = \"onLoanStatusBuildRowLinkTemplate\";\r\n\tpublic static readonly LoanStatusBuildRowLinkTemplateHandler = \"IPF.handlers.onLoanStatusBuildRowLinkTemplate\";\r\n\tpublic static readonly LogoutPageName = \"/Identity/Account/Logout\";\r\n\tpublic static readonly MinLoanAmount = 20;\r\n\tpublic static readonly NegativeValueRuleName = \"NegativeValue\";\r\n\tpublic static readonly NewBusinessFormId = \"new-business\";\t\t\r\n\tpublic static readonly PositiveValueRuleName = \"PositiveValue\";\r\n\tpublic static readonly TierKeyPageTier = \"PageTier\";\r\n}","export enum CustomerType {\r\n\tNotSet = 0,\r\n\tLimitedCompany = 1,\r\n\tPartnership = 2,\r\n\tPrivateIndividual = 3,\r\n\tSoleTrader = 4,\r\n}\r\n\r\nexport enum DataGridColumnType {\r\n\tNotSet = 0,\r\n\tDefault = 1,\r\n\tBoolean = 2,\r\n\tNegativeBoolean = 3,\r\n\tFinancial = 4,\r\n\tFormatted = 5,\r\n\tHtml = 6,\r\n\tHyperLink = 7,\r\n\tIcon = 8,\r\n\tMailTo = 9,\r\n\tTooltip = 10,\r\n\tConditionalClass = 11,\r\n\tBadge = 12,\r\n}\r\n\r\nexport enum DataSourceMode {\r\n\tNotSet = 0,\r\n\tClient = 1,\r\n\tServer = 2,\r\n}\r\n\r\nexport enum EditBusinessPartnerType {\r\n\tCustomer = 0,\r\n\tPartner = 1,\r\n\tProprietor = 2,\r\n}\r\n\r\nexport enum FilterType {\r\n\tNotSet = 0,\r\n\tTextBox = 1,\r\n\tDropDown = 2,\r\n\tTierSelector = 3,\r\n\tDate = 4,\r\n}\r\n\r\nexport enum GlobalSearchFilterType {\r\n\tProposal = 0,\r\n\tRACA = 1,\r\n\tDrawdown = 2,\r\n\tFSA = 3,\r\n\tCustomer = 4,\r\n\tPolicy = 5,\r\n\tWIP = 6,\r\n}\r\n\r\nexport enum ListSortDirection {\r\n\tAscending = 0,\r\n\tDescending = 1,\r\n}\r\n\r\nexport enum LoanType {\r\n\tNotSet = 0,\r\n\tConsumer = 1,\r\n\tCommercial = 2,\r\n}\r\n\r\nexport enum MessageType {\r\n\tInfo = 0,\r\n\tSuccess = 1,\r\n\tWarning = 2,\r\n\tError = 3,\r\n}\r\n\r\nexport enum MTAType {\r\n\tPositive = 0,\r\n\tNegative = 1,\r\n}\r\n\r\nexport enum NcqLogLevel {\r\n\tTrace = 0,\r\n\tDebug = 1,\r\n\tInformation = 2,\r\n\tWarning = 3,\r\n\tError = 4,\r\n\tCritical = 5,\r\n\tNone = 6,\r\n}\r\n\r\nexport enum NewBusinessPoliciesStage {\r\n\tNotSet = 0,\r\n\tPolicyDetails = 1,\r\n\tFinancialDetails = 2,\r\n\tResults = 3,\r\n}\r\n\r\nexport enum NewBusinessWizardStep {\r\n\tNotSet = 0,\r\n\tSearch = 1,\r\n\tCustomerType = 2,\r\n\tCustomerInformation = 3,\r\n\tParties = 4,\r\n\tPolicies = 5,\r\n\tBankDetails = 6,\r\n\tSummary = 7,\r\n}\r\n\r\nexport enum TierLevel {\r\n\tNotSet = 0,\r\n\tBroker = 1,\r\n\tBranch = 2,\r\n\tGroup = 3,\r\n}\r\n\r\nexport enum TimeoutDuration {\r\n\tNotSet = 0,\r\n\tFast = 1,\r\n\tStandard = 2,\r\n\tSlow = 3,\r\n}\r\n\r\nexport enum WipType {\r\n\tNewBusiness = 0,\r\n\tRenewal = 1,\r\n\tDrawdown = 2,\r\n\tMTA = 3,\r\n}\r\n\r\n","import { setParameterValue } from \"./set-parameter-value\";\r\nimport { SelectedTier } from \"../models/app\";\r\n\r\n/**\r\n * Appends tier query string parameters to the href attribute of an HTMLLinkElement.\r\n * @param linkElement The HTMLLinkElement to append params to.\r\n * @param pageTier The tier params to apply.\r\n */\r\nexport function appendTierQueryParams(linkElement: HTMLLinkElement, pageTier: SelectedTier):void {\r\n\tconst href: string = linkElement.getAttribute(\"href\") ?? \"\";\r\n\r\n\tif (href) {\r\n\t\t// build new URL to conveniently apply the tier parameter IDs\r\n\t\tlet url = new URL(href, linkElement.baseURI);\r\n\t\tlet params = new URLSearchParams(url.search);\r\n\r\n\t\t// set tier parameters on the query string\r\n\t\tsetParameterValue(params, \"tier1\", pageTier?.group?.id);\r\n\t\tsetParameterValue(params, \"tier2\", pageTier?.branch?.id);\r\n\t\tsetParameterValue(params, \"tier3\", pageTier?.broker?.id);\r\n\r\n\t\turl.search = params.toString();\r\n\r\n\t\t// set href attribute\r\n\t\tlinkElement.setAttribute(\"href\", url.toString());\r\n\t}\r\n}","import { EventConstants } from \"../EventConstants\";\r\n\r\n/**\r\n * Adds an event to an element to on pressing the enter key, trigger the click of a button element.\r\n * @param triggerSelector The selector for the element to add the key down event to.\r\n * @param targetSelector The button element selector.\r\n * @param validator An optional validation function to call, to determine if the button should be clicked or not.\r\n */\r\nexport const applyEnterButtonTarget = (triggerSelector: string, targetSelector: string, validator?: () => boolean) => {\r\n\r\n\t$(triggerSelector).off(EventConstants.keydown_ipf).on(EventConstants.keydown_ipf, event => {\r\n\r\n\t\t// handle the enter key being pressed\r\n\t\tif (event.key === EventConstants.key_enter) {\r\n\r\n\t\t\t// if there is no validator function or it doesn't return false explicitly, trigger the click\r\n\t\t\tif (!validator || validator() !== false) {\r\n\t\t\t\t$(targetSelector).click();\r\n\t\t\t}\r\n\t\t\tevent.preventDefault();\r\n\t\t}\r\n\t});\r\n}","/**\r\n * Converts a string to a number if compatible, otherwise returns the string as is.\r\n * @param value The string value to convert.\r\n */\r\nexport const asNumberOrString = (value: string) => {\r\n\r\n\tlet numValue: number;\r\n\tif (!isNaN((numValue = parseInt(value)))) {\r\n\r\n\t\treturn numValue;\r\n\t}\r\n\telse {\r\n\r\n\t\treturn value;\r\n\t}\r\n}","import { getProperty } from \"./get-property\";\r\n\r\n/**\r\n * Calls a function by name, which can be a shallow or deep object path starting from window.\r\n * @param functionName The full path of the function.\r\n * @param arg An optional argument to pass to the function.\r\n */\r\nexport function callFunction(functionName: string, arg?: any) {\r\n\r\n\t// check for a deep path\r\n\tconst lastDot = functionName.lastIndexOf(\".\");\r\n\tif (lastDot > -1) {\r\n\r\n\t\t// it's a path, get the direct parent first\r\n\t\tconst path = functionName.substring(0, lastDot);\r\n\t\tconst name = functionName.substring(lastDot + 1);\r\n\t\tconst container = getProperty(window, path);\r\n\r\n\t\tif (container) {\r\n\r\n\t\t\t// get the function and attempt to call it\r\n\t\t\treturn container[name](arg);\r\n\t\t}\r\n\t}\r\n\telse {\r\n\r\n\t\t// get the function and attempt to call it\r\n\t\treturn getProperty(window, functionName)(arg);\r\n\t}\r\n}","import { IpfModule } from \"..\";\r\nimport { container } from \"../ioc/container.config\";\r\nimport { TYPES } from \"../ioc/types\";\r\nimport { getGlobal, setGlobal } from \"./global\";\r\n\r\nlet ipfModule: IpfModule;\r\n\r\n/**\r\n * Gets the IPF module from the DI container. \r\n */\r\nfunction getIpfModule() {\r\n\r\n\tif (!ipfModule) {\r\n\r\n\t\tipfModule = container.get(TYPES.IpfModule);\r\n\t}\r\n\r\n\treturn ipfModule;\r\n}\r\n/**\r\n * Adds a message to the client log. Useful for debugging.\r\n * @param message The message to log.\r\n */\r\nfunction addMessageToLog(message: string) {\r\n\r\n\tlet messages = getGlobal>(\"clientLog\");\r\n\r\n\tif (!messages) {\r\n\r\n\t\tmessages = new Array();\r\n\t\tsetGlobal(\"clientLog\", messages);\r\n\t}\r\n\r\n\tmessages.push(message);\r\n}\r\n\r\n/**\r\n * Logs a message to the console and the message log.\r\n * @param message The message to log.\r\n * @param prefix Optional message prefix.\r\n */\r\nexport function logInfo(message: string, prefix?: string) {\r\n\r\n\tconst ipf = getIpfModule();\r\n\r\n\tif (ipf.context.clientDebugEnabled) {\r\n\r\n\t\tif (prefix) {\r\n\r\n\t\t\tmessage = prefix + \" - \" + message;\r\n\t\t}\r\n\r\n\t\tconsole.log(message);\r\n\t\taddMessageToLog(message);\r\n\t}\r\n}\r\n\r\n/**\r\n * Logs an object to the console and the message log.\r\n * @param obj The object to log.\r\n */\r\nexport function logObject(obj: object) {\r\n\r\n\tconst ipf = getIpfModule();\r\n\r\n\tif (ipf.context.clientDebugEnabled) {\r\n\r\n\t\tconsole.log(obj);\r\n\t\taddMessageToLog(JSON.stringify(obj));\r\n\t}\r\n}\r\n\r\n/**\r\n * Logs an error to the console and the message log.\r\n * @param message The message to log.\r\n * @param prefix Optional message prefix.\r\n */\r\nexport function logError(message: string, prefix?: string) {\r\n\r\n\tconst ipf = getIpfModule();\r\n\r\n\tif (ipf.context.clientDebugEnabled) {\r\n\r\n\t\tif (prefix) {\r\n\r\n\t\t\tmessage = prefix + \" - \" + message;\r\n\t\t}\r\n\r\n\t\tconsole.error(message);\r\n\t\taddMessageToLog(message);\r\n\t}\r\n}\r\n\r\n","/**\r\n * Executes logic only when a given function is satisfied.\r\n * @param doHandler The logic to execute.\r\n * @param whenHandler The function to test.\r\n * @param maxIteration Optional maximum number of iterations to attempt. Default is 20.\r\n * @param timeout Optional timeout between attempts. Default is 50ms.\r\n * @param delay Optional additional delay.\r\n * @param iteration The current iteration, not to be passed directly by the caller.\r\n */\r\nexport function doWhen(doHandler: () => void, whenHandler: () => boolean, maxIteration?: number, timeout?: number, delay?: number, iteration?: number) {\r\n\r\n\tif (!maxIteration) maxIteration = 20;\r\n\tif (!timeout) timeout = 50;\r\n\r\n\tconst ensuredIteration = iteration ?? 0; \r\n\r\n\t// check the when handler to see if execution can be performed yet\r\n\tif (whenHandler()) {\r\n\r\n\t\tif (delay) {\r\n\t\t\tsetTimeout(() => {\r\n\t\t\t\tdoHandler();\r\n\t\t\t}, delay);\r\n\t\t}\r\n\t\telse {\r\n\t\t\tdoHandler();\r\n\t\t}\r\n\t}\r\n\t// check max iteration\r\n\telse if (ensuredIteration < maxIteration) {\r\n\r\n\t\t// try again\r\n\t\tsetTimeout(() => {\r\n\t\t\tdoWhen(doHandler, whenHandler, maxIteration, timeout, delay, ensuredIteration + 1);\r\n\t\t}, timeout);\r\n\t}\r\n}","/**\r\n * Formats the displayed value of an HTMLInputElement instance.\r\n * Applies events to constrain the number of decimals input and applies formatting on input.\r\n * @param input The input eleent.\r\n * @param isOnInput Optional flag determining whether the call is from an oninput event handler or not.\r\n */\r\nexport function formatNumericInput(input: HTMLInputElement, isOnInput?: boolean) {\r\n\r\n\t// get caret pos as we may need to restore this later\r\n\tlet stringValue = input.value;\r\n\tconst originalCaretPos = input.selectionStart ?? stringValue.length;\r\n\r\n\tconst decimalsAttr = input.getAttribute(\"data-decimals\");\r\n\tconst allowedDecimals = decimalsAttr ? parseInt(decimalsAttr) : 2;\r\n\r\n\t// decimal handling\r\n\tlet decimalIndex: number;\r\n\tif ((decimalIndex = stringValue.indexOf('.')) > -1) {\r\n\r\n\t\tlet segments = stringValue.split('.');\r\n\r\n\t\t// undo multiple decimal point input\r\n\t\tif (segments.length > 2) {\r\n\t\t\tconst withoutDecs = segments.join('');\r\n\t\t\tstringValue = `${withoutDecs.slice(0, decimalIndex)}.${withoutDecs.slice(decimalIndex)}`;\r\n\t\t\tinput.value = stringValue;\r\n\t\t}\r\n\r\n\t\t// if there were multiple decimal places get segments again\r\n\t\tif (segments.length > 2) {\r\n\t\t\tsegments = input.value.split('.');\r\n\t\t}\r\n\r\n\t\t// constrain the number of decimals input\r\n\t\tif (segments.length == 2 && segments[1].length > allowedDecimals) {\r\n\t\t\tstringValue = `${segments[0]}.${segments[1].slice(0, allowedDecimals)}`;\r\n\t\t\tinput.value = stringValue;\r\n\t\t}\r\n\t}\r\n\r\n\t// if there is a value format it\r\n\t// if this is oninput then don't format if in the middle of writing the decimal portion\r\n\tif (stringValue && (!isOnInput || !(input.value.endsWith(\".\")))) {\r\n\r\n\t\tconst value = parseFloat(stringValue.replace(/[^0-9\\.]+/g, \"\"));\r\n\r\n\t\tif (!isNaN(value)) {\r\n\t\t\t// following ensures formatted input has correct trailing fractional 0 on blur\r\n\t\t\tlet formatted = value.toLocaleString(undefined, { minimumFractionDigits: isOnInput ? undefined : allowedDecimals });\r\n\t\t\tif (isOnInput && decimalIndex > -1 && formatted.indexOf(\".\") === -1 || (stringValue.endsWith(\"0\") && !formatted.endsWith(\"0\"))) {\r\n\t\t\t\t// ensure trailing zeros in decimal value\r\n\t\t\t\tformatted = formatted.split(\".\")[0] + \".\" + stringValue.split(\".\")[1];\r\n\t\t\t}\r\n\t\t\tinput.value = formatted;\r\n\t\t}\r\n\r\n\t\t// restore caret pos if oninput\r\n\t\tif (isOnInput) {\r\n\t\t\tconst newCaretPos = input.value.length - stringValue.length + originalCaretPos;\r\n\t\t\tinput.setSelectionRange(newCaretPos, newCaretPos);\r\n\t\t}\r\n\t}\r\n}","import { MessageType } from \"../enums.generated\";\r\n\r\n/**\r\n * Gets the icon class for a given MessageType.\r\n * @param type The message type.\r\n * @returns Icon class string.\r\n */\r\nexport function getMessageIcon(type: MessageType) {\r\n\r\n\tlet iconClass = \"fas \";\r\n\tswitch (type) {\r\n\t\tcase MessageType.Error:\r\n\t\t\ticonClass += \"fa-exclamation-circle\";\r\n\t\t\tbreak;\r\n\t\tcase MessageType.Success:\r\n\t\t\ticonClass += \"fa-thumbs-up\";\r\n\t\t\tbreak;\r\n\t\tcase MessageType.Warning:\r\n\t\t\ticonClass += \"fa-exclamation-triangle\";\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\ticonClass += \"fa-info-circle\";\r\n\t\t\tbreak;\r\n\t}\r\n\treturn iconClass;\r\n}","/**\r\n * Gets a property of an object by name or path.\r\n * @param obj The object.\r\n * @param name The property name or path.\r\n * @returns The property of any type.\r\n */\r\nexport function getProperty(obj: any, name: string): any {\r\n\r\n\tif (!name) return null;\r\n\tif (!obj) return null;\r\n\r\n\tlet ref;\r\n\r\n\t// if it's a deep path...\r\n if (name.indexOf('.') > -1) {\r\n\r\n try {\r\n\r\n\t\t\t// loop through the path to get the property\r\n let items = name.split('.'), inScope;\r\n for (var i = 0; i < items.length; i++) {\r\n\r\n if (i > 0 && !inScope) break;\r\n\r\n let item = items[i];\r\n\r\n if (!inScope) {\r\n\r\n inScope = !obj ? (window as any)[item] : obj[item];\r\n }\r\n else {\r\n\r\n inScope = inScope[item];\r\n }\r\n }\r\n ref = inScope;\r\n }\r\n catch (err) { }\r\n }\r\n else {\r\n\r\n\t\tref = obj[name];\r\n }\r\n\r\n return ref;\r\n}\r\n\r\nexport function getTypedProperty(obj: any, name: string): T {\r\n\r\n\treturn getProperty(obj, name) as T;\r\n}","/**\r\n * Gets the validation attributes for a HTMLInputElement instance.\r\n * @param input The input element.\r\n * @returns Object containing the attributes.\r\n */\r\nexport function getValidationAttributes(input: HTMLInputElement) {\r\n\tconst atts: any = {};\r\n\tapply(input, atts, \"data-val\");\r\n\tapply(input, atts, \"data-val-required\");\r\n\tapply(input, atts, \"data-val-length\");\r\n\tapply(input, atts, \"data-val-length-max\");\r\n\tapply(input, atts, \"data-val-regex\");\r\n\tapply(input, atts, \"data-val-regex-pattern\");\r\n\treturn atts;\r\n}\r\n\r\nfunction apply(input: HTMLInputElement, target: any, name: string) {\r\n\tconst dataVal = input.getAttribute(name);\r\n\tif (dataVal) {\r\n\t\ttarget[name] = dataVal;\r\n\t}\r\n}","import { IpfModule } from \"..\";\r\n\r\n/**\r\n * Gets a global variable from the window.\r\n * @param name The name of the global variable.\r\n */\r\nexport function getGlobal(name: string) {\r\n\treturn (window as any)[name] as T;\r\n}\r\n\r\n/**\r\n * Sets a global variable on the window.\r\n * @param name The name of the global variable.\r\n * @param value The value.\r\n */\r\nexport function setGlobal(name: string, value: T) {\r\n\t(window as any)[name] = value;\r\n}\r\n\r\n/**\r\n * Gets the IPF module global variable.\r\n * @returns Instance of IpfModule.\r\n */\r\nexport function ipf() {\r\n\treturn getGlobal(\"IPF\");\r\n}\r\n\r\n/**\r\n * Sets the IPF module global variable.\r\n * @value Instance of IpfModule.\r\n */\r\nexport function setIpfGlobal(value: IpfModule) {\r\n\tsetGlobal(\"IPF\", value);\r\n}","/**\r\n * Determines if an element is a form button or not.\r\n * @param element The HTMLElement to test.\r\n * @returns true if the HTMLElement is a button element or an input element with a type of submit.\r\n */\r\nexport const isFormButton = (element: HTMLElement) => {\r\n\tif (element.tagName === \"BUTTON\") {\r\n\t\treturn true;\r\n\t}\r\n\telse if (element.tagName === \"INPUT\") {\r\n\t\tconst type = element.getAttribute(\"type\");\r\n\t\treturn type && [\"button\", \"submit\"].includes(type);\r\n\t}\r\n\treturn false\r\n}","/**\r\n * Determines if an object is null or undefined.\r\n * @param obj The object to test.\r\n * @returns Boolean value.\r\n */\r\nexport function isNullOrUndefined(obj: any): boolean {\r\n \r\n return obj === undefined || obj === null;\r\n}","/**\r\n * Determines if a Date instance is valid.\r\n * @param date The date.\r\n * @returns Boolean value.\r\n */\r\nexport function isValidDate(date: Date) {\r\n\treturn date instanceof Date && !isNaN(date.getTime());\r\n}","import { WipType } from \"../enums.generated\";\r\nimport { BuildRowLinkTemplateArgs } from \"../models/data-grid\";\r\nimport { urlDataFormat } from \"./string\";\r\n\r\n/**\r\n * Handler for building broker report row links.\r\n * @param args Args object containining necessary grid row information.\r\n * @returns The relevant URL.\r\n */\r\nexport function onBrokerReportGridBuildRowLinkTemplate (args: BuildRowLinkTemplateArgs) {\r\n\tconsole.log(args);\r\n\tlet template: string;\r\n\tif (args.dataItem.mtaId) {\r\n\t\ttemplate = args.urlService.url(\"MTA/Details/(mtaId)\");\r\n\t}\r\n\telse if (args.dataItem.drawdown) {\r\n\t\ttemplate = args.options.rowLinkTemplate;\r\n\t}\r\n\telse {\r\n\t\ttemplate = args.urlService.url(\"Agreement/(contract)\");\r\n\t}\r\n\treturn urlDataFormat(template, args.dataItem);\r\n}","import { WipType } from \"../enums.generated\";\r\nimport { BuildRowLinkTemplateArgs } from \"../models/data-grid\";\r\nimport { urlDataFormat } from \"./string\";\r\n\r\n/**\r\n * Handler for building loan status row links.\r\n * @param args Args object containining necessary grid row information.\r\n * @returns The loan status URL.\r\n */\r\nexport function onLoanStatusBuildRowLinkTemplate (args: BuildRowLinkTemplateArgs) {\r\n\r\n\tlet template: string;\r\n\tif (args.dataItem.mtaId) {\r\n\t\ttemplate = args.urlService.url(\"MTA/Details/(mtaId)\");\r\n\t}\r\n\telse if (args.dataItem.wipType === WipType.MTA) {\r\n\t\ttemplate = args.options.rowLinkTemplate.replace(\"NewBusiness\", \"MTA\");\r\n\t}\r\n\telse if (args.dataItem.agreementNumber) {\r\n\t\ttemplate = args.dataItem.setLiveDate ? args.urlService.url(\"Agreement/(agreementNumber)\") :\r\n\t\t\targs.options.rowLinkTemplate.replace(\"wip=(wipId)\", \"agt=(agreementNumber)\");\r\n\t}\r\n\telse {\r\n\t\ttemplate = args.options.rowLinkTemplate;\r\n\t}\r\n\treturn urlDataFormat(template, args.dataItem);\r\n}","/**\r\n * Parses a Boolean from a string. Currently only converts the True/true/False/false string values.\r\n * @param value The string to parse.\r\n * @returns Boolean value or null if not a valid string.\r\n */\r\nexport function parseBoolean(value: string): boolean | null {\r\n\r\n\tconst lcase = value?.toLowerCase();\r\n\tif (lcase === \"true\") {\r\n\t\treturn true;\r\n\t}\r\n\telse if (lcase === \"false\") {\r\n\t\treturn false;\r\n\t}\r\n\telse {\r\n\t\treturn null;\r\n\t}\r\n}","/**\r\n * Converts a number of seconds into a formatted string.\r\n * @param seconds The number of seconds.\r\n * @returns Seconds as a formatted string e.g. 2 hours 1 minute 34 seconds\r\n */\r\nexport function secondsToString(seconds: number) {\r\n\r\n\tconst perMinute = 60;\r\n\tconst perHour = perMinute * 60;\r\n\tlet hours: number = 0;\r\n\tlet minutes: number = 0;\r\n\tconst str = [];\r\n\r\n\tif (seconds >= perHour) {\r\n\r\n\t\thours = Math.floor(seconds / perHour);\r\n\t\tseconds = seconds % perHour;\r\n\t}\r\n\r\n\tif (seconds >= perMinute) {\r\n\r\n\t\tminutes = Math.floor(seconds / perMinute);\r\n\t\tseconds = seconds % perMinute;\r\n\t}\r\n\r\n\tif (hours > 0) {\r\n\r\n\t\tstr.push([hours, hours > 1 ? \"hours\" : \"hour\"].join(' '));\r\n\t}\r\n\r\n\tif (minutes) {\r\n\r\n\t\tstr.push([minutes, minutes > 1 ? \"minutes\" : \"minute\"].join(' '));\r\n\t}\r\n\r\n\tstr.push([seconds, seconds !== 1 ? \"seconds\" : \"second\"].join(' '));\r\n\r\n\treturn str.join(\" \");\r\n}","/**\r\n * Sets a parameter on a URLSearchParams instance.\r\n * @param params The URLSearchParams instance.\r\n * @param paramName The parameter name.\r\n * @param newValue The parameter value.\r\n */\r\nexport function setParameterValue(params: URLSearchParams, paramName: string, newValue: string | undefined): void {\r\n\tif (newValue) {\r\n\t\tparams.set(paramName, newValue);\r\n\t}\r\n\telse {\r\n\t\tparams.delete(paramName);\r\n\t}\r\n}","/**\r\n * Sets a property on an object.\r\n * @param obj The object.\r\n * @param path The property name or deep path.\r\n * @param value The property value.\r\n */\r\nexport function setProperty(obj: any, path: string, value: any): any {\r\n\r\n if (path.indexOf('.') > -1) {\r\n\r\n const lastIndex = path.lastIndexOf('.');\r\n const parentName = path.substring(0, lastIndex);\r\n const name = path.substring(lastIndex + 1);\r\n const items = parentName.split('.');\r\n\r\n let inScope: any;\r\n\r\n items.forEach((item: string) => {\r\n\r\n if (!inScope) {\r\n\r\n inScope = obj[item];\r\n }\r\n else {\r\n\r\n inScope = inScope[item];\r\n }\r\n });\r\n\r\n if (inScope) {\r\n inScope[name] = value;\r\n }\r\n }\r\n else {\r\n\r\n obj[path] = value;\r\n }\r\n}","import { getProperty } from \"../functions/get-property\";\r\n\r\n/**\r\n * Formats a string with supplied data properties.\r\n * @param formatString The format string e.g. Please format me with a {value}.\r\n * @param data The object data to use for formatting.\r\n * @returns Formatted data string.\r\n */\r\nexport function dataFormat(formatString: string, data: object) {\r\n\r\n\tif (!formatString) return \"\";\r\n\tif (formatString.indexOf('{') == -1 || formatString.indexOf('}') == -1) return formatString;\r\n\r\n\tlet outputString = formatString;\r\n\tlet matches = formatString.match(/{(.*?)}/g);\r\n\r\n\tif (matches !== null) {\r\n\r\n\t\tmatches.forEach((val) => {\r\n\r\n\t\t\tlet field = val.replace(/{/g, '').replace(/}/, ''),\r\n\t\t\t\tvalue = getProperty(data, field);\r\n\r\n\t\t\toutputString = outputString.replace(val, value ? value : '');\r\n\t\t});\r\n\t}\r\n\r\n\treturn outputString;\r\n}\r\n\r\n/**\r\n * Formats a URL string with supplied data properties.\r\n * @param formatString The format string e.g. /item/(id).\r\n * @param data The object data to use for formatting.\r\n * @returns Formatted URL string.\r\n */\r\nexport function urlDataFormat(formatString: string, data: object) {\r\n\r\n\tif (!formatString) return \"\";\r\n\tif (formatString.indexOf('(') == -1 || formatString.indexOf(')') == -1) return formatString;\r\n\r\n\tlet outputString = formatString;\r\n\tlet matches = formatString.match(/\\((.*?)\\)/g);\r\n\r\n\tif (matches !== null) {\r\n\r\n\t\tmatches.forEach(function (val) {\r\n\r\n\t\t\tlet field = val.replace(/\\(/g, \"\").replace(/\\)/, \"\"),\r\n\t\t\t\tvalue = getProperty(data, field),\r\n\t\t\t\tencodedValue = value ? encodeURIComponent(value) : \"\";\r\n\r\n\t\t\toutputString = outputString.replace(val, encodedValue);\r\n\t\t});\r\n\t}\r\n\r\n\treturn outputString;\r\n}\r\n\r\n/**\r\n * Adds a CSS class to a string.\r\n * @param cssClasses The string to add the CSS class to.\r\n * @param cssClass The CSS class to add.\r\n * @returns The appended string.\r\n */\r\nexport function addClass(cssClasses: string, cssClass: string) {\r\n\r\n\tif (cssClasses) {\r\n\t\tcssClasses += \" \";\r\n\t\tcssClasses += cssClass;\r\n\t}\r\n\telse {\r\n\t\tcssClasses = cssClass;\r\n\t}\r\n\treturn cssClasses;\r\n}","import { Container } from \"inversify\";\r\nimport \"reflect-metadata\";\r\nimport { IpfModule } from \"..\";\r\nimport { IpfApplication } from \"../IpfApplication\";\r\nimport { BootstrapMessageService } from \"../react/component-services/BootstrapMessageService\";\r\nimport { MaterialDataGridService } from \"../react/component-services/MaterialDataGridService\";\r\nimport { MaterialFormComponentService } from \"../react/component-services/MaterialFormComponentService\";\r\nimport { MaterialLoaderService } from \"../react/component-services/MaterialLoaderService\";\r\nimport { MaterialStepperService } from \"../react/component-services/MaterialStepperService\";\r\nimport { MaterialTierSelectorService } from \"../react/component-services/MaterialTierSelectorService\";\r\nimport { AjaxService, DataGridService, FormComponentService, FormService, LoaderService, MessageService, PageService, ScriptService, SearchFilterService, SessionValidationService, TierSelectorService, UrlService, UserTierService, ValidationService, WizardService } from \"../services\";\r\nimport { IpfFormService } from \"../services/IpfFormService\";\r\nimport { IpfPageService } from \"../services/IpfPageService\";\r\nimport { IpfScriptService } from \"../services/IpfScriptService\";\r\nimport { IpfSearchFilterService } from \"../services/IpfSearchFilterService\";\r\nimport { IpfSessionValidationService } from \"../services/IpfSessionValidationService\";\r\nimport { IpfUrlService } from \"../services/IpfUrlService\";\r\nimport { IpfUserTierService } from \"../services/IpfUserTierService\";\r\nimport { JQueryAjaxService } from \"../services/JQueryAjaxService\";\r\nimport { JQueryValidationService } from \"../services/JQueryValidationService\";\r\nimport { TYPES } from \"./types\";\r\n\r\n/**\r\n * The dependency injection container for the client-side application. \r\n */\r\nexport const container = new Container();\r\n\r\n// register each concrete service type with corresponding identifier for injection\r\ncontainer.bind(TYPES.AjaxService).to(JQueryAjaxService).inSingletonScope();\r\ncontainer.bind(TYPES.FormComponentService).to(MaterialFormComponentService).inSingletonScope();\r\ncontainer.bind(TYPES.FormService).to(IpfFormService).inSingletonScope();\r\ncontainer.bind(TYPES.DataGridService).to(MaterialDataGridService);\r\ncontainer.bind(TYPES.LoaderService).to(MaterialLoaderService).inSingletonScope();\r\ncontainer.bind(TYPES.MessageService).to(BootstrapMessageService).inSingletonScope();\r\ncontainer.bind(TYPES.PageService).to(IpfPageService).inSingletonScope();\r\ncontainer.bind(TYPES.ScriptService).to(IpfScriptService).inSingletonScope();\r\ncontainer.bind(TYPES.SearchFilterService).to(IpfSearchFilterService);\r\ncontainer.bind(TYPES.SessionValidationService).to(IpfSessionValidationService).inSingletonScope();\r\ncontainer.bind(TYPES.TierSelectorService).to(MaterialTierSelectorService).inSingletonScope();\r\ncontainer.bind(TYPES.UrlService).to(IpfUrlService).inSingletonScope();\r\ncontainer.bind(TYPES.UserTierService).to(IpfUserTierService).inSingletonScope();\r\ncontainer.bind(TYPES.ValidationService).to(JQueryValidationService).inSingletonScope();\r\ncontainer.bind(TYPES.WizardService).to(MaterialStepperService).inSingletonScope();\r\ncontainer.bind(TYPES.IpfModule).to(IpfApplication).inSingletonScope();","/**\r\n * The injectable service type names\r\n */\r\nexport const TYPES = {\r\n\tAjaxService: \"AjaxService\",\r\n\tClientContext: \"ClientContext\",\r\n\tFormComponentService: \"FormComponentService\",\r\n\tFormService: \"FormService\",\r\n\tDataGridService: \"DataGridService\",\r\n\tIpfModule: \"IpfModule\",\r\n\tLoaderService: \"LoaderService\",\r\n\tMessageService: \"MessageService\",\r\n\tPageService: \"PageService\",\r\n\tScriptService: \"ScriptService\",\r\n\tSearchFilterService: \"SearchFilterService\",\r\n\tSessionValidationService: \"SessionValidationService\",\r\n\tTierSelectorService: \"TierSelectorService\",\r\n\tUrlService: \"UrlService\",\r\n\tUserTierService: \"UserTierService\",\r\n\tValidationService: \"ValidationService\",\r\n\tWizardService: \"WizardService\"\r\n};\r\n","import \"bootstrap\";\r\nimport { IpfModule } from \".\";\r\nimport { container } from \"./ioc/container.config\";\r\nimport { TYPES } from \"./ioc/types\";\r\nimport { PageService } from \"./services\";\r\n\r\n// expose the IPF module and reference as IPF\r\nexport const IPF = container.get(TYPES.IpfModule);\r\n\r\n// register the ready event of the page service\r\ndocument.addEventListener(\"DOMContentLoaded\", () => {\r\n const pageService = container.get(TYPES.PageService);\r\n pageService.ready();\r\n});","import { MessageType, NcqLogLevel, TimeoutDuration } from \"../enums.generated\";\r\n\r\n/**\r\n * Client context information interface. Holds contextual information about the client state and configuration.\r\n */\r\nexport interface ClientContext {\r\n\tpathBase: string;\r\n\tdateFormat: string;\r\n\tuserId: number;\r\n\tuserTier: CurrentUserSelectedTier;\r\n\tcontent: { [key: string]: string; };\r\n\tsessionExpiry?: SessionExpiryInfo;\r\n\tclientDebugEnabled: boolean;\r\n\tclientLoggingDisabled: boolean;\r\n}\r\n\r\n/**\r\n * Group / tier 3 interface.\r\n */\r\nexport interface Group extends Tier {\r\n\r\n\t/**\r\n\t * Group / tier 3 label.\r\n\t */\r\n\tgroupLabel: string;\r\n\r\n\t/**\r\n\t * Branch / tier 2 label.\r\n\t */\r\n\tbranchLabel: string;\r\n\r\n\t/**\r\n\t * Broker / tier 3 label.\r\n\t */\r\n\tbrokerLabel: string;\r\n}\r\n\r\n/**\r\n * Base message interface.\r\n */\r\nexport interface MessageBase {\r\n\r\n\t/** \r\n\t * Message title.\r\n\t */\r\n\ttitle: string;\r\n\r\n\t/**\r\n\t * Message text.\r\n\t */\r\n\ttext: string;\r\n\r\n\t/**\r\n\t * Message type.\r\n\t */\r\n\ttype?: MessageType;\r\n}\r\n\r\n/**\r\n * Message interface.\r\n * @see MessageBase\r\n */\r\nexport interface Message extends MessageBase {\r\n\r\n\t/**\r\n\t * Message element ID.\r\n\t */\r\n\tid?: string;\r\n\r\n\t/**\r\n\t * Is the message dismissible?\r\n\t */\r\n\tdismissible?: boolean;\r\n\r\n\t/**\r\n\t * Function that dismisses a message.\r\n\t */\r\n\tdismiss?: (message: Message) => void;\r\n\r\n\t/**\r\n\t * Timeout for displaying the message. Once the timeout has elapsed the message will be hidden.\r\n\t */\r\n\ttimeoutDuration?: TimeoutDuration;\r\n\r\n\t/**\r\n\t * The current timeout (if any) for the message that is about to timeout.\r\n\t */\r\n\ttimeout?: NodeJS.Timeout;\r\n}\r\n\r\n/**\r\n * Selected tier interface.\r\n */\r\nexport interface SelectedTier {\r\n\r\n\t/**\r\n\t * Group / tier 1.\r\n\t */\r\n\tgroup?: Group;\r\n\r\n\t/**\r\n\t * Branch / tier 2.\r\n\t */\r\n\tbranch?: Tier;\r\n\r\n\t/**\r\n\t * Broker / tier 3.\r\n\t */\r\n\tbroker?: Tier;\r\n}\r\n\r\n/** \r\n * Current users selected tier interface.\r\n * @see MessageBase\r\n */\r\nexport interface CurrentUserSelectedTier extends SelectedTier {\r\n\r\n\t/**\r\n\t * The current users ID.\r\n\t */\r\n\tuserId: number;\r\n}\r\n\r\n/**\r\n * Tier interface.\r\n */\r\nexport interface Tier {\r\n\r\n\t/**\r\n\t * Tier ID string.\r\n\t */\r\n\tid: string;\r\n\r\n\t/**\r\n\t * Tier name string.\r\n\t */\r\n\tname: string;\r\n\r\n\t/**\r\n\t * Tier path string.\r\n\t */\r\n\tpath: string;\r\n}\r\n\r\n/**\r\n * Ensure tier level enumeration. Used to denote which level of tier to ensure.\r\n */\r\nexport enum EnsureTierLevel {\r\n\r\n\t/**\r\n\t * Don't ensure any tier.\r\n\t */\r\n\tNone,\r\n\r\n\t/**\r\n\t * Ensure group / tier 1.\r\n\t */\r\n\tGroup,\r\n\r\n\t/**\r\n\t * Ensure broker / tier 3.\r\n\t */\r\n\tBroker\r\n}\r\n\r\n/**\r\n * Font based icon interface.\r\n */\r\nexport interface Icon {\r\n\r\n\t/**\r\n\t * Font class name.\r\n\t */\r\n\tclassName: string;\r\n\r\n\t/**\r\n\t * Icon tooltip, if any.\r\n\t */\r\n\ttooltip: string;\r\n}\r\n\r\n/**\r\n * Confirmation prompt options interface.\r\n * @see MessageBase \r\n */\r\nexport interface ConfirmationPromptOptions extends MessageBase {\r\n\r\n\t/**\r\n\t * Auto open the prompt, default is true.\r\n\t */\r\n\tautoOpen?: boolean;\r\n\r\n\t/**\r\n\t * Function to open the prompt.\r\n\t */\r\n\topen?: () => void;\r\n\r\n\t/**\r\n\t * Function to close the prompt.\r\n\t */\r\n\tclose?: () => void;\r\n\r\n\t/**\r\n\t * Function to refresh the prompt.\r\n\t */\r\n\trefresh?: () => void;\r\n\r\n\t/**\r\n\t * The confirm button options.\r\n\t */\r\n\tconfirmOption?: ConfirmationOption;\r\n\r\n\t/**\r\n\t * The cancel button options.\r\n\t */\r\n\tcancelOption?: ConfirmationOption;\r\n\r\n\t/**\r\n\t * Flag to reverse the order buttons are displayed.\r\n\t */\r\n\treverseButtons?: boolean;\r\n\r\n\t/**\r\n\t * Content element to display within the prompt.\r\n\t */\r\n\tcontent?: HTMLElement;\r\n\r\n\t/**\r\n\t * Flag to close after transitions have completed.\r\n\t */\r\n\tcloseAfterTransition?: boolean;\r\n\r\n\t/**\r\n\t * On prompt open handler function, called after the prompt has been opened.\r\n\t */\r\n\tonOpen?: () => void;\r\n\r\n\t/**\r\n\t * On prompt rendered handler function, called after the prompt is rendered for display.\r\n\t */\r\n\tonRendered?: (isOpen?: boolean) => void;\r\n\r\n\t/**\r\n\t * Array of messages to display within the prompt.\r\n\t */\r\n\tmessages?: Array;\r\n\r\n\t/**\r\n\t * Flag to render message text as HTML.\r\n\t */\r\n\trenderTextAsHtml?: boolean;\r\n\r\n\t/** \r\n\t * Target element ID for the prompt, this dictates which element the prompt is added to. \r\n\t * This is important for adding prompts which call page handlers.\r\n\t */\r\n\ttargetElementId?: string;\r\n\r\n\t/**\r\n\t * Flag to close prompt on click of the modal background.\r\n\t */\r\n\tcloseOnBackdropClick?: boolean;\r\n}\r\n\r\n/**\r\n * Confirmation option interface, defines properties required to display prompt buttons.\r\n */\r\nexport interface ConfirmationOption {\r\n\r\n\t/**\r\n\t * Navigate URL for the button.\r\n\t */\r\n\tactionUrl: string | undefined;\r\n\r\n\t/**\r\n\t * Page handler for the button.\r\n\t */\r\n\tpageHandler: string | undefined;\r\n\r\n\t/**\r\n\t * Button style.\r\n\t */\r\n\tstyle: \"primary\" | \"secondary\";\r\n\r\n\t/**\r\n\t * Button text displayed.\r\n\t */\r\n\ttext: string;\r\n\r\n\t/**\r\n\t * Function handler for button clicks.\r\n\t */\r\n\thandler?: () => void;\r\n}\r\n\r\n/** Session expiry info interface, defines properties required to display the session expiry prompt. */\r\nexport interface SessionExpiryInfo {\r\n\r\n\t/**\r\n\t * Absolute session expiry time in seconds. \r\n\t * When this number of seconds expires the user will be logged out. \r\n\t * It is the maximum session duration in seconds. \r\n\t */\r\n\tabsoluteSessionExpirySeconds?: number;\r\n\r\n\t/** \r\n\t * Session expiry in seconds.\r\n\t * This is a rolling expiry that is refreshed when the server is next called.\r\n\t */\r\n\tsessionExpirySeconds?: number;\r\n\r\n\t/**\r\n\t * Flag to determine whether the session absolutely expires at midnight.\r\n\t */\r\n\tsessionExpiryAtMidnight: boolean;\r\n\r\n\t/**\r\n\t * Number of seconds left on the session until the session expiry warning prompt should be displayed.\r\n\t */\r\n\tsessionExpiryWarningSeconds?: number;\r\n\r\n\t/**\r\n\t * Session length in minutes.\r\n\t */\r\n\tsessionTimeout: number;\r\n}\r\n\r\n/**\r\n * Log message interface, used for logging client-side messages to the server.\r\n */\r\nexport interface LogMessage {\r\n\r\n\t/**\r\n\t * Log type string.\r\n\t */\r\n\tlogType: string;\r\n\r\n\t/**\r\n\t * Log message string.\r\n\t */\r\n\tmessage: string;\r\n\r\n\t/**\r\n\t * Log details string.\r\n\t */\r\n\tdetail: string;\r\n\r\n\t/**\r\n\t * Log level.\r\n\t */\r\n\tlevel: NcqLogLevel;\r\n}","export type HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\r\n\r\n/** AJAX request options interface. Defines properties required to make an AJAX HTTP request. */\r\nexport interface AjaxRequestOptions {\r\n\r\n\t/** The URL to call. */\r\n\turl: string;\r\n\r\n\t/** The HTTP method, defaults to HTTP GET. */\r\n\tmethod?: HttpMethod;\r\n\r\n\t/** Request body data to be sent. */\r\n\tdata?: any;\r\n\r\n\t/** Success handler for the AJAX request. */\r\n\tsuccess?: (data: TResponseType) => void;\r\n\r\n\t/** Auth token to send as the authorisation token value. */\r\n\tauthToken?: string;\r\n}\r\n\r\n/** MVC API action call interface. Defines properties required to call an API action. */\r\nexport interface ApiAction {\r\n\r\n\t/** Base URL. Contains scheme, hostname and any virtual directory. */\r\n\tbaseUrl?: string;\r\n\r\n\t/** Controller name. */\r\n\tcontroller: string;\r\n\r\n\t/** Action name. */\r\n\taction: string;\r\n\r\n\t/** Request body data to be sent. */\r\n\tdata?: any;\r\n\r\n\t/** The HTTP method, defaults to HTTP GET. */\r\n\tmethod?: HttpMethod;\r\n}\r\n\r\n/** API URL interface. Defines properties required to call an API. */\r\nexport interface ApiUrl {\r\n\r\n\t/** Base URL. Contains scheme, hostname and any virtual directory. */\r\n\tbaseUrl: string;\r\n\r\n\t/** URL path. */\r\n\tpath: string;\r\n\r\n\t/** Request body data to be sent. */\r\n\tdata: any;\r\n\r\n\t/** The HTTP method. */\r\n\tmethod?: HttpMethod;\r\n}\r\n\r\n/** API response interface, defines the properties that are returned with an API call. */\r\nexport interface ApiResponse {\r\n\r\n\t/** Determines if the request was successful and the response is valid. */\r\n\tisValid: boolean;\r\n\r\n\t/** The result of the request. Typcially returned data or information about the action that was performed. */\r\n\tresult: TResult;\r\n}\r\n\r\n/** HTTP methods. */\r\nexport class HttpMethods {\r\n\r\n\t/** HTTP GET */\r\n\tpublic static Get: HttpMethod = \"GET\";\r\n\r\n\t/** HTTP POST */\r\n\tpublic static Post: HttpMethod = \"POST\";\r\n\r\n\t/** HTTP PUT */\r\n\tpublic static Put: HttpMethod = \"PUT\";\r\n\r\n\t/** HTTP DELETE */\r\n\tpublic static Delete: HttpMethod = \"DELETE\";\r\n}","import { Guid } from \"../util/Guid\";\r\n\r\n/** Wizard configuration class. Used to configure a wizard and synchronise it's state. */\r\nexport class WizardConfig {\r\n\r\n\tprivate _targetElement: Element;\r\n\tprivate _steps: Array;\r\n\tprivate _activeStepElement: HTMLInputElement | null;\r\n\r\n\t/**\r\n\t * Initialises a new instance of the WizardConfig class.\r\n\t * @param targetElement The element containing the wizard steps.\r\n\t * @param steps Array of WizardStep.\r\n\t * @param activeStepElement The currently active step element.\r\n\t */\r\n\tconstructor(targetElement: Element, steps: Array, activeStepElement: HTMLInputElement | null) {\r\n\t\tthis._targetElement = targetElement;\r\n\t\tthis._steps = steps;\r\n\t\tthis._activeStepElement = activeStepElement;\r\n\t}\r\n\r\n\t/**\r\n\t * Array of wizard steps.\r\n\t * @see WizardStep\r\n\t */ \r\n\tpublic get steps(): Array {\r\n\r\n\t\treturn this._steps;\r\n\t}\r\n\r\n\t/** The element containing the wizard steps. */\r\n\tpublic get targetElement(): Element {\r\n\r\n\t\treturn this._targetElement;\r\n\t}\r\n\r\n\t/** The currently active step element. */\r\n\tpublic get activeStepElement(): HTMLInputElement | null {\r\n\r\n\t\treturn this._activeStepElement;\r\n\t}\r\n}\r\n\r\n/** Wizard step configuration class. Used to configure a wizard step and synchronise it's state. */\r\nexport class WizardStep {\r\n\r\n\ttitle: string;\r\n\tcontent: Element;\r\n\tindex: number;\r\n\tguid: string;\r\n visible: boolean;\r\n\tnavigatable: boolean;\r\n\tcompleted: boolean;\r\n\r\n\t/**\r\n\t * Initialises a new instance of the WizardStep class.\r\n\t * @param stepElement The element containing step content.\r\n\t * @param title Step title, displayed as the header for the wizard step.\r\n\t * @param index The step index.\r\n\t */\r\n\tconstructor(stepElement: Element, title: string, index: number) {\r\n\r\n\t\tthis.title = title;\r\n\t\tthis.content = stepElement;\r\n\t\tthis.index = index;\r\n\t\tthis.guid = Guid.newGuid();\r\n\t\tthis.visible = true;\r\n\t\tthis.navigatable = stepElement.getAttribute(\"data-navigatable\") === \"true\";\r\n\t\tthis.completed = stepElement.getAttribute(\"data-completed\") === \"true\";\r\n\t}\r\n\r\n\t/** The step key, used to identify the step. */\r\n\tget key() {\r\n\r\n\t\tconst stepKey = this.content.getAttribute(\"data-step\");\r\n\t\treturn stepKey || `Step${this.index}`;\r\n\t}\r\n}","import { createTheme } from \"@mui/material/styles\";\r\n\r\n/**\r\n * MUI app theme, used to apply IPF specific styling to MUI components.\r\n */\r\nexport const AppTheme = createTheme({\r\n palette: {\r\n primary: {\r\n\t\t\tmain: \"#303849\"\r\n },\r\n secondary: {\r\n\t\t\tmain: '#328589'\r\n },\r\n\t},\r\n\ttypography: {\r\n\t\tfontFamily: [\r\n\t\t\t'Inter',\r\n\t\t\t'-apple-system',\r\n\t\t\t'BlinkMacSystemFont',\r\n\t\t\t'\"Segoe UI\"',\r\n\t\t\t'Roboto',\r\n\t\t\t'\"Helvetica Neue\"',\r\n\t\t\t'Arial',\r\n\t\t\t'sans-serif',\r\n\t\t\t'\"Apple Color Emoji\"',\r\n\t\t\t'\"Segoe UI Emoji\"',\r\n\t\t\t'\"Segoe UI Symbol\"',\r\n\t\t].join(','),\r\n\t},\r\n});","import { StyledEngineProvider, ThemeProvider } from \"@mui/material/styles\";\r\nimport React from \"react\";\r\nimport ReactDOM from \"react-dom\";\r\nimport { AppTheme } from \"./AppTheme\";\r\n\r\n/**\r\n * React DOM proxy class, used to centralise the rendering and unmounting of React components.\r\n */\r\nexport class ReactDOMProxy {\r\n\r\n\tprivate static readonly componentClassName = \"react-component\";\r\n\r\n\t/**\r\n\t * Renders a styled component to a container element by wrapping it with a ThemeProvider and a StyledEngineProvider.\r\n\t * @param element The component to render.\r\n\t * @param container The container to render the component to.\r\n\t * @param callback Callback which is called after the component has been rendered.\r\n\t */\r\n\tpublic static renderStyled(element: JSX.Element, container?: Element, callback?: () => void) {\r\n\r\n\t\tconst styledElement =\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t{element}\r\n\t\t\t\t\r\n\t\t\t;\r\n\t\tthis.render(styledElement, container ?? document.createElement(\"div\"), callback);\r\n\t}\r\n\r\n\t/**\r\n\t * Renders a component to a container element.\r\n\t * @param element The component to render.\r\n\t * @param container The container to render the component to.\r\n\t * @param callback Callback which is called after the component has been rendered.\r\n\t */\r\n public static render(element: JSX.Element, container: Element, callback?: () => void) {\r\n\r\n\t\tReactDOM.render(element, container, callback);\r\n container.classList.add(ReactDOMProxy.componentClassName);\r\n }\r\n\r\n\t/**\r\n\t * Unmounts all React components within a container element.\r\n\t * @param container A container element to search.\r\n\t */\r\n public static unmountAll(container: Element) {\r\n\r\n container.querySelectorAll(`.${ReactDOMProxy.componentClassName}`).forEach(element => {\r\n\r\n ReactDOMProxy.unmount(element);\r\n element.classList.remove(ReactDOMProxy.componentClassName);\r\n });\r\n }\r\n\r\n\t/**\r\n\t * Unmounts a component.\r\n\t * @param container The container the component was rendered to.\r\n\t */\r\n public static unmount(container: Element) {\r\n\r\n ReactDOM.unmountComponentAtNode(container);\r\n }\r\n}","import { inject, injectable } from \"inversify\";\r\nimport React from \"react\";\r\nimport { IpfModule } from \"../..\";\r\nimport { Constants } from \"../../constants.generated\";\r\nimport { TimeoutDuration } from \"../../enums.generated\";\r\nimport { EventConstants } from \"../../EventConstants\";\r\nimport { TYPES } from \"../../ioc/types\";\r\nimport { Message } from \"../../models/app\";\r\nimport { MessageService } from \"../../services\";\r\nimport { ServiceBase } from \"../../services/ServiceBase\";\r\nimport { MessageList, MessageListOptions } from \"../components/MessageList\";\r\nimport { ReactDOMProxy } from \"../ReactDOMProxy\";\r\n\r\n/**\r\n * Messaging service, used to display Bootstrap toasts. Could later be extended to output Bootstrap alerts.\r\n */\r\n@injectable()\r\nexport class BootstrapMessageService extends ServiceBase implements MessageService {\r\n\r\n\tprivate messageList: MessageListOptions | undefined;\r\n\r\n\t/**\r\n\t * Initialises a new instance of the BootstrapMessageService class.\r\n\t * @param ipfModule IPF module, used to store and retrieve temp data.\r\n\t */\r\n\tpublic constructor(\r\n\t\t@inject(TYPES.IpfModule) private ipfModule: IpfModule\r\n\t) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic applyEffects(container: Element) {\r\n\r\n\t\tif (container) {\r\n\r\n\t\t\tthis.applyMessageEffects(container);\r\n\t\t\tthis.applyToastEffects(container);\t\t\t\r\n\t\t}\r\n\r\n\t\tconst messages = this.ipfModule.getData>(Constants.DataKeyMessages);\r\n\t\tif (messages?.length > 0) {\r\n\r\n\t\t\tmessages.forEach(message => {\r\n\r\n\t\t\t\tthis.showMessage(message);\r\n\t\t\t});\r\n\r\n\t\t\t// clear the messages\r\n\t\t\tthis.ipfModule.clearData(Constants.DataKeyMessages);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic clearMessages() {\r\n\r\n\t\tif (this.messageList?.clearMessages) {\r\n\t\t\tthis.messageList.clearMessages();\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic showMessage(message: Message) {\r\n\r\n\t\tconst messageTarget = document.getElementById(\"message-target\");\r\n\r\n\t\tif (messageTarget) {\r\n\r\n\t\t\tif (this.messageList) {\r\n\r\n\t\t\t\tif (this.messageList.addMessage)\r\n\t\t\t\t\tthis.messageList.addMessage(message);\r\n\t\t\t}\r\n\t\t\telse {\r\n\r\n\t\t\t\tthis.messageList = {\r\n\t\t\t\t\tmessages: []\r\n\t\t\t\t} as MessageListOptions;\r\n\r\n\t\t\t\tReactDOMProxy.renderStyled(\r\n\t\t\t\t\t,\r\n\t\t\t\t\tmessageTarget\r\n\t\t\t\t);\r\n\r\n\t\t\t\tif (this.messageList.addMessage)\r\n\t\t\t\t\tthis.messageList.addMessage(message);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate applyMessageEffects(container: Element) {\r\n\r\n\t\t$(\".alert[data-dismiss-timeout],.toast[data-dismiss-timeout]\", container).each((i, element) => {\r\n\r\n\t\t\tconst jElement = $(element);\r\n\r\n\t\t\tif (jElement.data(\"dismiss-timeout\")) {\r\n\r\n\t\t\t\tconst timeout = jElement.data(\"dismiss-timeout\") as TimeoutDuration;\r\n\t\t\t\tlet duration: number;\r\n\r\n\t\t\t\tswitch (timeout) {\r\n\t\t\t\t\tcase TimeoutDuration.Fast:\r\n\t\t\t\t\t\tduration = 7500;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase TimeoutDuration.Standard:\r\n\t\t\t\t\t\tduration = 15000;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase TimeoutDuration.Slow:\r\n\t\t\t\t\t\tduration = 30000;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tdefault:\r\n\t\t\t\t\t\tduration = 0;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tsetTimeout(() => {\r\n\t\t\t\t\tjElement.fadeOut(() => {\r\n\t\t\t\t\t\tjElement.remove();\r\n\t\t\t\t\t});\r\n\t\t\t\t}, duration);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tprivate applyToastEffects(container: Element) {\r\n\r\n\t\t$('.toast [data-dismiss]', container).off(EventConstants.click_ipf).on(EventConstants.click_ipf, event => {\r\n\r\n\t\t\tconst jElement = $(event.currentTarget).closest(\".toast\");\r\n\t\t\tjElement.fadeOut(() => {\r\n\t\t\t\tjElement.remove();\r\n\t\t\t});\r\n\t\t});\r\n\t}\r\n}","import { LinkProps, Theme, Tooltip } from \"@mui/material\";\r\nimport withStyles from '@mui/styles/withStyles';\r\nimport { GridCellParams, GridCellValue, GridColumnHeaderParams, GridEnrichedColDef, GridSortCellParams, GridSortModel } from \"@mui/x-data-grid\";\r\nimport { inject, injectable } from \"inversify\";\r\nimport React from \"react\";\r\nimport { IpfModule } from \"../..\";\r\nimport { Constants } from \"../../constants.generated\";\r\nimport { DataGridColumnType, ListSortDirection } from \"../../enums.generated\";\r\nimport { EventConstants } from \"../../EventConstants\";\r\nimport { callFunction } from \"../../functions/call-function\";\r\nimport { doWhen } from \"../../functions/do-when\";\r\nimport { getProperty, getTypedProperty } from \"../../functions/get-property\";\r\nimport { isNullOrUndefined } from \"../../functions/is-null-or-undefined\";\r\nimport { addClass, dataFormat, urlDataFormat } from \"../../functions/string\";\r\nimport { container } from \"../../ioc/container.config\";\r\nimport { TYPES } from \"../../ioc/types\";\r\nimport { Icon } from \"../../models/app\";\r\nimport { BuildRowLinkTemplateArgs, DataGridColumnOptions, DataGridOptions, DataGridRefreshArgs, DataGridState } from \"../../models/data-grid\";\r\nimport { ApiUrl } from \"../../models/http\";\r\nimport { ApiModel, FieldSort } from \"../../models/search\";\r\nimport { AjaxService, DataGridService, FormService, SearchFilterService, UrlService } from \"../../services\";\r\nimport { ServiceBase } from \"../../services/ServiceBase\";\r\nimport { Guid } from \"../../util/Guid\";\r\nimport { AppTheme } from \"../AppTheme\";\r\nimport { DataGridComponent } from \"../components/DataGridComponent\";\r\nimport { ReactDOMProxy } from \"../ReactDOMProxy\";\r\n\r\n/**\r\n * A MUI styled Tooltip for use on data grids.\r\n */\r\nconst LightTooltip = withStyles((theme: Theme) => ({\r\n\ttooltip: {\r\n\t\tbackgroundColor: AppTheme.palette.background.paper,\r\n\t\tcolor: AppTheme.palette.text.primary,\r\n\t\tboxShadow: theme.shadows[2],\r\n\t\tfontSize: 12,\r\n\t\tfontWeight: \"normal\",\r\n\t\tmarginTop: 0\r\n\t},\r\n}))(Tooltip);\r\n\r\n/**\r\n * MUI data grid service, used to render MUI grids to specific elements on a page.\r\n */\r\n@injectable()\r\nexport class MaterialDataGridService extends ServiceBase implements DataGridService {\r\n\r\n\tprivate static readonly iconCellClass = \"icon\";\r\n\r\n\t/**\r\n\t * Map of cell rendering functions which return a React element for rendering, mapped by DataGridColumnType.\r\n\t * @see DataGridColumnType\r\n\t */ \r\n\tprivate static readonly cellRenderers = new Map JSX.Element>([\r\n\t\t[DataGridColumnType.Boolean, MaterialDataGridService.renderBool],\r\n\t\t[DataGridColumnType.NegativeBoolean, MaterialDataGridService.renderNegativeBool],\r\n\t\t[DataGridColumnType.Formatted, MaterialDataGridService.renderFormatted],\r\n\t\t[DataGridColumnType.Html, MaterialDataGridService.renderHtml],\r\n\t\t[DataGridColumnType.HyperLink, MaterialDataGridService.renderHyperLink],\r\n\t\t[DataGridColumnType.Icon, MaterialDataGridService.renderIcon],\r\n\t\t[DataGridColumnType.MailTo, MaterialDataGridService.renderMailTo],\r\n\t\t[DataGridColumnType.Tooltip, MaterialDataGridService.renderTooltip],\r\n\t\t[DataGridColumnType.ConditionalClass, MaterialDataGridService.renderConditionalClass],\r\n\t\t[DataGridColumnType.Badge, MaterialDataGridService.renderBadge],\r\n\t]);\r\n\r\n\t/**\r\n\t * Map of cell formatter functions which format the columns by adding CSS classes, mapped by DataGridColumnType.\r\n\t * @see DataGridColumnType\r\n\t */ \r\n\tprivate static readonly cellFormatters = new Map void>([\r\n\t\t[DataGridColumnType.Boolean, MaterialDataGridService.formatIcon],\r\n\t\t[DataGridColumnType.Financial, MaterialDataGridService.formatFinancial],\r\n\t\t[DataGridColumnType.Icon, MaterialDataGridService.formatIcon]\r\n\t]);\r\n\r\n\tprivate static readonly gridRefreshers = new Map void>();\r\n\r\n\t// static renderer needs access to the UrlService singleton\r\n\tprivate static _urlService: UrlService;\r\n\r\n\t/**\r\n\t * Initialises a new instance of the MaterialDataGridService class.\r\n\t * @param ajaxService AJAX service, used to make AJAX HTTP requests.\r\n\t * @param formService Form service, used to bind the client side view model.\r\n\t * @param ipfModule IPF module, containing contextual information and functions.\r\n\t * @param filterService Search filter service, used to render controls, for filtering data grids.\r\n\t * @param urlService URL service, used to generate URLs.\r\n\t */\r\n\tconstructor(\r\n\t\t@inject(TYPES.AjaxService) private ajaxService: AjaxService,\r\n\t\t@inject(TYPES.FormService) private formService: FormService,\r\n\t\t@inject(TYPES.IpfModule) private ipfModule: IpfModule,\r\n\t\t@inject(TYPES.SearchFilterService) private filterService: SearchFilterService,\r\n\t\t@inject(TYPES.UrlService) private urlService: UrlService) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the URL service. This is static so the static renderer functions can access it.\r\n\t */\r\n\tprivate static get urlServiceStatic() {\r\n\t\tif (!MaterialDataGridService._urlService) {\r\n\t\t\tMaterialDataGridService._urlService = container.get(TYPES.UrlService);\r\n\t\t}\r\n\t\treturn MaterialDataGridService._urlService;\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n public applyAll(target: Element) {\r\n\r\n\t\ttarget.querySelectorAll(\"[data-grid]\").forEach(element => {\r\n\t\t\tthis.render(element);\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic refresh(elementId: string) {\r\n\r\n\t\tconst gridElement = document.getElementById(elementId);\r\n\r\n\t\tif (!gridElement) return;\r\n\r\n\t\tconst refresher = MaterialDataGridService.gridRefreshers.get(elementId);\r\n\r\n\t\tif (refresher) {\r\n\r\n\t\t\trefresher({ resetPageIndex: true });\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Renders a grid within the supplied target element.\r\n\t * The element ID is used to lookup the IPF data containing the data grid configuration.\r\n\t * @param element The target element with an ID attribute that matches the IPF data key of the data grid configuration.\r\n\t */\r\n\tprivate render(element: Element) {\r\n\r\n\t\tconst gridOptions = this.ipfModule.getData(element.id);\r\n\t\tconst sortModel = this.convertSortModel(gridOptions.apiModel?.sorts ?? gridOptions.fieldSorts, gridOptions.columns);\r\n\t\tconst getData = (apiUrl: ApiUrl, options: DataGridOptions, state: DataGridState) => {\r\n\t\t\treturn this.getData(apiUrl, options, state);\r\n\t\t};\r\n\t\tconst onRendering = (options: DataGridOptions, state: DataGridState, refresh: (args: DataGridRefreshArgs) => void, redraw: () => void) => {\r\n\t\t\treturn this.onRendering(options, state, refresh, redraw);\r\n\t\t};\r\n\t\tconst onRendered = (options: DataGridOptions, state: DataGridState, refresh: (args: DataGridRefreshArgs) => void) => {\r\n\t\t\treturn this.onRendered(options, state, refresh);\r\n\t\t};\r\n\r\n\t\tif (!gridOptions.keyField) {\r\n\t\t\tgridOptions.keyField = \"id\";\r\n\t\t}\r\n\r\n\t\t// render data grid component with configured options and event handlers\r\n\t\tReactDOMProxy.renderStyled(\r\n\t\t\t,\r\n\t\t\telement\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * An event handler called when during rendering. Used to resize columns, setup filters and apply tear down functions.\r\n\t * @param options The data grid options used to configure the grid.\r\n\t * @param state The current data grid state.\r\n\t * @param refresh A function used to refresh the data grid.\r\n\t * @param redraw A function used to redraw the grid when columns are auto sized and the window is resized.\r\n\t */\r\n\tprivate onRendering(options: DataGridOptions, state: DataGridState, refresh: (args: DataGridRefreshArgs) => void, redraw: () => void) {\r\n\r\n\t\tconst tearDownFuncs = new Array<() => void>();\r\n\r\n\t\t// auto size the columns\r\n\t\tif (options.autoSizeColumns) {\r\n\t\t\ttearDownFuncs.push(this.sizeColumns(state.columns, options.elementId, redraw));\r\n\t\t}\r\n\r\n\t\tconst filterElementId = options.filtersElementId;\r\n\r\n\t\t// setup filters if there is an API model with filters defined\r\n\t\tif (filterElementId) {\r\n\r\n\t\t\tconst filtersElement = document.getElementById(filterElementId);\r\n\t\t\tif (filtersElement) {\r\n\r\n\t\t\t\ttearDownFuncs.push(this.filterService.setupFilters(filtersElement, refresh));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn tearDownFuncs;\r\n\t}\r\n\r\n\t/**\r\n\t * An event handler called after the data grid has been rendered. Used to apply additional behaviours not supported by MUI data grids.\r\n\t * @param options The data grid options used to configure the grid.\r\n\t * @param state The current data grid state.\r\n\t * @param refresh A function used to refresh the data grid.\r\n\t */\r\n\tprivate onRendered(options: DataGridOptions, state: DataGridState, refresh: (args: DataGridRefreshArgs) => void) {\r\n\r\n\t\tconst gridElement = document.getElementById(options.elementId);\r\n\r\n\t\tif (!gridElement) return () => { }; \r\n\r\n\t\tMaterialDataGridService.gridRefreshers.set(options.elementId, refresh);\r\n\r\n\t\tdoWhen(() => {\r\n\t\t\t// this useEffect callback seems to be called before the grid has actually been displayed when changing paging parameters, so a timeout is required.\r\n\t\t\tglobal.setTimeout(() => {\r\n\t\t\t\tthis.applyRowClass(options, state, gridElement),\r\n\t\t\t\tthis.applyFinancialColumnAlignment(gridElement);\r\n\t\t\t\tthis.applyDetailRow(options, state, gridElement);\r\n\t\t\t\tthis.applyActivateOnRowClick(options, state, gridElement);\r\n\t\t\t}, 50);\r\n\t\t}, () => gridElement.querySelectorAll(\".MuiDataGrid-virtualScrollerRenderZone .MuiDataGrid-row\").length > 0);\r\n\r\n\t\tconst hasPageHandlers = options.columns.find(col => col.pageHandler) != undefined;\r\n\t\tconst hasApiHandlers = options.columns.find(col => col.apiHandler) != undefined;\r\n\r\n\t\t// apply page handlers rows and cells\r\n\t\tif (hasPageHandlers) {\r\n\r\n\t\t\tconst form = gridElement.closest(\"form\") as HTMLFormElement;\r\n\r\n\t\t\tif (form) {\r\n\r\n\t\t\t\tthis.formService.applyPageHandlers(form);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// apply api handlers rows and cells\r\n\t\tif (hasApiHandlers) {\r\n\r\n\t\t\tthis.formService.applyApiHandlers(gridElement, () => {\r\n\r\n\t\t\t\tif (options.apiUrl) {\r\n\r\n\t\t\t\t\trefresh({ resetPageIndex: false });\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\t// handle navigating to template URLs on row click\r\n\t\tconst handleRowLinkTemplateClick = (event: MouseEvent) => {\r\n\r\n\t\t\tconst target = event.target as HTMLElement;\r\n\r\n\t\t\t// ignore link clicks\r\n\t\t\tif (target.tagName === \"A\" || target.parentElement?.tagName === \"A\") {\r\n\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (state.data) {\r\n\r\n\t\t\t\t// attempt to get the row identifier\r\n\t\t\t\tconst id = target.closest(\".MuiDataGrid-row[data-id]\")?.getAttribute(\"data-id\");\r\n\r\n\t\t\t\tif (id) {\r\n\r\n\t\t\t\t\t// get the data item for the row identifier\r\n\t\t\t\t\tconst keyField = options.keyField;\r\n\t\t\t\t\tconst dataItem = state.data.find(item => getProperty(item, keyField) == id);\r\n\r\n\t\t\t\t\t// if there is a build row link template handler\r\n\t\t\t\t\tif (options.onBuildRowLinkTemplate) {\r\n\r\n\t\t\t\t\t\t// call the function by name and pass arguments\r\n\t\t\t\t\t\tconst href = callFunction(options.onBuildRowLinkTemplate, {\r\n\t\t\t\t\t\t\tdataItem,\r\n\t\t\t\t\t\t\toptions,\r\n\t\t\t\t\t\t\turlService: this.urlService\r\n\t\t\t\t\t\t} as BuildRowLinkTemplateArgs) as string;\r\n\r\n\t\t\t\t\t\t// if a URL is returned navigate to it\r\n\t\t\t\t\t\tif (href) {\r\n\r\n\t\t\t\t\t\t\twindow.location.href = href;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\r\n\t\t\t\t\t\t// otherwise navigate to the formatted template URL\r\n\t\t\t\t\t\twindow.location.href = urlDataFormat(options.rowLinkTemplate, dataItem);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t// if there is a row link template appy the grid-navigateable, to style the rows on hover state\r\n\t\tif (options.rowLinkTemplate && gridElement) {\r\n\t\t\tgridElement.addEventListener(EventConstants.click, handleRowLinkTemplateClick);\r\n\t\t\tgridElement.classList.add(\"grid-navigateable\");\r\n\t\t}\r\n\r\n\t\t// return tear down function\r\n\t\treturn () => {\r\n\t\t\tif (options.rowLinkTemplate && gridElement) {\r\n\t\t\t\tgridElement.removeEventListener(EventConstants.click, handleRowLinkTemplateClick);\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\t/**\r\n\t * Convert column models to MUI column definitions.\r\n\t * @param input The data grid options, containing the column models to convert.\r\n\t * @returns Array\r\n\t * @see GridEnrichedColDef\r\n\t */\r\n\tprivate convertColumns(input: DataGridOptions) {\r\n\r\n\t\tconst columns = new Array();\r\n\r\n\t\tinput.columns.forEach((column, index) => {\r\n\r\n\t\t\tconst colDef = {\r\n\t\t\t\tfield: column.field,\r\n\t\t\t\theaderName: column.title,\r\n\t\t\t\twidth: column.width,\r\n\t\t\t\tsortable: column.sortable,\r\n\t\t\t\thideSortIcons: true,\r\n\t\t\t\tdisableColumnMenu: true,\r\n\t\t\t\trenderHeader: column.sortable ?\r\n\t\t\t\t\tcolDef => MaterialDataGridService.getColumnSortHeader(colDef, input.getState?.()) :\r\n\t\t\t\t\t() => undefined\r\n\t\t\t} as GridEnrichedColDef;\r\n\r\n\t\t\t// apply column sort comparator, used with client data source mode\r\n\t\t\tif (column.sortField) {\r\n\r\n\t\t\t\tcolDef.sortComparator = (v1: GridCellValue, v2: GridCellValue, cellParams1: GridSortCellParams, cellParams2: GridSortCellParams) => {\r\n\r\n\t\t\t\t\tconst sortCol = input.columns.find(c => c.field === cellParams1.field);\r\n\t\t\t\t\tlet sortValue1: GridCellValue;\r\n\t\t\t\t\tlet sortValue2: GridCellValue;\r\n\r\n\t\t\t\t\tif (sortCol?.sortField) {\r\n\r\n\t\t\t\t\t\tsortValue1 = cellParams1.value;\r\n\t\t\t\t\t\tsortValue2 = cellParams2.value;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\r\n\t\t\t\t\t\tsortValue1 = v1;\r\n\t\t\t\t\t\tsortValue2 = v2;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (sortValue1 && !sortValue2) {\r\n\t\t\t\t\t\treturn 1;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if (!sortValue1 && sortValue2) {\r\n\t\t\t\t\t\treturn -1;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if (sortValue1 && sortValue2) {\r\n\t\t\t\t\t\treturn sortValue1 > sortValue2 ? 1 : -1;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\treturn 0;\r\n\t\t\t\t\t}\r\n\t\t\t\t};\r\n\t\t\t}\r\n\r\n\t\t\t// apply calculated column types\r\n\t\t\tlet columnType: DataGridColumnType;\r\n\t\t\tif (column.formattedField &&\r\n\t\t\t\t(column.displayType !== DataGridColumnType.HyperLink &&\r\n\t\t\t\t\tcolumn.displayType !== DataGridColumnType.ConditionalClass && !column.conditionalClassName)) {\r\n\r\n\t\t\t\tcolumnType = DataGridColumnType.Formatted;\r\n\t\t\t}\r\n\t\t\telse if (column.conditionalClassName) {\r\n\r\n\t\t\t\tcolumnType = DataGridColumnType.ConditionalClass;\r\n\t\t\t}\r\n\t\t\telse {\r\n\r\n\t\t\t\tcolumnType = column.displayType;\r\n\t\t\t}\r\n\r\n\t\t\t// apply custom cell rendering by column type\r\n\t\t\tconst renderer = MaterialDataGridService.cellRenderers.get(columnType);\r\n\r\n\t\t\tif (renderer) {\r\n\r\n\t\t\t\tcolDef.renderCell = params => renderer(column, params);\r\n\t\t\t}\r\n\r\n\t\t\tif (index === (input.columns.length - 1)) {\r\n\r\n\t\t\t\tcolDef.headerClassName = \"col-cell-last\";\r\n\t\t\t}\r\n\r\n\t\t\t// apply custom cell modification by column type\r\n\t\t\tconst formatter = MaterialDataGridService.cellFormatters.get(column.displayType);\r\n\r\n\t\t\tif (formatter) {\r\n\r\n\t\t\t\tformatter(colDef);\r\n\t\t\t}\r\n\r\n\t\t\t// apply column class name to the header and the data cell of the MUI column definition\r\n\t\t\tif (column.className) {\r\n\r\n\t\t\t\tcolDef.headerClassName = addClass(colDef?.headerClassName as string, column.className);\r\n\t\t\t\tcolDef.cellClassName = addClass(colDef?.cellClassName as string, column.className);\r\n\t\t\t}\r\n\r\n\t\t\tcolumns.push(colDef);\r\n\t\t});\r\n\r\n\t\treturn columns;\r\n\t}\r\n\r\n\t/**\r\n\t * Auto size columns, takes the column width (applies default width of 100 if undefined),\r\n\t * and then sets column widths proportionately to fill the available container width.\r\n\t * @param columns The grid columns.\r\n\t * @param elementId The container element ID.\r\n\t * @param refresh A function used to refresh the data grid.\r\n\t */\r\n\tprivate sizeColumns(columns: Array, elementId: string, refresh: () => void) {\r\n\r\n\t\tconst container = document.getElementById(elementId);\r\n\r\n\t\tif (!container) return () => { };\r\n\r\n\t\tlet tWidth: number = 0;\r\n\t\tconst colWidths = new Array();\r\n\t\tcolumns.forEach(column => {\r\n\t\t\tconst width = column.width ?? 100;\r\n\t\t\tcolWidths.push(width);\r\n\t\t\ttWidth += width;\r\n\t\t});\r\n\r\n\t\t// calculate the sizing proportion\r\n\t\tconst sizingMultiplier = (container.clientWidth > 0 ? container.clientWidth : 100) / (tWidth + 20);\r\n\r\n\t\t// now size each column\r\n\t\tcolumns.forEach((column, index) => {\r\n\t\t\tcolumn.width = sizingMultiplier * colWidths[index];\r\n\t\t});\r\n\r\n\t\t// grid redraw function for handling window resize\r\n\t\tlet resizeTimeout: NodeJS.Timeout;\r\n\t\tconst redraw = () => {\r\n\t\t\tif (resizeTimeout) clearTimeout(resizeTimeout);\r\n\t\t\tresizeTimeout = global.setTimeout(() => {\r\n\t\t\t\trefresh();\r\n\t\t\t}, 50);\r\n\t\t};\r\n\r\n\t\t// window resize event handler, which redraws data grid\r\n\t\twindow.addEventListener(\"resize\", redraw);\r\n\r\n\t\t// return tear down function\r\n\t\treturn () => {\r\n\t\t\twindow.removeEventListener(\"resize\", redraw);\r\n\t\t};\r\n\t}\r\n\r\n\t/**\r\n\t * Boolean column renderer, outputs a tick icon if the value equals true.\r\n\t * @param column The data grid column options.\r\n\t * @param params The data cell params.\r\n\t */\r\n\tprivate static renderBool(column: DataGridColumnOptions, params: GridCellParams) {\r\n\r\n\t\tconst boolValue = getTypedProperty(params.row, params.field);\r\n\t\tif (boolValue === true) {\r\n\r\n\t\t\treturn ;\r\n\t\t}\r\n\t\treturn ;\r\n\t}\r\n\r\n\t/**\r\n\t * Negative boolean column renderer, outputs an error icon if the value equals true.\r\n\t * @param column The data grid column options.\r\n\t * @param params The data cell params.\r\n\t */\r\n\tprivate static renderNegativeBool(column: DataGridColumnOptions, params: GridCellParams) {\r\n\r\n\t\tconst boolValue = getTypedProperty(params.row, params.field);\r\n\t\tif (boolValue === true) {\r\n\r\n\t\t\treturn ;\r\n\t\t}\r\n\t\treturn ;\r\n\t}\r\n\r\n\t/**\r\n\t * Formatted column renderer, outputs a formatted field value, based on the formattedField of the column.\r\n\t * @param column The data grid column options.\r\n\t * @param params The data cell params.\r\n\t */\r\n\tprivate static renderFormatted(column: DataGridColumnOptions, params: GridCellParams) {\r\n\r\n\t\treturn {getTypedProperty(params.row, column.formattedField)}\r\n\t}\r\n\r\n\t/**\r\n\t * Hyperlink column renderer, outputs a hyperlink element.\r\n\t * @param column The data grid column options.\r\n\t * @param params The data cell params.\r\n\t */\r\n\tprivate static renderHyperLink(column: DataGridColumnOptions, params: GridCellParams) {\r\n\r\n\t\tconst href = urlDataFormat(column.linkTemplate, params.row);\r\n\r\n\t\tconst link = {} as LinkProps;\r\n\t\tif (href) {\r\n\r\n\t\t\tlink.href = MaterialDataGridService.urlServiceStatic.url(href);\r\n\t\t}\r\n\r\n\t\tif (column.target) {\r\n\r\n\t\t\tlink.target = column.target;\r\n\t\t}\r\n\r\n\t\tif (column.tooltip) {\r\n\r\n\t\t\tlink.title = column.tooltip;\r\n\t\t}\r\n\r\n\t\tif (column.linkCssClass) {\r\n\r\n\t\t\tlink.className = column.linkCssClass;\r\n\t\t}\r\n\r\n\t\tlet linkInnerContent;\r\n\t\tif (column.icon) {\r\n\r\n\t\t\tconst ico = \"fas \" + column.icon;\r\n\t\t\tlinkInnerContent = ;\r\n\t\t}\r\n\t\telse if (column.label) {\r\n\r\n\t\t\tlinkInnerContent = column.label;\r\n\t\t}\r\n\r\n\t\tif (!linkInnerContent) {\r\n\r\n\t\t\tlinkInnerContent = getProperty(params.row, column.formattedField ?? params.field);\r\n\t\t}\r\n\r\n\t\tif (column.pageHandler) {\r\n\r\n\t\t\tconst linkAny = link as any;\r\n\t\t\tconst pageHandler = dataFormat(column.pageHandler, params.row);\r\n\t\t\tlinkAny[\"data-page-handler\"] = pageHandler;\r\n\t\t\tlinkAny[\"formNoValidate\"] = true;\r\n\t\t\tlink.role = \"button\";\r\n\t\t\tlink.tabIndex = 0;\r\n\t\t}\r\n\t\telse if (column.apiHandler) {\r\n\r\n\t\t\tconst apih = $.extend(true, {}, column.apiHandler);\r\n\t\t\tapih.path = dataFormat(column.apiHandler.path, params.row);\r\n\r\n\t\t\tif (column.apiHandler.data) {\r\n\r\n\t\t\t\tfor (const k in apih.data) {\r\n\r\n\t\t\t\t\tconst value = apih.data[k];\r\n\r\n\t\t\t\t\tif (typeof value === \"string\") {\r\n\r\n\t\t\t\t\t\tapih.data[k] = dataFormat(value, params.row);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tconst linkAny = link as any;\r\n\t\t\tlinkAny[\"data-api-handler\"] = JSON.stringify(apih);\r\n\t\t\tlinkAny[\"formNoValidate\"] = true;\r\n\t\t\tlink.role = \"button\";\r\n\t\t\tlink.tabIndex = 0;\r\n\t\t}\r\n\t\telse if (column.urlField) {\r\n\r\n\t\t\tlink.href = getProperty(params.row, column.urlField);\r\n\r\n\t\t\tif (!link.href) {\r\n\r\n\t\t\t\treturn \r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// if this column link should be clicked when the row is clicked..\r\n\t\tif (column.activateOnRowClick) {\r\n\r\n\t\t\tconst linkAny = link as any;\r\n\t\t\tlinkAny[\"data-activate-on-row-click\"] = true;\r\n\t\t}\r\n\r\n\t\t// apply tooltip wrapper around the link if renderTooltip equals true\r\n\t\tif (column.renderTooltip) {\r\n\r\n\t\t\tconst text = getProperty(params.row, params.field);\r\n\t\t\tif (text) {\r\n\r\n\t\t\t\tlink.className = addClass(link.className ?? \"\", \"grid-text-tooltip\");\r\n\t\t\t\treturn {linkInnerContent};\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// if not a link, then apply the button role to the element\r\n\t\tif (!href && !column.activateOnRowClick) {\r\n\r\n\t\t\tlink.role = \"button\";\r\n\t\t}\r\n\r\n\t\t// return link element\r\n\t\treturn {linkInnerContent};\r\n\t}\r\n\r\n\t/**\r\n\t * Mail to column renderer, outputs a hyperlink element with an email mailto attribute.\r\n\t * @param column The data grid column options.\r\n\t * @param params The data cell params.\r\n\t */\r\n\tprivate static renderMailTo(column: DataGridColumnOptions, params: GridCellParams) {\r\n\r\n\t\tconst email = getProperty(params.row, column.field) as string;\r\n\t\tconst mailTo = \"mailto: \" + email;\r\n\t\treturn {email};\r\n\t}\r\n\r\n\t/**\r\n\t * Tooltip column renderer, outputs a text with an accompanying tooltip.\r\n\t * Useful for when text is truncated with ellipsis due to being too long\r\n\t * @param column The data grid column options.\r\n\t * @param params The data cell params.\r\n\t */\r\n\tprivate static renderTooltip(column: DataGridColumnOptions, params: GridCellParams) {\r\n\r\n\t\tconst text = getProperty(params.row, column.field) as string;\r\n\t\treturn text ? {text} : ;\r\n\t}\r\n\r\n\t/**\r\n\t * Conditional CSS class column renderer, outputs a value wrapped with a class if the configured condition is met.\r\n\t * @param column The data grid column options.\r\n\t * @param params The data cell params.\r\n\t */\r\n\tprivate static renderConditionalClass(column: DataGridColumnOptions, params: GridCellParams) {\r\n\r\n\t\tconst text = getProperty(params.row, column.formattedField ?? column.field) as string;\r\n\t\tlet cssClass: string | null;\r\n\r\n\t\tif (column.conditionalClassName.rule == Constants.NegativeValueRuleName) {\r\n\r\n\t\t\tconst value = getProperty(params.row, column.conditionalClassName.field ?? column.field) as number;\r\n\t\t\tcssClass = value < 0 ? column.conditionalClassName.className : null;\r\n\t\t}\r\n\t\telse if (column.conditionalClassName.rule == Constants.PositiveValueRuleName) {\r\n\r\n\t\t\tconst value = getProperty(params.row, column.conditionalClassName.field ?? column.field) as number;\r\n\t\t\tcssClass = value > 0 ? column.conditionalClassName.className : null;\r\n\t\t}\r\n\t\telse if (column.conditionalClassName.rule == Constants.HasNumericValueRuleName) {\r\n\r\n\t\t\tconst value = getProperty(params.row, column.conditionalClassName.field ?? column.field) as number;\r\n\t\t\tcssClass = (value ?? 0) != 0 ? column.conditionalClassName.className : null;\r\n\t\t}\r\n\t\telse if (column.conditionalClassName.field) {\r\n\r\n\t\t\tconst value = getProperty(params.row, column.conditionalClassName.field) as boolean;\r\n\t\t\tcssClass = value === true ? column.conditionalClassName.className : null;\r\n\t\t}\r\n\t\telse {\r\n\r\n\t\t\tcssClass = null;\r\n\t\t}\r\n\r\n\t\treturn cssClass ? {text} : {text};\r\n\t}\r\n\r\n\t/**\r\n\t * Badge column renderer, outputs column text as a Bootstrap badge element.\r\n\t * @param column The data grid column options.\r\n\t * @param params The data cell params.\r\n\t */\r\n\tprivate static renderBadge(column: DataGridColumnOptions, params: GridCellParams) {\r\n\r\n\t\tconst text = getProperty(params.row, column.field) as string;\r\n\t\tconst badgeCssClass = getProperty(params.row, column.badgeCssClassField) as string;\r\n\t\tconst fullCssClass = badgeCssClass ? `badge badge-${badgeCssClass}` : null;\r\n\t\treturn fullCssClass ? {text} : {text};\r\n\t}\r\n\r\n\t/**\r\n\t * HTML column renderer, outputs HTML directly.\r\n\t * @param column The data grid column options.\r\n\t * @param params The data cell params.\r\n\t */\r\n\tprivate static renderHtml(column: DataGridColumnOptions, params: GridCellParams) {\r\n\r\n\t\tconst value = getProperty(params.row, column.field) as string;\r\n\t\treturn ;\r\n\t}\r\n\r\n\t/**\r\n\t * Icon column renderer, outputs an icon element.\r\n\t * @param column The data grid column options.\r\n\t * @param params The data cell params.\r\n\t */\r\n\tprivate static renderIcon(column: DataGridColumnOptions, params: GridCellParams) {\r\n\r\n\t\tconst icon = getProperty(params.row, column.field) as Icon;\r\n\t\treturn ;\r\n\t}\r\n\r\n\t/**\r\n\t * Financial column column modifier, applies financial CSS class.\r\n\t * @param column The data column definition.\r\n\t */\r\n\tprivate static formatFinancial(column: GridEnrichedColDef) {\r\n\r\n\t\tcolumn.headerClassName = addClass(column?.cellClassName as string, Constants.CssClassFinancial);\r\n\t\tcolumn.cellClassName = addClass(column?.cellClassName as string, Constants.CssClassFinancial);\r\n\t}\r\n\r\n\t/**\r\n\t * Icon column column modifier, applies icon CSS class.\r\n\t * @param column The data column definition.\r\n\t */\r\n\tprivate static formatIcon(column: GridEnrichedColDef) {\r\n\r\n\t\tcolumn.headerClassName = addClass(column?.cellClassName as string, MaterialDataGridService.iconCellClass);\r\n\t\tcolumn.cellClassName = addClass(column?.cellClassName as string, MaterialDataGridService.iconCellClass);\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the column sort header element.\r\n\t * @param params The data column header params.\r\n\t * @param state The data grid state.\r\n\t * @returns Column header title and icon with a tooltip.\r\n\t */\r\n\tprivate static getColumnSortHeader(params: GridColumnHeaderParams, state?: DataGridState) {\r\n\r\n\t\tconst colDef = params.colDef;\r\n\t\tconst sortField = state?.sortModel.find(s => s.field === colDef.field);\r\n\t\tconst sortDir = sortField?.sort ?? \"off\";\r\n\t\tconst sortDirIcon = sortField?.sort === \"desc\" ? \"fa-sort-amount-down\" : \"fa-sort-amount-up-alt\";\r\n\t\tlet iconClass = `fas ${sortDirIcon} col-sort-icon col-sort-${sortDir}`;\r\n\t\tlet tooltipTitle;\r\n\r\n\t\tswitch (sortDir) {\r\n\t\t\tcase \"asc\":\r\n\t\t\t\ttooltipTitle = `Click to sort by ${colDef.headerName ?? colDef.field} descending`;\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"desc\":\r\n\t\t\t\ttooltipTitle = \"Click to remove sorting\";\r\n\t\t\t\tbreak;\r\n\t\t\tdefault:\r\n\t\t\t\ttooltipTitle = `Click to sort by ${colDef.headerName ?? colDef.field} ascending`;\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\t// return column header title and icon with a tooltip\r\n\t\treturn \r\n\t\t\t
\r\n\t\t\t\t
{colDef.headerName}
\r\n\t\t\t\t\r\n\t\t\t
\r\n\t\t
;\r\n\t}\r\n\r\n\t/**\r\n\t * Converts a sort model to the MUI equivalent.\r\n\t * @param input The input field sorts.\r\n\t * @param columns The array of column options.\r\n\t */\r\n\tprivate convertSortModel(input: Array, columns: Array) {\r\n\r\n\t\treturn (input ? input.map(sort => {\r\n\t\t\tconst column = this.getColumn(columns, sort.field);\r\n\t\t\treturn {\r\n\t\t\t\tfield: column?.field ?? sort.field,\r\n\t\t\t\tsort: (sort.direction == ListSortDirection.Descending ? \"desc\" : \"asc\")\r\n\t\t\t}\r\n\t\t}) : []) as GridSortModel;\r\n\t}\r\n\r\n\t/**\r\n\t * Finds a column by field name.\r\n\t * @param columns The array of columns to search.\r\n\t * @param field The field name to match.\r\n\t * @returns DataGridColumnOptions or null if not matched.\r\n\t * @see DataGridColumnOptions\r\n\t */\r\n\tprivate getColumn(columns: Array, field: string) {\r\n\r\n\t\tconst lowered = field.toLowerCase();\r\n\t\treturn columns.find(col => col.field.toLowerCase() === lowered);\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the data for the grid, when data source mode is server bound.\r\n\t * @param apiUrl the API URL to query.\r\n\t * @param options The data grid options.\r\n\t * @param state the current data grid state.\r\n\t * @returns Promise of any data type.\r\n\t */\r\n\tprivate getData(apiUrl: ApiUrl, options: DataGridOptions, state: DataGridState) {\r\n\r\n\t\t// build the URL\r\n\t\tconst url = this.urlService.apiUrl(apiUrl);\r\n\r\n\t\tlet apiModel: ApiModel | undefined;\r\n\t\tif ((apiModel = options.apiModel)) {\r\n\r\n\t\t\t// apply paging to request model\r\n\t\t\tif (apiModel.paging && state.page >= 0 && state.pageSize > 0) {\r\n\r\n\t\t\t\tapiModel.paging.page = state.page + 1;\r\n\t\t\t\tapiModel.paging.pageSize = state.pageSize;\r\n\t\t\t}\r\n\r\n\t\t\t// apply sorting to request model\r\n\t\t\tif (state.sortModel) {\r\n\r\n\t\t\t\tapiModel.sorts = state.sortModel.map(sortItem => {\r\n\t\t\t\t\treturn {\r\n\t\t\t\t\t\tdirection: sortItem.sort === \"desc\" ? ListSortDirection.Descending : ListSortDirection.Ascending,\r\n\t\t\t\t\t\tfield: sortItem.field\r\n\t\t\t\t\t};\r\n\t\t\t\t});\r\n\t\t\t}\r\n\r\n\t\t\t// apply filtering to request model\r\n\t\t\tif (options.filtersElementId) {\r\n\r\n\t\t\t\tconst filtersElement = document.getElementById(options.filtersElementId);\r\n\r\n\t\t\t\tif (filtersElement) {\r\n\t\t\t\t\tthis.filterService.applyFilters(filtersElement, apiModel.filters ?? apiModel, apiModel);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// perrform AJAX request to get data\r\n\t\treturn this.ajaxService.request({\r\n\t\t\turl,\r\n\t\t\tmethod: apiUrl.method,\r\n\t\t\tdata: apiModel\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * Applies financial column alignment to financial column cells.\r\n\t * @param gridElement The data grid element.\r\n\t */\r\n\tprivate applyFinancialColumnAlignment(gridElement: Element) {\r\n\r\n\t\t// check for finanical column cells\r\n\t\tconst financialCols = gridElement.querySelectorAll(\".MuiDataGrid-virtualScrollerRenderZone .financial\");\r\n\t\tif (financialCols.length > 0) {\r\n\r\n\t\t\tlet maxWidth: number | undefined;\r\n\t\t\tconst valueElements = new Array();\r\n\t\t\tfinancialCols.forEach(element => {\r\n\r\n\t\t\t\tconst cell = element as HTMLDivElement;\r\n\r\n\t\t\t\t// if the cell has text\r\n\t\t\t\tif (cell.innerText) {\r\n\r\n\t\t\t\t\t// create new value element, wrapping the text or pickup previously created one and re-use\r\n\t\t\t\t\tconst valueElement = cell.querySelector(\"span\") ?? document.createElement(\"span\");\r\n\t\t\t\t\tvalueElement.classList.add(\"cell-decimal-value\");\r\n\t\t\t\t\tvalueElement.innerHTML = cell.innerText;\r\n\r\n\t\t\t\t\t// clear the previously width if any\r\n\t\t\t\t\tif (valueElement.style.width) {\r\n\t\t\t\t\t\tvalueElement.style.width = \"\";\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// check for a link, if there is one place the created value element inside it\r\n\t\t\t\t\tconst link = cell.querySelector(\"a\");\r\n\t\t\t\t\tif (link) {\r\n\r\n\t\t\t\t\t\tlink.innerHTML = \"\";\r\n\t\t\t\t\t\tlink.appendChild(valueElement);\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\r\n\t\t\t\t\t\t// otherwise just clear cell text and place the created value element inside the cell directly\r\n\t\t\t\t\t\tcell.innerHTML = \"\";\r\n\t\t\t\t\t\tcell.appendChild(valueElement);\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\tvalueElements.push(valueElement);\r\n\r\n\t\t\t\t\t// keep a reference the maximum value element width\r\n\t\t\t\t\tconst valueElementWidth = valueElement.getBoundingClientRect().width;\r\n\t\t\t\t\tif (!maxWidth || maxWidth < valueElementWidth) {\r\n\t\t\t\t\t\tmaxWidth = valueElementWidth;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tcell.style.visibility = \"visible\";\r\n\t\t\t});\r\n\r\n\t\t\t// if there's a max width\r\n\t\t\tif (maxWidth) {\r\n\r\n\t\t\t\t// loop value elements and set each one to the max width\r\n\t\t\t\tvalueElements.forEach(element => {\r\n\t\t\t\t\tconst valueElement = element as HTMLSpanElement;\r\n\t\t\t\t\tvalueElement.style.width = `${maxWidth}px`;\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Applies detail row content to the configured row.\r\n\t * @param options The data grid options.\r\n\t * @param state The current data grid state.\r\n\t * @param gridElement The data grid target element.\r\n\t */\r\n\tprivate applyDetailRow(options: DataGridOptions, state: DataGridState, gridElement: Element) {\r\n\r\n\t\t// if detail row key, detail row element ID and key field are set,\r\n\t\t// then detail row content should attempt to be inserted\r\n\t\tif (!isNullOrUndefined(options.detailRowKey) && options.detailRowElementId && options.keyField) {\r\n\r\n\t\t\t// get the detail row content element\r\n\t\t\tconst detailRowElement = document.getElementById(options.detailRowElementId);\r\n\r\n\t\t\tif (detailRowElement) {\r\n\r\n\t\t\t\t// clear any existing sub row element\r\n\t\t\t\t$(gridElement).find(\".sub-row\").remove();\r\n\r\n\t\t\t\t// loop row elements\r\n\t\t\t\tgridElement.querySelectorAll(\".MuiDataGrid-virtualScrollerRenderZone .MuiDataGrid-row\").forEach(rowElement => {\r\n\r\n\t\t\t\t\tconst id = rowElement.getAttribute(\"data-id\");\r\n\t\t\t\t\tconst dataItem = state.data.find(item => getProperty(item, options.keyField) == id);\r\n\t\t\t\t\tlet hasChildRow = false;\r\n\t\t\t\t\tconst keyValue = getProperty(dataItem, options.keyField);\r\n\r\n\t\t\t\t\t// check the data item key equals the configured detail row key\r\n\t\t\t\t\tif (keyValue === options.detailRowKey) {\r\n\r\n\t\t\t\t\t\t// now create the container sub row element and add to the grid\r\n\t\t\t\t\t\tconst detailRowContainer = document.createElement(\"div\");\r\n\t\t\t\t\t\tdetailRowContainer.classList.add(\"sub-row\");\r\n\t\t\t\t\t\tdetailRowContainer.appendChild(detailRowElement);\r\n\r\n\t\t\t\t\t\trowElement.after(detailRowContainer);\r\n\t\t\t\t\t\trowElement.classList.add(\"expanded\");\r\n\r\n\t\t\t\t\t\t// ensure styles are compatible\r\n\t\t\t\t\t\tconst renderingZone = rowElement.closest(\".MuiDataGrid-virtualScrollerRenderZone\") as HTMLElement;\r\n\t\t\t\t\t\tif (renderingZone) {\r\n\t\t\t\t\t\t\trenderingZone.style.removeProperty(\"max-height\");\r\n\t\t\t\t\t\t\trenderingZone.style.removeProperty(\"width\");\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tconst gridViewPort = rowElement.closest(\".MuiDataGrid-virtualScrollerContent\") as HTMLElement;\r\n\t\t\t\t\t\tif (gridViewPort) gridViewPort.style.removeProperty(\"height\");\r\n\t\t\t\t\t\tconst gridWindow = rowElement.closest(\".MuiDataGrid-virtualScrollerRenderZone\") as HTMLElement;\r\n\t\t\t\t\t\tif (gridWindow) {\r\n\t\t\t\t\t\t\tgridWindow.style.removeProperty(\"max-height\");\r\n\t\t\t\t\t\t\tgridWindow.style.removeProperty(\"overflow-y\");\r\n\t\t\t\t\t\t\tgridWindow.style.position = \"static\";\r\n\t\t\t\t\t\t\tgridWindow.style.removeProperty(\"top\");\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tconst gridRoot = rowElement.closest(\".MuiDataGrid-root\") as HTMLElement;\r\n\t\t\t\t\t\tif (gridRoot) gridRoot.style.removeProperty(\"height\");\r\n\r\n\t\t\t\t\t\thasChildRow = true;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// ensure other rows can be clicked with page handler called\r\n\t\t\t\t\tif (hasChildRow === false && options.rowPageHandler) {\r\n\r\n\t\t\t\t\t\trowElement.setAttribute(\"data-page-handler\", dataFormat(options.rowPageHandler, dataItem));\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Applies row level hyperlink elements from column cell hyperlinks.\r\n\t * @param options The data grid options.\r\n\t * @param state The current data grid state.\r\n\t * @param gridElement The data grid target element.\r\n\t */\r\n\tprivate applyActivateOnRowClick(options: DataGridOptions, state: DataGridState, gridElement: Element) {\r\n\r\n\t\tgridElement.querySelectorAll(\"[data-activate-on-row-click]\").forEach(element => {\r\n\r\n\t\t\tconst rowElement = element.closest(\".MuiDataGrid-row\") as HTMLElement;\r\n\r\n\t\t\tif (rowElement) {\r\n\r\n\t\t\t\t// apply page handler to the row\r\n\t\t\t\tconst pageHandler = element.getAttribute(\"data-page-handler\");\r\n\t\t\t\tif (pageHandler) {\r\n\r\n\t\t\t\t\tconst id = rowElement.getAttribute(\"data-id\");\r\n\t\t\t\t\tconst dataItem = state.data.find(item => getProperty(item, options.keyField) == id);\r\n\t\t\t\t\tconst keyValue = getProperty(dataItem, options.keyField);\r\n\t\t\t\t\tif (keyValue !== Guid.empty) {\r\n\t\t\t\t\t\trowElement.setAttribute(\"data-page-handler\", pageHandler);\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// apply api handler to the row\r\n\t\t\t\tconst apiHandler = element.getAttribute(\"data-api-handler\");\r\n\t\t\t\tif (apiHandler) {\r\n\r\n\t\t\t\t\trowElement.setAttribute(\"data-api-handler\", apiHandler);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst href = element.getAttribute(\"href\");\r\n\t\t\t\tif (href) {\r\n\r\n\t\t\t\t\t// set data-href on row to that of the link href\r\n\t\t\t\t\trowElement.setAttribute(\"data-href\", href);\r\n\r\n\t\t\t\t\t// add click event handler on the row element\r\n\t\t\t\t\trowElement.addEventListener(\"click\", event => {\r\n\r\n\t\t\t\t\t\tconst target = event.target as HTMLElement;\r\n\r\n\t\t\t\t\t\t// ignore link clicks\r\n\t\t\t\t\t\tif (target.tagName === \"A\" || target.parentElement?.tagName === \"A\") {\r\n\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// check for link target\r\n\t\t\t\t\t\tconst link = rowElement.querySelector(\"a[data-activate-on-row-click]\") as HTMLAnchorElement;\r\n\t\t\t\t\t\tif (link.target === \"_blank\") {\r\n\r\n\t\t\t\t\t\t\t// open in new window\r\n\t\t\t\t\t\t\twindow.open(href);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t// navigate to the href\r\n\t\t\t\t\t\twindow.location.href = href;\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * Applies conditional row CSS class.\r\n\t * @param options The data grid options.\r\n\t * @param state The current data grid state.\r\n\t * @param gridElement The data grid target element.\r\n\t */\r\n\tprivate applyRowClass(options: DataGridOptions, state: DataGridState, gridElement: Element) {\r\n\r\n\t\tif (!options.conditionalRowClassName?.className) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// loop the row elements\r\n\t\tgridElement.querySelectorAll(\".MuiDataGrid-virtualScrollerRenderZone .MuiDataGrid-row\").forEach(rowElement => {\r\n\r\n\t\t\tconst id = rowElement.getAttribute(\"data-id\");\r\n\t\t\tconst dataItem = state.data.find(item => getProperty(item, options.keyField) == id);\r\n\t\t\tconst value = getProperty(dataItem, options.conditionalRowClassName.field);\r\n\r\n\t\t\t// apply CSS class if rule is equality and the values match\r\n\r\n\t\t\tif (options.conditionalRowClassName.rule === Constants.EqualityRuleName) {\r\n\r\n\t\t\t\tif (options.conditionalRowClassName.value === value) {\r\n\r\n\t\t\t\t\trowElement.classList.add(options.conditionalRowClassName.className);\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\r\n\t\t\t\t\trowElement.classList.remove(options.conditionalRowClassName.className);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}","import { SwitchProps } from \"@mui/material\";\r\nimport { inject, injectable } from \"inversify\";\r\nimport moment from \"moment\";\r\nimport React from \"react\";\r\nimport { IpfModule } from \"../..\";\r\nimport { Constants } from \"../../constants.generated\";\r\nimport { MessageType } from \"../../enums.generated\";\r\nimport { EventConstants } from \"../../EventConstants\";\r\nimport { doWhen } from \"../../functions/do-when\";\r\nimport { getProperty } from \"../../functions/get-property\";\r\nimport { isFormButton } from \"../../functions/is-form-button\";\r\nimport { isValidDate } from \"../../functions/is-valid-date\";\r\nimport { TYPES } from \"../../ioc/types\";\r\nimport { ConfirmationOption, ConfirmationPromptOptions } from \"../../models/app\";\r\nimport { FormComponentService, LoaderService, TierSelectorService, ValidationService } from \"../../services\";\r\nimport { ServiceBase } from \"../../services/ServiceBase\";\r\nimport { ConfirmationPrompt } from \"../components/ConfirmationPrompt\";\r\nimport { DatePickerOptions, IpfDatePicker } from \"../components/DatePicker\";\r\nimport { MobileNumberInput, MobileNumberOptions } from \"../components/MobileNumberInput\";\r\nimport { SwitchControl } from \"../components/SwitchControl\";\r\nimport { TextInputSearch, TextInputSearchOptions } from \"../components/TextInputSearch\";\r\nimport { ReactDOMProxy } from \"../ReactDOMProxy\";\r\n\r\n/**\r\n * MUI form component service, used to inject MUI form controls into the UI.\r\n */\r\n@injectable()\r\nexport class MaterialFormComponentService extends ServiceBase implements FormComponentService {\r\n\r\n\t/**\r\n\t * Initialises a new instance of the MaterialFormComponentService class.\r\n\t * @param ipfModule IPF module, containing contextual information and functions.\r\n\t * @param tierSelectorService Tier selector service, used to apply tier selection controls to the UI.\r\n\t * @param validationService Form validation service.\r\n\t * @param loaderService Page and element loader service.\r\n\t */\r\n\tpublic constructor(\r\n\t\t@inject(TYPES.IpfModule) private ipfModule: IpfModule,\r\n\t\t@inject(TYPES.TierSelectorService) private tierSelectorService: TierSelectorService,\r\n\t\t@inject(TYPES.ValidationService) private validationService: ValidationService,\r\n\t\t@inject(TYPES.LoaderService) private loaderService: LoaderService) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n applyAll(target: Element): void {\r\n\r\n\t\tthis.applySwitchComponents(target);\r\n\t\tthis.applyDatePickers(target);\r\n\t\tthis.applyMobileInput(target);\r\n\t\tthis.applyTextInputSearchComponents(target);\r\n\t\tthis.applyConfirmationPromptComponents(target);\r\n\t\tthis.applySubmitLoaders(target);\r\n\t}\r\n\r\n\t//#region Switch\r\n\r\n\t/**\r\n\t * Applies switch components to target checkbox input elements.\r\n\t * @param target The container element containing the input elements.\r\n\t */\r\n private applySwitchComponents(target: Element) {\r\n\r\n\t\ttarget.querySelectorAll(\"input[data-switch]\").forEach(input => this.renderSwitch(input));\r\n\t}\r\n\r\n\t/**\r\n\t * Renders a MUI switch component.\r\n\t * @param element The target checkbox input element.\r\n\t */\r\n private renderSwitch(element: Element) {\r\n\r\n\t\tif (!element.parentElement) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n const input = element as HTMLInputElement;\r\n\r\n input.classList.add(\"hide\");\r\n\r\n const switchProps: SwitchProps = {\r\n checked: input.checked\r\n };\r\n\r\n if (input.getAttribute(\"data-size\") === \"small\") {\r\n\r\n switchProps.size = \"small\";\r\n }\r\n\r\n const props = {\r\n offLabel: input.getAttribute(\"data-off-label\"),\r\n onLabel: input.getAttribute(\"data-on-label\"),\r\n onChange: (checked: boolean) => {\r\n\r\n\t\t\t\tinput.checked = checked;\r\n\t\t\t\tinput.dispatchEvent(new Event(EventConstants.change));\r\n },\r\n switchProps\r\n };\r\n\r\n const target = document.createElement(\"span\");\r\n\t\telement.parentElement.insertBefore(target, element);\r\n\r\n\t\tReactDOMProxy.renderStyled(\r\n ,\r\n target\r\n );\r\n\t}\r\n\r\n\t//#endregion\r\n\r\n\t//#region Text input search\r\n\r\n\t/**\r\n\t * Applies text input search components to input elements. Enabling search as you type functionality.\r\n\t * @param target The container element containing the input elements.\r\n\t */\r\n\tprivate applyTextInputSearchComponents(target: Element) {\r\n\r\n\t\ttarget.querySelectorAll(\"input[data-text-search]\").forEach(input => this.renderTextInputSearch(input));\r\n\t}\r\n\r\n\t/**\r\n\t * Renders a text input search component.\r\n\t * @param element The target checkbox input element.\r\n\t */\r\n\tprivate renderTextInputSearch(element: Element) {\r\n\r\n\t\tif (!element.parentElement) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst input = element as HTMLInputElement;\r\n\r\n\t\tconst target = document.createElement(\"div\");\r\n\t\telement.after(target);\r\n\r\n\t\tconst props: TextInputSearchOptions = {\r\n\t\t\tinput,\r\n\t\t\tselected: { value: null }\r\n\t\t};\r\n\r\n\t\tconst self = this;\r\n\r\n\t\tinput.addEventListener(\"resultselected\", () => {\r\n\r\n\t\t\tconst valueField = input.parentElement?.querySelector(\"[data-text-search-value]\") as HTMLInputElement;\r\n\r\n\t\t\tif (valueField) {\r\n\r\n\t\t\t\tself.setTextInputSearchValueField(props, valueField, input);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tReactDOMProxy.renderStyled(\r\n\t\t\t,\r\n\t\t\ttarget\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * Set the value of the text input search value field element.\r\n\t * @param options Text input search options.\r\n\t * @param valueField The value field element.\r\n\t * @param inputField The input field element.\r\n\t */\r\n\tprivate setTextInputSearchValueField(options: TextInputSearchOptions, valueField: HTMLInputElement, inputField: HTMLInputElement) {\r\n\r\n\t\tconst isTierSelector = valueField.hasAttribute(\"data-tier-selector\");\r\n\r\n\t\tif (isTierSelector) {\r\n\r\n\t\t\tthis.tierSelectorService.setTierSelectorValue(options.selected.value, valueField);\r\n\t\t}\r\n\t\telse {\r\n\r\n\t\t\tvalueField.value = getProperty(options.selected.value, inputField.getAttribute(\"data-value-field\") ?? \"\") ?? \"\";\r\n\t\t}\r\n\r\n\t\tvalueField.dispatchEvent(new Event(EventConstants.change));\r\n\t}\r\n\r\n\t//#endregion\r\n\r\n\t//#region Confirmation prompts\r\n\r\n\t/**\r\n\t * Applies confirmation prompt components.\r\n\t * Can either be a single configured prompt to be displayed within IPF data or prompts,\r\n\t * that are displayed on click of a button.\r\n\t * @param target The container element containing the input elements.\r\n\t */\r\n\tprivate applyConfirmationPromptComponents(target: Element) {\r\n\r\n\t\t// check confirmation prompt configuration with IPF data\r\n\t\tconst prompt = this.ipfModule.getData(Constants.DataKeyPrompt);\r\n\t\tif (prompt) {\r\n\r\n\t\t\t// configure confirm option handler\r\n\t\t\tif (prompt.confirmOption) {\r\n\r\n\t\t\t\tconst confirmActionUrl = prompt.confirmOption.actionUrl;\r\n\t\t\t\tif (confirmActionUrl) {\r\n\r\n\t\t\t\t\tprompt.confirmOption.handler = () => {\r\n\r\n\t\t\t\t\t\twindow.location.href = confirmActionUrl;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// configure cancel option handler\r\n\t\t\tconst cancelActionUrl = prompt.cancelOption?.actionUrl;\r\n\t\t\tif (prompt.cancelOption && cancelActionUrl) {\r\n\r\n\t\t\t\tprompt.cancelOption.handler = () => {\r\n\r\n\t\t\t\t\twindow.location.href = cancelActionUrl;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tthis.showConfirmationPrompt(prompt);\r\n\r\n\t\t\t// clear the prompt data\r\n\t\t\tthis.ipfModule.clearData(Constants.DataKeyPrompt);\r\n\t\t}\r\n\r\n\t\t// find all elements with conform text and render a confirmation click handler\r\n\t\ttarget.querySelectorAll(\"[data-confirm-text]\").forEach(element => this.renderButtonConfirmationPrompt(element));\r\n\t}\r\n\r\n\t/**\r\n\t * Renders a confirmation prompt component for a button, shown when the button is clicked.\r\n\t * @param element The target element.\r\n\t */\r\n\tprivate renderButtonConfirmationPrompt(element: Element) {\r\n\r\n\t\tif (!element?.parentElement) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// extract prompt properties from the button\r\n\t\tconst button = element as HTMLElement;\r\n\t\tconst excludeCancelBtn = button.getAttribute(\"data-confirm-cancel-exclude\") === \"true\";\r\n\t\tconst title = button.getAttribute(\"data-confirm-title\") ?? !excludeCancelBtn ? \"Confirmation is required\" : \"\";\r\n\t\tlet text = button.getAttribute(\"data-confirm-text\");\r\n\r\n\t\tif (text) {\r\n\r\n\t\t\tconst onConfirm = () => {\r\n\t\t\t\tbutton.setAttribute(\"data-confirmed\", \"true\");\r\n\t\t\t\tbutton.click();\r\n\t\t\t};\r\n\r\n\t\t\tconst confirmOption = {\r\n\t\t\t\ttext: button.getAttribute(\"data-confirm-confirm-label\") ?? \"Confirm\",\r\n\t\t\t\tstyle: \"primary\",\r\n\t\t\t\thandler: onConfirm\r\n\t\t\t} as ConfirmationOption;\r\n\r\n\t\t\tconst cancelOption = !excludeCancelBtn ? {\r\n\t\t\t\t\ttext: button.getAttribute(\"data-confirm-cancel-label\") ?? \"Cancel\",\r\n\t\t\t\t\tstyle: \"secondary\"\r\n\t\t\t} as ConfirmationOption: undefined;\r\n\r\n\t\t\tconst renderHtml = button.getAttribute(\"data-confirm-html-content\") === \"true\";\r\n\r\n\t\t\tif (renderHtml) {\r\n\t\t\t\ttext = text.replace(/\\r\\n/g, \"
\");\r\n\t\t\t}\r\n\r\n\t\t\tconst typeAttr = button.getAttribute(\"data-confirm-type\");\r\n\t\t\tconst type = typeAttr ? MessageType[typeAttr as keyof typeof MessageType] : undefined;\r\n\r\n\t\t\tconst options: ConfirmationPromptOptions = {\r\n\t\t\t\ttitle,\r\n\t\t\t\ttext,\r\n\t\t\t\ttype,\r\n\t\t\t\tconfirmOption: confirmOption,\r\n\t\t\t\tcancelOption,\r\n\t\t\t\trenderTextAsHtml: renderHtml\r\n\t\t\t};\r\n\r\n\t\t\t// add click handler to show the prompt\r\n\t\t\tbutton.onclick = event => {\r\n\r\n\t\t\t\t// if the prompt was confirmed then remove the attribute and continue as normal\r\n\t\t\t\tif (isFormButton(button) && button.getAttribute(\"data-confirmed\") === \"true\") {\r\n\r\n\t\t\t\t\tbutton.removeAttribute(\"data-confirmed\");\r\n\t\t\t\t}\r\n\t\t\t\t// otherwise open the prompt\r\n\t\t\t\telse if (options.open) {\r\n\t\t\t\t\toptions.open();\r\n\t\t\t\t\tevent.preventDefault();\r\n\t\t\t\t}\r\n\t\t\t};\r\n\r\n\t\t\t// add a new target container to the buttons parent element\r\n\t\t\tconst target = document.createElement(\"div\");\r\n\t\t\telement.parentElement.appendChild(target);\r\n\r\n\t\t\t// render prompt the added target container element\r\n\t\t\tReactDOMProxy.renderStyled(\r\n\t\t\t\t,\r\n\t\t\t\ttarget\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic showConfirmationPrompt(options: ConfirmationPromptOptions, targetElement?: Element) {\r\n\r\n\t\t// create target element for the prompt\r\n\t\tconst target = document.createElement(\"div\");\r\n\r\n\t\t// if targetElement not provided, append to body element\r\n\t\tif (!targetElement) {\r\n\t\t\tdocument.body.append(target);\r\n\t\t}\r\n\t\telse {\r\n\t\t\ttargetElement.after(target);\r\n\t\t}\r\n\r\n\t\t// show prompt once rendered\r\n\t\toptions.autoOpen = true;\r\n\r\n\t\t// create callback to append content element if it is provided\r\n\t\tconst callback = options.content ? () => {\r\n\t\t\tif (options.content) {\r\n\t\t\t\tconst ensuredContent = options.content;\r\n\t\t\t\tdoWhen(() => {\r\n\r\n\t\t\t\t\tconst dialogContent = document.getElementById(\"dialog-content\");\r\n\r\n\t\t\t\t\tif (!dialogContent) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (ensuredContent.id && dialogContent.querySelector(`#${ensuredContent.id}`)) {\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tdialogContent.appendChild(ensuredContent);\r\n\t\t\t\t}, () => document.getElementById(\"dialog-content\") != null);\r\n\t\t\t}\r\n\r\n\t\t\t// call on open handler if there is one\r\n\t\t\tif (options.onOpen) {\r\n\t\t\t\toptions?.onOpen();\r\n\t\t\t}\r\n\t\t} : () => {\r\n\r\n\t\t\t// call on open handler if there is one\r\n\t\t\tif (options.onOpen) {\r\n\t\t\t\toptions?.onOpen();\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t// render the prompt to the target with callback function once rendered\r\n\t\tReactDOMProxy.renderStyled(\r\n\t\t\t,\r\n\t\t\ttarget,\r\n\t\t\tcallback\r\n\t\t);\r\n\t}\r\n\r\n\t//#endregion\r\n\r\n\t//#region Button loaders\r\n\r\n\t/**\r\n\t * Applies submit form loaders, which displays a loading animation component.\r\n\t * Elements must be within a form or have a form attribute referencing a form element.\r\n\t * @param target The container element containing the elements which require a loader component is displayed on click.\r\n\t */\r\n\tprivate applySubmitLoaders(target: Element) {\r\n\r\n\t\ttarget.querySelectorAll(\"[data-submit-loader]\").forEach(element => this.applySubmitLoaderBehaviour(element));\r\n\t}\r\n\r\n\t/**\r\n\t * Applies an individual submit loader component for an element, when clicked.\r\n\t * The element must be within a form or have a form attribute referencing a form element.\r\n\t * @param element The target element.\r\n\t */\r\n\tprivate applySubmitLoaderBehaviour(element: Element) {\r\n\r\n\t\tlet form: HTMLFormElement | null;\r\n\r\n\t\t// get the closest form or the referenced form via form attribute\r\n\t\tif (element instanceof HTMLButtonElement && element.hasAttribute(\"form\")) {\r\n\r\n\t\t\tform = document.querySelector(`#${element.getAttribute(\"form\")}`);\r\n\t\t}\r\n\t\telse {\r\n\r\n\t\t\tform = element.closest(\"form\");\r\n\t\t}\r\n\r\n\t\tif (!form) {\r\n\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// add a submit event listener to the form\r\n\t\tform.addEventListener(\"submit\", event => {\r\n\r\n\t\t\t// validate the form, if not valid then don't show the loader\r\n\t\t\tif (form && this.validationService.isValidForm(form) === false) {\r\n\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\t// if already loading, prevent submit by calling preventDefault\r\n\t\t\tif (element.getAttribute(\"data-loading\")) {\r\n\r\n\t\t\t\tevent.preventDefault();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\t// get the type of submit loader\r\n\t\t\tconst dataSubmitLoaderValue = element.getAttribute(\"data-submit-loader\");\r\n\r\n\t\t\t// if it's silent then just set the data-loading attribute and return\r\n\t\t\tif (dataSubmitLoaderValue === Constants.LoaderSilentDisable) {\r\n\r\n\t\t\t\telement.setAttribute(\"data-loading\", \"1\");\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\t// this wasn't a silent-disable loader so show the form loader\r\n\r\n\t\t\tlet loaderTarget: Element | null;\r\n\r\n\t\t\t// check for a selector\r\n\t\t\tif (dataSubmitLoaderValue) {\r\n\r\n\t\t\t\tloaderTarget = document.querySelector(dataSubmitLoaderValue);\r\n\t\t\t}\r\n\t\t\telse {\r\n\r\n\t\t\t\t// no selector so use the form as the target\r\n\t\t\t\tloaderTarget = form;\r\n\t\t\t}\r\n\r\n\t\t\t// add loading element to the loader target element\r\n\t\t\tif (loaderTarget) {\r\n\r\n\t\t\t\tlet loadingContainer = loaderTarget.parentElement;\r\n\r\n\t\t\t\tif (loadingContainer && loaderTarget.parentElement) {\r\n\r\n\t\t\t\t\tif (!loadingContainer.classList.contains(\"loading-container\")) {\r\n\r\n\t\t\t\t\t\tloadingContainer = document.createElement(\"div\");\r\n\t\t\t\t\t\tloadingContainer.className = \"loading-container\";\r\n\t\t\t\t\t\tloaderTarget.parentElement.insertBefore(loadingContainer, loaderTarget);\r\n\t\t\t\t\t\tloadingContainer.appendChild(loaderTarget);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (loadingContainer) {\r\n\t\t\t\t\t\tloaderTarget.classList.add(\"form-loading\");\r\n\t\t\t\t\t\tthis.loaderService.render(loadingContainer);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t//#endregion\r\n\r\n\t//#region Date pickers\r\n\r\n\t/**\r\n\t * Find and applies MUI date pickers within an element.\r\n\t * @param target The container element containing the input elements which require a date picker.\r\n\t */\r\n\tprivate applyDatePickers(target: Element) {\r\n\r\n\t\ttarget.querySelectorAll(\"[data-date-picker]\").forEach(element => this.renderDatePicker(element as HTMLInputElement));\r\n\t}\r\n\r\n\t/**\r\n\t * Renders a date picker component for the input element.\r\n\t * @param input The input element.\r\n\t */\r\n\tprivate renderDatePicker(input: HTMLInputElement) {\r\n\r\n\t\tif (!input || !input.parentElement) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst ipf = this.ipfModule;\r\n\t\tconst selectedDate = input.value ? moment(input.value).toDate() : undefined;\r\n\r\n\t\t// if read only, just display formatted value and don't render date picker component\r\n\t\tif (input.hasAttribute(\"readonly\")) {\r\n\r\n\t\t\tconst newInput = document.createElement(\"input\");\r\n\t\t\tnewInput.classList.add(\"form-control\");\r\n\t\t\tnewInput.setAttribute(\"readonly\", \"readonly\");\r\n\t\t\tif (selectedDate) {\r\n\t\t\t\tnewInput.value = moment(selectedDate).format(ipf.context.dateFormat.toUpperCase());\r\n\t\t\t}\r\n\t\t\tinput.parentElement.insertBefore(newInput, input);\r\n\t\t\tinput.style.display = \"none\";\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// build date picker component options\r\n\t\tconst target = document.createElement(\"div\");\r\n\t\tinput.parentElement.insertBefore(target, input);\r\n\t\tconst minDate = input.getAttribute(\"data-val-min-date-value\") ? moment(input.getAttribute(\"data-val-min-date-value\")).toDate() : undefined;\r\n\t\tconst maxDate = input.getAttribute(\"data-val-max-date-value\") ? moment(input.getAttribute(\"data-val-max-date-value\")).toDate() : undefined;\r\n\t\tconst defaultCalendarDate = input.getAttribute(\"data-default-calendar-date-is-max-date\") == \"true\" ? maxDate : undefined;\r\n\t\tconst placeholder = input.placeholder;\r\n\t\tconst props = {\r\n\t\t\tinput,\r\n\t\t\tselectedDate,\r\n\t\t\tformat: ipf.context.dateFormat,\r\n\t\t\tminDate,\r\n\t\t\tmaxDate,\r\n\t\t\tdefaultCalendarDate,\r\n\t\t\tplaceholder,\r\n\t\t\tonChange(date?: Date) {\r\n\r\n\t\t\t\t// set underlying input field value\r\n\t\t\t\tif (date && isValidDate(date)) {\r\n\t\t\t\t\tdate.setHours(0, 0, 0, 0);\r\n\t\t\t\t\tif (input.getAttribute(\"type\") === \"datetime-local\") {\r\n\t\t\t\t\t\tinput.value = moment(date).format(\"YYYY-MM-DDT00:00\");\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\t\t\t\t\t\tinput.value = date.toISOString();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\r\n\t\t\t\t\tinput.value = \"\";\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// dispatch events so any client view models are updated and event handlers called\r\n\t\t\t\tinput.dispatchEvent(new Event(EventConstants.blur));\r\n\t\t\t\tinput.dispatchEvent(new Event(EventConstants.change));\r\n\t\t\t}\r\n\t\t} as DatePickerOptions;\r\n\r\n\t\t// add clear handler for IPF search filtering integration\r\n\t\tconst clear = () => {\r\n\t\t\tif (props.clear && !input.value) {\r\n\t\t\t\tprops.clear();\r\n\t\t\t}\r\n\t\t}\r\n\t\tinput.addEventListener(EventConstants.change_ipffilter, clear);\r\n\r\n\t\t// hide the underlying input\r\n\t\tinput.classList.add(\"invisible-input\");\r\n\r\n\t\t// prevent tab onto this field as it needs to remain 'visible' for validation\r\n\t\tinput.tabIndex = 10000;\r\n\r\n\t\t// render the date picker component\r\n\t\tReactDOMProxy.renderStyled(\r\n\t\t\t,\r\n\t\t\ttarget,\r\n\t\t\t() => {\r\n\t\t\t\t// requires a check for the control to actually finish rendering\r\n\t\t\t\tlet muiInput: HTMLInputElement | null;\r\n\t\t\t\tdoWhen(() => this.applyDatePickerBehaviour(muiInput, input, props), () => (muiInput = target.querySelector(\".MuiInputBase-input\")) != null);\r\n\t\t\t}\r\n\t\t);\r\n\t}\r\n\r\n\tprivate applyDatePickerBehaviour(muiInput: HTMLInputElement | null, input: HTMLInputElement, props: DatePickerOptions) {\r\n\r\n\t\t// TODO: investigate a better fix for this issue, MUI5 date picker seems to not respect the placeholder value passed to it and using inputProps results in format issue.\r\n\t\tif (muiInput) {\r\n\t\t\tmuiInput.placeholder = props.placeholder;\r\n\t\t}\r\n\t}\r\n\r\n\t//#endregion\r\n\r\n\t//#region Mobile Number Inputs\r\n\r\n\t/**\r\n\t * Find and applies mobile input components within an element.\r\n\t * @param target The container element containing the input elements which require a mobile input component.\r\n\t */\r\n\tprivate applyMobileInput(target: Element) {\r\n\r\n\t\ttarget.querySelectorAll(\"[data-mobile-number-input]\").forEach(element => this.renderMobileInput(element as HTMLInputElement));\r\n\t}\r\n\r\n\tprivate renderMobileInput(input: HTMLInputElement) {\r\n\r\n\t\tif (!input || !input.parentElement) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst value = input.value;\r\n\r\n\t\t// if read only, just display value and don't render mobile input component\r\n\t\tif (input.hasAttribute(\"readonly\")) {\r\n\r\n\t\t\tconst newInput = document.createElement(\"input\");\r\n\t\t\tnewInput.classList.add(\"form-control\");\r\n\t\t\tnewInput.setAttribute(\"readonly\", \"readonly\");\r\n\t\t\tnewInput.value = value;\r\n\t\t\tinput.parentElement.insertBefore(newInput, input);\r\n\t\t\tinput.style.display = \"none\";\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// build mobile input options\r\n\t\tconst target = document.createElement(\"div\");\r\n\t\tinput.parentElement.insertBefore(target, input);\r\n\t\tconst placeholder = input.placeholder;\r\n\t\tconst props = {\r\n\t\t\tinput,\r\n\t\t\tvalue,\r\n\t\t\tplaceholder,\r\n\t\t\tonChange(number: string) {\r\n\r\n\t\t\t\t// update input value\r\n\t\t\t\tinput.value = number;\r\n\r\n\t\t\t\t// dispatch events so any client view models are updated and event handlers called\r\n\t\t\t\tinput.dispatchEvent(new Event(EventConstants.blur));\r\n\t\t\t\tinput.dispatchEvent(new Event(EventConstants.change));\r\n\t\t\t}\r\n\t\t} as MobileNumberOptions;\r\n\r\n\t\t// hide the underlying input\r\n\t\tinput.classList.add(\"invisible-input\");\r\n\r\n\t\t// prevent tab onto this field as it needs to remain 'visible' for validation\r\n\t\tinput.tabIndex = 10000;\r\n\r\n\t\t// render the mobile input component\r\n\t\tReactDOMProxy.render(\r\n\t\t\t,\r\n\t\t\ttarget\r\n\t\t);\r\n\t}\r\n\r\n\t//#endregion\r\n}","import { injectable } from \"inversify\";\r\nimport * as React from \"react\";\r\nimport { LoaderService } from \"../../services\";\r\nimport { ServiceBase } from \"../../services/ServiceBase\";\r\nimport { ElementLoader } from \"../components/ElementLoader\";\r\nimport { getDefaultPageLoaderOptions, PageLoader } from \"../components/PageLoader\";\r\nimport { ReactDOMProxy } from \"../ReactDOMProxy\";\r\n\r\n/**\r\n * MUI loader component service. Displays animated loader components at a page or element level.\r\n */\r\n@injectable()\r\nexport class MaterialLoaderService extends ServiceBase implements LoaderService {\r\n\r\n\tprivate pageLoader = getDefaultPageLoaderOptions();\r\n\r\n\t/**\r\n\t * Initialises a new instance of the MaterialLoaderService class.\r\n\t */\r\n constructor() {\r\n\r\n\t\tsuper();\r\n\r\n\t\t// add page loader element and render the component, so it is ready to be used on demand\r\n let pageLoaderContainer = document.getElementById(\"page-loader\");\r\n\r\n if (!pageLoaderContainer) {\r\n\r\n pageLoaderContainer = document.createElement(\"div\");\r\n pageLoaderContainer.id = \"page-loader\";\r\n document.body.appendChild(pageLoaderContainer);\r\n }\r\n\r\n if (pageLoaderContainer) {\r\n\r\n\t\t\tReactDOMProxy.renderStyled(\r\n\t\t\t\t,\r\n pageLoaderContainer\r\n );\r\n }\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic showPageLoader(): void {\r\n\r\n\t\tthis.pageLoader.show();\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic hidePageLoader(): void {\r\n\r\n\t\tthis.pageLoader.hide();\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n public render(target: Element): void {\r\n\r\n if (target) {\r\n\t\t\t\t\r\n let elementLoaderWrapper = target.querySelector(\".element-loader-wrapper\");\r\n\r\n\t\t\tif (!elementLoaderWrapper) {\r\n\t\t\t\telementLoaderWrapper = document.createElement(\"div\");\r\n elementLoaderWrapper.className = \"element-loader-wrapper\";\r\n target.appendChild(elementLoaderWrapper);\r\n\t\t\t}\r\n\r\n\t\t\tReactDOMProxy.renderStyled(\r\n\t\t\t\t,\r\n elementLoaderWrapper\r\n\t\t\t);\r\n }\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic remove(target: Element): void {\r\n\r\n\t\tconst loaderWrapper = target.querySelector(\".element-loader-wrapper\");\r\n\r\n\t\tif (loaderWrapper) {\r\n\r\n\t\t\tReactDOMProxy.unmount(loaderWrapper);\r\n\t\t\tloaderWrapper.remove();\r\n\t\t}\r\n\t}\r\n}","import { injectable } from \"inversify\";\r\nimport React from \"react\";\r\nimport { WizardConfig, WizardStep } from \"../../models/wizard\";\r\nimport { WizardService } from \"../../services\";\r\nimport { ServiceBase } from \"../../services/ServiceBase\";\r\nimport { Wizard } from \"../components/Wizard\";\r\nimport { ReactDOMProxy } from \"../ReactDOMProxy\";\r\n\r\n/**\r\n * MUI stepper service, used to fulfill wizard service requirements and provide wizard like functionality.\r\n */\r\n@injectable()\r\nexport class MaterialStepperService extends ServiceBase implements WizardService {\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tapplyAll(target: Element): void {\r\n\r\n\t\ttarget.querySelectorAll(\"[data-wizard]\").forEach(this.render);\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n render(targetElement: Element) {\r\n\r\n\t\t// get step element using attribute selector\r\n const stepElements = targetElement.querySelectorAll(\"[data-step]\");\r\n\r\n\t\t// get active step element using attribute selector\r\n const activeStepElement = targetElement.querySelector(\"[data-active-step]\") as HTMLInputElement;\r\n\r\n\t\t// create wizard configuration\r\n const wizardConfig = new WizardConfig(targetElement, MaterialStepperService.getSteps(stepElements), activeStepElement);\r\n\r\n\t\t// output the wizard component\r\n ReactDOMProxy.renderStyled(\r\n ,\r\n targetElement\r\n );\r\n }\r\n\r\n\t/**\r\n\t * Gets the wizard steps for an array of step elements.\r\n\t * @param stepElements Node list of elements.\r\n\t * @returns Array of WizardStep.\r\n\t */\r\n private static getSteps(stepElements: NodeListOf): Array {\r\n\r\n const steps = new Array();\r\n\r\n stepElements.forEach((stepElement, index) => {\r\n\r\n const titleElement = stepElement.querySelector(\"[data-step-title]\");\r\n const title = titleElement?.innerHTML || \"\";\r\n\r\n steps.push(new WizardStep(stepElement, title, index));\r\n\r\n if (titleElement) {\r\n\r\n titleElement.parentNode?.removeChild(titleElement);\r\n }\r\n });\r\n\r\n return steps;\r\n }\r\n\r\n}","import { inject, injectable } from \"inversify\";\r\nimport React from \"react\";\r\nimport { Constants } from \"../../constants.generated\";\r\nimport { EventConstants } from \"../../EventConstants\";\r\nimport { TYPES } from \"../../ioc/types\";\r\nimport { SelectedTier } from \"../../models/app\";\r\nimport { TierSelectorService, UrlService, UserTierService } from \"../../services\";\r\nimport { ServiceBase } from \"../../services/ServiceBase\";\r\nimport { SelectedTierComponent } from \"../components/SelectedTierComponent\";\r\nimport { SelectTierButton } from \"../components/SelectTierButton\";\r\nimport { ReactDOMProxy } from \"../ReactDOMProxy\";\r\n\r\n/**\r\n * MUI tier selector service. Used to render and manage the tier selector for the application.\r\n * Covers both the global tier selector and input level tier selectors.\r\n */\r\n@injectable()\r\nexport class MaterialTierSelectorService extends ServiceBase implements TierSelectorService {\r\n\r\n\tprivate globalTierSelector: JSX.Element | undefined;\r\n\r\n\t/**\r\n\t * Initialises a new instance of the MaterialDataGridService class.\r\n\t * @param userTierService User tier service, used to check the users current tier settings and get the current page level tier.\r\n\t * @param urlService URL service, used to generate URLs.\r\n\t */\r\n\tpublic constructor(\r\n\t\t@inject(TYPES.UserTierService) private userTierService: UserTierService,\r\n\t\t@inject(TYPES.UrlService) private urlService: UrlService) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic applyGlobalTierSelectors(target: Element) {\r\n\r\n\t\ttarget.querySelectorAll(\"div[data-tier-selector]\").forEach(element => this.renderGlobalTierSelector(element));\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic applyInputTierSelectors(target: Element) {\r\n\r\n\t\ttarget.querySelectorAll(\"input[data-tier-selector]\").forEach((element) => this.renderInputTierSelector(element));\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic setTierSelectorValue(value: any, valueField: HTMLInputElement) {\r\n\r\n\t\tconst selectedTier = value as SelectedTier;\r\n\r\n\t\tif (selectedTier)\r\n\t\t\tvalueField.value = JSON.stringify(selectedTier);\r\n\t}\r\n\r\n\t/**\r\n\t * Renders the global tier selector.\r\n\t * @param element The target element for the global tier selector.\r\n\t */\r\n\tprivate renderGlobalTierSelector(element: Element) {\r\n\r\n\t\tif (!this.globalTierSelector) {\r\n\t\t\tconst requireBrokerSelection = element.hasAttribute(\"data-require-broker-selection\");\r\n\t\t\tconst requireGroupSelection = element.hasAttribute(\"data-require-group-selection\");\r\n\t\t\tconst urlParams = this.urlService.getQueryParams();\r\n\t\t\tconst brokerId = this.userTierService.getPageTier()?.broker?.id;\r\n\t\t\tconst groupId = this.userTierService.getPageTier()?.group?.id;\r\n\t\t\tconst autoOpen = (requireBrokerSelection && !(brokerId || urlParams.get(\"tier3\"))) || (requireGroupSelection && !(groupId || urlParams.get(\"tier1\")));\r\n\t\t\tconst onCancel = requireBrokerSelection || requireGroupSelection ? () => {\r\n\r\n\t\t\t\t// check if tier should be selected or not, if it's required and none selected, send the user to loan status\r\n\t\t\t\tif ((requireBrokerSelection && !brokerId) || (requireGroupSelection && !groupId)) {\r\n\t\t\t\t\twindow.location.href = this.urlService.url('~/');\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t\treturn true;\r\n\t\t\t} : undefined;\r\n\r\n\t\t\tthis.globalTierSelector = ;\r\n\r\n\t\t\t// output global tier selector component\r\n\t\t\tReactDOMProxy.renderStyled(\r\n\t\t\t\tthis.globalTierSelector,\r\n\t\t\t\telement\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Renders an input level tier selector. Allowing tier selection integrated with an input element.\r\n\t * @param element The input element.\r\n\t */\r\n\tprivate renderInputTierSelector(element: Element) {\r\n\r\n\t\tif (!element.parentElement) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst input = element as HTMLInputElement;\r\n\t\tconst inputGroup = input.parentElement;\r\n\r\n\t\tif (!inputGroup?.classList.contains(\"input-group\")) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// get or create an input group append element, to place the select tier button into\r\n\t\tlet inputGroupAppend = inputGroup.querySelector(\".input-group-append\");\r\n\r\n\t\tif (!inputGroupAppend) {\r\n\t\t\tinputGroupAppend = document.createElement(\"div\");\r\n\t\t\tinputGroupAppend.classList.add(\"input-group-append\");\r\n\t\t\tinputGroup.appendChild(inputGroupAppend);\r\n\t\t}\r\n\r\n\t\tconst inputText = inputGroup.querySelector(\"input[type=text]\") as HTMLInputElement;\r\n\r\n\t\tif (inputText && !inputText.getAttribute(\"autocomplete\"))\r\n\t\t\tinputText.setAttribute(\"autocomplete\", \"off\");\r\n\r\n\t\t// ensure the root tier for the input control is fixed to the page tier\r\n\t\tlet rootTier: SelectedTier = {};\r\n\t\tif (input.getAttribute(\"data-tier-root\") === Constants.TierKeyPageTier) {\r\n\t\t\trootTier = this.userTierService.getPageTier() ?? {};\r\n\r\n\t\t\t// subscribe to the page tier change event\r\n\t\t\tthis.userTierService.subscribe(input.id || input.name, (tier: SelectedTier | null) => {\r\n\t\t\t\tif (tier) {\r\n\t\t\t\t\trootTier.group = tier.group;\r\n\t\t\t\t\trootTier.branch = tier.branch;\r\n\t\t\t\t\trootTier.broker = tier.broker;\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\trootTier.group = undefined;\r\n\t\t\t\t\trootTier.branch = undefined;\r\n\t\t\t\t\trootTier.broker = undefined;\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\t// get the current tier value for the input control\r\n\t\tlet selectedTier: SelectedTier | undefined;\r\n\t\tif (input.value) {\r\n\t\t\tselectedTier = JSON.parse(input.value) as SelectedTier;\r\n\t\t}\r\n\t\telse if (input.getAttribute(\"data-tier-default\") === Constants.TierKeyPageTier) {\r\n\t\t\tselectedTier = this.userTierService.getPageTier() ?? undefined;\r\n\t\t}\r\n\t\telse {\r\n\t\t\tselectedTier = {};\r\n\t\t}\r\n\r\n\t\t// ensure default text for the input\r\n\t\tconst defaultText = input.getAttribute(\"data-tier-default-text\") ?? \"Finance House\";\r\n\r\n\t\tif (selectedTier && inputText && !inputText.value) {\r\n\t\t\tinputText.value = MaterialTierSelectorService.getSelectedTierPath(selectedTier, defaultText);\r\n\t\t\tthis.setTierSelectorValue(selectedTier, input);\r\n\t\t}\r\n\r\n\t\t// if the user is not allowed to change broker then this control should not be editable at all\r\n\t\tif (!this.userTierService.isAllowedToChangeBroker()) {\r\n\t\t\tconst inputGroupPrepend = inputGroup.querySelector(\".input-group-prepend\");\r\n\t\t\tif (inputGroupPrepend) {\r\n\t\t\t\tinputGroupPrepend.remove();\r\n\t\t\t}\r\n\t\t\tif (inputText) {\r\n\t\t\t\tinputText.disabled = true;\r\n\t\t\t}\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// tier selected handler\r\n\t\tconst tierSelected = (tier: SelectedTier) => {\r\n\r\n\t\t\tselectedTier = tier;\r\n\r\n\t\t\t// set the hidden input value\r\n\t\t\tthis.setTierSelectorValue(tier, input);\r\n\r\n\t\t\tif (inputText) {\r\n\t\t\t\tinputText.value = MaterialTierSelectorService.getSelectedTierPath(tier, defaultText);\r\n\t\t\t}\r\n\r\n\t\t\tinput.dispatchEvent(new Event(EventConstants.change));\r\n\t\t};\r\n\r\n\t\t// add a change event lister to the text box\r\n\t\t// this keeps the selectedTier value in sync\r\n\t\tinput.addEventListener(EventConstants.change, () => {\r\n\r\n\t\t\tconst json = input.value;\r\n\t\t\tconst tier: SelectedTier = json ? (JSON.parse(input.value) as SelectedTier) : {};\r\n\r\n\t\t\tif (tier && selectedTier) {\r\n\r\n\t\t\t\tselectedTier.group = tier.group;\r\n\t\t\t\tselectedTier.branch = tier.branch;\r\n\t\t\t\tselectedTier.broker = tier.broker;\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tselectedTier = {};\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t// get tier button text or default\r\n\t\tconst label = element.getAttribute(\"data-tier-button-label\") || \"Find\";\r\n\t\t// do the same for the tooltip\r\n\t\tconst tooltip = element.getAttribute(\"data-button-tooltip\") || \"Find the appropriate tier\";\r\n\r\n\t\t// output select tier button, which includes a button to open the tier selector and the tier selector\r\n\t\tReactDOMProxy.renderStyled(\r\n\t\t\t,\r\n\t\t\tinputGroupAppend\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the selected tier path from a tier, or the supplied default text if there is no path.\r\n\t * @param tier The selected tier.\r\n\t * @param defaultText\r\n\t */\r\n\tprivate static getSelectedTierPath(tier: SelectedTier, defaultText: string) {\r\n\r\n\t\tlet path: string;\r\n\t\tif (tier.broker?.id) {\r\n\t\t\tpath = tier.broker.path;\r\n\t\t}\r\n\t\telse if (tier.branch?.id) {\r\n\t\t\tpath = tier.branch.path;\r\n\t\t}\r\n\t\telse {\r\n\t\t\tpath = tier.group?.path ?? (defaultText);\r\n\t\t}\r\n\t\treturn path;\r\n\t}\r\n}","import React, { FunctionComponent } from \"react\";\r\nimport { MessageType } from \"../../enums.generated\";\r\nimport { Message } from \"../../models/app\";\r\n\r\nconst getAlertCssClass = (type: MessageType) => {\r\n\tlet cssClass = \"alert \";\r\n\tswitch (type) {\r\n\t\tcase MessageType.Error:\r\n\t\t\tcssClass += \"alert-danger\";\r\n\t\t\tbreak;\r\n\t\tcase MessageType.Success:\r\n\t\t\tcssClass += \"alert-success\";\r\n\t\t\tbreak;\r\n\t\tcase MessageType.Warning:\r\n\t\t\tcssClass += \"alert-warning\";\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\tcssClass += \"alert-info\";\r\n\t\t\tbreak;\r\n\t}\r\n\treturn cssClass;\r\n}\r\n\r\n/**\r\n * Alert function component, outputs a bootstrap alert element.\r\n * @param props Alert props containing alert type and text.\r\n */\r\nexport const Alert: FunctionComponent<{ options: Message }> = (props: { options: Message }) => {\r\n\r\n\tconst messageType = props.options.type ?? MessageType.Info;\r\n\r\n\treturn (\r\n\t\t
\r\n\t\t\t{props.options.text}\r\n\t\t
\r\n\t)\r\n}","import { Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle } from \"@mui/material\";\r\nimport React, { FunctionComponent, useEffect, useState } from \"react\";\r\nimport { IpfModule } from \"../..\";\r\nimport { MessageType } from \"../../enums.generated\";\r\nimport { getMessageIcon } from \"../../functions/get-message-icon\";\r\nimport { TYPES } from \"../../ioc/types\";\r\nimport { ConfirmationPromptOptions } from \"../../models/app\";\r\nimport { Guid } from \"../../util/Guid\";\r\nimport { useInject } from \"../hooks/useInject\";\r\nimport { Alert } from \"./Alert\";\r\n\r\n/**\r\n * Confirmation prompt component properties, enabling configuration of the prompt content and action buttons.\r\n */\r\nexport type ConfirmationPromptProps = { options: ConfirmationPromptOptions };\r\n\r\nconst getPromptCssClass = (type?: MessageType) => {\r\n\tlet cssClass: string | undefined;\r\n\tswitch (type) {\r\n\t\tcase MessageType.Error:\r\n\t\t\tcssClass = \"prompt-danger\";\r\n\t\t\tbreak;\r\n\t\tcase MessageType.Success:\r\n\t\t\tcssClass = \"prompt-success\";\r\n\t\t\tbreak;\r\n\t\tcase MessageType.Warning:\r\n\t\t\tcssClass = \"prompt-warning\";\r\n\t\t\tbreak;\r\n\t\tcase MessageType.Warning:\r\n\t\t\tcssClass = \"prompt-info\";\r\n\t\t\tbreak;\r\n\t}\r\n\treturn cssClass;\r\n}\r\n\r\n/**\r\n * Confirmation prompt component, outputs a Material UI prompt, display a configurable range of messages and allows configuration of confirm and cancel action buttons.\r\n * @param props Prompt properties, enabling configuration of the prompt content and buttons.\r\n * @see Dialog\r\n */\r\nexport const ConfirmationPrompt: FunctionComponent = (props: ConfirmationPromptProps) => {\r\n\tconst [open, setOpen] = useState(props.options.autoOpen ?? false);\r\n\tconst ipfModule = useInject(TYPES.IpfModule);\r\n\r\n\tuseEffect(() => {\r\n\r\n\t\t// once rendered call the onRendered handler\r\n\t\tif (props.options.onRendered) {\r\n\t\t\tprops.options.onRendered(open);\r\n\t\t}\r\n\t});\r\n\r\n\t// confirm button handler\r\n\tconst handleConfirm = props.options.confirmOption?.pageHandler ? undefined : () => {\r\n\r\n\t\tif (props.options.confirmOption?.handler) {\r\n\t\t\tprops.options.confirmOption.handler();\r\n\t\t}\r\n\r\n\t\tsetOpen(false);\r\n\t};\r\n\r\n\t// cancel button handler\r\n\tconst handleClose = props.options.cancelOption?.pageHandler ? undefined : (reason: string) => {\r\n\r\n\t\tif (ipfModule.context.clientDebugEnabled) {\r\n\r\n\t\t\tconsole.log(\"ConfirmationPrompt.handleClose called with reason: %s\", reason);\r\n\t\t}\r\n\r\n\t\tif (props.options.closeOnBackdropClick === false && reason == \"backdropClick\") {\r\n\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (props.options.cancelOption?.handler) {\r\n\t\t\tprops.options.cancelOption.handler();\r\n\t\t}\r\n\r\n\t\tsetOpen(false);\r\n\t};\r\n\r\n\tprops.options.open = () => {\r\n\t\tsetOpen(true);\r\n\t};\r\n\r\n\tprops.options.close = () => {\r\n\t\tsetOpen(false);\r\n\t};\r\n\r\n\t// if there is a message type then build an icon element\r\n\tconst icon = props.options.type ? : null;\r\n\r\n\t// create confirm button element\r\n\tconst confirmType = props.options.confirmOption?.pageHandler ? \"submit\" : undefined;\r\n\tconst confirmElement = props.options.confirmOption ? : null;\r\n\r\n\t// create cancel button element\r\n\tconst cancelElement = props.options.cancelOption ? : null;\r\n\r\n\t// build the list of buttons\r\n\tlet buttons = new Array();\r\n\tif (cancelElement) {\r\n\t\tbuttons.push(cancelElement);\r\n\t}\r\n\tif (confirmElement) {\r\n\t\tbuttons.push(confirmElement);\r\n\t}\r\n\tif (props.options.reverseButtons === true) {\r\n\t\tbuttons = buttons.reverse();\r\n\t}\r\n\r\n\t// place buttons within dialog actions element\r\n\tconst buttonsElement = buttons.length ?\r\n\t\t\r\n\t\t\t{buttons}\r\n\t\t : null;\r\n\r\n\t// if there are messages then build dialog content containing a set of messages as alert elements\r\n\tlet content: JSX.Element;\r\n\tif (props.options.messages) {\r\n\r\n\t\tconst messageElements = props.options.messages.map(message => {\r\n\t\t\tif (!message.id) {\r\n\t\t\t\tmessage.id = Guid.newGuid();\r\n\t\t\t}\r\n\t\t\treturn ;\r\n\t\t});\r\n\r\n\t\tcontent = {props.options.content ?
:
\r\n\t\t\t{messageElements}\r\n\t\t
}
;\r\n\t}\r\n\t// otherwise set dialogue content text\r\n\telse {\r\n\r\n\t\tconst textElement = props.options.renderTextAsHtml ? : {props.options.text};\r\n\t\tcontent = {props.options.content ?
: \r\n\t\t\t{!props.options.title ? icon : undefined}{textElement}\r\n\t\t}
;\r\n\t}\r\n\r\n\tlet container: HTMLElement | null;\r\n\r\n\t// if inserting a content element into the prompt then set the prompt container as any parent form\r\n\t// this is important and enables the asp-page-handler buttons to work when pressed\r\n\tif (props.options.content) {\r\n\t\tcontainer = props.options.content.closest(\"form\");\r\n\t}\r\n\t// if there's a target element ID then get that element and set as the prompt container\r\n\telse if (props.options.targetElementId) {\r\n\t\tcontainer = document.getElementById(props.options.targetElementId);\r\n\t}\r\n\telse {\r\n\t\tcontainer = null;\r\n\t}\r\n\r\n\t// now output MUI Dialog\r\n\treturn (\r\n\t\t
\r\n\t\t\t {\r\n\t\t\t\t\tif (handleClose) handleClose(reason);\r\n\t\t\t\t}}\r\n\t\t\t\taria-labelledby=\"alert-dialog-title\"\r\n\t\t\t\taria-describedby=\"alert-dialog-description\"\r\n\t\t\t\tclassName={getPromptCssClass(props.options.type)}\r\n\t\t\t\tmaxWidth=\"lg\"\r\n\t\t\t\tcloseAfterTransition={props.options.closeAfterTransition}\r\n\t\t\t\ttransitionDuration={props.options.closeAfterTransition ? 0 : undefined}\r\n\t\t\t\tcontainer={container}\r\n\t\t\t>\r\n\t\t\t\t{props.options.title ? icon : undefined}{props.options.title}\r\n\t\t\t\t{content}\r\n\t\t\t\t{buttonsElement}\r\n\t\t\t\r\n\t\t
\r\n );\r\n}","import { StyledEngineProvider, ThemeProvider } from '@mui/material';\r\nimport Pagination from '@mui/material/Pagination';\r\nimport { DataGrid, GridEnrichedColDef, GridRowModel, GridRowParams, GridSlotsComponent, GridSortModel, useGridApiContext } from '@mui/x-data-grid';\r\nimport React, { FunctionComponent, useEffect, useState } from 'react';\r\nimport { DataSourceMode, MessageType } from '../../enums.generated';\r\nimport { callFunction } from '../../functions/call-function';\r\nimport { getProperty, getTypedProperty } from '../../functions/get-property';\r\nimport { addClass } from '../../functions/string';\r\nimport { Message } from '../../models/app';\r\nimport { DataGridBoundEventArgs, DataGridErrorEventArgs, DataGridOptions, DataGridRefreshArgs, DataGridState } from '../../models/data-grid';\r\nimport { ApiUrl } from '../../models/http';\r\nimport { Guid } from '../../util/Guid';\r\nimport { AppTheme } from '../AppTheme';\r\nimport { Alert } from './Alert';\r\n\r\n/**\r\n * Data grid component properties, enabling configuration of the data grid columns, sorting, data binding and paging.\r\n */\r\ntype DataGridProps = {\r\n\toptions: DataGridOptions,\r\n\tcolumns: Array,\r\n\tsortModel: GridSortModel,\r\n\tgetData: (apiUrl: ApiUrl, options: DataGridOptions, state: DataGridState) => Promise,\r\n\tonRendering: (options: DataGridOptions, state: DataGridState, refresh: (args: DataGridRefreshArgs) => void, redraw: () => void) => Array<() => void>,\r\n\tonRendered: (options: DataGridOptions, state: DataGridState, refresh: (args: DataGridRefreshArgs) => void) => () => void;\r\n\telement: Element;\r\n};\r\n\r\nconst NoRecordsOverlay = (text?: string) => {\r\n\treturn (\r\n\t\t
\r\n\t\t\t{text ?? \"No records found\"}\r\n\t\t
\r\n\t);\r\n}\r\n\r\nconst CustomPagination = (options: DataGridOptions, state: DataGridState) => {\r\n\tconst apiRef = useGridApiContext();\r\n\tconst pageNumber = state.page + 1;\r\n\tconst start = state.pageSize * state.page + 1;\r\n\tconst nextStart = start + state.pageSize;\r\n\tconst end = nextStart > state.totalRecords ? state.totalRecords : nextStart - 1;\r\n\tlet rowsPerPage: JSX.Element | undefined;\r\n\r\n\t// on page dropdown change handler\r\n\tconst onChange = (event: React.ChangeEvent) => {\r\n\t\tconst selectedValue = event.currentTarget.selectedOptions[0].value;\r\n\t\tapiRef.current.setPageSize(parseInt(selectedValue));\r\n\t};\r\n\r\n\t// create page size dropdown\r\n\tif (options.pageSizeOptions) {\r\n\t\tconst pageSizeOptions = options.pageSizeOptions.map(count => )\r\n\t\trowsPerPage = ;\r\n\t}\r\n\r\n\tconst totalPages = Math.ceil(state.totalRecords / state.pageSize);\r\n\tconst navDisabled = state.totalRecords <= state.pageSize;\r\n\r\n\t// create page size container element\r\n\tconst pageSizeContainer = rowsPerPage ?
\r\n\t\tPage Size: {rowsPerPage}\r\n\t
: undefined;\r\n\r\n\t// output Pagination compoonent along with page size element\r\n\treturn (\r\n \r\n \r\n
\r\n {pageSizeContainer}\r\n
\r\n\t\t\t\t\t\t{start}-{end} of {state.totalRecords}\r\n
\r\n apiRef.current.setPage(value - 1)}\r\n />\r\n
\r\n
\r\n
\r\n );\r\n}\r\n\r\n/**\r\n * Data grid component, displays tabular data, allowing column sorting, data pagination and more.\r\n * @param props The data grid properties used to configure the data grid displayed.\r\n * @see DataGrid\r\n */\r\nexport const DataGridComponent: FunctionComponent = (props: DataGridProps) => {\r\n\r\n\t// setup the data grid state\r\n\tconst [state, setState] = useState({\r\n\t\tcolumns: props.columns,\r\n\t\tdata: props.options.data ?? new Array(),\r\n\t\tloading: !props.options.data,\r\n\t\tpage: 0,\r\n\t\tpageSize: (props.options.dataMode === DataSourceMode.Server ? props.options.apiModel?.paging.pageSize : props.options.pageSize) ?? props.options.pageSize,\r\n\t\tsortModel: props.sortModel,\r\n\t\ttotalRecords: props.options.data?.length ?? 0,\r\n\t\tapiBindingEnabled: props.options.autoBind !== false\r\n\t} as DataGridState);\r\n\r\n\tprops.options.getState = () => state;\r\n\r\n\tconst tearDownFuncs = Array<() => void>();\r\n\r\n\t// effects to be executed after component is rendered\r\n\tuseEffect(() => {\r\n\t\ttearDownFuncs.push(props.onRendered(props.options, state, refreshGrid));\r\n\t\treturn () => {\r\n\t\t\ttearDownFuncs.forEach(func => func());\r\n\t\t};\r\n\t});\r\n\r\n\tconst refreshState = () => {\r\n\r\n\t\t// refresh state by copying to new object\r\n\t\tsetState({ ...state });\r\n\t};\r\n\r\n\t/**\r\n\t * Refresh grid handler. Called to update the data source of an API bound grid.\r\n\t * @param args Refresh args.\r\n\t */\r\n\tconst refreshGrid = (args: DataGridRefreshArgs) => {\r\n\r\n\t\t// reset page index if args to do so\r\n\t\tif (args.resetPageIndex) {\r\n\t\t\tstate.page = 0;\r\n\t\t}\r\n\r\n\t\t// set state to loading so loader is displayed while data is reloaded\r\n\t\tstate.loading = true;\r\n\r\n\t\tif (!state.apiBindingEnabled) {\r\n\t\t\tstate.apiBindingEnabled = true;\r\n\t\t}\r\n\r\n\t\trefreshState();\r\n\t}\r\n\r\n\t/**\r\n\t * Page change handler.\r\n\t * @param page The new page number.\r\n\t */\r\n\tconst handlePageChange = (page: number) => {\r\n\t\tif (page !== state.page) {\r\n\t\t\tstate.page = page;\r\n\t\t\tstate.loading = true;\r\n\t\t\trefreshState();\r\n\t\t}\r\n\t};\r\n\r\n\t/**\r\n\t * Page size change handler.\r\n\t * @param pageSize The new page size.\r\n\t */\r\n\tconst handlePageSizeChange = (pageSize: number) => {\r\n\t\tif (pageSize !== state.pageSize) {\r\n\t\t\tstate.pageSize = pageSize;\r\n\t\t\tstate.loading = true;\r\n\t\t\trefreshState();\r\n\t\t}\r\n\t};\r\n\r\n\t/**\r\n\t * Sort change handler, triggered when column headers are clicked.\r\n\t * @param params Sort change parameters.\r\n\t */\r\n\tconst handleSortModelChange = (params: GridSortModel) => {\r\n\t\tif (!state.loading) {\r\n\t\t\tstate.sortModel = params;\r\n\t\t\tstate.loading = true;\r\n\t\t\trefreshState();\r\n\t\t}\r\n\t};\r\n\r\n\t// call on rendering provided by caller and then execute any functions to tear down any previously rendered elements or behaviours added.\r\n\tprops.onRendering(props.options, state, refreshGrid, refreshState).forEach(func => tearDownFuncs.push(func));\r\n\r\n\t// if loading flag is true and API binding enabled, get the data\r\n\tif (state.loading === true && props.options.apiUrl && state.apiBindingEnabled) {\r\n\r\n\t\tstate.apiResult = undefined;\r\n\r\n\t\t// call the get data method provided by the call, it will return a promise\r\n\t\tconst responsePromise = props.getData(props.options.apiUrl, props.options, state);\r\n\r\n\t\tresponsePromise\r\n\t\t\t.then(response => {\r\n\r\n\t\t\t\t// if successful update data grid state and display the data\r\n\t\t\t\tif (response) {\r\n\r\n\t\t\t\t\tstate.apiResult = response;\r\n\r\n\t\t\t\t\tif (response instanceof Array) {\r\n\r\n\t\t\t\t\t\tstate.data = response;\r\n\t\t\t\t\t\tstate.totalRecords = response.length;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if (props.options.apiProperty) {\r\n\r\n\t\t\t\t\t\tstate.data = getTypedProperty>(response, props.options.apiProperty);\r\n\t\t\t\t\t\tstate.totalRecords = response.count;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\r\n\t\t\t\t\t\tstate.data = [];\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// hide the loader\r\n\t\t\t\tstate.loading = false;\r\n\r\n\t\t\t\trefreshState();\r\n\t\t\t})\r\n\t\t\t.catch(() => {\r\n\r\n\t\t\t\tif (props.options.onGridError) {\r\n\r\n\t\t\t\t\tcallFunction(props.options.onGridError, {\r\n\t\t\t\t\t\toptions: props.options,\r\n\t\t\t\t\t\telement: props.element\r\n\t\t\t\t\t} as DataGridErrorEventArgs);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t}\r\n\r\n\t// ensure there is an 'id' property as this is used by the grid internally to identify rows\r\n\tstate.data.forEach(item => {\r\n\t\tif (!item.id) {\r\n\t\t\titem.id = Guid.newGuid();\r\n\t\t}\r\n\t});\r\n\r\n\t// if API binding completed or data was provided (client-side binding) then revert loading state to false\r\n\tif ((props.options.data || !state.apiBindingEnabled) && state.loading === true) {\r\n\t\tstate.loading = false;\r\n\t}\r\n\r\n\t// determine the minimum page size\r\n\tconst minPageSize = props.options.pageSizeSelectionEnabled && props.options.pageSizeOptions ?\r\n\t\tprops.options.pageSizeOptions[0] :\r\n\t\tstate.pageSize;\r\n\r\n\t// hide footer pagination if total records is less than min page size\r\n\tconst hideFooterPagination = state.totalRecords ?\r\n\t\tstate.totalRecords <= minPageSize :\r\n\t\tstate.data.length <= minPageSize;\r\n\r\n\tconst dataMode = props.options.dataMode === DataSourceMode.Server ? \"server\" : \"client\";\r\n\tconst pageSizes = props.options.pageSizeSelectionEnabled ? props.options.pageSizeOptions : undefined;\r\n\r\n\t// custom no records component\r\n\tconst components: Partial = {\r\n\t\tNoRowsOverlay: () => NoRecordsOverlay(props.options.noResultsMessage)\r\n\t};\r\n\r\n\t// custom pagination\r\n\tif (!hideFooterPagination) {\r\n\t\tcomponents.Pagination = () => CustomPagination(props.options, state);\r\n\t}\r\n\r\n\t// create title element if applicable\r\n\tconst titleElement = props.options.title ?

{props.options.title}

: null;\r\n\tlet cssClass = props.options.cssClass ?? \"\";\r\n\r\n\t// add hidden class if hidden until bound and using API binding\r\n\tif (props.options.hiddenUntilBound && !state.apiBindingEnabled) {\r\n\t\tcssClass = addClass(cssClass, \"hide\");\r\n\t}\r\n\r\n\t// if displaying fresh data call the on grid data bound handler\r\n\tif (!state.loading && (props.options.data || state.apiBindingEnabled) && props.options.onGridDataBound) {\r\n\t\tcallFunction(props.options.onGridDataBound, {\r\n\t\t\tdata: state.data,\r\n\t\t\telement: props.element\r\n\t\t} as DataGridBoundEventArgs);\r\n\t}\r\n\r\n\t// row selection handling\r\n\tlet rowSelected = props.options.onRowSelected ? (params: GridRowParams) => {\r\n\t\tcallFunction(props.options.onRowSelected, params);\r\n\t} : undefined;\r\n\r\n\t// determine whether grid should be down or a no results message alert\r\n\tconst showGrid = (!props.options.noResultsMessage || state.loading) || state.data.length > 0;\r\n\tlet noResultsMessage: string | undefined;\r\n\tif (!showGrid) {\r\n\r\n\t\tif (state.apiResult && state.apiResult.noResultsMessage) {\r\n\r\n\t\t\tnoResultsMessage = state.apiResult.noResultsMessage;\r\n\t\t}\r\n\t\telse {\r\n\r\n\t\t\tnoResultsMessage = props.options.noResultsMessage;\r\n\t\t}\r\n\t}\r\n\r\n\t// build component options\r\n\tconst gridElement = showGrid ? getProperty(row, props.options.keyField ?? \"id\") : undefined}\r\n\t/> : ;\r\n\r\n\t// output component\r\n\treturn (\r\n\t\t
\r\n\t\t\t{titleElement}\r\n\t\t\t{gridElement}\r\n\t\t
\r\n );\r\n}\r\n","import { DatePicker } from \"@mui/lab/\";\r\nimport LocalizationProvider from '@mui/lab/LocalizationProvider';\r\nimport { TextField } from \"@mui/material\";\r\nimport React, { FunctionComponent, useState } from \"react\";\r\nimport { isValidDate } from \"../../functions/is-valid-date\";\r\nimport DateFnsAdapterWrapper from \"../../util/DateFnsAdapterWrapper\";\r\nimport { Guid } from \"../../util/Guid\";\r\n\r\n/**\r\n * Date picker component properties. Contains options for configuring a date picker.\r\n */\r\ntype DatePickerProps = { options: DatePickerOptions };\r\n\r\n/**\r\n * Date picker options type, provides settings for configurating a date picker.\r\n */\r\nexport type DatePickerOptions = {\r\n\tselectedDate?: Date;\r\n\tformat: string;\r\n\tonChange?: (date: Date | null) => void;\r\n\tclear?: () => void;\r\n\tminDate?: Date;\r\n\tmaxDate?: Date;\r\n\tdefaultCalendarDate?: Date;\r\n\tplaceholder: string;\r\n\tinput: HTMLInputElement;\r\n};\r\n\r\n/**\r\n * Date picker state interface.\r\n */\r\ninterface DatePickerState {\r\n\topen?: boolean;\r\n\tselectedDate: Date | null;\r\n\tisInputInvalid: boolean;\r\n\tguid: string;\r\n}\r\n\r\n/**\r\n * Gets open calendar icon element.\r\n */\r\nconst OpenCalendarIcon = function () {\r\n\treturn ;\r\n};\r\n\r\n/**\r\n * IPF date picker component, renders a customised MUI date picker.\r\n * @param props Date picker configuration properties.\r\n * @see DatePicker.\r\n */\r\nexport const IpfDatePicker: FunctionComponent = function (props: DatePickerProps) {\r\n\tconst [state, setState] = useState({\r\n\t\tselectedDate: props.options.selectedDate,\r\n\t\tisInputInvalid: false,\r\n\t\tguid: Guid.newGuid()\r\n\t} as DatePickerState);\r\n\r\n\tconst refreshState = () => {\r\n\t\tsetState({ ...state });\r\n\t};\r\n\r\n\t/**\r\n\t * Open date picker dialog handler.\r\n\t */\r\n\tconst handleOpen = () => {\r\n\t\tstate.open = true;\r\n\t\trefreshState();\r\n\t};\r\n\r\n\t/**\r\n\t * Close date picker dialog handler.\r\n\t */\r\n\tconst handleClose = () => {\r\n\t\tstate.open = false;\r\n\t\trefreshState();\r\n\t};\r\n\r\n\t/**\r\n\t * Resets validation.\r\n\t */\r\n\tconst resetValidation = () => {\r\n\t\tstate.isInputInvalid = false;\r\n\t}\r\n\r\n\t/**\r\n\t * Date picker value change handler. Handles typed input and date selection changes. \r\n\t * @param date\r\n\t */\r\n\tconst handleChange = (date: Date | null) => {\r\n\r\n\t\t// update state\r\n\t\tif (date && !isValidDate(date)) {\r\n\t\t\tstate.selectedDate = date;\t\t\r\n\t\t}\r\n\t\telse {\r\n\r\n\t\t\tif (date?.getTime() !== state.selectedDate?.getTime()) {\r\n\t\t\t\tstate.selectedDate = date;\r\n\t\t\t}\r\n\r\n\t\t\t// reset validation if valid\r\n\t\t\tresetValidation();\r\n\t\t}\r\n\r\n\t\t// fire any provided on change handler\r\n\t\tif (props.options.onChange) {\r\n\t\t\tprops.options.onChange(state.selectedDate);\r\n\t\t}\r\n\t\trefreshState();\r\n\t};\r\n\r\n\t/**\r\n\t * Text input blur handler, validates input and refreshes state.\r\n\t */\r\n\tconst handleBlur = () => {\r\n\r\n\t\tresetValidation();\r\n\r\n\t\tif (state.selectedDate && !isValidDate(state.selectedDate)) {\r\n\t\t\tstate.selectedDate = null;\r\n\t\t\tstate.isInputInvalid = true;\r\n\t\t}\r\n\t\telse if (state.selectedDate) {\r\n\t\t\tif (props.options.maxDate && state.selectedDate > props.options.maxDate) {\r\n\t\t\t\tstate.isInputInvalid = true;\r\n\t\t\t}\r\n\t\t\telse if (props.options.minDate && state.selectedDate < props.options.minDate) {\r\n\t\t\t\tstate.isInputInvalid = true;\r\n\t\t\t}\r\n\t\t}\r\n\t\telse if (props.options.input.hasAttribute(\"data-val-required\")) {\r\n\t\t\tstate.isInputInvalid = true;\r\n\t\t}\r\n\r\n\t\tif (state.isInputInvalid) {\r\n\t\t\trefreshState();\r\n\t\t}\r\n\t}\r\n\r\n\tprops.options.clear = () => {\r\n\t\tstate.selectedDate = null;\r\n\t\trefreshState();\r\n\t};\r\n\r\n\t// setup date format format\r\n\tconst defaultFormat = \"dd/MM/yyyy\";\r\n\tconst format = props.options.format?.replace(/m/g, \"M\") ?? defaultFormat;\r\n\r\n\t// output configured MUI date picker\r\n\treturn (\r\n\t\t\r\n\t\t\t {\r\n\t\t\t\t\tif (state.isInputInvalid && params.inputProps) {\r\n\t\t\t\t\t\tparams.inputProps.className = \"input-validation-error\";\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn ;\r\n\t\t\t\t}}\r\n\t\t\t\tcomponents={{ OpenPickerIcon: OpenCalendarIcon }}\r\n\t\t\t\tinputFormat={format}\r\n\t\t\t\tvalue={state.selectedDate ?? null}\r\n\t\t\t\topen={state.open ?? false}\r\n\t\t\t\tonOpen={handleOpen}\r\n\t\t\t\tonClose={handleClose}\r\n\t\t\t\tonChange={handleChange}\r\n\t\t\t\tOpenPickerButtonProps={{\r\n\t\t\t\t\t'aria-label': 'Select date',\r\n\t\t\t\t}}\r\n\t\t\t\tPopperProps={{ className: \"date-picker-popover\" }}\r\n\t\t\t\tminDate={props.options.minDate}\r\n\t\t\t\tmaxDate={props.options.maxDate}\r\n\t\t\t\tdefaultCalendarMonth={state.selectedDate ?? props.options.defaultCalendarDate ?? new Date()}\r\n\t\t\t\tignoreInvalidInputs={false}\r\n\t\t\t/>\r\n\t\t\r\n );\r\n}","import { CircularProgress } from \"@mui/material\";\r\nimport React, { FunctionComponent } from \"react\";\r\n\r\n/**\r\n * A loader element, used to display a loading animation over a specific element.\r\n * Displays a circular progress element.\r\n * @see CircularProgress\r\n */\r\nexport const ElementLoader: FunctionComponent = () => {\r\n\r\n return (\r\n
\r\n \r\n
\r\n );\r\n}","import React, { FunctionComponent, useState } from \"react\";\r\nimport { TimeoutDuration } from \"../../enums.generated\";\r\nimport { Message } from \"../../models/app\";\r\nimport { Guid } from \"../../util/Guid\";\r\nimport { Toast } from \"./Toast\";\r\n\r\n/**\r\n * Message list interface, used to configure a list of messages.\r\n */\r\nexport interface MessageListOptions {\r\n\tmessages: Array;\r\n\taddMessage?: (message: Message) => void;\r\n\tclearMessages?: () => void;\r\n}\r\n\r\n/**\r\n *Message list state interface.\r\n */\r\ninterface MessageListState {\t\r\n\tmessages: Array;\r\n}\r\n\r\n/**\r\n * Message list component, displays one or many messages as Boostrap toasts.\r\n * @param props\r\n */\r\nexport const MessageList: FunctionComponent<{ options: MessageListOptions }> = (props: { options: MessageListOptions }) => {\r\n\r\n\t// setup state\r\n\tconst [state, setState] = useState({\r\n\t\tmessages: props.options.messages\r\n\t} as MessageListState);\r\n\r\n\t// refresh state hander\r\n\tconst refreshState = () => {\r\n\r\n\t\tsetState({ ...state });\r\n\t};\r\n\r\n\t// add message handler\r\n\tconst addMessage = (message: Message) => {\r\n\r\n\t\tconst match = state.messages.find(m => m.title === message.title && m.text === message.text);\r\n\t\tif (!match) {\r\n\t\t\tstate.messages.push(message);\r\n\t\t\trefreshState();\r\n\r\n\t\t\t// if there's a timeout then hide the message once the duration has passed\r\n\t\t\tif (message.timeoutDuration) {\r\n\r\n\t\t\t\tlet duration: number | undefined;\r\n\r\n\t\t\t\tswitch (message.timeoutDuration) {\r\n\t\t\t\t\tcase TimeoutDuration.Fast:\r\n\t\t\t\t\t\tduration = 7500;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase TimeoutDuration.Standard:\r\n\t\t\t\t\t\tduration = 15000;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase TimeoutDuration.Slow:\r\n\t\t\t\t\t\tduration = 30000;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tmessage.timeout = global.setTimeout(() => {\r\n\t\t\t\t\tdismissMessage(message);\r\n\t\t\t\t}, duration);\r\n\t\t\t}\r\n\t\t}\r\n\t};\r\n\r\n\t// dismiss message handler\r\n\tconst dismissMessage = (message: Message) => {\r\n\r\n\t\tconst index = state.messages.findIndex(m => m.id === message.id);\r\n\t\tstate.messages.splice(index, 1);\r\n\r\n\t\tif (message.timeout) {\r\n\t\t\tclearTimeout(message.timeout);\r\n\t\t}\r\n\r\n\t\trefreshState();\r\n\t};\r\n\r\n\t// clear messages handler\r\n\tconst clearMessages = () => {\r\n\r\n\t\t// dismiss each message to ensure any timeouts are cleared\r\n\t\tstate.messages.forEach(message => {\r\n\t\t\tdismissMessage(message);\r\n\t\t});\r\n\t\tstate.messages = [];\r\n\t\trefreshState();\r\n\t};\r\n\r\n\tprops.options.addMessage = addMessage;\r\n\tprops.options.clearMessages = clearMessages;\r\n\r\n\t// the toast elements to display\r\n\tconst messageElements = state.messages.map(message => {\r\n\r\n\t\tmessage.dismiss = dismissMessage;\r\n\r\n\t\tif (!message.id) {\r\n\r\n\t\t\tmessage.id = Guid.newGuid();\r\n\t\t}\r\n\r\n\t\treturn ;\r\n\t});\r\n\r\n\t// output the toasts wrapped within a div\r\n\treturn (\r\n\t\t
\r\n\t\t\t{messageElements}\r\n\t\t
\r\n\t)\r\n}","import React, { FunctionComponent, useState } from \"react\";\r\nimport { getValidationAttributes } from \"../../functions/get-validation-attributes\";\r\nimport { addClass } from \"../../functions/string\";\r\nimport { Guid } from \"../../util/Guid\";\r\n\r\n/**\r\n * Mobile number input properties. Used to configure mobile number input control.\r\n */\r\nexport type MobileNumberProps = { options: MobileNumberOptions };\r\n\r\n/**\r\n * Mobile number input configuration options.\r\n */\r\nexport type MobileNumberOptions = {\r\n\r\n\t/**\r\n\t * Initial value for the mobile number input.\r\n\t */\r\n\tvalue?: string;\r\n\r\n\t/**\r\n\t * Initially selected country code.\r\n\t */\r\n\tselectedCountry?: string;\r\n\r\n\t/**\r\n\t * On change handler, called when the input changes.\r\n\t */\r\n\tonChange?: (number: string) => void;\r\n\r\n\t/**\r\n\t * Clear handler, used by caller to clear user input.\r\n\t */\r\n\tclear?: () => void;\r\n\r\n\t/**\r\n\t * Placeholder text displayed when there is no input value.\r\n\t */\r\n\tplaceholder: string;\r\n\r\n\t/**\r\n\t * Target input element.\r\n\t */\r\n\tinput: HTMLInputElement;\r\n};\r\n\r\n/**\r\n * Mobile number input state.\r\n */\r\ninterface MobileNumberInputState {\r\n\tvalue: string;\r\n\tcountry: TelCountry;\r\n\toriginalValue: string;\r\n\tguid: string;\r\n\tisInputInvalid: boolean;\r\n}\r\n\r\n/**\r\n * Telephone country interface, used to configure country selection options.\r\n */\r\ninterface TelCountry {\r\n\tcode: string;\r\n\tname: string;\r\n\tclassName: string;\r\n\tprefix: string;\r\n}\r\n\r\n// GB\r\nconst gb: TelCountry = { code: \"gb\", name: \"GB\", className: \"tel-co-gb\", prefix: \"07\" };\r\n// Ireland\r\nconst ie: TelCountry = { code: \"ie\", name: \"IE\", className: \"tel-co-ie\", prefix: \"08\" };\r\n\r\n/**\r\n * Clean mobile number function.\r\n * @param number The number to clean.\r\n * @returns Cleaned mobile number. \r\n */\r\nconst clean = (number: string) => {\r\n\r\n\tif (number.match(/([^0-9])/)) {\r\n\t\tnumber = number.replace(/([^0-9])/, \"\")\r\n\t}\r\n\r\n\tif (number.startsWith(\"447\")) {\r\n\t\tnumber = number.replace(\"447\", gb.prefix);\r\n\t}\r\n\telse if (number.startsWith(\"44\")) {\r\n\t\tnumber = number.replace(\"44\", \"0\");\r\n\t}\r\n\telse if (number.startsWith(\"3537\")) {\r\n\t\tnumber = number.replace(\"3537\", \"0\");\r\n\t}\r\n\telse if (number.startsWith(\"353\")) {\r\n\t\tnumber = number.replace(\"353\", ie.prefix);\r\n\t}\r\n\r\n\treturn number;\r\n}\r\n\r\n/**\r\n * Mobile number input compoment. Allows country code selection and constrains input.\r\n * @param props Mobile number input properties, enabling configuration and event handling.\r\n */\r\nexport const MobileNumberInput: FunctionComponent = function (props: MobileNumberProps) {\r\n\r\n\t// setup initial state\r\n\tconst [state, setState] = useState({\r\n\t\toriginalValue: props.options.value ? props.options.value : gb.prefix,\r\n\t\tvalue: props.options.value ? props.options.value : gb.prefix,\r\n\t\tcountry: props.options.value?.startsWith(ie.prefix) ? ie : gb,\r\n\t\tguid: Guid.newGuid()\r\n\t} as MobileNumberInputState);\r\n\r\n\t// refresh state handler\r\n\tconst refreshState = () => {\r\n\t\tsetState({ ...state });\r\n\t};\r\n\r\n\t// reset validation handler\r\n\tconst resetValidation = () => {\r\n\t\tstate.isInputInvalid = false;\r\n\t}\r\n\r\n\t// change handler\r\n\tconst handleChange = (e: React.ChangeEvent) => {\r\n\r\n\t\tlet number = e.target.value;\r\n\r\n\t\t// if number has changed, update value and country state\r\n\t\tif (number !== state.value) {\r\n\r\n\t\t\tstate.value = number;\r\n\t\t\tstate.country = state.value?.startsWith(ie.prefix) ? { ...ie } : { ...gb };\r\n\t\t}\r\n\r\n\t\trefreshState();\r\n\t};\r\n\r\n\t// blur handler\r\n\tconst handleBlur = (e: React.FocusEvent) => {\r\n\r\n\t\t// clear existing validation\r\n\t\tresetValidation();\r\n\r\n\t\t// set cleaned value and country state\r\n\t\tstate.value = clean(e.target.value);\r\n\t\tstate.country = state.value.startsWith(ie.prefix) ? { ...ie } : { ...gb };\r\n\r\n\t\tif ((!state.value || state.value === gb.prefix || state.value === ie.prefix) && props.options.input.hasAttribute(\"data-val-required\")) {\r\n\t\t\tstate.isInputInvalid = true;\r\n\t\t}\r\n\t\t// validate the input\r\n\t\telse if (state.value && props.options.input.hasAttribute(\"data-val-regex\")) {\r\n\r\n\t\t\tconst pattern = props.options.input.getAttribute(\"data-val-regex-pattern\");\r\n\t\t\tif (pattern) {\r\n\t\t\t\tconst formatRegex = new RegExp(pattern);\r\n\t\t\t\tif (!formatRegex.test(state.value)) {\r\n\t\t\t\t\tstate.isInputInvalid = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// call provided on change handler\r\n\t\tif (state.value !== state.originalValue && props.options.onChange) {\r\n\r\n\t\t\tprops.options.onChange(state.value);\r\n\t\t}\r\n\r\n\t\t// stash original value for comparison\r\n\t\tstate.originalValue = state.value;\r\n\r\n\t\trefreshState();\r\n\t};\r\n\r\n\t// country change handler\r\n\tconst handleCountryChange = () => {\r\n\r\n\t\tlet newPrefix: string;\r\n\t\tif (state.country.code == gb.code) {\r\n\t\t\tstate.country = { ...ie };\r\n\t\t\tnewPrefix = ie.prefix;\r\n\t\t}\r\n\t\telse {\r\n\t\t\tstate.country = { ...gb };\r\n\t\t\tnewPrefix = gb.prefix;\r\n\t\t}\r\n\r\n\t\tstate.value = state.value.length > 2 ? newPrefix + state.value.substring(2) : newPrefix;\r\n\r\n\t\tif (props.options.onChange) {\r\n\t\t\tprops.options.onChange(state.value);\r\n\t\t}\r\n\r\n\t\trefreshState();\r\n\t};\r\n\r\n\tconst defaultCssClass = \"form-control mobile-input\";\r\n\tconst cssClass = state.isInputInvalid ? addClass(defaultCssClass, \"input-validation-error\") : defaultCssClass;\r\n\r\n\t// output the component\r\n\treturn (\r\n\t\t\r\n\t\t\t{state.country.name}\r\n\t\t\t\r\n\t\t\r\n\t);\r\n}","import { Backdrop, CircularProgress, Theme } from \"@mui/material\";\r\nimport { createStyles, makeStyles } from \"@mui/styles\";\r\nimport React, { FunctionComponent, useState } from \"react\";\r\nimport { AppTheme } from \"../AppTheme\";\r\n\r\nconst notYetRendered = \"Page loader not yet rendered.\";\r\n\r\n/**\r\n * Page loader options interface, exposes methods for showing and hiding the element.\r\n */\r\nexport interface PageLoaderOptions {\r\n\tshow: () => void;\r\n\thide: () => void;\r\n}\r\n\r\n/**\r\n * Page loader properties. Contains page loader options.\r\n */\r\ntype PageLoaderProps = {\r\n\toptions: PageLoaderOptions;\r\n}\r\n\r\n/**\r\n * Gets default page loader options.\r\n * @returns PageLoaderOptions\r\n */\r\nexport const getDefaultPageLoaderOptions = () => {\r\n\treturn {\r\n\t\tnotYetRendered: \"page loader not yet rendered\",\r\n\t\tshow() {\r\n\t\t\tconsole.warn(notYetRendered);\r\n\t\t},\r\n\t\thide() {\r\n\t\t\tconsole.warn(notYetRendered);\r\n\t\t}\r\n\t} as PageLoaderOptions\r\n};\r\n\r\n// configure styles for the backdrop\r\nconst useStyles = makeStyles((theme: Theme) =>\r\n\tcreateStyles({\r\n\t\tbackdrop: {\r\n\t\t\tzIndex: AppTheme.zIndex.drawer + 1,\r\n\t\t\tcolor: AppTheme.palette.primary.main\r\n\t\t}\r\n\t})\r\n);\r\n\r\n/**\r\n * Page loader component, when rendered, a loading circular progress animation and backdrop is displayed over the page.\r\n * @param props Page loader properties.\r\n */\r\nexport const PageLoader: FunctionComponent = (props: PageLoaderProps) => {\r\n\r\n\t// setup initial state (not visible)\r\n\tconst [state, setState] = useState({\r\n\t\topen: false\r\n\t});\r\n\r\n\tconst classes = useStyles();\r\n\r\n\t// apply show handler, making the rendered component showable to the caller\r\n\tprops.options.show = () => {\r\n\r\n\t\tsetState({\r\n\t\t\topen: true\r\n\t\t});\r\n\t}\r\n\r\n\t// apply hide handler, making the rendered component showable to the caller\r\n\tprops.options.hide = () => {\r\n\r\n\t\tsetState({\r\n\t\t\topen: false\r\n\t\t});\r\n\t}\r\n\r\n\t// output the loader and backdrop components\r\n\treturn (\r\n\t\t
\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t
\r\n\t);\r\n};","import React, { FunctionComponent } from 'react';\r\nimport { SelectedTier } from '../../models/app';\r\nimport { SelectTierDialog, SelectTierDialogOptions } from './SelectTierDialog';\r\n\r\n/**\r\n * Select tier button options interface. Configures properties required for selecting a tier.\r\n */\r\nexport interface SelectTierOptions {\r\n\r\n\t/**\r\n\t * The select tier button text displayed to the user.\r\n\t */\r\n\tlabel: string;\r\n\r\n\t/**\r\n\t * The select tier button toolip text displayed to the user on hover of the button.\r\n\t */\r\n\ttooltip: string;\r\n\r\n\t/**\r\n\t * On tier selected handler\r\n\t * @param tier The new tier selected.\r\n\t */\r\n\tonSelect?: (tier: SelectedTier) => void;\r\n\r\n\t/**\r\n\t * On tier selection cancelled (dialog closed / cancel button pressed).\r\n\t * @param tier The new tier selected.\r\n\t */\r\n\tonDialogCancel?: () => boolean;\r\n\r\n\t/**\r\n\t * Currently selected tier.\r\n\t */\r\n\tselectedTier?: SelectedTier;\r\n\r\n\t/**\r\n\t * Root / minimum level tier that cannot be changed.\r\n\t */\r\n\trootTier?: SelectedTier;\r\n\r\n\t/**\r\n\t * Determines whether tier 3 broker is required or not.\r\n\t */\r\n\trequiresBroker?: boolean;\r\n\r\n\t/**\r\n\t * Determines whether tier 2 group is required or not.\r\n\t */\r\n\trequiresGroup?: boolean;\r\n\r\n\t/**\r\n\t * Determines whether the tier selection component should be open by default.\r\n\t */\r\n\tautoOpen?: boolean;\r\n}\r\n\r\n/**\r\n * Select tier button component. Outputs a select tier button that can be used to select a tier at page level,\r\n * or to select a tier for an input element within a form.\r\n * @param props Configuration properties.\r\n * @see SelectTierOptions\r\n */\r\nexport const SelectTierButton: FunctionComponent = (props: SelectTierOptions) => {\r\n\r\n\tlet selectedTier = props.selectedTier;\r\n\r\n\t// create select tier dialog component options\r\n\tconst options: SelectTierDialogOptions = {\r\n\t\tselectedTier: props.selectedTier,\r\n\t\tonSelect: (tier: SelectedTier) => {\r\n\r\n\t\t\t// on tier selected\r\n\r\n\t\t\tselectedTier = tier;\r\n\r\n\t\t\t// call provided handler, if provided\r\n\t\t\tif (props.onSelect)\r\n\t\t\t\tprops.onSelect(tier);\r\n\t\t},\r\n\t\trequiresBroker: props.requiresBroker,\r\n\t\trequiresGroup: props.requiresGroup,\r\n\t\tautoOpen: props.autoOpen,\r\n\t\tonCancel: props.onDialogCancel\r\n\t};\r\n\r\n\t// open select tier dialog handler\r\n\tconst handleOpen = () => {\r\n\r\n\t\tif (options.open) {\r\n\t\t\toptions.open(selectedTier, props.rootTier);\r\n\t\t}\r\n\t};\r\n\r\n\t// output the button and select tier dialog elements\r\n\treturn (\r\n\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\r\n );\r\n}","import { Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, TextField, Theme } from \"@mui/material\";\r\nimport Autocomplete from '@mui/material/Autocomplete';\r\nimport createStyles from '@mui/styles/createStyles';\r\nimport makeStyles from '@mui/styles/makeStyles';\r\nimport React, { FunctionComponent, useState } from 'react';\r\nimport { IpfModule } from \"../..\";\r\nimport { EventConstants } from \"../../EventConstants\";\r\nimport { TYPES } from \"../../ioc/types\";\r\nimport { SelectedTier, Tier } from \"../../models/app\";\r\nimport { ApiResponse } from \"../../models/http\";\r\nimport { AjaxService, UrlService, UserTierService } from \"../../services\";\r\nimport { useInject } from \"../hooks/useInject\";\r\n\r\n/**\r\n * Select tier dialog options interface.\r\n */\r\nexport interface SelectTierDialogOptions {\r\n\r\n\t/**\r\n\t * Open dialog handler that gets populated after rendering.\r\n\t * @param selectedTier Currently selected tier.\r\n\t * @param rootTier Minimum tier that cannot be changed.\r\n\t */\r\n\topen?: (selectedTier: SelectedTier | undefined, rootTier: SelectedTier | undefined) => void;\r\n\r\n\t/**\r\n\t * On tier selected handler. Called when a tier has been selected.\r\n\t * @param tier The tier selected.\r\n\t */\r\n\tonSelect?: (tier: SelectedTier) => void;\r\n\r\n\t/**\r\n\t * On tier selection cancelled. Called when the selection prompt is closed without selecting a new tier.\r\n\t */\r\n\tonCancel?: () => boolean;\r\n\r\n\t/**\r\n\t * Currently selected tier. Prepopulates the tier selection controls.\r\n\t */\r\n\tselectedTier?: SelectedTier;\r\n\r\n\t/**\r\n\t * Determines whether tier 3 broker is required or not.\r\n\t */\r\n\trequiresBroker?: boolean;\r\n\r\n\t/**\r\n\t * Determines whether tier 2 group is required or not.\r\n\t */\r\n\trequiresGroup?: boolean;\r\n\r\n\t/**\r\n\t * Determines whether the tier selection component should be open by default.\r\n\t */\r\n\tautoOpen?: boolean;\r\n}\r\n\r\n/**\r\n * Select tier dialog component state interface.\r\n */\r\ninterface SelectTierDialogState {\r\n\topen: boolean;\r\n\r\n\tgroup: Tier;\r\n\tbranch: Tier;\r\n\tbroker: Tier;\r\n\r\n\tgroupOptions: Array;\r\n\tbranchOptions: Array;\r\n\tbrokerOptions: Array;\r\n\r\n\tgroupOpen: boolean | undefined;\r\n\tbranchOpen: boolean | undefined;\r\n\tbrokerOpen: boolean | undefined;\r\n\r\n\tgroupEnabled: boolean;\r\n\tbranchEnabled: boolean;\r\n\tbrokerEnabled: boolean;\r\n\r\n\tgroupHidden: boolean;\r\n\tbranchHidden: boolean;\r\n\tbrokerHidden: boolean;\r\n\r\n\tgroupLabel: string;\r\n\tbranchLabel: string;\r\n\tbrokerLabel: string;\r\n}\r\n\r\n// create custom styles for formControl class to be applied to the tier combo box dropdowns\r\nconst useStyles = makeStyles((theme: Theme) =>\r\n\tcreateStyles({\r\n\t\tformControl: {\r\n\t\t\tmarginTop: theme.spacing(3),\r\n\t\t\tminWidth: 400,\r\n\t\t}\r\n\t})\r\n);\r\n\r\n/**\r\n * Gets an unset tier with no values assigned.\r\n */\r\nconst unsetTier = () => {\r\n\treturn {} as Tier;\r\n};\r\n\r\n/**\r\n * Gets the list of tier 1 groups to display in the combo box.\r\n * @param urlService URL service to build URL.\r\n * @param ajaxService AJAX service to call the server and get the data.\r\n * @param search An optional search string, for combo box text filtering.\r\n * @returns Promise of an API response containing an array of tiers.\r\n */\r\nconst getGroups = (urlService: UrlService, ajaxService: AjaxService, search?: string) => {\r\n\r\n\treturn getTiers(urlService, ajaxService, \"groups\", search);\r\n};\r\n\r\n/**\r\n * Gets the list of tier 2 branches to display in the combo box.\r\n * @param urlService URL service to build URL.\r\n * @param ajaxService AJAX service to call the server and get the data.\r\n * @param search An optional search string, for combo box text filtering.\r\n * @returns Promise of an API response containing an array of tiers.\r\n */\r\nconst getBranches = (urlService: UrlService, ajaxService: AjaxService, groupId: string, search?: string) => {\r\n\r\n\treturn getTiers(urlService, ajaxService, `groups/${groupId}/branches`, search);\r\n};\r\n\r\n/**\r\n * Gets the list of tier 3 brokers to display in the combo box.\r\n * @param urlService URL service to build URL.\r\n * @param ajaxService AJAX service to call the server and get the data.\r\n * @param search An optional search string, for combo box text filtering.\r\n * @returns Promise of an API response containing an array of tiers.\r\n */\r\nconst getBrokers = async (urlService: UrlService, ajaxService: AjaxService, groupId: string, branchId: string, search?: string) => {\r\n\r\n\treturn getTiers(urlService, ajaxService, `groups/${groupId}/branches/${branchId}/brokers`, search);\r\n};\r\n\r\n/**\r\n * Gets a collection of tiers.\r\n * @param urlService URL service to build URL.\r\n * @param ajaxService AJAX service to call the server and get the data.\r\n * @param action The tier specific action path to call to get the data.\r\n * @param search An optional search string, for combo box text filtering.\r\n * @returns Promise of an API response containing an array of tiers.\r\n */\r\nconst getTiers = (urlService: UrlService, ajaxService: AjaxService, action: string, search?: string) => {\r\n\r\n\tlet data: { search: string } | undefined;\r\n\tif (search) {\r\n\t\tdata = { search };\r\n\t}\r\n\r\n\t// build the action URL\r\n\tconst url = urlService.apiAction({\r\n\t\tcontroller: \"tier\",\r\n\t\taction,\r\n\t\tdata\r\n\t});\r\n\r\n\t// request the tiers\r\n\treturn ajaxService.request>>({\r\n\t\turl\r\n\t});\r\n};\r\n\r\n/**\r\n * Select tier dialog, returns a prompt with tier selection controls.\r\n * @param props Configuration properties, enabling preselection and event handling.\r\n * @see SelectTierDialogOptions\r\n * @see Dialog\r\n * @see Autocomplete\r\n */\r\nexport const SelectTierDialog: FunctionComponent<{ options: SelectTierDialogOptions }> = (props: { options: SelectTierDialogOptions }) => {\r\n\r\n\t// get dependencies, user tier and page tier\r\n\tconst userTierService = useInject(TYPES.UserTierService);\r\n\tconst urlService = useInject(TYPES.UrlService);\r\n\tconst ajaxService = useInject(TYPES.AjaxService);\r\n\tconst ipfModule = useInject(TYPES.IpfModule);\r\n\tconst userTier = ipfModule.context.userTier;\r\n\tconst pageTier = userTierService.getPageTier();\r\n\r\n\t// setup initial statye\r\n\tconst [state, setState] = useState({\r\n\t\topen: props.options.autoOpen ?? false,\r\n\r\n\t\tgroup: unsetTier(),\r\n\t\tbranch: unsetTier(),\r\n\t\tbroker: unsetTier(),\r\n\r\n\t\tgroupOptions: [] as Tier[],\r\n\t\tbranchOptions: [] as Tier[],\r\n\t\tbrokerOptions: [] as Tier[],\r\n\r\n\t\tgroupEnabled: true,\r\n\t\tbranchEnabled: false,\r\n\t\tbrokerEnabled: false,\r\n\r\n\t\tgroupHidden: !userTierService.isAllowedToChangeGroup(),\r\n\t\tbranchHidden: !userTierService.isAllowedToChangeBranch(),\r\n\t\tbrokerHidden: !userTierService.isAllowedToChangeBroker(),\r\n\r\n\t\tgroupLabel: userTier?.group?.groupLabel || \"Group\",\r\n\t\tbranchLabel: userTier?.group?.branchLabel || \"Broker\",\r\n\t\tbrokerLabel: userTier?.group?.brokerLabel || \"Broker Branch\"\r\n\t} as SelectTierDialogState);\r\n\r\n\tconst classes = useStyles();\r\n\r\n\t// refresh state handler\r\n\tconst refreshState = () => {\r\n\t\tsetState({ ...state });\r\n\t};\r\n\r\n\t// if auto open by default, setup state, specific to the current page tier\r\n\tif (props.options.autoOpen) {\r\n\r\n\t\tlet updateState: boolean | undefined;\r\n\r\n\t\tif (!state.group.id && pageTier?.group) {\r\n\t\t\tstate.group = pageTier.group;\r\n\t\t\tstate.groupEnabled = false;\r\n\t\t\tstate.branchEnabled = true;\r\n\t\t\tupdateState = true;\r\n\t\t}\r\n\t\tif (!state.branch.id && pageTier?.branch) {\r\n\t\t\tstate.branch = pageTier.branch;\r\n\t\t\tstate.branchEnabled = false;\r\n\t\t\tstate.brokerEnabled = true;\r\n\t\t\tupdateState = true;\r\n\t\t}\r\n\t\tif (!state.broker.id && pageTier?.broker) {\r\n\t\t\tstate.broker = pageTier.broker;\r\n\t\t\tstate.brokerEnabled = false;\r\n\t\t\tupdateState = true;\r\n\t\t}\r\n\t\tif (updateState) {\r\n\t\t\trefreshState();\r\n\t\t}\r\n\t}\r\n\r\n\t// cancel button handler, closes the dialog\r\n\tconst cancelHandler = () => {\r\n\r\n\t\tif (!props.options.onCancel || props.options.onCancel()) {\r\n\t\t\tstate.open = false;\r\n\t\t\trefreshState();\r\n\t\t}\r\n\t};\r\n\r\n\t// open handler, enables opening the dialog on demand with a tier selected and a minimum root tier\r\n\tconst openHandler = (selectedTier: SelectedTier | undefined, rootTier: SelectedTier | undefined) => {\r\n\r\n\t\t// apply selected tier to state\r\n\t\tif (selectedTier) {\r\n\r\n\t\t\tif (selectedTier.group?.id) {\r\n\t\t\t\tstate.group = selectedTier.group;\r\n\t\t\t\tstate.branchEnabled = true;\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tstate.group = unsetTier();\r\n\t\t\t\tstate.branchEnabled = false;\r\n\t\t\t}\r\n\r\n\t\t\tif (selectedTier.branch?.id) {\r\n\t\t\t\tstate.branch = selectedTier.branch;\r\n\t\t\t\tstate.brokerEnabled = true;\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tstate.branch = unsetTier();\r\n\t\t\t\tstate.brokerEnabled = false;\r\n\t\t\t}\r\n\r\n\t\t\tif (selectedTier.broker?.id) {\r\n\t\t\t\tstate.broker = selectedTier.broker;\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tstate.broker = unsetTier();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// use root tier to apply non-editable tiers to state\r\n\t\tif (rootTier) {\r\n\r\n\t\t\tif (rootTier.group?.id) {\r\n\t\t\t\tstate.group = rootTier.group;\r\n\t\t\t\tstate.groupEnabled = false;\r\n\t\t\t\tstate.branchEnabled = true;\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tstate.groupEnabled = true;\r\n\t\t\t}\r\n\t\t\tif (rootTier.branch?.id) {\r\n\t\t\t\tstate.branch = rootTier.branch;\r\n\t\t\t\tstate.branchEnabled = false;\r\n\t\t\t\tstate.brokerEnabled = true;\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tstate.branchEnabled = state.group?.id != undefined;\r\n\t\t\t}\r\n\t\t\tif (rootTier.broker?.id) {\r\n\t\t\t\tstate.broker = rootTier.broker;\r\n\t\t\t\tstate.brokerEnabled = false;\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tstate.brokerEnabled = state.branch?.id != undefined;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tstate.open = true;\r\n\t\trefreshState();\r\n\t};\r\n\r\n\t// expose the open handler\r\n\tprops.options.open = openHandler;\r\n\r\n\t// tier 1 group selected handler\r\n\tconst groupSelected = (event: React.ChangeEvent<{}>, value: Tier | null) => {\r\n\r\n\t\tconst selectedGroup = value || unsetTier();\r\n\t\tstate.group = selectedGroup;\r\n\t\tstate.broker = unsetTier();\r\n\t\tstate.branch = unsetTier();\r\n\t\tsetEnabledState(selectedGroup, state.branch);\r\n\t};\r\n\r\n\t// tier 2 branch selected handler\r\n\tconst branchSelected = (event: React.ChangeEvent<{}>, value: Tier | null) => {\r\n\t\tconst selectedBranch = value || unsetTier();\r\n\t\tstate.branch = selectedBranch;\r\n\t\tstate.broker = unsetTier();\r\n\t\tsetEnabledState(state.group, selectedBranch);\r\n\t};\r\n\r\n\t// tier 3 broker selected handler\r\n\tconst brokerSelected = (event: React.ChangeEvent<{}>, value: Tier | null) => {\r\n\t\tconst selectedBroker = value || unsetTier();\r\n\t\tstate.broker = selectedBroker;\r\n\t\trefreshState();\r\n\t};\r\n\r\n\t// function refreshes the enabled state of the tier combo boxes\r\n\tconst setEnabledState = (selectedGroup: Tier, selectedBranch: Tier) => {\r\n\r\n\t\tconst groupId = selectedGroup?.id;\r\n\t\tconst hasGroup = groupId !== undefined && groupId.length > 0;\r\n\r\n\t\tconst branchId = selectedBranch?.id;\r\n\t\tconst hasBranch = branchId !== undefined && branchId.length > 0;\r\n\r\n\t\tif (state.branchEnabled !== hasGroup) {\r\n\t\t\tstate.branchEnabled = hasGroup;\r\n\t\t\tif (!hasGroup && state.branch) {\r\n\t\t\t\tstate.branch = unsetTier();\r\n\t\t\t\tif (state.broker)\r\n\t\t\t\t\tstate.broker = unsetTier();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (state.branchEnabled !== hasGroup || state.brokerEnabled !== hasBranch) {\r\n\t\t\tstate.brokerEnabled = hasGroup && hasBranch;\r\n\t\t\tif (!hasBranch && state.branch)\r\n\t\t\t\tstate.broker = unsetTier();\r\n\t\t}\r\n\r\n\t\trefreshState();\r\n\t};\r\n\r\n\t// button click handler for when a tier has been chosen and is confirmed for selection\r\n\tconst selectTierHandler = () => {\r\n\r\n\t\t// check required properties are set\r\n\t\tif (props.options.requiresBroker && !state.broker.id) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\telse if (props.options.requiresGroup && !state.group.id) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (props.options.onSelect) {\r\n\r\n\t\t\t// call provided on select handler\r\n\t\t\tprops.options.onSelect({\r\n\t\t\t\tgroup: state.group.id ? state.group : undefined,\r\n\t\t\t\tbranch: state.branch.id ? state.branch : undefined,\r\n\t\t\t\tbroker: state.broker.id ? state.broker : undefined\r\n\t\t\t} as SelectedTier);\r\n\t\t}\r\n\r\n\t\tstate.open = false;\r\n\t\trefreshState();\r\n\t};\r\n\r\n\t// create cancel button if applicable\r\n\tconst cancelButton = !(props.options.requiresBroker || props.options.requiresGroup) || props.options.onCancel ? : null;\r\n\r\n\t// set message to display\r\n\tconst message = props.options.requiresBroker ? \"Please select a broker branch.\" : props.options.requiresGroup ? \"Please select a group.\" : \"Select a tier to filter site content.\";\r\n\r\n\t// output dialog with auto complete combo controls\r\n\treturn (\r\n \r\n\t\t\tSelect Tier\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t{message}\r\n\t\t\t\t\r\n\t\t\t\t option.name ?? \"\"}\r\n\t\t\t\t\tclassName={classes.formControl}\r\n\t\t\t\t\tvalue={state.group}\r\n\t\t\t\t\trenderInput={params => }\r\n\t\t\t\t\tonChange={groupSelected}\r\n\t\t\t\t\tonOpen={async () => {\r\n\t\t\t\t\t\tconst response = await getGroups(urlService, ajaxService);\r\n\t\t\t\t\t\tif (response?.isValid === true) {\r\n\t\t\t\t\t\t\tstate.groupOptions = response.result;\r\n\t\t\t\t\t\t\trefreshState();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}}\r\n\t\t\t\t\tonInputChange={async (event, value, reason) => {\r\n\t\t\t\t\t\tif (reason === EventConstants.input) {\r\n\t\t\t\t\t\t\tconst response = await getGroups(urlService, ajaxService, value);\r\n\t\t\t\t\t\t\tif (response?.isValid === true) {\r\n\t\t\t\t\t\t\t\tstate.groupOptions = response.result;\r\n\t\t\t\t\t\t\t\trefreshState();\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}}\r\n\t\t\t\t/>\r\n\t\t\t\t option.name ?? \"\"}\r\n\t\t\t\t\tclassName={classes.formControl}\r\n\t\t\t\t\tvalue={state.branch}\r\n\t\t\t\t\trenderInput={params => }\r\n\t\t\t\t\tonChange={branchSelected}\r\n\t\t\t\t\tonOpen={async () => {\r\n\t\t\t\t\t\tif (state.group) {\r\n\t\t\t\t\t\t\tconst response = await getBranches(urlService, ajaxService, state.group.id);\r\n\t\t\t\t\t\t\tif (response?.isValid === true) {\r\n\t\t\t\t\t\t\t\tstate.branchOptions = response.result;\r\n\t\t\t\t\t\t\t\trefreshState();\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}}\r\n\t\t\t\t\tonInputChange={async (event, value, reason) => {\r\n\t\t\t\t\t\tif (reason === EventConstants.input) {\r\n\t\t\t\t\t\t\tconst response = await getBranches(urlService, ajaxService, state.group.id, value);\r\n\t\t\t\t\t\t\tif (response?.isValid === true) {\r\n\t\t\t\t\t\t\t\tstate.branchOptions = response.result;\r\n\t\t\t\t\t\t\t\trefreshState();\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}}\r\n\t\t\t\t/>\r\n\t\t\t\t option.name ?? \"\"}\r\n\t\t\t\t\tclassName={classes.formControl}\r\n\t\t\t\t\tvalue={state.broker}\r\n\t\t\t\t\trenderInput={params => }\r\n\t\t\t\t\tonChange={brokerSelected}\r\n\t\t\t\t\tonOpen={async () => {\r\n\t\t\t\t\t\tif (state.group && state.branch) {\r\n\t\t\t\t\t\t\tconst response = await getBrokers(urlService, ajaxService, state.group.id, state.branch.id);\r\n\t\t\t\t\t\t\tif (response?.isValid === true) {\r\n\t\t\t\t\t\t\t\tstate.brokerOptions = response.result;\r\n\t\t\t\t\t\t\t\trefreshState();\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}}\r\n\t\t\t\t\tonInputChange={async (event, value, reason) => {\r\n\t\t\t\t\t\tif (reason === EventConstants.input) {\r\n\t\t\t\t\t\t\tconst response = await getBrokers(urlService, ajaxService, state.group.id, state.branch.id, value);\r\n\t\t\t\t\t\t\tif (response?.isValid === true) {\r\n\t\t\t\t\t\t\t\tstate.brokerOptions = response.result;\r\n\t\t\t\t\t\t\t\trefreshState();\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}}\r\n\t\t\t\t/>\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t{cancelButton}\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n );\r\n}","import { Breadcrumbs, Link, Typography } from \"@mui/material\";\r\nimport React, { useState } from \"react\";\r\nimport { IpfModule } from \"../..\";\r\nimport { TierLevel } from \"../../enums.generated\";\r\nimport { TYPES } from \"../../ioc/types\";\r\nimport { SelectedTier, Tier } from \"../../models/app\";\r\nimport { UserTierService } from \"../../services\";\r\nimport { useInject } from \"../hooks/useInject\";\r\nimport { SelectTierButton } from \"./SelectTierButton\";\r\n\r\n/**\r\n * Selected tier component options interface.\r\n */\r\nexport interface SelectedTierOptions {\r\n\r\n\t/**\r\n\t * Determines whether tier 3 broker is required or not.\r\n\t */\r\n\trequiresBroker?: boolean;\r\n\r\n\t/**\r\n\t * Determines whether tier 2 group is required or not.\r\n\t */\r\n\trequiresGroup?: boolean;\r\n\r\n\t/**\r\n\t * Determines whether the tier selection component should be open by default.\r\n\t */\r\n\tautoOpen?: boolean;\r\n\r\n\t/**\r\n\t * Handler function for determining whether the select tier dialog should be allowed to closed / cancelled out of selection.\r\n\t * @returns Boolean indicating whether the dialog should be closed or not.\r\n\t */\r\n\tonDialogCancel?: () => boolean;\r\n}\r\n\r\n/**\r\n * Selected tier component, bring together the selected tier, the select tier button and the select tier dialog components together into a single component.\r\n * @param props Configuration properties.\r\n * @see SelectedTierOptions\r\n */\r\nexport const SelectedTierComponent = (props: SelectedTierOptions) => {\r\n\r\n\tconst userTierService = useInject(TYPES.UserTierService);\r\n\tconst ipfModule = useInject(TYPES.IpfModule);\r\n\tconst currentTier = userTierService.getCurrentTier();\r\n\r\n\t// setup initial state\r\n\tconst [selectedTier, setSelectedTier] = useState(currentTier || {} as SelectedTier);\r\n\r\n\t// tier selected handler function\r\n\tconst tierSelected = (tier: SelectedTier) => {\r\n\r\n\t\tuserTierService.setPageTier(tier);\r\n\r\n\t\tsetSelectedTier(tier);\r\n\r\n\t\tif (ipfModule.onPageTierChanged)\r\n\t\t\tipfModule.onPageTierChanged();\r\n\t}\r\n\r\n\t// gets a tier link for display in the tier breadcrumbs component\r\n\tconst getLink = (tier: Tier | undefined, level: TierLevel) => {\r\n\r\n\t\tif (tier?.id) {\r\n\r\n\t\t\t// return link component with on click handler defined\r\n\t\t\treturn {\r\n\r\n\t\t\t\t// copy selected tier\r\n\t\t\t\tconst newSelectedTier = { ...selectedTier } as SelectedTier;\r\n\r\n\t\t\t\t// clear appropriate tier properties\r\n\t\t\t\tswitch (level) {\r\n\t\t\t\t\tcase TierLevel.Group:\r\n\t\t\t\t\t\tnewSelectedTier.branch = undefined;\r\n\t\t\t\t\t\tnewSelectedTier.broker = undefined;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\tcase TierLevel.Branch:\r\n\t\t\t\t\t\tnewSelectedTier.broker = undefined;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// now select the updated tier\r\n\t\t\t\ttierSelected(newSelectedTier);\r\n\r\n\t\t\t\tevent.preventDefault();\r\n\t\t\t}}>\r\n\t\t\t\t\t\t{tier.name}\r\n\t\t\t\t\t;\r\n\t\t}\r\n\t\telse {\r\n\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\t}\r\n\r\n\t// gets the typography element for the tier breadcrumb\r\n\tconst getText = (tier: Tier | undefined) => {\r\n\r\n\t\tif (tier?.id) {\r\n\r\n\t\t\treturn {tier.name};\r\n\t\t}\r\n\t\telse {\r\n\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\t}\r\n\r\n\tlet selectedElement: JSX.Element;\r\n\tlet selectTierButton: JSX.Element | null;\r\n\r\n\tconst brokerElement = getText(selectedTier.broker);\r\n\r\n\t// check if change of tier is allowed\r\n\t// if not then set broker name as selected element without any breadcrumbs\r\n\tif (userTierService.isFullyConstrained() && brokerElement) {\r\n\r\n\t\tselectedElement =
{brokerElement}
;\r\n\t\tselectTierButton = null;\r\n\t}\r\n\telse {\r\n\r\n\t\t// otherwise build group, branch, broker elements with a link or read only text,\r\n\t\t// depending on the users permissions\r\n\t\tconst groupElement = userTierService.isAllowedToChangeGroup() ? getLink(selectedTier.group, TierLevel.Group) : getText(selectedTier.group);\r\n\t\tconst branchElement = userTierService.isAllowedToChangeBranch() ? getLink(selectedTier.branch, TierLevel.Branch) : getText(selectedTier.branch);\r\n\r\n\t\t// if there any tier elements selected, build the breadcrumbs\r\n\t\tif (groupElement || branchElement || brokerElement) {\r\n\r\n\t\t\tselectedElement =\r\n\t\t\t\t\">\r\n\t\t\t\t\t{groupElement}\r\n\t\t\t\t\t{branchElement}\r\n\t\t\t\t\t{brokerElement}\r\n\t\t\t\t;\r\n\t\t}\r\n\t\t// otherwise it's finance house level\r\n\t\telse {\r\n\r\n\t\t\tselectedElement =
Finance House
;\r\n\t\t}\r\n\r\n\t\t// if the user is allowed to change the page tier,\r\n\t\t// set the select tier button\r\n\t\tif (userTierService.isAllowedToChangePageTier()) {\r\n\r\n\t\t\tselectTierButton =\r\n\t\t\t\t;\r\n\t\t}\r\n\t\telse {\r\n\r\n\t\t\tselectTierButton = null;\r\n\t\t}\r\n\t}\r\n\r\n\t// output selected tier element and select tier button (depending on permissions and current state)\r\n\treturn (\r\n\t\t
\r\n\t\t\t{selectedElement}\r\n\t\t\t{selectTierButton}\r\n\t\t
\r\n );\r\n}","import { Switch, SwitchProps } from \"@mui/material\";\r\nimport withStyles from '@mui/styles/withStyles';\r\nimport React, { FunctionComponent, useState } from \"react\";\r\nimport { AppTheme } from \"../AppTheme\";\r\n\r\n/**\r\n * Switch control properties.\r\n */\r\ntype SwitchControlInput = { offLabel: string | null, onLabel: string | null, onChange?: (checked: boolean) => void, switchProps: SwitchProps };\r\n\r\n// create MUI switch component with customised styles\r\nconst StyledSwitch = withStyles({\r\n switchBase: {\r\n color: AppTheme.palette.primary.main,\r\n '&.MuiSwitch-switchBase.Mui-checked': {\r\n color: AppTheme.palette.primary.main,\r\n },\r\n '&.MuiSwitch-track': {\r\n backgroundColor: AppTheme.palette.primary.main,\r\n },\r\n '&.MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track': {\r\n backgroundColor: AppTheme.palette.primary.main,\r\n },\r\n }, \r\n checked: {},\r\n track: {},\r\n})(Switch);\r\n\r\n/**\r\n * Switch component, like a checkbox but appears like a switch.\r\n * @param props Configuration properties.\r\n * @see SwitchControlInput\r\n * @see Switch\r\n */\r\nexport const SwitchControl: FunctionComponent = function (props: SwitchControlInput) {\r\n const [checked, setChecked] = useState(props.switchProps.checked);\r\n\r\n\t// change handler for the switch control\r\n const handleChange = (event: React.ChangeEvent, checked: boolean) => {\r\n\r\n if (props.onChange) {\r\n\r\n\t\t\t// call provided on change handler\r\n props.onChange(checked);\r\n }\r\n\r\n props.switchProps.checked = checked;\r\n\r\n setChecked(checked);\r\n };\r\n\r\n\t// click handler for the off label state\r\n const labelOffClick = (event: React.MouseEvent) => {\r\n\r\n if (event.currentTarget.classList.contains(\"switch-off-label\") && checked !== false) {\r\n\r\n props.switchProps.checked = false;\r\n\r\n if (props.onChange) {\r\n\r\n props.onChange(false);\r\n }\r\n\r\n setChecked(false);\r\n }\r\n };\r\n\r\n\t// click handler for the on label state\r\n const labelOnClick = (event: React.MouseEvent) => {\r\n\r\n if (event.currentTarget.classList.contains(\"switch-on-label\") && checked !== true) {\r\n\r\n props.switchProps.checked = true;\r\n\r\n if (props.onChange) {\r\n\r\n props.onChange(true);\r\n }\r\n\r\n setChecked(true);\r\n }\r\n };\r\n\r\n\t// create on / off span elements\r\n const offLabel = props.offLabel ? {props.offLabel} : null;\r\n const onLabel = props.onLabel ? {props.onLabel} : null;\r\n\r\n\t// output styled switch wrapped in a span\r\n\treturn (\r\n\t\t\r\n {offLabel}\r\n \r\n {onLabel}\r\n );\r\n}","import React, { FunctionComponent, useEffect, useState } from \"react\";\r\nimport { EventConstants } from \"../../EventConstants\";\r\nimport { getProperty } from \"../../functions/get-property\";\r\nimport { TYPES } from \"../../ioc/types\";\r\nimport { ApiAction, ApiResponse } from \"../../models/http\";\r\nimport { AjaxService, UrlService } from \"../../services\";\r\nimport { Guid } from \"../../util/Guid\";\r\nimport { useInject } from \"../hooks/useInject\";\r\n\r\n/**\r\n * Text input search options interface. Configured the searchable text input control.\r\n */\r\nexport interface TextInputSearchOptions {\r\n\tinput: HTMLInputElement;\r\n\tselected: { value?: any };\r\n}\r\n\r\n// get data by search text function\r\nconst getData = (urlService: UrlService, ajaxService: AjaxService, action: ApiAction, search: string) => {\r\n\r\n\taction.data = { search };\r\n\r\n\tconst url = urlService.apiAction(action);\r\n\r\n\treturn ajaxService.request>>({\r\n\t\turl\r\n\t});\r\n}\r\n\r\nconst containerCss = \"text-search-results\";\r\nconst containerVisibleCss = `${containerCss} show`;\r\nconst resultCss = \"text-search-result\";\r\nconst focusedResultCss = \"focused\";\r\n\r\n// Text input search state interface, defines the state for the TextInputSearch component.\r\ninterface TextInputSearchState {\r\n\tsearchResults: Array;\r\n\tshowResults: boolean;\r\n\tresultsGuid: string;\r\n\tselectedText: string;\r\n}\r\n\r\n/**\r\n * Text input search component, provides search functionality for a text input.\r\n * @param props Configuration properties.\r\n * @see TextInputSearchOptions\r\n */\r\nexport const TextInputSearch: FunctionComponent = (props: TextInputSearchOptions) => {\r\n\r\n\t// create initial state\r\n\tconst [state, setState] = useState({\r\n\t\tsearchResults: [] as Array,\r\n\t\tshowResults: false,\r\n\t\tresultsGuid: Guid.newGuid(),\r\n\t\tselectedText: \"\"\r\n\t} as TextInputSearchState);\r\n\r\n\t// add effects that are exectuted after rendering\r\n\tuseEffect(() => {\r\n\r\n\t\t// function handling a click when results are displayed,\r\n\t\t// if not a search result then hide the results\r\n\t\tconst handleBodyClick = (event: MouseEvent) => {\r\n\r\n\t\t\tconst target = event.target as HTMLElement;\r\n\r\n\t\t\tif (state.showResults === true && !(target.classList.contains(\"text-search-result\") || target.classList.contains(\"text-search-results\"))) {\r\n\r\n\t\t\t\thideResults();\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t// add event listener\r\n\t\tif (state.showResults) {\r\n\r\n\t\t\tdocument.addEventListener(EventConstants.click, handleBodyClick);\r\n\t\t}\r\n\r\n\t\t// remove the event listener on tear down\r\n\t\treturn () => {\r\n\t\t\tdocument.removeEventListener(EventConstants.click, handleBodyClick);\r\n\t\t};\r\n\t});\r\n\r\n\t// get dependencies\r\n\tconst urlService = useInject(TYPES.UrlService);\r\n\tconst ajaxService = useInject(TYPES.AjaxService);\r\n\r\n\tconst input = props.input;\r\n\tconst textFieldName = input.getAttribute(\"data-text-field\") ?? \"Name\";\r\n\tconst valueFieldName = input.getAttribute(\"data-value-field\") ?? \"Id\";\r\n\tconst controller = input.getAttribute(\"data-controller\") ?? \"\";\r\n\tconst action = input.getAttribute(\"data-action\") ?? \"\";\r\n\r\n\tconst apiAction = {\r\n\t\tcontroller,\r\n\t\taction\r\n\t};\r\n\r\n\tif (!input.getAttribute(\"autocomplete\"))\r\n\t\tinput.setAttribute(\"autocomplete\", \"off\");\r\n\r\n\tlet resultElements;\r\n\r\n\t// if there are results then create a results div element\r\n\tif (state.searchResults?.length) {\r\n\r\n\t\tresultElements = state.searchResults.map((result) => {\r\n\t\t\tconst value = getProperty(result, valueFieldName);\r\n\t\t\treturn
{getProperty(result, textFieldName)}
\r\n\t\t});\r\n\t}\r\n\telse {\r\n\r\n\t\tresultElements = new Array();\r\n\t}\r\n\r\n\tconst containerClass = state.showResults ? containerVisibleCss : containerCss;\r\n\r\n\tconst refreshState = () => {\r\n\t\tsetState({ ...state });\r\n\t}\r\n\r\n\t// hide results handler for when escape or tab is pressed or a click is made somewhere else on the page\r\n\tconst hideResults = () => {\r\n\r\n\t\tif (state.selectedText && input.value && input.value !== state.selectedText) {\r\n\t\t\tinput.value = state.selectedText;\r\n\t\t}\r\n\t\telse if (!input.value) {\r\n\t\t\tselectItem(\"\");\r\n\t\t}\r\n\t\tstate.showResults = false;\r\n\t\trefreshState();\r\n\t}\r\n\r\n\t// function to handle item selection\r\n\tconst selectItem = (value: string) => {\r\n\r\n\t\tconst dataItem = state.searchResults.find(result => getProperty(result, valueFieldName) === value);\r\n\t\tconst text = dataItem ? getProperty(dataItem, textFieldName) : \"\" ?? \"\";\r\n\r\n\t\tprops.selected.value = dataItem;\r\n\t\tinput.value = text;\r\n\r\n\t\tstate.selectedText = text;\r\n\t\tstate.showResults = false;\r\n\t\trefreshState();\r\n\r\n\t\tinput.dispatchEvent(new Event(\"resultselected\"));\r\n\t}\r\n\r\n\t// input focus handler, ensures selectedText is set\r\n\tinput.onfocus = () => {\r\n\r\n\t\tif (input.value && state.selectedText !== input.value) {\r\n\t\t\tstate.selectedText = input.value;\r\n\t\t\trefreshState();\r\n\t\t}\r\n\t};\r\n\r\n\t// on keyboard input handler, performs search as user types functionality to search and display results\r\n\tinput.oninput = () => {\r\n\r\n\t\tconst value = input.value;\r\n\r\n\t\tif (!value?.trim()) {\r\n\t\t\tstate.showResults = false;\r\n\t\t\trefreshState();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst responsePromise = getData(urlService, ajaxService, apiAction, value);\r\n\r\n\t\tresponsePromise.then(response => {\r\n\r\n\t\t\tif (response?.isValid && response.result.length > 0) {\r\n\r\n\t\t\t\tstate.searchResults = response.result;\r\n\t\t\t\tstate.showResults = true;\r\n\t\t\t\trefreshState();\r\n\t\t\t}\r\n\t\t\telse {\r\n\r\n\t\t\t\tstate.showResults = false;\r\n\t\t\t\trefreshState();\r\n\t\t\t}\r\n\t\t});\r\n\t};\r\n\r\n\t// add keydown event to catch arrow, enter, tab and escape events\r\n\tinput.onkeydown = event => {\r\n\r\n\t\tswitch (event.key) {\r\n\r\n\t\t\t// navigates the search results\r\n\t\t\tcase \"ArrowDown\":\r\n\t\t\tcase \"ArrowUp\":\r\n\t\t\t\t{\r\n\r\n\t\t\t\t\tconst resultsElement = document.getElementById(state.resultsGuid);\r\n\t\t\t\t\tconst resultElements = resultsElement?.querySelectorAll(`.${resultCss}`);\r\n\r\n\t\t\t\t\tif (resultsElement && resultElements?.length) {\r\n\r\n\t\t\t\t\t\tconst hovered = resultsElement.querySelector(`.${resultCss}.${focusedResultCss}`);\r\n\r\n\t\t\t\t\t\tif (!hovered) {\r\n\r\n\t\t\t\t\t\t\tconst newIndex = event.key === \"ArrowDown\" ? 0 : resultElements.length - 1;\r\n\t\t\t\t\t\t\tresultElements.item(newIndex).classList.add(focusedResultCss);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse {\r\n\r\n\t\t\t\t\t\t\thovered.classList.remove(focusedResultCss);\r\n\r\n\t\t\t\t\t\t\tlet index = state.searchResults.findIndex(result => getProperty(result, valueFieldName) === hovered?.getAttribute(\"data-value\"));\r\n\t\t\t\t\t\t\tlet newIndex = event.key === \"ArrowDown\" ? index + 1 : index - 1;\r\n\r\n\t\t\t\t\t\t\tif (newIndex >= 0 && newIndex < resultElements.length) {\r\n\r\n\t\t\t\t\t\t\t\tresultElements.item(newIndex).classList.add(focusedResultCss);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\telse {\r\n\r\n\t\t\t\t\t\t\t\tnewIndex = event.key === \"ArrowDown\" ? 0 : resultElements.length - 1;\r\n\t\t\t\t\t\t\t\tresultElements.item(newIndex).classList.add(focusedResultCss);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tevent.preventDefault();\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t// selects the hovered/navigated result\r\n\t\t\tcase \"Enter\":\r\n\t\t\t\t{\r\n\t\t\t\t\tconst resultsElement = document.getElementById(state.resultsGuid);\r\n\t\t\t\t\tconst resultElements = resultsElement?.querySelectorAll(`.${resultCss}`);\r\n\r\n\t\t\t\t\tif (resultsElement && resultElements?.length) {\r\n\r\n\t\t\t\t\t\tconst value = resultsElement.querySelector(`.${resultCss}.${focusedResultCss}`)?.getAttribute(\"data-value\");\r\n\t\t\t\t\t\tif (value)\r\n\t\t\t\t\t\t\tselectItem(value);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tevent.preventDefault();\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t// hides the results\r\n\t\t\tcase \"Tab\":\r\n\t\t\tcase \"Escape\":\r\n\t\t\t\thideResults();\r\n\t\t}\r\n\t};\r\n\r\n\t// result clicked handler\r\n\tconst resultClicked = (event: React.MouseEvent) => {\r\n\r\n\t\tconst element = event.target as HTMLElement;\r\n\t\tconst value = element.getAttribute(\"data-value\");\r\n\t\tif (value)\r\n\t\t\tselectItem(value);\r\n\t};\r\n\r\n\t// output div containing result elements\r\n\treturn (\r\n\t\t
\r\n\t\t\t{resultElements}\r\n\t\t
\r\n );\r\n}","import React, { FunctionComponent } from \"react\";\r\nimport { MessageType } from \"../../enums.generated\";\r\nimport { getMessageIcon } from \"../../functions/get-message-icon\";\r\nimport { Message } from \"../../models/app\";\r\n\r\n// function gets the toast CSS class to apply by message type\r\nconst getToastCssClass = (type: MessageType) => {\r\n\tlet cssClass = \"toast \";\r\n\tswitch (type) {\r\n\t\tcase MessageType.Error:\r\n\t\t\tcssClass += \"toast-danger\";\r\n\t\t\tbreak;\r\n\t\tcase MessageType.Success:\r\n\t\t\tcssClass += \"toast-success\";\r\n\t\t\tbreak;\r\n\t\tcase MessageType.Warning:\r\n\t\t\tcssClass += \"toast-warning\";\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\tcssClass += \"toast-info\";\r\n\t\t\tbreak;\r\n\t}\r\n\treturn cssClass;\r\n}\r\n\r\n/**\r\n * Toast component. Outputs a Bootstrap toast.\r\n * @param props Configuration properties.\r\n * @see Message\r\n */\r\nexport const Toast: FunctionComponent<{ options: Message }> = (props: { options: Message }) => {\r\n\r\n\t// dismiss toast handler, triggered by clicking the close toast icon\r\n\tconst dismissHandler = (event: React.MouseEvent) => {\r\n\r\n\t\tevent.preventDefault();\r\n\r\n\t\tif (props.options.dismiss)\r\n\t\t\tprops.options.dismiss(props.options);\r\n\t};\r\n\r\n\t// create dismiss button element\r\n\tconst dismissButton = props.options.dismissible !== false ?\r\n\t\t : null;\r\n\r\n\tconst messageType = props.options.type ?? MessageType.Info;\r\n\r\n\treturn (\r\n\t\t
\r\n\t\t\t
\r\n\t\t\t\t\r\n\t\t\t\t{props.options.title}\r\n\t\t\t\t{dismissButton}\r\n\t\t\t
\r\n\t\t\t
\r\n\t\t\t\t{props.options.text}\r\n\t\t\t
\r\n\t\t
\r\n\t)\r\n}","import { Button, Paper, Step, StepButton, StepContent, StepLabel, Stepper, Typography } from '@mui/material';\r\nimport React, { Component } from 'react';\r\nimport { WizardConfig, WizardStep } from \"../../models/wizard\";\r\nimport { JQueryValidationService } from '../../services/JQueryValidationService';\r\n\r\n/**\r\n * Wizard class component, outputs a MUI Stepper component.\r\n * @see Stepper\r\n */\r\nexport class Wizard extends Component<{ config: WizardConfig }, { stepIndex: number, steps: Array }> {\r\n\r\n\t/**\r\n\t * Initialises a new instance of the Wizard class.\r\n\t * @param props Configuration properties.\r\n\t */\r\n constructor(props: { config: WizardConfig }) {\r\n super(props);\r\n\r\n\t\t// create initial state\r\n this.state = {\r\n stepIndex: this.getActiveStepIndex(),\r\n steps: props.config.steps\r\n };\r\n }\r\n\r\n\t/**\r\n\t * Event handler called after the component is inserted into the DOM.\r\n\t */\r\n componentDidMount() {\r\n\r\n this.insertStepContent();\r\n\r\n if (this.props.config.activeStepElement && !this.props.config.activeStepElement.value) {\r\n\r\n this.setActiveStepElementValue(this.state.stepIndex);\r\n }\r\n }\r\n\r\n\t/**\r\n\t * Event handler called after state has been updated.\r\n\t */\r\n componentDidUpdate() {\r\n\r\n this.insertStepContent(true);\r\n }\r\n\r\n\t/**\r\n\t * Function which navigates to a specific wizard step.\r\n\t * @param step The wizard step to navigate to.\r\n\t */\r\n\tnavigate(step: WizardStep) {\r\n\r\n\t\tif (step.navigatable && this.getActiveStepIndex() !== step.index) {\r\n\r\n\t\t\tconst currentIndex = this.getActiveStepIndex();\r\n\t\t\tconst form = this.props.config.targetElement.closest(\"form\");\r\n\r\n\t\t\tif (form) {\r\n\r\n\t\t\t\t// if going forwards the current form must be valid\r\n\t\t\t\tconst jForm = $(form);\r\n\t\t\t\tif (currentIndex < step.index && (jForm.data(JQueryValidationService.validatorData) && jForm.valid() === false)) {\r\n\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tthis.setActiveStepElementValue(step.index);\r\n\t\t\tthis.setState({\r\n\t\t\t\tstepIndex: step.index\r\n\t\t\t});\r\n\r\n\t\t\t// submit parent form if there is one\r\n\t\t\tif (form && form.hasAttribute(\"data-ajax\")) {\r\n\r\n\t\t\t\tconst event = new Event(\"submit\", {\r\n\t\t\t\t\tcancelable: true\r\n\t\t\t\t});\r\n\t\t\t\tform.dispatchEvent(event);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Sets the active wizard step.\r\n\t * @param stepIndex The new step index.\r\n\t */\r\n setActiveStep(stepIndex: number) {\r\n\r\n this.setActiveStepElementValue(stepIndex);\r\n\r\n this.setState({\r\n stepIndex\r\n });\r\n }\r\n\r\n\t/**\r\n\t * Inserts the active content element into the corresponding wizard step element.\r\n\t * @param isUpdate Determines whether this call is this an update or initial insert.\r\n\t */\r\n private insertStepContent(isUpdate: boolean = false) {\r\n\r\n const target = this.props.config.targetElement;\r\n let stepsContainer = target.querySelector(\"[data-steps-container]\");\r\n let activeStepElement = target.querySelector(\"[data-active-step]\");\r\n\r\n if (!stepsContainer) {\r\n\r\n stepsContainer = document.createElement(\"div\");\r\n stepsContainer.setAttribute(\"data-steps-container\", \"\");\r\n target.appendChild(stepsContainer);\r\n }\r\n\r\n if (!activeStepElement && this.props.config.activeStepElement) {\r\n\r\n target.appendChild(this.props.config.activeStepElement);\r\n }\r\n\r\n let visibleIndex = 0;\r\n\r\n\t\t// loop each wizard step\r\n this.state.steps.forEach((step: WizardStep) => {\r\n\r\n if (isUpdate === true && step.visible === false) {\r\n\r\n return true;\r\n }\r\n\r\n\t\t\t// if this is the visible step\r\n if (visibleIndex === this.state.stepIndex) {\r\n\r\n const contentTarget = document.getElementById(step.guid);\r\n\r\n if (contentTarget) {\r\n\r\n\t\t\t\t\t// append the content element to the step\r\n contentTarget.appendChild(step.content);\r\n\r\n\t\t\t\t\t// now check for buttons that navigate backwards and forward\r\n step.content.querySelectorAll(\"[data-step-forward],[data-step-backward]\").forEach(btn => {\r\n\r\n (btn as HTMLElement).onclick = event => {\r\n\r\n\t\t\t\t\t\t\t// handle forward button click\r\n if (btn.hasAttribute(\"data-step-forward\")) {\r\n\r\n this.forward();\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t// handle backward button click\r\n else {\r\n\r\n this.backward();\r\n\t\t\t\t\t\t\t}\r\n\r\n event.preventDefault();\r\n };\r\n });\r\n\r\n // attempt to set focus to the first input element with [autofocus] in the step\r\n let focusElement = step.content.querySelector(\"[autofocus]\");\r\n if (focusElement instanceof HTMLElement) {\r\n\r\n (focusElement as HTMLElement).focus();\r\n }\r\n else {\r\n\r\n // set focus to the first input element in the step\r\n focusElement = step.content.querySelector(\"input,select,button,a\");\r\n\r\n if (focusElement instanceof HTMLElement) {\r\n\r\n (focusElement as HTMLElement).focus();\r\n }\r\n }\r\n }\r\n }\r\n else {\r\n\r\n\t\t\t\t// otherwise place the content back in the step container\r\n stepsContainer?.appendChild(step.content);\r\n }\r\n\r\n visibleIndex++;\r\n });\r\n }\r\n\r\n\t/**\r\n\t * Set the active step element field value by index. The value is looked up by index.\r\n\t * @param stepIndex The active step index.\r\n\t */\r\n private setActiveStepElementValue(stepIndex: number) {\r\n\r\n if (this.props.config.activeStepElement) {\r\n\r\n const visibleSteps = this.props.config.steps.filter(step => step.visible);\r\n\r\n if (stepIndex < visibleSteps.length) {\r\n\r\n this.props.config.activeStepElement.value = visibleSteps[stepIndex].key;\r\n }\r\n }\r\n }\r\n\r\n\t/**\r\n\t * Gets the active step index.\r\n\t */\r\n private getActiveStepIndex() {\r\n\r\n let stepIndex = 0;\r\n\r\n const activeStepKey = this.props.config.activeStepElement?.value;\r\n\r\n if (activeStepKey) {\r\n\r\n const visibleSteps = this.props.config.steps.filter(step => step.visible);\r\n\r\n visibleSteps.forEach((step, index) => {\r\n\r\n if (step.key === activeStepKey) {\r\n\r\n stepIndex = index;\r\n }\r\n });\r\n }\r\n\r\n return stepIndex;\r\n }\r\n\r\n\t/**\r\n\t * Navigate forward through the stepper by 1 step.\r\n\t */\r\n forward() {\r\n\r\n this.setActiveStep(this.state.stepIndex + 1);\r\n };\r\n\r\n\t/**\r\n\t * Navigate backward through the stepper by 1 step.\r\n\t */\r\n backward() {\r\n\r\n this.setActiveStep(this.state.stepIndex - 1);\r\n }\r\n\r\n\t/**\r\n\t * Resets the step back to the 1st available step.\r\n\t */\r\n reset() {\r\n\r\n this.setActiveStep(0);\r\n }\r\n\r\n\t// output the configured MUI stepper\r\n render() {\r\n\t\treturn (\r\n\t\t\t\r\n \r\n {this.state.steps.filter(step => step.visible).map(step =>\r\n\t\t\t\t\t\t\r\n this.navigate(step)} className=\"form-no-validate\">\r\n {step.title}\r\n \r\n \r\n
\r\n
\r\n
\r\n )}\r\n
\r\n {this.state.stepIndex === this.state.steps.length && (\r\n \r\n All steps completed - you're finished\r\n \r\n \r\n )}\r\n\t\t\t
\r\n );\r\n }\r\n}\r\n","import { interfaces } from 'inversify';\r\nimport { container } from '../../ioc/container.config';\r\n\r\n/**\r\n * React hook function, which enables getting a dependency by service type.\r\n * @template T\r\n * @param identifier The service identifier.\r\n */\r\nexport function useInject(identifier: interfaces.ServiceIdentifier) {\r\n\tif (!container) { throw new Error(); }\r\n\treturn container.get(identifier);\r\n};","import { inject, injectable } from \"inversify\";\r\nimport { AjaxService, FormComponentService, FormService, TierSelectorService, UrlService, ValidationService } from \".\";\r\nimport { IpfModule } from \"..\";\r\nimport { EventConstants } from \"../EventConstants\";\r\nimport { formatNumericInput } from \"../functions/format-numeric-input\";\r\nimport { getProperty } from \"../functions/get-property\";\r\nimport { isFormButton } from \"../functions/is-form-button\";\r\nimport { parseBoolean } from \"../functions/parse-boolean\";\r\nimport { setProperty } from \"../functions/set-property\";\r\nimport { TYPES } from \"../ioc/types\";\r\nimport { ApiUrl } from \"../models/http\";\r\nimport { ServiceBase } from \"./ServiceBase\";\r\n\r\n/**\r\n * IPF form service class, it's purpose is to apply additional behaviours to form controls.\r\n * @see FormService\r\n */\r\n@injectable()\r\nexport class IpfFormService extends ServiceBase implements FormService {\r\n\r\n\t/**\r\n\t * Initialises a new instance of the IpfFormService class.\r\n\t * @param ajaxService AJAX service, used to make AJAX HTTP requests.\r\n\t * @param formComponentService Form component service, used to render React controls.\r\n\t * @param tierSelectorService Tier selector service, used to apply tier selectors to input elements.\r\n\t * @param urlService URL service, used to generate URLs.\r\n\t * @param validationService Validation service, used to apply validation functionality to forms.\r\n\t * @param ipfModule IPF module, containing contextual information and functions.\r\n\t */\r\n\tpublic constructor(\r\n\t\t@inject(TYPES.AjaxService) private ajaxService: AjaxService,\r\n\t\t@inject(TYPES.FormComponentService) private formComponentService: FormComponentService,\r\n\t\t@inject(TYPES.TierSelectorService) private tierSelectorService: TierSelectorService,\r\n\t\t@inject(TYPES.UrlService) private urlService: UrlService,\r\n\t\t@inject(TYPES.ValidationService) private validationService: ValidationService,\r\n\t\t@inject(TYPES.IpfModule) private ipfModule: IpfModule\r\n\t) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n public applyAll(target: Element): void {\r\n\r\n target.querySelectorAll(\"form\").forEach((element: Element) => {\r\n\r\n\t\t\tconst form = element as HTMLFormElement;\r\n\r\n\t\t\tthis.applyPageHandlers(form);\r\n\r\n this.formComponentService.applyAll(form);\r\n\r\n\t\t\tthis.tierSelectorService.applyInputTierSelectors(form);\r\n\r\n\t\t\tthis.validationService.applyValidation(form);\r\n\r\n\t\t\tIpfFormService.applyRateAmountToggle(form);\r\n\r\n\t\t\tIpfFormService.applyFieldBehaviours(form);\r\n\r\n\t\t\tIpfFormService.applyNumericInputFormatting(form);\r\n\t\t});\r\n\r\n }\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n public applyPageHandlers(form: HTMLFormElement): void {\r\n\r\n const originalAction = form.action;\r\n\r\n\t\t// add a change event handler to the form, targeting elements with data-page-handler attributes\r\n\t\t$(form).off(EventConstants.change_ipf).on(EventConstants.change_ipf, \"[data-page-handler]\", (e) => {\r\n\r\n const element = e.currentTarget;\r\n\r\n\t\t\t// if input element\r\n\t\t\tif (element instanceof HTMLInputElement) {\r\n\r\n\t\t\t\t// exclude input with type=submit\r\n\t\t\t\tconst input = element as HTMLInputElement;\r\n\t\t\t\tif (!isFormButton(input)) {\r\n\r\n\t\t\t\t\tconst pageHandler = element.getAttribute(\"data-page-handler\");\r\n\r\n\t\t\t\t\tif (pageHandler) {\r\n\r\n\t\t\t\t\t\t// on change get the page handler URL, set form action to it, then submit the form\r\n\t\t\t\t\t\tconst handlerUrl = IpfFormService.getFormPageHandlerUrl(originalAction, pageHandler);\r\n\t\t\t\t\t\tform.action = handlerUrl;\r\n\t\t\t\t\t\tIpfFormService.submitForm(form, originalAction);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// else if select dropdown element\r\n\t\t\telse if (element instanceof HTMLSelectElement) {\r\n\r\n\t\t\t\tconst pageHandler = element.getAttribute(\"data-page-handler\");\r\n\r\n\t\t\t\tif (pageHandler) {\r\n\r\n\t\t\t\t\t// on change get the page handler URL, set form action to it, then submit the form\r\n\t\t\t\t\tconst handlerUrl = IpfFormService.getFormPageHandlerUrl(originalAction, pageHandler);\r\n\t\t\t\t\tform.action = handlerUrl;\r\n\t\t\t\t\tIpfFormService.submitForm(form, originalAction);\r\n\t\t\t\t}\r\n\t\t\t}\r\n });\r\n\r\n\t\t// add a click event handler to the form, targeting elements with data-page-handler attributes, buttons with a formaction, but not dropdowns\r\n\t\t$(form).off(EventConstants.click_ipf).on(EventConstants.click_ipf, \"[data-page-handler]:not(select), button[formaction]\", e => {\r\n\r\n const element = e.currentTarget;\r\n\r\n if (element instanceof HTMLElement) {\r\n\r\n\t\t\t\tconst pageHandler = element.getAttribute(\"data-page-handler\") ?? \"\";\r\n\t\t\t\tconst isSubmitButton = element.tagName === \"BUTTON\" && element.getAttribute(\"type\") !== \"button\";\r\n\r\n\t\t\t\t// if this is a page handler or a button with type=submit\r\n\t\t\t\tif (pageHandler || isSubmitButton) {\r\n\r\n\t\t\t\t\t// get the handler URL\r\n\t\t\t\t\tconst handlerUrl = IpfFormService.getFormPageHandlerUrl(originalAction, pageHandler);\r\n\t\t\t\t\tconst isNonSubmitButton = element.tagName === \"BUTTON\" && element.getAttribute(\"type\") === \"button\";\r\n\r\n\t\t\t\t\t// if it's a button with type=button need to set formAction attribute\r\n\t\t\t\t\tif (isNonSubmitButton) {\r\n\r\n\t\t\t\t\t\tconst btn = element as HTMLButtonElement;\r\n\t\t\t\t\t\tbtn.formAction = handlerUrl;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// ensure the active last focused element is known\r\n\t\t\t\t\tthis.setEnsuredActiveElement(form, element);\r\n\r\n\t\t\t\t\tconst isLinkButton = element.tagName === \"A\";\r\n\t\t\t\t\tconst isDiv = element.tagName === \"DIV\";\r\n\r\n\t\t\t\t\t// if it's a link button, div, or button with type=button\r\n\t\t\t\t\t// set form action and submit the form\r\n\t\t\t\t\tif (isNonSubmitButton || isLinkButton || isDiv) {\r\n\r\n\t\t\t\t\t\tform.action = handlerUrl;\r\n\t\t\t\t\t\tIpfFormService.submitForm(form, originalAction);\r\n\t\t\t\t\t\te.stopPropagation();\r\n }\r\n }\r\n }\r\n });\r\n }\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n public applyApiHandlers(container: HTMLElement, successCallback?: (response: any) => void): void {\r\n\r\n\t\t// add a change event handler to the form, targeting elements with data-api-handler attributes\r\n\t\t$(container).off(EventConstants.change_ipf).on(EventConstants.change_ipf, \"[data-api-handler]\", e => {\r\n\r\n const element = e.currentTarget;\r\n\r\n\t\t\t// if input element\r\n if (element instanceof HTMLInputElement) {\r\n\r\n const handlerString = element.getAttribute(\"data-api-handler\");\r\n\r\n\t\t\t\t// check this is not a button and there is a handler string\r\n\t\t\t\tif (!isFormButton(element) && handlerString) {\r\n\r\n\t\t\t\t\t// JSON parse the API URL call details\r\n const apiHandler = JSON.parse(handlerString) as ApiUrl;\r\n\r\n if (apiHandler) {\r\n\r\n\t\t\t\t\t\t// now perform the AJAX request\r\n\t\t\t\t\t\tthis.ajaxService.request({\r\n\t\t\t\t\t\t\turl: this.urlService.apiUrl(apiHandler),\r\n method: apiHandler.method || \"POST\",\r\n data: apiHandler.data\r\n })\r\n .then((response: any) => {\r\n\r\n\t\t\t\t\t\t\t\t// call the callback if supplied and pass it the response\r\n if (successCallback) {\r\n\r\n successCallback(response);\r\n }\r\n });\r\n }\r\n return;\r\n }\r\n }\r\n });\r\n\r\n\t\t// add a click event handler to the form, targeting elements with data-api-handler attributes\r\n $(container).off(\"click.ipfform\").on(\"click.ipfform\", \"[data-api-handler]\", e => {\r\n\r\n const element = e.currentTarget as HTMLElement;\r\n const handlerString = element.getAttribute(\"data-api-handler\");\r\n\r\n if (handlerString) {\r\n\r\n\t\t\t\t\t// JSON parse the API URL call details\r\n const apiHandler = JSON.parse(handlerString) as ApiUrl;\r\n\r\n if (apiHandler) {\r\n\r\n\t\t\t\t\t// now perform the AJAX request\r\n\t\t\t\t\tthis.ajaxService.request({\r\n\t\t\t\t\t\turl: this.urlService.apiUrl(apiHandler),\r\n method: apiHandler.method || \"POST\",\r\n data: apiHandler.data || {}\r\n })\r\n .then((response: any) => {\r\n\r\n\t\t\t\t\t\t\t// call the callback if supplied and pass it the response\r\n if (successCallback) {\r\n\r\n successCallback(response);\r\n }\r\n });\r\n }\r\n }\r\n });\r\n }\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic bindModel(options: { element: Element | JQuery, model: TBindType, onChange?: (field: string) => void }): TBindType {\r\n\r\n const modelAny = options.model as any;\r\n\r\n\t\t// add a change event handler to the form\r\n\t\t$(options.element).off(EventConstants.change_ipf).on(EventConstants.change_ipf, \"input:not([data-bind=false]):not([data-bind-event=oninput]),select:not([data-bind=false])\", (event) => {\r\n\r\n const field = $(event.currentTarget);\r\n\r\n\t\t\t// set the model value to that extracted from the field\r\n IpfFormService.setFieldValue(modelAny, field);\r\n\r\n\t\t\t// if an onchange was provided, call it and pass name of the changed field\r\n if (options.onChange) {\r\n\r\n\t\t\t\tconst dataBind = field.data(\"bind\");\r\n\t\t\t\tconst name = typeof dataBind === \"string\" ? dataBind : field.attr(\"name\") as string;\r\n options.onChange(name);\r\n }\r\n\t\t});\r\n\r\n\t\t// add an input event handler to the form\r\n\t\t$(options.element).off(EventConstants.input_ipf).on(EventConstants.input_ipf, \"input[data-bind-event=oninput]\", (event) => {\r\n\r\n\t\t\tconst field = $(event.currentTarget);\r\n\r\n\t\t\t// set the model value to that extracted from the field\r\n\t\t\tIpfFormService.setFieldValue(modelAny, field);\r\n\r\n\t\t\t// if an onchange was provided, call it and pass name of the changed field\r\n\t\t\tif (options.onChange) {\r\n\r\n\t\t\t\tconst dataBind = field.data(\"bind\");\r\n\t\t\t\tconst name = typeof dataBind === \"string\" ? dataBind : field.attr(\"name\") as string;\r\n\t\t\t\toptions.onChange(name);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t// now loop all input and select elements and extract values to set the initial model values\r\n $(options.element).find(\"input,select\").not(\"[data-bind=false]\").each((index: number, element: Element) => {\r\n\r\n const field = $(element);\r\n const dataBind = field.data(\"bind\");\r\n const path = typeof dataBind === \"string\" ? dataBind : field.attr(\"name\") as string;\r\n\r\n if (path && path.indexOf(\".\") > -1) {\r\n\r\n const lastIndex = path.lastIndexOf('.');\r\n const parentName = path.substring(0, lastIndex);\r\n const items = parentName.split('.');\r\n\r\n let inScope: any = modelAny;\r\n\r\n\t\t\t\t// loop through path segments and setup container objects (where not set) for the whole property path\r\n for (let i = 0; i < items.length; i++) {\r\n\r\n const name = items[i];\r\n const prop = getProperty(inScope, name);\r\n\r\n if (!prop) {\r\n\r\n let obj = {};\r\n inScope[name] = obj;\r\n inScope = obj;\r\n }\r\n else {\r\n\r\n inScope = prop;\r\n }\r\n }\r\n }\r\n\r\n\t\t\t// now set the field value\r\n IpfFormService.setFieldValue(modelAny, field);\r\n });\r\n\r\n return options.model;\r\n }\r\n\r\n\t/**\r\n\t * Submits form programatically by dispatching the submit event on the target form.\r\n\t * @param form The target form element to submit.\r\n\t * @param originalAction The action attribute to reinstate after submitting.\r\n\t */\r\n\tprivate static submitForm(form: HTMLFormElement, originalAction: string): void {\r\n\r\n if (form.hasAttribute(\"data-ajax\")) {\r\n\r\n\t\t\tconst event = new Event(\"submit\", {\r\n\t\t\t\tcancelable: true\r\n\t\t\t});\r\n\r\n\t\t\tform.dispatchEvent(event);\r\n }\r\n else {\r\n\r\n form.submit();\r\n }\r\n\r\n form.action = originalAction;\r\n }\r\n\r\n\t/**\r\n\t * Gets the form page handler URL by joining form action and a formatted page handler.\r\n\t * @param formAction The form action.\r\n\t * @param pageHandlerString The page handler.\r\n\t */\r\n private static getFormPageHandlerUrl(formAction: string, pageHandlerString: string): string {\r\n\r\n\t\t// get any URL query string\r\n let query: string;\r\n let queryIndex: number;\r\n if ((queryIndex = formAction.indexOf(\"?\")) > -1) {\r\n\r\n query = formAction.substring(queryIndex);\r\n formAction = formAction.substring(0, queryIndex);\r\n }\r\n else {\r\n\r\n query = \"\";\r\n }\r\n\r\n\t\t// get any URL hash string\r\n let hash: string;\r\n let hashIndex: number;\r\n if ((hashIndex = formAction.indexOf(\"#\")) > -1) {\r\n\r\n hash = formAction.substring(hashIndex);\r\n formAction = formAction.substring(0, hashIndex);\r\n }\r\n else {\r\n\r\n hash = \"\";\r\n }\r\n\r\n const testPageHandlerString = pageHandlerString.toLowerCase();\r\n\r\n\t\tlet pageHandler: string;\r\n\r\n\t\t// test for on[verb] prefix, if found remove it as the server requires it without to route correctly\r\n\t\tif (testPageHandlerString.startsWith(\"onpost\")) {\r\n\r\n\t\t\tpageHandler = pageHandlerString.substring(6);\r\n\t\t}\r\n\t\telse if (testPageHandlerString.startsWith(\"onget\")) {\r\n\r\n pageHandler = pageHandlerString.substring(5);\r\n }\r\n\t\telse if (testPageHandlerString.startsWith(\"onput\")) {\r\n\r\n pageHandler = pageHandlerString.substring(5);\r\n }\r\n\t\telse if (testPageHandlerString.startsWith(\"ondelete\")) {\r\n\r\n pageHandler = pageHandlerString.substring(8);\r\n }\r\n else {\r\n\r\n\t\t\tpageHandler = pageHandlerString;\r\n\t\t}\r\n\r\n let action = [formAction, pageHandler].join(\"/\");\r\n\r\n if (query) {\r\n\r\n action += query;\r\n }\r\n\r\n if (hash) {\r\n\r\n action += hash;\r\n }\r\n\r\n\t\treturn action;\r\n }\r\n\r\n\t/**\r\n\t * Sets the value of a model field from its corresponding element.\r\n\t * @param model The model.\r\n\t * @param field The field element, must have a name attribute to map the value to.\r\n\t */\r\n private static setFieldValue(model: any, field: JQuery) {\r\n\r\n\t\tconst dataBind = field.data(\"bind\");\r\n\r\n\t\t// extract the field name from the name attribute\r\n const name = typeof dataBind === \"string\" ? dataBind : field.attr(\"name\") as string;\r\n\r\n if (!name) {\r\n\r\n return;\r\n }\r\n\r\n\t\t// if radio button only extract if checked\r\n\t\tif (field.attr(\"type\") === \"radio\") {\r\n\r\n if (field.prop(\"checked\") === true) {\r\n\r\n\t\t\t\tsetProperty(model, name, IpfFormService.extractFieldValue(field));\r\n }\r\n\t\t}\r\n\t\t// if checkbox\r\n else if (field.attr(\"type\") === \"checkbox\") {\r\n\r\n setProperty(model, name, field.prop(\"checked\"));\r\n }\r\n else {\r\n\r\n\t\t\tsetProperty(model, name, IpfFormService.extractFieldValue(field));\r\n }\r\n\t}\r\n\r\n\t/**\r\n\t * Extracts the field value from an element.\r\n\t * @param field The field element.\r\n\t * @returns Date | Number | Boolean | String.\r\n\t */\r\n\tprivate static extractFieldValue(field: JQuery) {\r\n\r\n\t\tlet stringValue = field.val()?.toString() ?? \"\";\r\n\r\n\t\t// if the field has numeric formatting applied, strip all chars except digits and dot\r\n\t\tif (field.is(\"[data-numeric-format]\")) {\r\n\r\n\t\t\tstringValue = stringValue.replace(/[^0-9\\.]+/g, \"\");\r\n\t\t}\r\n\r\n\t\tconst fieldType = field.data(\"bind-type\");\r\n\t\tconst isString = fieldType?.toLowerCase() === \"string\";\r\n\t\tlet numberValue: number;\r\n\t\tlet booleanValue: boolean | null;\r\n\r\n\t\tif (field.attr(\"type\") === \"datetime-local\") {\r\n\r\n\t\t\treturn stringValue ? new Date(stringValue) : stringValue;\r\n\t\t}\r\n\t\telse if (!isString && (!isNaN(numberValue = parseFloat(stringValue)) || !isNaN(numberValue = parseInt(stringValue)))) {\r\n\r\n return numberValue;\r\n\t\t}\r\n\t\telse if (!isString && typeof (booleanValue = parseBoolean(stringValue)) === \"boolean\") {\r\n\t\t\t\r\n\t\t\treturn booleanValue;\r\n\t\t}\r\n\t\telse {\r\n\r\n\t\t\treturn stringValue;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Apply toggle behaviour to fields that allow switching between a rate value and an amount.\r\n\t * @param form The ancestor form element.\r\n\t */\r\n private static applyRateAmountToggle(form: HTMLFormElement) {\r\n\r\n const toggle = (input: HTMLInputElement, rateField: JQuery, amountField: JQuery, autoFocus: boolean) => {\r\n\r\n if(input.checked === true) {\r\n\t\t\t\tamountField.css(\"visibility\", \"visible\");\r\n\t\t\t\tamountField.css(\"height\", \"auto\");\r\n\r\n if (autoFocus) amountField.find(\"input\").focus();\r\n\r\n\t\t\t\trateField.css(\"visibility\", \"hidden\");\r\n\t\t\t\trateField.css(\"height\", \"0px\");\r\n }\r\n else {\r\n\t\t\t\trateField.css(\"visibility\", \"visible\");\r\n\t\t\t\trateField.css(\"height\", \"auto\");\r\n\r\n if (autoFocus) rateField.find(\"input\").focus();\r\n\r\n\t\t\t\tamountField.css(\"visibility\", \"hidden\");\r\n\t\t\t\tamountField.css(\"height\", \"0px\");\r\n }\r\n }\r\n\r\n\t\t// find all relevant toggle fields\r\n form.querySelectorAll(\"input[data-toggle-rate-amount]\").forEach((element: Element) => {\r\n\r\n\t\t\tconst input = element as HTMLInputElement;\r\n\t\t\tconst jinput = $(element);\r\n\t\t\tconst fieldWrap = jinput.closest(\".field-wrap\");\r\n const rateField = fieldWrap.find(\".rate-field\");\r\n const amountField = fieldWrap.find(\".amount-field\");\r\n\r\n toggle(input, rateField, amountField, false);\r\n\r\n\t\t\t// toggle the display to switch between rate and amount\r\n\t\t\tinput.addEventListener(EventConstants.change, () => {\r\n\r\n\t\t\t\ttoggle(input, rateField, amountField, true);\r\n\t\t\t\tjinput.trigger(EventConstants.change_ipf);\r\n });\r\n });\r\n\t}\r\n\r\n\t/**\r\n\t * Applies various field behaviours to elements within a
element.\r\n\t * @param form The element.\r\n\t */\r\n\tprivate static applyFieldBehaviours(form: HTMLFormElement) {\r\n\r\n\t\tconst jForm = $(form);\r\n\t\tconst trims = jForm.find(\"[data-trim]\");\r\n\r\n\t\t// trim text boxes with data-trim attribute on change\r\n\t\ttrims.off(EventConstants.blur_ipf).on(EventConstants.blur_ipf, event => {\r\n\r\n\t\t\tconst textBox = $(event.currentTarget);\r\n\t\t\tlet value = textBox.val()?.toString();\r\n\r\n\t\t\tif (value) {\r\n\r\n\t\t\t\t// to trim emails remove the text first otherwise it doesn't change the visible text\r\n\t\t\t\tif (textBox.attr(\"type\") === \"email\") {\r\n\t\t\t\t\ttextBox.val(\"\");\r\n\t\t\t\t}\r\n\t\t\t\ttextBox.val(value.trim());\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t// trim text boxes with data-trim attribute on paste\r\n\t\ttrims.off(EventConstants.paste_ipf).on(EventConstants.paste_ipf, event => {\r\n\r\n\t\t\tconst textBox = $(event.currentTarget);\r\n\t\t\tconst clipboard = (event.originalEvent as any).clipboardData;\r\n\t\t\tlet value = clipboard?.getData(\"text\");\r\n\r\n\t\t\tif (value) {\r\n\r\n\t\t\t\ttextBox.val(value.trim());\r\n\t\t\t\tevent.preventDefault();\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * Applies numeric input formatting to elements within a element.\r\n\t * @param form The element.\r\n\t */\r\n\tprivate static applyNumericInputFormatting(form: HTMLFormElement) {\r\n\r\n\t\t// get all inputs with the data-numeric-format attribute\r\n\t\tconst inputs = form.querySelectorAll(\"[data-numeric-format]\");\r\n\r\n\t\t// apply formatting now\r\n\t\tinputs.forEach(input =>\r\n\t\t\tformatNumericInput(input)\r\n\t\t);\r\n\r\n\t\t// add blur event\r\n\t\t$(inputs).off(EventConstants.blur_ipfnumericformat).on(EventConstants.blur_ipfnumericformat, event =>\r\n\t\t\tformatNumericInput(event.currentTarget as HTMLInputElement)\r\n\t\t);\r\n\r\n\t\t// add input event\r\n\t\t$(inputs).off(EventConstants.input_ipfnumericformat).on(EventConstants.input_ipfnumericformat, event => \r\n\t\t\tformatNumericInput(event.currentTarget as HTMLInputElement, true)\r\n\t\t);\r\n\r\n\t\t// clear numeric value on focus if it is equal to 0\r\n\t\t$(inputs).focus((event) => {\r\n\t\t\tconst input = $(event.currentTarget);\r\n\t\t\tconst value = input.val();\r\n\t\t\tif (value === 0 || (value && parseFloat(value.toString()) === 0)) {\r\n\t\t\t\tinput.val(\"\");\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * Sets the active form element global variable,\r\n\t * used to identity which element was last focused when submitting an AJAX form.\r\n\t * This enables button level form actions to be extracted, whilst catering for browser bugs in Safari.\r\n\t * @param form The target form.\r\n\t * @param element The focused element.\r\n\t */\r\n\tprivate setEnsuredActiveElement(form: HTMLFormElement, element: HTMLElement) {\r\n\r\n\t\tconst activeElement = document.activeElement;\r\n\r\n\t\t// safari workaround for SubmitEvent.submitter and document.activeElement= browser bugs:\r\n\t\t// is an AJAX form then set the ipfModule.ensuredActiveElement for use in AjaxService implementation\r\n\t\t// only set ipfModule.ensuredActiveElement when the activeElement isn't set or is not an input/button/select element\r\n\t\tif ((!activeElement ||\r\n\t\t\tactiveElement.tagName === document.body.tagName ||\r\n\t\t\t[\"INPUT\", \"BUTTON\", \"SELECT\"].indexOf(activeElement.tagName) === -1) &&\r\n\t\t\tform.hasAttribute(\"data-ajax\")) {\r\n\t\t\tthis.ipfModule.ensuredActiveElement = element;\r\n\t\t}\r\n\t}\r\n}","import { inject, injectable } from \"inversify\";\r\nimport { AjaxService, DataGridService, FormService, LoaderService, MessageService, PageService, ScriptService, TierSelectorService, UrlService, UserTierService, WizardService } from \".\";\r\nimport { IpfModule } from \"..\";\r\nimport { NcqLogLevel } from \"../enums.generated\";\r\nimport { TYPES } from \"../ioc/types\";\r\nimport { LogMessage } from \"../models/app\";\r\nimport { HttpMethods } from \"../models/http\";\r\nimport { ServiceBase } from \"./ServiceBase\";\r\n\r\n/**\r\n * IPF page service, used to setup the page and execute scripts.\r\n * This service is key to the lifecyle of JavaScript when loading pages.\r\n */\r\n@injectable()\r\nexport class IpfPageService extends ServiceBase implements PageService {\r\n\r\n\t/**\r\n\t * Initialises a new instance of the IpfPageService class.\r\n\t * @param ajaxService AJAX service, used to make AJAX HTTP requests.\r\n\t * @param formService Form service, used to manage forms.\r\n\t * @param dataGridService Data grid service, used to render data grids.\r\n\t * @param ipfModule IPF module, containing contextual information and functions.\r\n\t * @param loaderService Loader service, used to show loading elements.\r\n\t * @param messageService Message service, used to display messages.\r\n\t * @param scriptService Script service, used to execute scripts.\r\n\t * @param tierSelectorService Tier selector service, used to apply tier selectors to input elements.\r\n\t * @param wizardService Wizard service, used to setup form wizards.\r\n\t * @param urlService URL service, used to generate URLs.\r\n\t * @param userTierService User tier service, used to apply tier params to URLs.\r\n\t */\r\n\tpublic constructor(\r\n\t\t@inject(TYPES.AjaxService) private ajaxService: AjaxService,\r\n\t\t@inject(TYPES.FormService) private formService: FormService,\r\n\t\t@inject(TYPES.DataGridService) private dataGridService: DataGridService,\r\n\t\t@inject(TYPES.IpfModule) private ipfModule: IpfModule,\r\n\t\t@inject(TYPES.LoaderService) private loaderService: LoaderService,\r\n\t\t@inject(TYPES.MessageService) private messageService: MessageService,\r\n\t\t@inject(TYPES.ScriptService) private scriptService: ScriptService,\r\n\t\t@inject(TYPES.TierSelectorService) private tierSelectorService: TierSelectorService,\r\n\t\t@inject(TYPES.WizardService) private wizardService: WizardService,\r\n\t\t@inject(TYPES.UrlService) private urlService: UrlService,\r\n\t\t@inject(TYPES.UserTierService) private userTierService: UserTierService\r\n\t) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tready() {\r\n\r\n\t\tconst pageLoaderTimeout = setTimeout(() => {\r\n\t\t\tthis.loaderService.showPageLoader();\r\n\t\t}, 1000);\r\n\r\n\t\tconst self = this;\r\n\r\n\t\ttry {\r\n\r\n\t\t\tdocument.querySelector(\"body\")?.classList.add(\"page-service-ready\");\r\n\r\n\t\t\tthis.scriptService.register(() => {\r\n\r\n\t\t\t\tdocument.querySelector(\"body\")?.classList.add(\"page-service-ready-register\");\r\n\r\n\t\t\t\tthis.ipfModule.onReady.forEach(handler => handler());\r\n\r\n\t\t\t\tthis.ajaxService.unobstrusive(document.body);\r\n\r\n\t\t\t\tthis.applyEffects(document.body);\r\n\r\n\t\t\t\tthis.applySearch();\r\n\t\t\t});\r\n\r\n\t\t\tthis.scriptService.run();\r\n\t\t}\r\n\t\tcatch (error) {\r\n\r\n\t\t\tdocument.querySelector(\"body\")?.setAttribute(\"data-error\", (error as Error)?.message);\r\n\t\t}\r\n\t\tfinally {\r\n\r\n\t\t\twindow.addEventListener(\"load\", function () {\r\n\r\n\t\t\t\tif (pageLoaderTimeout) clearTimeout(pageLoaderTimeout);\r\n\t\t\t\tself.loaderService.hidePageLoader();\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\twindow.onerror = function (event, source, lineno, colno, error) {\r\n\r\n\t\t\tdocument.querySelector(\"body\")?.setAttribute(\"data-error\", error?.message ?? \"\");\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tapplyEffects(element: Element) {\r\n\r\n\t\tthis.setupErrorHandling();\r\n\r\n\t\ttry {\r\n\r\n\t\t\tthis.formService.applyAll(element);\r\n\t\t\tthis.tierSelectorService.applyGlobalTierSelectors(element);\r\n\t\t\tthis.wizardService.applyAll(element);\r\n\t\t\tthis.dataGridService.applyAll(element);\r\n\t\t\tthis.messageService.applyEffects(element);\r\n\t\t\tthis.userTierService.applyTierLinks();\r\n\t\t}\r\n\t\tcatch (error) {\r\n\r\n\t\t\tthis.logError(error as Error);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Applies search functionalithy to the page, by locating the search form and\r\n\t * adding an on submit event listener, which navigates to the search page.\r\n\t */\r\n\tapplySearch() {\r\n\r\n\t\tdocument.getElementById(\"search-form\")?.addEventListener(\"submit\", event => {\r\n\r\n\t\t\tconst searchValue = (document.getElementById(\"search-input\") as HTMLInputElement)?.value.trim();\r\n\r\n\t\t\tif (searchValue) {\r\n\t\t\t\twindow.location.href = this.urlService.url(`Search?query=${encodeURIComponent(searchValue)}`)\r\n\t\t\t}\r\n\r\n\t\t\tevent.preventDefault();\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * Setup client-side error handling for the application.\r\n\t * Logs errors to the console and optionally the server.\r\n\t */\r\n\tprivate setupErrorHandling() {\r\n\r\n\t\tif (!this.ipfModule.context.clientLoggingDisabled && this.ipfModule.context.userId > 0) {\r\n\r\n\t\t\t// add on error handler to the window, every unhandled JS exception will trigger a callback to this function\r\n\t\t\twindow.onerror = (message, source, lineno, colno, error) => {\r\n\r\n\t\t\t\ttry {\r\n\r\n\t\t\t\t\tlet msg: string;\r\n\t\t\t\t\tlet detail: string;\r\n\r\n\t\t\t\t\tif (typeof message === \"string\") {\r\n\r\n\t\t\t\t\t\tmsg = message;\r\n\t\t\t\t\t\tdetail = `Source: ${source}\\r\\nLine: ${lineno}\\r\\nColumn: ${colno}\\r\\n\\r\\nStack trace:\\r\\n${error?.stack}`;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\r\n\t\t\t\t\t\tmsg = error?.message ?? \"\";\r\n\t\t\t\t\t\tdetail = `Stack trace:\\r\\n${error?.stack}`;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tthis.logErrorInternal(msg, detail);\r\n\t\t\t\t}\r\n\t\t\t\tcatch (error) {\r\n\r\n\t\t\t\t\tconsole.error(error);\r\n\t\t\t\t}\r\n\t\t\t};\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Logs the given error to the console and optionally to the server, when clientLoggingDisabled is not disabled.\r\n\t * @param error The error to log.\r\n\t */\r\n\tprivate logError(error: Error) {\r\n\r\n\t\tconsole.error(error);\r\n\r\n\t\tif (!this.ipfModule.context.clientLoggingDisabled && this.ipfModule.context.userId > 0) {\r\n\r\n\t\t\ttry {\r\n\r\n\t\t\t\tthis.logErrorInternal(error.message, `Stack trace:\\r\\n${error?.stack}`);\r\n\t\t\t}\r\n\t\t\tcatch (error) {\r\n\r\n\t\t\t\tconsole.error(error);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Performs an AJAX request to log a message with details.\r\n\t * @param message The error message.\r\n\t * @param detail The error details.\r\n\t */\r\n\tprivate logErrorInternal(message: string, detail: string) {\r\n\r\n\t\tthis.ajaxService.request({\r\n\t\t\turl: this.urlService.url(\"/Log\"),\r\n\t\t\tmethod: HttpMethods.Post,\r\n\t\t\tdata: {\r\n\t\t\t\tlevel: NcqLogLevel.Error,\r\n\t\t\t\tlogType: \"Portal-Client\",\r\n\t\t\t\tmessage: message,\r\n\t\t\t\tdetail: detail\r\n\t\t\t} as LogMessage\r\n\t\t});\r\n\t}\r\n}","import { injectable } from \"inversify\";\r\nimport { ScriptService } from \".\";\r\nimport { ServiceBase } from \"./ServiceBase\";\r\n\r\n/**\r\n * Script service, enables registering scripts and executing them at a later time in the order registered.\r\n */\r\n@injectable()\r\nexport class IpfScriptService extends ServiceBase implements ScriptService {\r\n\r\n private scripts: Array = [];\r\n private executedScripts: Array = [];\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n public register(func: Function): void {\r\n\r\n this.scripts.push(func);\r\n }\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n public run(): void {\r\n\r\n const copy: Array = [];\r\n\r\n this.scripts.forEach(script => {\r\n\r\n copy.push(script);\r\n });\r\n\r\n copy.forEach((script, index) => {\r\n\r\n script();\r\n\r\n this.scripts.splice(0, 1);\r\n\r\n this.executedScripts.push(script);\r\n });\r\n }\r\n}","import { inject, injectable } from \"inversify\";\r\nimport { SearchFilterService, UrlService, UserTierService } from \".\";\r\nimport { IpfModule } from \"..\";\r\nimport { Constants } from \"../constants.generated\";\r\nimport { FilterType } from \"../enums.generated\";\r\nimport { EventConstants } from \"../EventConstants\";\r\nimport { applyEnterButtonTarget } from \"../functions/apply-enter-button-target\";\r\nimport { asNumberOrString } from \"../functions/as-number-or-string\";\r\nimport { logError } from \"../functions/client-log\";\r\nimport { TYPES } from \"../ioc/types\";\r\nimport { DataGridRefreshArgs } from \"../models/data-grid\";\r\nimport { ApiModel } from \"../models/search\";\r\nimport { Guid } from \"../util/Guid\";\r\nimport { ServiceBase } from \"./ServiceBase\";\r\n\r\n/**\r\n * Search filter service. Enables filtering one or many data grids.\r\n */\r\n@injectable()\r\nexport class IpfSearchFilterService extends ServiceBase implements SearchFilterService {\r\n\r\n\t/**\r\n\t * Map of filter value retrievers mapped by filter type.\r\n\t */ \r\n\tprivate static readonly filterValueRetrievers = new Map any>([\r\n\t\t[FilterType.TextBox, IpfSearchFilterService.getTextBoxFilterValue],\r\n\t\t[FilterType.DropDown, IpfSearchFilterService.getDropDownFilterValue],\r\n\t\t[FilterType.TierSelector, IpfSearchFilterService.getTierSelectorFilterValue],\r\n\t\t[FilterType.Date, IpfSearchFilterService.getTextBoxFilterValue]\r\n\t]);\r\n\r\n\t/**\r\n\t * Map of filter value clearers mapped by filter type.\r\n\t */\r\n\tprivate static readonly filterValueClearers = new Map any>([\r\n\t\t[FilterType.TextBox, IpfSearchFilterService.clearTextBoxFilterValue],\r\n\t\t[FilterType.DropDown, IpfSearchFilterService.clearDropDownFilterValue],\r\n\t\t[FilterType.TierSelector, IpfSearchFilterService.clearTierSelectorFilterValue],\r\n\t\t[FilterType.Date, IpfSearchFilterService.clearDateFilterValue]\r\n\t]);\r\n\r\n\tprivate static readonly apiModels = new Map();\r\n\r\n\t/**\r\n\t * Initialises a new instance of the IpfSearchFilterService class.\r\n\t * @param userTierService User tier service, used to apply tier params to URLs.\r\n\t * @param urlService URL service, used to generate URLs.\r\n\t * @param ipfModule IPF module, containing contextual information and functions.\r\n\t */\r\n\tconstructor(\r\n\t\t@inject(TYPES.UserTierService) private userTierService: UserTierService,\r\n\t\t@inject(TYPES.UrlService) private urlService: UrlService,\r\n\t\t@inject(TYPES.IpfModule) private ipfModule: IpfModule) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic setupFilters(element: Element, onChangeHandler: (args: DataGridRefreshArgs) => void) {\r\n\r\n\t\tconst changeArgs: DataGridRefreshArgs = { resetPageIndex: true };\r\n\t\tconst elements = new Array();\r\n\t\tlet inputTimeout: NodeJS.Timeout;\r\n\r\n\t\t// this is the onput text filter handler, which searches as the user types\r\n\t\tconst onInput = (event: Event) => {\r\n\t\t\tif (inputTimeout) clearTimeout(inputTimeout);\r\n\t\t\tinputTimeout = global.setTimeout(() => {\r\n\t\t\t\tonChangeHandler(changeArgs);\r\n\t\t\t\tif (event.target instanceof HTMLInputElement) {\r\n\t\t\t\t\tthis.insertClearFilter(event.target);\r\n\t\t\t\t}\r\n\t\t\t}, 500);\r\n\t\t};\r\n\r\n\t\t// this is the most commonly used on change filter,\r\n\t\t// which searches when the user blurs the text box, selects a date or dropdown item\r\n\t\tconst onChange = (event: Event) => {\r\n\t\t\tonChangeHandler(changeArgs);\r\n\t\t\tif (event.target instanceof Element) {\r\n\t\t\t\tthis.insertClearFilter(event.target);\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t// this is the export button click handler\r\n\t\tconst onExport = (event: Event) => {\r\n\r\n\t\t\tthis.export(element, event);\r\n\t\t}\r\n\r\n\t\t// filter sets can either search on filter change or if there is a filter submit element on button click\r\n\t\tconst submitElement = element.querySelector(\"[data-filter-submit]\");\r\n\r\n\t\tlet submitHandler: () => void;\r\n\r\n\t\t// apply filter submit behaviour\r\n\t\tif (submitElement) {\r\n\r\n\t\t\tconst validator = () => {\r\n\r\n\t\t\t\tlet valid = true;\r\n\t\t\t\telement.querySelectorAll(\"[data-filter-min-length]\").forEach(filterElement => {\r\n\r\n\t\t\t\t\tif (valid && filterElement instanceof HTMLInputElement) {\r\n\r\n\t\t\t\t\t\tconst minLength = parseInt(filterElement.getAttribute(\"data-filter-min-length\") ?? \"0\");\r\n\r\n\t\t\t\t\t\tif (minLength && filterElement.value.trim().length < minLength) {\r\n\t\t\t\t\t\t\tvalid = false;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\r\n\t\t\t\treturn valid;\r\n\t\t\t}\r\n\r\n\t\t\tsubmitHandler = () => {\r\n\r\n\t\t\t\t// if filters validate, trigger the search\r\n\t\t\t\tif (validator() === true) {\r\n\t\t\t\t\tonChangeHandler(changeArgs);\r\n\t\t\t\t}\r\n\t\t\t};\r\n\r\n\t\t\tsubmitElement.addEventListener(EventConstants.click, submitHandler);\r\n\r\n\t\t\telements.push(submitElement);\r\n\r\n\t\t\tif (!submitElement.id) {\r\n\t\t\t\tsubmitElement.id = Guid.newGuid();\r\n\t\t\t}\r\n\r\n\t\t\t// hook up enter pressed events on the filters\r\n\t\t\tapplyEnterButtonTarget(`#${element.id} input[data-filter]`, `#${submitElement.id}`, validator);\r\n\t\t}\r\n\t\telse {\r\n\t\t\tsubmitHandler = () => onChangeHandler(changeArgs);\r\n\t\t}\r\n\r\n\t\tconst exportButton = element.querySelector(\"[data-export]\");\r\n\t\tif (exportButton) {\r\n\r\n\t\t\texportButton.addEventListener(EventConstants.click, onExport);\r\n\r\n\t\t\t// if there is an export button and no submit search button then need to ensure export isn't triggered.\r\n\t\t\t// this is because the default browser behaviour is to trigger a click of the 1st submit button it finds, when text boxes are focused and enter is pressed.\r\n\t\t\tif (exportButton && !submitElement) {\r\n\r\n\t\t\t\t// get all date picker and standard text input fields\r\n\t\t\t\telement.querySelectorAll(\".date-picker .MuiInputBase-input, input[data-filter]\").forEach(dateInput => {\r\n\r\n\t\t\t\t\t// ensure there are no duplicate events firing\r\n\t\t\t\t\tdateInput.removeEventListener(EventConstants.keydown, this.handleInputFilterEnter);\r\n\r\n\t\t\t\t\t// handle keydown event\r\n\t\t\t\t\tdateInput.addEventListener(EventConstants.keydown, this.handleInputFilterEnter);\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\telement.querySelectorAll(\"[data-filter]\").forEach(filterElement => {\r\n\r\n\t\t\tif (filterElement instanceof HTMLInputElement || filterElement instanceof HTMLSelectElement) {\r\n\r\n\t\t\t\tconst event = filterElement.getAttribute(\"data-filter-event\");\r\n\r\n\t\t\t\t// attach on change/input events to the filter elements\r\n\t\t\t\tif (event !== EventConstants.none) {\r\n\r\n\t\t\t\t\tfilterElement.addEventListener(event ?? EventConstants.change, event === EventConstants.input ? onInput : onChange);\r\n\t\t\t\t\telements.push(filterElement);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis.insertClearFilter(filterElement);\r\n\t\t\t}\r\n\r\n\t\t\tconst filterType = this.getFilterType(filterElement);\r\n\r\n\t\t\tif (filterType === FilterType.TierSelector && filterElement.getAttribute(\"data-tier-root\") === Constants.TierKeyPageTier) {\r\n\r\n\t\t\t\t// subscribe to the page tier change event\r\n\t\t\t\tthis.userTierService.subscribe(element.id, () => {\r\n\t\t\t\t\tconst clearFilter = filterElement.parentElement?.querySelector(\".clear-filter\");\r\n\t\t\t\t\tclearFilter?.dispatchEvent(new Event(EventConstants.click));\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t// return tear down function which removes events\r\n\t\treturn () => {\r\n\r\n\t\t\telements.forEach(filterElement => {\r\n\r\n\t\t\t\tif (filterElement.hasAttribute(\"data-filter-submit\")) {\r\n\t\t\t\t\tfilterElement.removeEventListener(EventConstants.click, submitHandler);\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tconst event = filterElement.getAttribute(\"data-filter-event\");\r\n\t\t\t\t\tfilterElement.removeEventListener(event ?? EventConstants.change, event === EventConstants.input ? onInput : onChange);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\t\tif (exportButton) {\r\n\r\n\t\t\t\texportButton.removeEventListener(EventConstants.click, onExport);\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic applyFilters(filtersElement: Element, filters: object, apiModel?: ApiModel) {\r\n\r\n\t\tconst filterData = filters as any;\r\n\r\n\t\tfiltersElement.querySelectorAll(\"[data-filter]\").forEach(filterElement => {\r\n\r\n\t\t\tconst filterName = this.getFilterName(filterElement);\r\n\t\t\tconst filterType = this.getFilterType(filterElement);\r\n\r\n\t\t\t// get the filter value retriever and set filter model property\r\n\t\t\tconst valueRetriever = IpfSearchFilterService.filterValueRetrievers.get(filterType);\r\n\r\n\t\t\tif (valueRetriever) {\r\n\r\n\t\t\t\tconst filterValue = valueRetriever(filterElement);\r\n\t\t\t\tif (filterValue) {\r\n\r\n\t\t\t\t\tfilterData[filterName] = filterValue;\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\r\n\t\t\t\t\tfilterData[filterName] = undefined;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tif (apiModel) {\r\n\r\n\t\t\tIpfSearchFilterService.apiModels.set(filtersElement.id, apiModel);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate export(filtersElement: Element, event: Event) {\r\n\r\n\t\t// get the API model, which will be used to pass through the JSON filters through in a hidden field\r\n\t\t// as the file download request is not called with AJAX\r\n\t\tconst apiModel = IpfSearchFilterService.apiModels.get(filtersElement.id);\r\n\r\n\t\tif (apiModel) {\r\n\r\n\t\t\t// get the closest ancestor form, requires the filters are within a form\r\n\t\t\tconst form = filtersElement.closest(\"form\");\r\n\r\n\t\t\tif (form) {\r\n\r\n\t\t\t\tconst btn = event.currentTarget;\r\n\r\n\t\t\t\t// set the form or button action\r\n\t\t\t\tif (btn instanceof HTMLButtonElement && btn.formAction) {\r\n\r\n\t\t\t\t\tlet formAction: string;\r\n\t\t\t\t\tlet origFormAction = btn.getAttribute(\"data-original-form-action\");\r\n\t\t\t\t\tif (origFormAction) {\r\n\r\n\t\t\t\t\t\tformAction = origFormAction;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse {\r\n\r\n\t\t\t\t\t\tbtn.setAttribute(\"data-original-form-action\", btn.formAction);\r\n\t\t\t\t\t\tformAction = btn.formAction;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tbtn.formAction = this.urlService.getPageTierUrl(formAction);\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\r\n\t\t\t\t\tform.action = this.urlService.getPageTierUrl(form.action);\r\n\t\t\t\t}\r\n\r\n\t\t\t\ttry {\r\n\r\n\t\t\t\t\t// find the export query field and serialise the JSON search model to its value\r\n\t\t\t\t\tconst queryField = form.querySelector(`[name=${Constants.ExportQueryFieldName}]`);\r\n\t\t\t\t\tif (queryField) {\r\n\t\t\t\t\t\tqueryField.value = JSON.stringify(apiModel);\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if (this.ipfModule.context.clientDebugEnabled) {\r\n\t\t\t\t\t\tlogError(\"Export query field was not found.\")\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tcatch (error) {\r\n\r\n\t\t\t\t\tevent.preventDefault();\r\n\r\n\t\t\t\t\tif (this.ipfModule.context.clientDebugEnabled) {\r\n\t\t\t\t\t\tlogError(\"Error on export.\");\r\n\t\t\t\t\t\tthrow error;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// now let the event carry on and submit the form and perform the export...\r\n\t}\r\n\r\n\tprivate static getTextBoxFilterValue(element: Element) {\r\n\r\n\t\tif (element instanceof HTMLInputElement) {\r\n\r\n\t\t\tconst input = element as HTMLInputElement;\r\n\t\t\treturn input.value;\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static clearTextBoxFilterValue(element: Element) {\r\n\r\n\t\tif (element instanceof HTMLInputElement) {\r\n\r\n\t\t\tconst input = element as HTMLInputElement;\r\n\t\t\tinput.value = \"\";\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static getTierSelectorFilterValue(element: Element) {\r\n\r\n\t\tif (element instanceof HTMLInputElement) {\r\n\r\n\t\t\tconst input = element as HTMLInputElement;\r\n\t\t\treturn input.value ? JSON.parse(input.value) : null;\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static clearTierSelectorFilterValue(element: Element) {\r\n\r\n\t\tif (element instanceof HTMLInputElement) {\r\n\r\n\t\t\tconst input = element as HTMLInputElement;\r\n\t\t\tinput.value = \"\";\r\n\r\n\t\t\tconst textInput = input.parentElement?.querySelector(\"input[type=text]\");\r\n\r\n\t\t\tif (textInput instanceof HTMLInputElement) {\r\n\r\n\t\t\t\ttextInput.value = \"\";\r\n\t\t\t\ttextInput.dispatchEvent(new Event(EventConstants.change));\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static clearDateFilterValue(element: Element) {\r\n\r\n\t\tif (element instanceof HTMLInputElement) {\r\n\r\n\t\t\tconst input = element as HTMLInputElement;\r\n\t\t\tinput.value = \"\";\r\n\r\n\t\t\t// get the MUI text box \r\n\t\t\tconst muiInput = input.closest(\".input-group\")?.querySelector(\".MuiInputBase-input\");\r\n\r\n\t\t\tif (muiInput instanceof HTMLInputElement) {\r\n\r\n\t\t\t\t// clear it and trigger change event\r\n\t\t\t\tmuiInput.value = \"\";\r\n\t\t\t\tinput.dispatchEvent(new Event(EventConstants.change_ipffilter));\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate static getDropDownFilterValue(element: Element) {\r\n\r\n\t\tif (element instanceof HTMLSelectElement) {\r\n\r\n\t\t\tconst select = element as HTMLSelectElement;\r\n\t\t\tif (select.selectedOptions.length) {\r\n\r\n\t\t\t\treturn asNumberOrString(select.selectedOptions[0].value);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tprivate static clearDropDownFilterValue(element: Element) {\r\n\r\n\t\tif (element instanceof HTMLSelectElement) {\r\n\r\n\t\t\tconst select = element as HTMLSelectElement;\r\n\t\t\tselect.selectedIndex = 0;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate insertClearFilter(filterElement: Element) {\r\n\r\n\t\t// ensure this filter can be cleared first\r\n\t\tif (filterElement.hasAttribute(\"data-filter-disable-remove\")) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst filterType = this.getFilterType(filterElement);\r\n\t\tconst hasValue = (filterElement instanceof HTMLInputElement && filterElement.value.trim().length > 0 && (filterType !== FilterType.TierSelector || filterElement.value !== \"{}\")) ||\r\n\t\t\t(filterElement instanceof HTMLSelectElement && filterElement.selectedIndex > 0);\r\n\r\n\t\tif (filterElement.parentElement) {\r\n\r\n\t\t\t// check for existing clear button\r\n\t\t\tlet clearFilter = filterElement.parentElement.querySelector(\".clear-filter\") as HTMLButtonElement;\r\n\r\n\t\t\t// add the clear button, if the filter has a value and there is no clear button\r\n\t\t\tif (hasValue && !clearFilter) {\r\n\r\n\t\t\t\t// create clear filter button with an icon as its content\r\n\t\t\t\tclearFilter = document.createElement(\"button\") as HTMLButtonElement;\r\n\t\t\t\tclearFilter.type = \"button\";\r\n\t\t\t\tclearFilter.className = \"clear-filter\";\r\n\t\t\t\tclearFilter.title = \"Remove filter\";\r\n\t\t\t\tclearFilter.innerHTML = \"\";\r\n\t\t\t\tfilterElement.parentElement.appendChild(clearFilter);\r\n\r\n\t\t\t\t// get the filter clearer\r\n\t\t\t\tconst valueClearer = IpfSearchFilterService.filterValueClearers.get(filterType);\r\n\r\n\t\t\t\tif (valueClearer) {\r\n\r\n\t\t\t\t\tconst event = filterElement.getAttribute(\"data-filter-event\");\r\n\r\n\t\t\t\t\t// add click event to the clear filter button\r\n\t\t\t\t\tclearFilter.addEventListener(EventConstants.click, () => {\r\n\t\t\t\t\t\tvalueClearer(filterElement);\r\n\t\t\t\t\t\tclearFilter.style.display = \"none\";\r\n\t\t\t\t\t\tfilterElement.dispatchEvent(new Event(event ?? EventConstants.change));\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// already has a clear button, just show it\r\n\t\t\telse if (hasValue && clearFilter) {\r\n\r\n\t\t\t\tclearFilter.style.display = \"block\";\r\n\t\t\t}\r\n\t\t\t// no value so hide the clear button\r\n\t\t\telse if (clearFilter) {\r\n\r\n\t\t\t\tclearFilter.style.display = \"none\";\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate getFilterType(filterElement: Element) {\r\n\t\tconst filterTypeString = filterElement.getAttribute(\"data-filter\") ?? \"\";\r\n\t\treturn parseInt(filterTypeString) as FilterType;\r\n\t}\r\n\r\n\tprivate getFilterName(filterElement: Element) {\r\n\t\treturn (filterElement.hasAttribute(\"data-filter-name\") ?\r\n\t\t\tfilterElement.getAttribute(\"data-filter-name\") : filterElement.getAttribute(\"name\")) ?? \"\";\r\n\t}\r\n\r\n\tprivate handleInputFilterEnter(event: KeyboardEvent) {\r\n\r\n\t\tif (event.key === EventConstants.key_enter) {\r\n\r\n\t\t\tevent.preventDefault();\r\n\t\t}\r\n\t}\r\n}","import { inject, injectable } from \"inversify\";\r\nimport { AjaxService, FormComponentService, SessionValidationService, UrlService } from \".\";\r\nimport { IpfModule } from \"..\";\r\nimport { Constants } from \"../constants.generated\";\r\nimport { logInfo } from \"../functions/client-log\";\r\nimport { secondsToString } from \"../functions/seconds-to-string\";\r\nimport { TYPES } from \"../ioc/types\";\r\nimport { ConfirmationOption, ConfirmationPromptOptions, SessionExpiryInfo } from \"../models/app\";\r\nimport { HttpMethods } from \"../models/http\";\r\nimport { ServiceBase } from \"./ServiceBase\";\r\n\r\n/**\r\n * Session validation service, enables the setup and refresh of a session expiry timer.\r\n */\r\n@injectable()\r\nexport class IpfSessionValidationService extends ServiceBase implements SessionValidationService {\r\n\r\n\tprivate static readonly sessionExpiryLsKey = \"SessionExpiry\";\r\n\tprivate static readonly timerStartLsKey = \"SessionTimerStart\";\r\n\tprivate static readonly expirySecondsOffset = 5;\r\n\tprivate static readonly disableLogging = true;\r\n\r\n\tprivate intervalRef?: number;\r\n\tprivate expirySeconds: number = 0;\r\n\tprivate promptVisible = false;\r\n\tprivate expiryElement: HTMLElement | null = null;\r\n\tprivate tickerElement: HTMLElement | null = null;\r\n\tprivate static promptOptions: ConfirmationPromptOptions | undefined;\r\n\r\n\t/**\r\n\t * Initialises a new instance of the IpfSessionValidationService class.\r\n\t * @param ajaxService AJAX service, used to make AJAX HTTP requests.\r\n\t * @param ipfModule IPF module, containing contextual information and functions.\r\n\t * @param urlService URL service, used to generate URLs.\r\n\t * @param formComponentService Form component service, used to render React controls.\r\n\t */\r\n\tpublic constructor(\r\n\t\t@inject(TYPES.AjaxService) private ajaxService: AjaxService,\r\n\t\t@inject(TYPES.IpfModule) private ipfModule: IpfModule,\r\n\t\t@inject(TYPES.UrlService) private urlService: UrlService,\r\n\t\t@inject(TYPES.FormComponentService) private formComponentService: FormComponentService\r\n\t) {\r\n\t\tsuper();\r\n\r\n\t\tthis.sessionExpiry = this.ipfModule.context.sessionExpiry;\r\n\t}\r\n\r\n\t/**\r\n\t * Gets session expiry info from localStorage.\r\n\t */\r\n\tprivate get sessionExpiry() {\r\n\t\tconst json = localStorage.getItem(IpfSessionValidationService.sessionExpiryLsKey);\r\n\t\treturn json ? JSON.parse(json) as SessionExpiryInfo : this.ipfModule.context.sessionExpiry;\r\n\t}\r\n\r\n\t/**\r\n\t * Sets session expiry info into localStorage. The info is stored as a JSON string.\r\n\t */\r\n\tprivate set sessionExpiry(value: SessionExpiryInfo | undefined) {\r\n\t\tlocalStorage.setItem(IpfSessionValidationService.sessionExpiryLsKey, JSON.stringify(value));\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the timer start date. Retrieves from localStorage so works across browser tabs.\r\n\t */\r\n\tprivate get timerStart() {\r\n\t\tconst json = localStorage.getItem(IpfSessionValidationService.timerStartLsKey);\r\n\t\treturn json ? new Date(json) : null;\r\n\t}\r\n\r\n\t/**\r\n\t * Sets the timer start date into localStorage. The info is stored as an ISO date string.\r\n\t */\r\n\tprivate set timerStart(value: Date | null) {\r\n\r\n\t\tif (value) {\r\n\r\n\t\t\tlocalStorage.setItem(IpfSessionValidationService.timerStartLsKey, value.toISOString());\r\n\t\t}\r\n\t\telse {\r\n\r\n\t\t\tlocalStorage.removeItem(IpfSessionValidationService.timerStartLsKey);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tsetupSessionTimer() {\r\n\r\n\t\tlet sessionExpiry = this.sessionExpiry;\r\n\r\n\t\tif (!sessionExpiry) {\r\n\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.expiryElement = document.getElementById(\"session-timer\");\r\n\t\tthis.tickerElement = document.getElementById(\"session-time-left\");\r\n\r\n\t\tif (this.expiryElement && this.tickerElement && sessionExpiry.sessionExpiryWarningSeconds) {\r\n\r\n\t\t\tthis.startSessionExpiryTimer();\r\n\t\t\tthis.checkSessionExpiry();\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\trefreshSessionTimer() {\r\n\r\n\t\tconst sessionExpiry = this.sessionExpiry;\r\n\r\n\t\tif (sessionExpiry) {\r\n\r\n\t\t\t// convert from minutes to seconds\r\n\t\t\tconst sessionExpirySeconds = sessionExpiry.sessionTimeout * 60;\r\n\r\n\t\t\t// check the absolute session expiry and if it occurs sooner\r\n\t\t\tif (sessionExpiry.absoluteSessionExpirySeconds && sessionExpirySeconds > sessionExpiry.absoluteSessionExpirySeconds) {\r\n\r\n\t\t\t\tsessionExpiry.sessionExpirySeconds = sessionExpiry.absoluteSessionExpirySeconds;\r\n\t\t\t}\r\n\t\t\telse {\r\n\r\n\t\t\t\tsessionExpiry.sessionExpirySeconds = sessionExpirySeconds;\r\n\t\t\t}\r\n\r\n\t\t\tthis.startSessionExpiryTimer();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate checkSessionExpiry() {\r\n\r\n\t\tlet sessionExpiry = this.sessionExpiry;\r\n\r\n\t\tif (!this.timerStart) {\r\n\r\n\t\t\tthis.logUserOut();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst timeDiff = new Date().getTime() - this.timerStart.getTime();\r\n\t\tconst seconds = this.expirySeconds - Math.ceil(timeDiff / 1000);\r\n\r\n\t\t// log seconds until expiry\r\n\t\tthis.logExpirySeconds(seconds);\r\n\r\n\t\t// if the session expired log the user out\r\n\t\tif (seconds < 1) {\r\n\r\n\t\t\tthis.logUserOut();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// show the amount of time remaining to the user\r\n\t\tif (this.tickerElement) {\r\n\r\n\t\t\tthis.tickerElement.innerText = secondsToString(seconds > 0 ? seconds : 0);\r\n\t\t}\r\n\r\n\t\t// show the timer prompt\r\n\t\tif (!this.promptVisible && sessionExpiry && sessionExpiry.sessionExpiryWarningSeconds && seconds <= sessionExpiry.sessionExpiryWarningSeconds) {\r\n\r\n\t\t\tif (!serviceType.promptOptions) {\r\n\r\n\t\t\t\tserviceType.promptOptions = {\r\n\t\t\t\t\ttitle: \"Session Will Expire Soon\",\r\n\t\t\t\t\tcontent: this.expiryElement,\r\n\t\t\t\t\tcloseOnBackdropClick: false,\r\n\t\t\t\t\tconfirmOption: {\r\n\t\t\t\t\t\ttext: \"Stay Logged On\",\r\n\t\t\t\t\t\thandler: () => {\r\n\r\n\t\t\t\t\t\t\t// handle the user choosing to extend their session\r\n\t\t\t\t\t\t\tthis.ajaxService.request({\r\n\t\t\t\t\t\t\t\turl: this.urlService.url(\"/Session/Refresh\"),\r\n\t\t\t\t\t\t\t\tmethod: HttpMethods.Post\r\n\t\t\t\t\t\t\t})\r\n\t\t\t\t\t\t\t\t.then(result => {\r\n\r\n\t\t\t\t\t\t\t\t\tif (result) {\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\tif (serviceType.promptOptions?.close) {\r\n\t\t\t\t\t\t\t\t\t\t\tserviceType.promptOptions.close();\r\n\t\t\t\t\t\t\t\t\t\t\tthis.promptVisible = false;\r\n\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} as ConfirmationOption,\r\n\t\t\t\t\tcancelOption: {\r\n\t\t\t\t\t\ttext: \"Log Out\",\r\n\t\t\t\t\t\thandler: () => {\r\n\r\n\t\t\t\t\t\t\t// handle the user choosing to log out\r\n\t\t\t\t\t\t\t// call any provided close handler and ensure the prompt content is not visible\r\n\t\t\t\t\t\t\tif (serviceType.promptOptions?.close) {\r\n\t\t\t\t\t\t\t\tserviceType.promptOptions.close();\r\n\t\t\t\t\t\t\t\tthis.promptVisible = false;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tthis.logUserOut();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} as ConfirmationOption,\r\n\t\t\t\t\tonRendered: (isOpen: boolean) => {\r\n\r\n\t\t\t\t\t\tif (isOpen) {\r\n\r\n\t\t\t\t\t\t\t// once rendered and open, show the expiry timer\r\n\t\t\t\t\t\t\tthis.showExpiryTimer(true);\r\n\t\t\t\t\t\t\tthis.expiryElement?.closest(\"#dialog-content\")?.classList.add(\"session-expiry-dialog-content\");\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} as ConfirmationPromptOptions;\r\n\r\n\t\t\t\tthis.formComponentService.showConfirmationPrompt(serviceType.promptOptions);\r\n\t\t\t}\r\n\t\t\telse if (serviceType.promptOptions.open && this.expiryElement) {\r\n\r\n\t\t\t\tthis.showExpiryTimer(false);\r\n\t\t\t}\r\n\t\t}\r\n\t\telse if (this.promptVisible && (!sessionExpiry?.sessionExpiryWarningSeconds || seconds > sessionExpiry.sessionExpiryWarningSeconds)) {\r\n\r\n\t\t\tthis.hideExpiryTimer();\r\n\t\t}\r\n\t}\r\n\r\n\tprivate getSessionExpirySeconds() {\r\n\r\n\t\tconst sessionExpiry = this.sessionExpiry;\r\n\t\tlet expirySeconds = sessionExpiry?.sessionExpirySeconds ?? Number.MAX_VALUE;\r\n\r\n\t\tif (sessionExpiry && sessionExpiry.absoluteSessionExpirySeconds && sessionExpiry.absoluteSessionExpirySeconds < expirySeconds) {\r\n\r\n\t\t\texpirySeconds = sessionExpiry.absoluteSessionExpirySeconds;\r\n\t\t}\r\n\r\n\t\texpirySeconds -= IpfSessionValidationService.expirySecondsOffset;\r\n\r\n\t\treturn expirySeconds;\r\n\t}\r\n\r\n\tprivate setExpirySeconds() {\r\n\r\n\t\tthis.expirySeconds = this.getSessionExpirySeconds();\r\n\r\n\t\tthis.logSetExpirySeconds();\r\n\t}\r\n\r\n\tprivate startSessionExpiryTimer() {\r\n\r\n\t\tthis.stopSessionExpiryTimer();\r\n\t\tthis.setExpirySeconds();\r\n\t\tthis.timerStart = new Date();\r\n\t\tthis.intervalRef = window.setInterval(() => this.checkSessionExpiry(), 1000);\r\n\r\n\t\tthis.logStartSessionExpiryTimer();\r\n\t}\r\n\r\n\tprivate stopSessionExpiryTimer() {\r\n\r\n\t\tclearInterval(this.intervalRef);\r\n\t}\r\n\r\n\tprivate showExpiryTimer(isFirstime: boolean) {\r\n\r\n\t\tif (isFirstime && this.expiryElement) {\r\n\r\n\t\t\tthis.expiryElement.style.display = 'block';\r\n\t\t}\r\n\t\telse if (serviceType.promptOptions?.open && this.expiryElement) {\r\n\r\n\t\t\tserviceType.promptOptions.open();\r\n\t\t\tdocument.getElementById(\"dialog-content\")?.appendChild(this.expiryElement);\r\n\t\t}\r\n\r\n\t\tthis.promptVisible = true;\r\n\t}\r\n\r\n\tprivate hideExpiryTimer() {\r\n\r\n\t\tif (this.expiryElement) {\r\n\r\n\t\t\tdocument.body.appendChild(this.expiryElement);\r\n\t\t\tthis.expiryElement.style.display = 'none';\r\n\t\t}\r\n\r\n\t\tif (serviceType.promptOptions?.close) {\r\n\r\n\t\t\tserviceType.promptOptions.close();\r\n\t\t}\r\n\r\n\t\tthis.promptVisible = false;\r\n\t}\r\n\r\n\tprivate logExpirySeconds(seconds: number) {\r\n\r\n\t\tif (!serviceType.disableLogging) {\r\n\t\t\tlogInfo(`Session expiry in ${seconds} second(s). ${new Date().toISOString()}`);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate logSetExpirySeconds() {\r\n\r\n\r\n\t\tif (!serviceType.disableLogging) {\r\n\t\t\tlogInfo(`Session timer set to expire in ${this.expirySeconds} second(s). ${new Date().toISOString()}`);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate logStartSessionExpiryTimer() {\r\n\r\n\t\tif (!serviceType.disableLogging) {\r\n\t\t\tlogInfo(`Session timer started. ${new Date().toISOString()}`);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate logUserOut() {\r\n\r\n\t\tthis.stopSessionExpiryTimer();\r\n\t\tthis.timerStart = null;\r\n\r\n\t\tconst returnUrl = encodeURIComponent(window.location.pathname + window.location.search);\r\n\t\twindow.location.href = this.urlService.url(Constants.LogoutPageName, { returnUrl });\r\n\t}\r\n}\r\n\r\nconst serviceType = IpfSessionValidationService;","import { inject, injectable } from \"inversify\";\r\nimport { UrlService, UserTierService } from \".\";\r\nimport { IpfModule } from \"..\";\r\nimport { TYPES } from \"../ioc/types\";\r\nimport { SelectedTier } from \"../models/app\";\r\nimport { ApiAction, ApiUrl, HttpMethods } from \"../models/http\";\r\nimport { ServiceBase } from \"./ServiceBase\";\r\n\r\n/**\r\n * URL service, used to generate and manipulate URLs.\r\n */\r\n@injectable()\r\nexport class IpfUrlService extends ServiceBase implements UrlService {\r\n\r\n\tprivate static tierParamPlaceholders = [\"{GroupId}\", \"{BranchId}\", \"{BrokerId}\"];\r\n\r\n\t/**\r\n\t * Initialises a new instance of the IpfUrlService class.\r\n\t * @param ipfModule IPF module, containing contextual information and functions.\r\n\t * @param userTierService User tier service, used to apply tier params to URLs.\r\n\t */\r\n\tpublic constructor(\r\n\t\t@inject(TYPES.IpfModule) private ipfModule: IpfModule,\r\n\t\t@inject(TYPES.UserTierService) private userTierService: UserTierService\r\n\t) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n public url(path: string, queryData?: object): string {\r\n\r\n\t\tif (path.startsWith(\"~/\")) {\r\n\r\n\t\t\tpath = path.replace(\"~/\", \"/\");\r\n\t\t}\r\n\t\telse if (!path.startsWith(\"/\")) {\r\n\r\n\t\t\tpath = \"/\" + path;\r\n\t\t}\r\n\r\n\t\tlet url = this.getPathBaseEnsuredUrl(path);\r\n\r\n if (queryData) {\r\n\r\n url += this.getQueryString(queryData);\r\n }\r\n\r\n return url;\r\n }\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n public apiUrl(apiUrl: ApiUrl): string {\r\n\r\n let path = apiUrl.path;\r\n\r\n if (path.startsWith(\"~/\")) {\r\n\r\n path = path.replace(\"~/\", \"\");\r\n }\r\n\r\n else if (path.startsWith(\"/\")) {\r\n\r\n path = path.replace(\"/\", \"\");\r\n }\r\n\r\n\t\tlet url = this.getPathBaseEnsuredUrl([apiUrl.baseUrl, path].join(\"/\"));\r\n\r\n\t\tif (!apiUrl.method) {\r\n\r\n\t\t\tapiUrl.method = HttpMethods.Get;\r\n\t\t}\r\n\r\n\t\tif (apiUrl.data) {\r\n\r\n url += this.getQueryString(apiUrl.data);\r\n }\r\n\r\n return url;\r\n }\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n public apiAction(apiAction: ApiAction): string {\r\n\r\n\t\tconst urlFragments = [apiAction.baseUrl, apiAction.controller];\r\n\r\n if (apiAction.action) {\r\n\r\n urlFragments.push(apiAction.action);\r\n }\r\n\r\n\t\tlet url = this.getPathBaseEnsuredUrl(urlFragments.join(\"/\"));\r\n\r\n\t\tif (!apiAction.method) {\r\n\r\n\t\t\tapiAction.method = HttpMethods.Get;\r\n\t\t}\r\n\r\n\t\tif (apiAction.data && apiAction.method === HttpMethods.Get) {\r\n\r\n url += this.getQueryString(apiAction.data);\r\n }\r\n\r\n return url;\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic addQueryParam(queryString: string, paramName: string, paramValue: string) {\r\n\r\n\t\tif (queryString) {\r\n\r\n\t\t\tconst urlParams = new URLSearchParams(queryString);\r\n\t\t\turlParams.append(paramName, paramValue);\r\n\t\t\treturn \"?\" + urlParams.toString();\r\n\t\t}\r\n\t\telse {\r\n\r\n\t\t\treturn `?${paramName}=${paramValue}`;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic getQueryParams() {\r\n\r\n\t\tconst query = window.location.search;\r\n\t\tlet params: URLSearchParams;\r\n\r\n\t\tif (!query) {\r\n\r\n\t\t\tparams = new URLSearchParams(\"?\");\r\n\t\t}\r\n\t\telse {\r\n\r\n\t\t\tparams = new URLSearchParams(query.slice(1));\r\n\t\t}\r\n\r\n\t\treturn params;\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic getPageTierUrl(url?: string) {\r\n\r\n\t\tconst query = this.getQueryString({\r\n\t\t\tGroupId: IpfUrlService.tierParamPlaceholders[0],\r\n\t\t\tBranchId: IpfUrlService.tierParamPlaceholders[1],\r\n\t\t\tBrokerId: IpfUrlService.tierParamPlaceholders[2],\r\n\t\t}, url?.indexOf(\"?\") !== -1);\r\n\r\n\t\treturn url ? url + query : query;\r\n\t}\r\n\r\n\tprivate getQueryString(data: any, append?: boolean): string {\r\n\r\n\t\tlet queryParams = [];\r\n\t\tlet pageTier = this.userTierService.getPageTier();\r\n\r\n for (const propertyName in data) {\r\n\r\n\t\t\tif (data.hasOwnProperty(propertyName)) {\r\n\r\n\t\t\t\tlet paramValue = pageTier ? IpfUrlService.replaceTierParamValue(data[propertyName], pageTier) : data[propertyName];\r\n\r\n\t\t\t\tif (paramValue)\r\n\t\t\t\t\tqueryParams.push(`${propertyName}=${paramValue}`);\r\n }\r\n }\r\n\r\n\t\treturn queryParams.length > 0 ? (append === true ? \"&\" : \"?\") + queryParams.join(\"&\") : \"\";\r\n\t}\r\n\r\n\tprivate getPathBaseEnsuredUrl(url: string) {\r\n\r\n\t\tlet pathBase = this.getPathBase();\r\n\r\n\t\tif (pathBase && !url.startsWith(pathBase)) {\r\n\r\n\t\t\tif (!url.startsWith(\"/\")) {\r\n\r\n\t\t\t\tpathBase += \"/\";\r\n\t\t\t}\r\n\r\n\t\t\turl = `${pathBase}${url}`;\r\n\t\t}\r\n\r\n\t\treturn url;\r\n\t}\r\n\r\n\tprivate getPathBase() {\r\n\r\n\t\treturn this.ipfModule.context.pathBase;\r\n\t}\r\n\r\n\tprivate static replaceTierParamValue(paramValue: string, tier?: SelectedTier) {\r\n\r\n\t\tif (IpfUrlService.tierParamPlaceholders.includes(paramValue)) {\r\n\t\t\tswitch (paramValue) {\r\n\t\t\t\tcase \"{GroupId}\":\r\n\t\t\t\t\treturn tier?.group?.id ?? \"\";\r\n\t\t\t\tcase \"{BranchId}\":\r\n\t\t\t\t\treturn tier?.branch?.id ?? \"\";\r\n\t\t\t\tcase \"{BrokerId}\":\r\n\t\t\t\t\treturn tier?.broker?.id ?? \"\";\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn paramValue;\r\n\t}\r\n}","import { inject, injectable } from \"inversify\";\r\nimport { UserTierService } from \".\";\r\nimport { IpfModule } from \"..\";\r\nimport { Constants } from \"../constants.generated\";\r\nimport { isNullOrUndefined } from \"../functions/is-null-or-undefined\";\r\nimport { TYPES } from \"../ioc/types\";\r\nimport { CurrentUserSelectedTier, EnsureTierLevel, SelectedTier } from \"../models/app\";\r\nimport { ServiceBase } from \"./ServiceBase\";\r\nimport { appendTierQueryParams } from \"../functions/append-tier-query-params\";\r\n\r\n/**\r\n * User tier service, used to manage page tier state and check and secure the users tier.\r\n */\r\n@injectable()\r\nexport class IpfUserTierService extends ServiceBase implements UserTierService {\r\n\r\n\tprivate static readonly SelectedTierSessionKey: string = \"SelectedTier\";\r\n\r\n\tprivate readonly _subscribers = new Map void>();\r\n\r\n\tprivate userTier?: CurrentUserSelectedTier;\r\n\r\n\t/**\r\n\t * Initialises a new instance of the IpfUserTierService class.\r\n\t * @param ipfModule IPF module, containing contextual information and functions.\r\n\t */\r\n\tpublic constructor(\r\n\t\t@inject(TYPES.IpfModule) private ipfModule: IpfModule\r\n\t) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic getPageTier(): SelectedTier | null {\r\n\r\n\t\tconst userTier = this.getUserTier();\r\n\t\tconst sessionTierJson = sessionStorage.getItem(IpfUserTierService.SelectedTierSessionKey);\r\n\t\tlet pageTier: SelectedTier | null;\r\n\r\n\t\tif (sessionTierJson) {\r\n\r\n\t\t\tpageTier = JSON.parse(sessionTierJson) as SelectedTier;\r\n\r\n\t\t\tconst sesionTier = pageTier as CurrentUserSelectedTier;\r\n\t\t\tif (this.ipfModule.context.userId !== sesionTier.userId) {\r\n\r\n\t\t\t\tpageTier = {};\r\n\t\t\t\tsessionStorage.removeItem(IpfUserTierService.SelectedTierSessionKey);\r\n\t\t\t}\r\n\r\n\t\t\tif (pageTier && userTier)\r\n\t\t\t\tpageTier = this.ensureSecureSessionTier(userTier, pageTier);\r\n\t\t}\r\n\t\telse {\r\n\r\n\t\t\tpageTier = userTier;\r\n\t\t}\r\n\r\n\t\treturn pageTier;\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic getCurrentTier(): SelectedTier | null {\r\n\r\n\t\treturn this.ipfModule.getData(Constants.DataKeyCurrentBroker) ?? this.getPageTier();\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic setPageTier(pageTier: SelectedTier | null) {\r\n\r\n\t\tconst userTier = this.getUserTier();\r\n\t\tif (pageTier && userTier) {\r\n\t\t\tthis.ensureSecureSessionTier(userTier, pageTier);\r\n\t\t}\r\n\r\n\t\tconst currentUserTier = { ...pageTier, userId: this.ipfModule.context.userId } as CurrentUserSelectedTier;\r\n\t\tsessionStorage.setItem(IpfUserTierService.SelectedTierSessionKey, JSON.stringify(currentUserTier));\r\n\r\n\t\t// notify all subscribers\r\n\t\tthis._subscribers.forEach(subscriber => subscriber(pageTier));\r\n\r\n\t\tthis.applyTierLinks();\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic isFullyConstrained(): boolean {\r\n\r\n\t\tlet t = this.ipfModule.context.userTier;\r\n\t\treturn (t?.group?.id && t?.branch?.id && t?.broker?.id) ? true : false;\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic isAllowedToChangeGroup() {\r\n\r\n\t\treturn !this.getUserTier()?.group?.id;\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic isAllowedToChangeBranch() {\r\n\r\n\t\treturn !this.getUserTier()?.branch?.id;\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic isAllowedToChangeBroker() {\r\n\r\n\t\treturn !this.getUserTier()?.broker?.id;\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic isAllowedToChangePageTier() {\r\n\r\n\t\treturn (this.isAllowedToChangeGroup() || this.isAllowedToChangeBranch() || this.isAllowedToChangeBroker()) &&\r\n\t\t\t!this.ipfModule.getData(Constants.DataKeyCurrentBroker);\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic subscribe(id: string, subscriber: (tier: SelectedTier | null) => void) {\r\n\r\n\t\tthis._subscribers.set(id, subscriber);\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic ensureTierQueryString(level: EnsureTierLevel = EnsureTierLevel.Broker) {\r\n\r\n\t\tconst currentTier = this.getCurrentTier();\r\n\t\tconst hasCurrentBroker = !isNullOrUndefined(this.ipfModule.getData(Constants.DataKeyCurrentBroker));\r\n\r\n\t\tconst query = window.location.search;\r\n\t\tlet params: URLSearchParams;\r\n\r\n\t\tif (!query) {\r\n\r\n\t\t\tparams = new URLSearchParams(\"?\");\r\n\t\t}\r\n\t\telse {\r\n\r\n\t\t\tparams = new URLSearchParams(query.slice(1));\r\n\t\t}\r\n\r\n\t\tif (!hasCurrentBroker) {\r\n\r\n\t\t\tif (level >= EnsureTierLevel.Group) {\r\n\r\n\t\t\t\tthis.ensureTierQueryParam(currentTier?.group?.id, params, \"tier1\");\r\n\t\t\t}\r\n\r\n\t\t\tif (level >= EnsureTierLevel.Broker) {\r\n\r\n\t\t\t\tthis.ensureTierQueryParam(currentTier?.branch?.id, params, \"tier2\");\r\n\t\t\t\tthis.ensureTierQueryParam(currentTier?.broker?.id, params, \"tier3\");\r\n\t\t\t}\r\n\r\n\t\t\tif ((level === EnsureTierLevel.Broker && currentTier?.broker?.id) || (level === EnsureTierLevel.Group && currentTier?.group?.id)) {\r\n\r\n\t\t\t\tconst paramString = '?' + params.toString();\r\n\t\t\t\tif (window.location.search !== paramString) {\r\n\r\n\t\t\t\t\twindow.location.search = paramString;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis.subscribe(nameof(this.ensureTierQueryString), () => {\r\n\r\n\t\t\tthis.ensureTierQueryString(level);\r\n\t\t});\r\n\t}\r\n\r\n\tprivate ensureTierQueryParam(userTierId: string | undefined, params: URLSearchParams, tierParamName: string) {\r\n\r\n\t\tif (userTierId) {\r\n\r\n\t\t\tparams.set(tierParamName, userTierId);\r\n\t\t}\r\n\t\telse if (params.has(tierParamName)) {\r\n\r\n\t\t\tparams.delete(tierParamName);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate getUserTier(): CurrentUserSelectedTier | null {\r\n\r\n\t\tif (!this.userTier) {\r\n\r\n\t\t\tthis.userTier = this.ipfModule.context.userTier;\r\n\t\t}\r\n\t\treturn this.userTier === undefined ? null : this.userTier;\r\n\t}\r\n\r\n\tprivate ensureSecureSessionTier(userTier: SelectedTier, sessionTier: SelectedTier) {\r\n\r\n\t\tconst userBrokerId = userTier.broker?.id;\r\n\t\tconst userBranchId = userTier.branch?.id;\r\n\t\tconst userGroupId = userTier.group?.id;\r\n\r\n\t\tif (userBrokerId && sessionTier.broker?.id !== userBrokerId)\r\n\t\t\treturn userTier;\r\n\t\telse if (userBranchId && sessionTier.branch?.id !== userBranchId)\r\n\t\t\treturn userTier;\r\n\t\telse if (userGroupId && sessionTier.group?.id !== userGroupId)\r\n\t\t\treturn userTier;\r\n\t\telse\r\n\t\t\treturn sessionTier;\r\n\t}\r\n\r\n\tpublic applyTierLinks() {\r\n\t\tconst pageTier = this.getPageTier();\r\n\t\tif (!pageTier) { return; }\r\n\r\n\t\tdocument.querySelectorAll(\"a[data-tier-link]\").forEach(element => appendTierQueryParams(element, pageTier));\r\n\t}\r\n}","import { inject, injectable } from \"inversify\";\r\nimport { AjaxService, LoaderService, MessageService, ScriptService, ValidationService } from \".\";\r\nimport { IpfModule } from \"..\";\r\nimport { MessageType } from \"../enums.generated\";\r\nimport { callFunction } from \"../functions/call-function\";\r\nimport { logInfo } from \"../functions/client-log\";\r\nimport { getProperty } from \"../functions/get-property\";\r\nimport { TYPES } from \"../ioc/types\";\r\nimport { AjaxRequestOptions, HttpMethods } from \"../models/http\";\r\nimport { ServiceBase } from \"./ServiceBase\";\r\n\r\n/**\r\n * AJAx service, sends AJAX requests and configures forms to perform AJAX postbacks on submit.\r\n */\r\n@injectable()\r\nexport class JQueryAjaxService extends ServiceBase implements AjaxService {\r\n\r\n\t/**\r\n\t * Initialises a new instance of the IpfPageService class.\r\n\t * @param ipfModule IPF module, containing contextual information and functions.\r\n\t * @param loaderService Loader service, used to show loading elements.\r\n\t * @param messageService Message service, used to display messages.\r\n\t * @param scriptService Script service, used to execute scripts.\r\n\t * @param validationService Validation service, used to apply validation functionality to forms.\r\n\t */\r\n\tpublic constructor(\r\n\t\t@inject(TYPES.IpfModule) private ipfModule: IpfModule,\r\n\t\t@inject(TYPES.LoaderService) private loaderService: LoaderService,\r\n\t\t@inject(TYPES.MessageService) private messageService: MessageService,\r\n\t\t@inject(TYPES.ScriptService) private scriptService: ScriptService,\r\n\t\t@inject(TYPES.ValidationService) private validationService: ValidationService\r\n\t) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n public async request(options: AjaxRequestOptions): Promise {\r\n\r\n const settings: JQuery.AjaxSettings = {};\r\n settings.url = options.url;\r\n\t\tsettings.method = options.method?.toUpperCase() || HttpMethods.Get;\r\n\r\n if (options.data) {\r\n\r\n settings.contentType = \"application/json; charset=utf-8\";\r\n settings.data = JSON.stringify(options.data, (key, value) => {\r\n\r\n let returnValue: any;\r\n\r\n if (key.startsWith(\"_\")) {\r\n\r\n returnValue = undefined;\r\n }\r\n else {\r\n\r\n returnValue = value;\r\n }\r\n\r\n return returnValue;\r\n\t\t\t});\r\n }\r\n else {\r\n\r\n settings.contentType = false;\r\n\t\t}\r\n\r\n\t\tconst headers: JQuery.PlainObject = {};\r\n\r\n\t\tif (options.authToken) {\r\n\r\n\t\t\theaders[\"Authorization\"] = `Bearer ${options.authToken}`;\r\n\t\t}\r\n\r\n\t\t// adds the antiforgery token to the RequestVerificationToken header\r\n if (settings.method !== \"GET\") {\r\n\r\n const token = $('input:hidden[name=\"__RequestVerificationToken\"]').val();\r\n\r\n if (token) {\r\n\r\n\t\t\t\theaders[\"RequestVerificationToken\"] = token as string;\r\n }\r\n }\r\n\r\n\t\tsettings.headers = headers;\r\n settings.dataType = \"json\";\r\n\r\n return new Promise((resolve, reject) => {\r\n\r\n\t\t\tsettings.success = (data, status, response) => {\r\n\r\n if (status === \"success\") {\r\n\r\n\t\t\t\t\tresolve(data);\r\n\r\n\t\t\t\t\t// handle cases where a redirect is required\r\n\t\t\t\t\tconst location = response.getResponseHeader(\"Location\") as string;\r\n\t\t\t\t\tif (location) {\r\n\t\t\t\t\t\twindow.location.href = location;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (options.success) {\r\n\r\n\t\t\t\t\t\toptions.success(data);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\treturn data;\r\n }\r\n else {\r\n\r\n reject({\r\n\t\t\t\t\t\tdata,\r\n status\r\n });\r\n }\r\n };\r\n\r\n settings.error = (response, status, message) => {\r\n\r\n\t\t\t\tthis.handleAjaxError(response, status, message);\r\n\r\n reject({\r\n response,\r\n status,\r\n message\r\n });\r\n\t\t\t};\r\n\r\n\t\t\tsettings.complete = () => {\r\n\r\n\t\t\t\tthis.ipfModule.refreshSessionTimeout();\r\n\t\t\t};\r\n\r\n $.ajax(settings);\r\n });\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic unobstrusive(container: HTMLElement): void {\r\n\r\n\t\tlogInfo(\"ajax-service-unobstrusive\", \"AjaxService\");\r\n\r\n\t\t// find all elements with a data-ajax attribute\r\n\t\tcontainer.querySelectorAll(\"form[data-ajax]\").forEach(form => {\r\n\r\n\t\t\tlogInfo(\"ajax-service-unobstrusive-form\", \"AjaxService\");\r\n\r\n\t\t\t// setup the AJAX form\r\n\t\t\tthis.setupAjaxForm(form as HTMLFormElement);\r\n\t\t});\r\n\t}\r\n\r\n\tprivate setupAjaxForm(form: HTMLFormElement): void {\r\n\r\n\t\tlogInfo(\"ajax-service-setupAjaxForm\", \"AjaxService\");\r\n\r\n\t\t// add an on submit event listener\r\n\t\tform.addEventListener(\"submit\", event => {\r\n\r\n\t\t\tlogInfo(\"ajax-service-onsubmit\", \"AjaxService\");\r\n\r\n\t\t\tlet disableAjax: boolean | undefined;\r\n\r\n\t\t\ttry {\r\n\r\n\t\t\t\tconst eventObj = event as any;\r\n\t\t\t\tlet submitter: Element | null = eventObj.submitter as Element;\r\n\r\n\t\t\t\t// check for a submitter element on the event object\r\n\t\t\t\tif (!submitter) {\r\n\r\n\t\t\t\t\t// safari workaround for SubmitEvent.submitter and document.activeElement= browser bugs:\r\n\t\t\t\t\t// when document.activeElement is null or is , assign ipfModule.ensuredActiveElement instead.\r\n\t\t\t\t\tlet ensuredActiveElement = this.ipfModule.ensuredActiveElement ?? document.activeElement;\r\n\r\n\t\t\t\t\t// if there is no active element then fallback to the event target \r\n\t\t\t\t\tif (!ensuredActiveElement) {\r\n\t\t\t\t\t\tensuredActiveElement = event.target as Element;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tsubmitter = ensuredActiveElement;\r\n\r\n\t\t\t\t\tlogInfo(\"ajax-service-submitter: \" + submitter.getAttribute(\"id\") ?? submitter.getAttribute(\"formaction\"), \"AjaxService\");\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// validate the form, if not valid then don't submit the ajax form\r\n\t\t\t\tif ((disableAjax = submitter.getAttribute(\"data-disable-ajax\") === \"true\") ||\r\n\t\t\t\t\t(submitter.getAttribute(\"formnovalidate\") == null &&\r\n\t\t\t\t\t\t!(submitter.classList.contains(\"form-no-validate\") || submitter.classList.contains(\"MuiDataGrid-cell\")) &&\r\n\t\t\t\t\t\tthis.validationService.isValidForm(form) === false)) {\r\n\r\n\t\t\t\t\tlogInfo(\"ajax-service-not-valid\", \"AjaxService\");\r\n\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n let loadingTimeout: NodeJS.Timeout;\r\n let ajaxContainer = form.parentElement;\r\n let ajaxTimeout: number = parseInt(form.getAttribute(\"data-ajax-timeout\") || \"0\");\r\n\r\n\t\t\t\t// show a loader element over the form\r\n if (ajaxContainer && form.parentElement) {\r\n\r\n if (!ajaxContainer.classList.contains(\"ajax-container\")) {\r\n\r\n ajaxContainer = document.createElement(\"div\");\r\n ajaxContainer.className = \"ajax-container\";\r\n\r\n form.parentElement.insertBefore(ajaxContainer, form);\r\n\r\n ajaxContainer.appendChild(form);\r\n }\r\n\r\n loadingTimeout = global.setTimeout(() => {\r\n if (ajaxContainer) {\r\n form.classList.add(\"form-loading\");\r\n this.loaderService.render(ajaxContainer);\r\n }\r\n }, ajaxTimeout > 0 ? 0 : 250);\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// call any AJAX before request handler\r\n\t\t\t\tconst ajaxBefore = form.getAttribute(\"data-ajax-before\");\r\n\t\t\t\tif (ajaxBefore) {\r\n\r\n\t\t\t\t\tcallFunction(ajaxBefore);\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// build $.ajax options\r\n\t\t\t\tlet url: string | null = submitter?.getAttribute(\"formaction\");\r\n const settings: JQuery.AjaxSettings = {};\r\n\t\t\t\tsettings.url = url ?? form.action;\r\n\t\t\t\tsettings.method = form.method?.toUpperCase() || HttpMethods.Post;\r\n settings.data = new FormData(form);\r\n settings.processData = false;\r\n\t\t\t\tsettings.contentType = false;\r\n\t\t\t\tsettings.error = (response: JQuery.jqXHR, status: string, message: string) => {\r\n\r\n\t\t\t\t\tthis.handleAjaxError(response, status, message);\r\n\r\n\t\t\t\t\tif (ajaxContainer) {\r\n\r\n\t\t\t\t\t\tthis.loaderService.remove(ajaxContainer);\r\n\t\t\t\t\t\tform.classList.remove(\"form-loading\");\r\n\t\t\t\t\t}\r\n\t\t\t\t};\r\n\r\n\t\t\t\t// successful response handler function\r\n\t\t\t\tsettings.success = (data, status, response) => {\r\n\r\n\t\t\t\t\t// handle cases where a redirect is required following an ajax form post\r\n\t\t\t\t\tconst location = response.getResponseHeader(\"Location\") as string;\r\n\t\t\t\t\tif (location) {\r\n\t\t\t\t\t\twindow.location.href = location;\r\n\t\t\t\t\t}\r\n\t\t\t\t};\r\n\r\n\t\t\t\t// setTimeout allows any timeout delay for the request\r\n\t\t\t\tsetTimeout(() => {\r\n\r\n\t\t\t\t\tthis.messageService.clearMessages();\r\n\r\n\t\t\t\t\tlogInfo(\"ajax-service-submit\", \"AjaxService\");\r\n\r\n\t\t\t\t\t$.ajax(settings)\r\n .then((response: string, status: JQuery.Ajax.SuccessTextStatus) => {\r\n\r\n\t\t\t\t\t\t\t// if successful return the expected response HTML\r\n\t\t\t\t\t\t\tif (status === \"success\") {\r\n\r\n return response;\r\n }\r\n else {\r\n\r\n return null;\r\n }\r\n })\r\n .then(html => {\r\n\r\n\t\t\t\t\t\t\tif (ajaxContainer) {\r\n\r\n\t\t\t\t\t\t\t\tif (html) {\r\n\r\n\t\t\t\t\t\t\t\t\t// update the AJAX containers HTML\r\n\t\t\t\t\t\t\t\t\t$(ajaxContainer).html(html);\r\n\r\n\t\t\t\t\t\t\t\t\t// find the replacement form and set it up again\r\n\t\t\t\t\t\t\t\t\tconst newForm = ajaxContainer.querySelector(\"form\") as HTMLFormElement;\r\n\t\t\t\t\t\t\t\t\tthis.setupAjaxForm(newForm);\r\n\t\t\t\t\t\t\t\t\tthis.validationService.reapplyUnobtrusiveValidator(newForm);\r\n\t\t\t\t\t\t\t\t\tthis.scriptService.run();\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\telse {\r\n\r\n\t\t\t\t\t\t\t\t\tform.classList.remove(\"form-loading\");\r\n\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\t// call any provided AJAX complete handler\r\n\t\t\t\t\t\t\t\tconst ajaxComplete = form.getAttribute(\"data-ajax-complete\");\r\n\t\t\t\t\t\t\t\tif (ajaxComplete) {\r\n\r\n\t\t\t\t\t\t\t\t\tcallFunction(ajaxComplete, ajaxContainer);\r\n\t\t\t\t\t\t\t\t}\r\n }\r\n\t\t\t\t\t\t})\r\n\t\t\t\t\t\t.catch(() => {\r\n\r\n\t\t\t\t\t\t\t// handle request errors\r\n\r\n\t\t\t\t\t\t\tconst ajaxError = form.getAttribute(\"data-ajax-error\");\r\n\r\n\t\t\t\t\t\t\tif (ajaxError) {\r\n\r\n\t\t\t\t\t\t\t\tconst onError = getProperty(window, ajaxError);\r\n\r\n\t\t\t\t\t\t\t\t// call on error handler if provided\r\n\t\t\t\t\t\t\t\tif (typeof onError === \"function\") {\r\n\r\n\t\t\t\t\t\t\t\t\tonError();\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t})\r\n .always(() => {\r\n\r\n\t\t\t\t\t\t\t// AJAX complete handler, always called whether request succeeeds or fails\r\n\t\t\t\t\t\t\tif (ajaxContainer) {\r\n\r\n\t\t\t\t\t\t\t\t// always remove the loader\r\n\t\t\t\t\t\t\t\tthis.loaderService.remove(ajaxContainer);\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t// clear loader display timeout, in case request completed quicker than the timeout\r\n\t\t\t\t\t\t\tclearTimeout(loadingTimeout);\r\n\r\n\t\t\t\t\t\t\t// refresh session timer as the user did something\r\n\t\t\t\t\t\t\tthis.ipfModule.refreshSessionTimeout();\r\n });\r\n }, ajaxTimeout);\r\n }\r\n finally {\r\n\r\n\t\t\t\t// always clear the ensured active element\r\n\t\t\t\tif (this.ipfModule.ensuredActiveElement) {\r\n\r\n\t\t\t\t\tthis.ipfModule.ensuredActiveElement = null;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (!disableAjax) {\r\n\r\n\t\t\t\t\tevent.preventDefault();\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n }\r\n });\r\n\t}\r\n\r\n\tprivate handleAjaxError(response: JQuery.jqXHR, status: string, message: string) {\r\n\r\n\t\tswitch (response.status) {\r\n\t\t\tcase 401:\r\n\t\t\t\t// if unauthorised reload the page to trigger a redirect\r\n\t\t\t\twindow.location.reload();\r\n\t\t\t\tbreak;\r\n\t\t\tdefault:\r\n\t\t\t\t// handle 500 errors and bad request, typically a failure of modelstate/antiforgery validation\r\n\t\t\t\tthis.messageService.showMessage({\r\n\t\t\t\t\ttitle: \"Page Error\",\r\n\t\t\t\t\ttext: this.ipfModule.context.content[\"GeneralApiErrorMessage\"] ?? \"\",\r\n\t\t\t\t\ttype: MessageType.Error\r\n\t\t\t\t});\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n}","import { injectable } from \"inversify\";\r\nimport { ValidationService } from \".\";\r\nimport { EventConstants } from \"../EventConstants\";\r\nimport { doWhen } from \"../functions/do-when\";\r\nimport { isNullOrUndefined } from \"../functions/is-null-or-undefined\";\r\nimport { ServiceBase } from \"./ServiceBase\";\r\n\r\n/**\r\n * JQuery validation services, used in conjunction with JQuery unobtrusive validation.\r\n * This class is used to apply validation modifications and to re-initialise validation and to manually trigger validation.\r\n */\r\n@injectable()\r\nexport class JQueryValidationService extends ServiceBase implements ValidationService {\r\n\r\n\tpublic static readonly validatorData = \"validator\";\r\n\r\n\t/**\r\n\t * Validation modifier functions, used to apply/reapply validators.\r\n\t */\r\n\tprivate validationModifiers = new Array\r\n\t(\r\n\t\tthis.applyEmailInputValidation,\r\n\t\tthis.applyMinPasswordLength,\r\n\t\tthis.applyNotEqual,\r\n\t\tthis.applyNumericInputValidation,\r\n\t\tthis.applyDateValidation\r\n\t);\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic applyValidation(form: HTMLFormElement): void {\r\n\r\n\t\tconst jForm = $(form);\r\n\r\n\t\t// jquery validate modifications\r\n\t\tif ($.validator) {\r\n\r\n\t\t\t// execute validation modifiers\r\n\t\t\tthis.validationModifiers.forEach(modifier => modifier());\r\n\r\n\t\t\tconst doHandler = () => {\r\n\r\n\t\t\t\tconst validator = jForm.data(JQueryValidationService.validatorData) as JQueryValidation.Validator;\r\n\r\n\t\t\t\t// disable the onkeyup validation, this improves usability and validate-ability\r\n\t\t\t\tif (validator) {\r\n\r\n\t\t\t\t\tvalidator.settings.ignore = \":hidden, .MuiInputBase-input\";\r\n\t\t\t\t\tvalidator.settings.onkeyup = false;\r\n\t\t\t\t\tvalidator.settings.onfocusout = function (element) {\r\n\t\t\t\t\t\tvalidator.element($(element));\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// apply on invalid handler\r\n\t\t\t\t\tjForm.off(\"invalid-form.validate\")\r\n\t\t\t\t\t\t.on(\"invalid-form.validate\", this.onInvalid);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tconst whenHandler = () => {\r\n\r\n\t\t\t\treturn !isNullOrUndefined(jForm.data(JQueryValidationService.validatorData));\r\n\t\t\t};\r\n\r\n\t\t\t// execute the following code with a doWhen to make sure jquery unobstrusive validation has run first\r\n\t\t\tdoWhen(doHandler, whenHandler);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic isValidForm(form: HTMLFormElement) {\r\n\r\n\t\tconst jForm = $(form);\r\n\t\t// true if valid or if there is no validator setup\r\n\t\treturn !jForm.data(JQueryValidationService.validatorData) || jForm.valid() === true;\r\n\t}\r\n\r\n\t/**\r\n\t * @inheritdoc\r\n\t */\r\n\tpublic reapplyUnobtrusiveValidator(form: HTMLFormElement) {\r\n\r\n\t\tif ($.validator?.unobtrusive) {\r\n\r\n\t\t\tconst jForm = $(form as HTMLElement);\r\n\t\t\tjForm.removeData(JQueryValidationService.validatorData).removeData(\"unobtrusiveValidation\");\r\n\t\t\t$.validator.unobtrusive.parse(document.body);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate applyEmailInputValidation() {\r\n\r\n\t\t// the following email validation is the same as the default query validation but requiring .com, .co etc suffix\r\n\t\t$.validator.methods[\"email\"] = function (this: JQueryValidation.RulesDictionary, value: string, element: HTMLInputElement) {\r\n\t\t\treturn this.optional(element) || /^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/.test(value);\r\n\t\t};\r\n\t}\r\n\r\n\tprivate applyMinPasswordLength() {\r\n\r\n\t\t$.validator.addMethod(\"password-min-length\",\r\n\t\t\t(value, element) => {\r\n\t\t\t\tconst minLength = parseInt(element.getAttribute(\"min-length\") ?? \"0\");\r\n\t\t\t\treturn value.length >= minLength;\r\n\t\t\t}\r\n\t\t);\r\n\r\n\t\t$.validator.unobtrusive.adapters.addBool(\"password-min-length\");\r\n\t}\r\n\r\n\tprivate applyNotEqual() {\r\n\r\n\t\t$.validator.addMethod(\"not-equal\",\r\n\t\t\t(value, element) => {\r\n\r\n\t\t\t\tlet notEqualField = element.getAttribute(\"data-val-not-equal-field\");\r\n\t\t\t\tconst inputElement = element as HTMLInputElement;\r\n\t\t\t\tconst fieldName = inputElement?.name;\r\n\r\n\t\t\t\t// check for a deep path, this code will only work for properties on the same model\r\n\t\t\t\tif (fieldName.indexOf(\".\") > -1) {\r\n\r\n\t\t\t\t\tconst parentPath = fieldName.substring(0, fieldName.lastIndexOf(\".\") + 1);\r\n\t\t\t\t\tnotEqualField = parentPath + notEqualField;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// get the other element to compare values\r\n\t\t\t\tconst notEqualInputElement = element.closest(\"form\")?.querySelector(`[name=\"${notEqualField}\"]`) as HTMLInputElement;\r\n\r\n\t\t\t\tif (notEqualInputElement && value || notEqualInputElement.value) {\r\n\r\n\t\t\t\t\t// as soon as this field is validateable, add change event onto the other field \r\n\t\t\t\t\t// to make it trigger blur on this field and ensure validation is kept in sync\r\n\t\t\t\t\t$(notEqualInputElement).off(EventConstants.change_ipfvalidator).on(EventConstants.change_ipfvalidator, () => {\r\n\r\n\t\t\t\t\t\t$(element).trigger(EventConstants.blur);\r\n\t\t\t\t\t});\r\n\r\n\t\t\t\t\t// valid if the values are not equal\r\n\t\t\t\t\treturn notEqualInputElement.value !== inputElement.value;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t);\r\n\r\n\t\t$.validator.unobtrusive.adapters.addBool(\"not-equal\");\r\n\t}\r\n\r\n\tprivate applyNumericInputValidation() {\r\n\r\n\t\t// the following number validation enables input with thousands comma separators\r\n\t\t$.validator.methods[\"number\"] = function (this: JQueryValidation.RulesDictionary, value: string, element: HTMLInputElement) {\r\n\t\t\treturn this.optional(element) || /^(?:-?\\d+|-?\\d{1,3}(?:,\\d{3})+)?(?:\\.\\d+)?$/.test(value);\r\n\t\t};\r\n\r\n\t\t// the following number validation enables input with thousands comma separators\r\n\t\t$.validator.methods[\"range\"] = function (this: JQueryValidation.RulesDictionary, value: string, element: HTMLInputElement, param: Array) {\r\n\t\t\tconst numValue = parseFloat(value.replace(/[^0-9\\.]+/g, \"\"));\r\n\t\t\treturn this.optional(element) || (numValue >= param[0] && numValue <= param[1]);\r\n\t\t};\r\n\t}\r\n\r\n\tprivate applyDateValidation() {\r\n\r\n\t\t$.validator.addMethod(\"min-date\",\r\n\t\t\t(value, element) => {\r\n\r\n\t\t\t\tconst minDateStr = element.getAttribute(\"data-val-min-date-value\");\r\n\r\n\t\t\t\tif (!minDateStr) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst minDate = new Date(minDateStr);\r\n\t\t\t\tconst date = new Date(value);\r\n\t\t\t\treturn date.getTime() >= minDate.getTime();\r\n\t\t\t}\r\n\t\t);\r\n\r\n\t\t$.validator.unobtrusive.adapters.addBool(\"min-date\");\r\n\r\n\t\t$.validator.addMethod(\"max-date\",\r\n\t\t\t(value, element) => {\r\n\r\n\t\t\t\tconst maxDateStr = element.getAttribute(\"data-val-max-date-value\");\r\n\r\n\t\t\t\tif (!maxDateStr) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst maxDate = new Date(maxDateStr);\r\n\t\t\t\tconst date = new Date(value);\r\n\t\t\t\treturn date.getTime() <= maxDate.getTime();\r\n\t\t\t}\r\n\t\t);\r\n\r\n\t\t$.validator.unobtrusive.adapters.addBool(\"max-date\");\r\n\t}\r\n\r\n\tprivate onInvalid() {\r\n\r\n\t\t// ensure react rendered input controls are highlighted\r\n\t\tdocument.querySelectorAll(\".invisible-input.input-validation-error\").forEach(element => {\r\n\t\t\tconst group = element.closest(\".input-group\");\r\n\t\t\tconst component = group?.querySelector(\".react-component\");\r\n\r\n\t\t\tif (!component) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst reactInput = component.querySelector(\".MuiInputBase-input, .form-control:not(.invisible-input)\");\r\n\t\t\tif (reactInput && !reactInput.classList.contains(\"input-validation-error\")) {\r\n\t\t\t\treactInput.classList.add(\"input-validation-error\");\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}","import { injectable } from \"inversify\";\r\n\r\n/**\r\n * Base service class. Merely a placeholder for now.\r\n * But could be home to some common methods or properties in the future.\r\n */\r\n@injectable()\r\nexport abstract class ServiceBase {\r\n\r\n}\r\n","import DateFnsAdapter from '@mui/lab/AdapterDateFns';\r\nimport { addYears, endOfYear, isAfter, startOfYear } from \"date-fns\";\r\n\r\n/**\r\n * Date adapter class that extends DateFnsAdapter, enabling the overriding of specific date adapter functions.\r\n */\r\nexport default class DateFnsAdapterWrapper extends DateFnsAdapter {\r\n\r\n\t/**\r\n\t * Initialises a new instance of the DateFnsAdapterWrapper class.\r\n\t */\r\n\tconstructor() {\r\n\t\tsuper();\r\n\r\n\t\t// overrides the getYearRange function, which is used to output years when selecting a year on the date picker\r\n\t\t// outputs years in descending order\r\n\t\tthis.getYearRange = (start: Date, end: Date) => {\r\n\r\n\t\t\tconst startDate = startOfYear(start);\r\n\t\t\tconst endDate = endOfYear(end);\r\n\t\t\tconst years: Date[] = [];\r\n\r\n\t\t\tlet current = endDate;\r\n\t\t\twhile (isAfter(current, startDate)) {\r\n\t\t\t\tyears.push(current);\r\n\t\t\t\tcurrent = addYears(current, -1);\r\n\t\t\t}\r\n\r\n\t\t\treturn years;\r\n\t\t};\r\n\t}\r\n}","/**\r\n * Guid class, providing static property and method to generate new GUIDs and reference empty GUID.\r\n */\r\nexport abstract class Guid {\r\n\r\n\t/**\r\n\t * Gets an empty GUID string.\r\n\t * @returns String.\r\n\t */ \r\n\tstatic get empty(): string {\r\n\t\treturn \"00000000-0000-0000-0000-000000000000\";\r\n\t}\r\n\r\n\t/**\r\n\t * Creates and returns a new random GUID string.\r\n\t * @returns String.\r\n\t */\r\n\tstatic newGuid(): string {\r\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function (c) {\r\n const r = Math.random() * 16 | 0,\r\n v = c == \"x\" ? r : (r & 0x3 | 0x8);\r\n return v.toString(16);\r\n });\r\n }\r\n}"],"sourceRoot":""}