{"version":3,"sources":["app/assets/icons/basket.svg","app/assets/icons/bulb.svg","app/assets/icons/certificate.svg","app/assets/icons/clock.svg","app/assets/icons/database.svg","app/assets/icons/error.svg","app/assets/icons/exclamation.svg","app/assets/icons/key.svg","app/assets/icons/products/estimator.svg","app/assets/icons/stop.svg","app/assets/icons/tools.svg","app/assets/icons/users.svg","app/assets/icons/users2.svg","app/assets/icons/verified-check.svg","internationalization/translations/en-US sync nonrecursive //.json$/i","internationalization/translations/fr-CA sync nonrecursive //.json$/i","services/authentication/authentication-service.ts","constants/local-storage/index.ts","constants/routes/admin-routes.ts","constants/routes/error-routes.ts","constants/routes/reports-routes.ts","constants/routes/index.ts","constants/users/user-roles.ts","constants/users/index.ts","utils/config.ts","utils/dates.ts","extensions/axiosMiddleware.ts","app/common-page-components/notification-panel/NotificationPanelContext.tsx","utils/imports.ts","internationalization/i18n.ts","constants/routes/api-routes.ts","services/api/users/users-api-service-helper.ts","services/api/users/users-api-service.ts","utils/user-authorization.ts","app/common-page-components/controls/button/BTButton.tsx","app/common-page-components/confirmation-overlay/ConfirmationOverlayContext.tsx","app/common-page-components/confirmation-overlay/ConfirmationOverlay.tsx","app/UserInformationContext.tsx","app/common-page-components/navigation-menu/NavigationMenu.tsx","app/common-page-components/layout/Layout.tsx","app/common-page-components/loading-page-overlay/LoadingPageOverlayContext.tsx","app/common-page-components/notification-panel/NotificationPanel.tsx","app/common-page-components/routes/AuthenticatedRoute.tsx","services/api/clients/clients-api-service-helper.ts","services/api/clients/clients-api-service.ts","constants/licenses/index.ts","services/api/licenses/licenses-api-service-helper.ts","services/api/licenses/licenses-api-service.ts","services/api/products/products-api-service-helper.ts","services/api/products/products-api-service.ts","services/api/reports/usage-api-service-helper.ts","services/api/reports/usage-api-service.ts","utils/general.ts","app/common-page-components/cards-container/BTCardsContainer.tsx","app/common-page-components/controls/floating-icon-button/BTFloatingIconButton.tsx","utils/forms.ts","app/common-page-components/forms/form-error-container/FormErrorContainer.tsx","app/common-page-components/forms/FormFooter.tsx","app/common-page-components/controls/icon-button/BTIconButton.tsx","app/common-page-components/forms/FormTextInput.tsx","app/common-page-components/forms/FormDropDownList.tsx","app/common-page-components/forms/FormSwitch.tsx","constants/domains/index.ts","app/pages/admin/clients/components/ClientEditForm.tsx","utils/uuid.ts","app/common-page-components/card/BTCard.tsx","app/pages/admin/clients/components/ClientListing.tsx","app/pages/admin/clients/data/LocationData.ts","app/pages/admin/clients/ClientsPage.tsx","app/common-page-components/forms/FormDatePicker.tsx","app/common-page-components/forms/FormMultiSelect.tsx","app/common-page-components/forms/FormNumericTextInput.tsx","app/pages/admin/licenses/components/LicenseEditForm.tsx","constants/products/index.ts","app/pages/admin/licenses/components/LicenseListing.tsx","app/pages/admin/licenses/LicensesPage.tsx","utils/yup.ts","app/pages/admin/products/components/ProductEditForm.tsx","app/pages/admin/products/components/ProductListing.tsx","app/pages/admin/products/ProductsPage.tsx","app/pages/admin/settings/SiteSettingsPage.tsx","app/pages/admin/users/components/UserEditForm.tsx","app/pages/admin/users/components/UserListing.tsx","app/pages/admin/users/UsersPage.tsx","services/api/estimator-hosted/estimator-hosted-service.ts","utils/nameof.ts","app/pages/admin/hosted-estimator-user-management/components/GridTextCell.tsx","app/pages/admin/hosted-estimator-user-management/components/GridDropdownCell.tsx","app/pages/admin/hosted-estimator-user-management/components/GridDropdownFilterCell.tsx","app/pages/admin/hosted-estimator-user-management/components/GridMultiSelectCell.tsx","app/pages/admin/hosted-estimator-user-management/components/TemporaryPasswordModal.tsx","constants/hosted-estimator-user-management/index.ts","app/pages/admin/hosted-estimator-user-management/components/EstimatorConfigurationModal.tsx","app/pages/admin/hosted-estimator-user-management/components/EstimatorCopyConfigurationModal.tsx","app/pages/admin/hosted-estimator-user-management/components/AddUsersModal.tsx","app/pages/admin/hosted-estimator-user-management/EstimatorHostedUserManagementPage.tsx","app/common-page-components/svg-image/SvgImage.tsx","app/pages/common/error/generic-error/GenericErrorPage.tsx","app/pages/common/error/page-not-found/PageNotFoundPage.tsx","app/pages/common/error/unauthorized/UnauthorizedPage.tsx","constants/links/index.ts","app/pages/common/home/HomePage.tsx","app/pages/common/login/LoginPage.tsx","utils/file.ts","constants/reports/filters/increments.ts","constants/reports/filters/products.ts","constants/reports/filters/index.ts","constants/charts/chart-defaults.ts","constants/charts/index.ts","utils/charts.tsx","app/pages/reports/charts/LicenseUsage/LicenseUsageChart.tsx","app/pages/reports/charts/LicenseCheckouts/LicenseCheckoutsChart.tsx","app/pages/reports/charts/LicenseDuration/LicenseDurationChart.tsx","app/pages/reports/components/ReportsPageCustomChart.tsx","app/pages/reports/reports.ts","utils/calendars.ts","app/pages/reports/charts/LicenseUsage/LicenseUsageFilter.tsx","app/pages/reports/charts/LicenseDuration/LicenseDurationFilter.tsx","app/pages/reports/charts/LicenseCheckouts/LicenseCheckoutsFilter.tsx","app/pages/reports/charts/RawData/RawDataFilter.tsx","app/pages/reports/components/ReportsPageCustomFilters.tsx","app/pages/reports/components/ReportsPageFilters.tsx","app/pages/reports/components/ReportsPageReportsListing.tsx","app/pages/reports/ReportsPage.tsx","app/App.tsx","app/common-page-components/loading-indicator/LoadingIndicator.tsx","app/common-page-components/loading-page-overlay/LoadingPageOverlay.tsx","internationalization/setup.ts","registerServiceWorker.ts","index.tsx"],"names":["module","exports","map","webpackContext","req","id","webpackContextResolve","__webpack_require__","o","e","Error","code","keys","Object","resolve","SSOErrorCode","LocalStorageKeys","AccessToken","AccessTokenError","AuthToken","SSOError","SSOPasswordResetCompleted","SSOPasswordResetInitiated","UserInformation","UserName","ADMIN_ROOT","AdminRoutes","Clients","join","Products","Licenses","SiteSettings","Users","EstimatorHostedUserManagement","ErrorRoutes","PageNotFound","Unauthorized","REPORTS_ROOT","ReportRoutes","Base","UsageReport","Checkouts","Duration","RawData","ApplicationRoutes","SITE_ROOT","HOME","ADMIN_CLIENTS","ADMIN_PRODUCTS","ADMIN_LICENSES","ADMIN_USERS","ADMIN_ESTIMATORHOSTED_USERMANAGEMENT","ADMIN_SITESETTINGS","ERROR_ERROR","ERROR_PAGENOTFOUND","ERROR_UNAUTHORIZED","REPORTS","REPORTS_USAGE","REPORTS_DURATION","REPORTS_CHECKOUTS","REPORTS_RAWDATA","UserRolesValues","UserRolesDisplayNames","UserConstants","CLIENTUSER","INTERNALUSER","ADMIN","BIDDAYSUPPORT","getConfig","key","env","window","ENV","configVal","process","localStorage","AuthenticationService","this","msalObj","Msal","signInConfig","setAuthRedirectCallBack","passwordResetConfig","loginRedirect","requestObj","clear","logout","getAccount","acquireTokenSilent","response","setItem","accessToken","jwtToken","parsedToken","parseJwtToken","exp","jwtTokenExpiration","parseInt","tokenExpirationAsDate","Date","email","emailAddress","name","JSON","parse","atob","split","handleRedirectCallback","error","includes","errorCode","navigateToSignInOrPasswordReset","message","indexOf","setSSOErrors","idTokenClaims","acr","token","idToken","rawIdToken","account","errorDescription","OtherError","LicensingAppSSOError","replace","trim","test","ssoError","stringify","scope","clientId","signInAuthority","passwordResetAuthority","redirectUri","cacheLocation","scopes","auth","authority","validateAuthority","postLogoutRedirectUri","cache","storeAuthStateInCookie","getShortDateString","dateObj","moment","utc","format","NotificationPanelTypes","axios","interceptors","use","data","getObjectWithDateStringsAsDates","result","cloneDeep","Array","isArray","r","value","dateValue","ISO_8601","isValid","toDate","request","getItem","headers","a","isAxiosError","status","getAccessToken","originalHttpConfig","config","fetch","Request","url","method","Authorization","mode","retryResult","getFileNameWithoutExtension","fileName","slice","importAll","requireContext","translations","TranslationFilesMap","require","loadTranslationsForLocale","locale","getTranslationsFunc","forEach","translationFile","i18n","addResourceBundle","API_URL","ApiRoutes","ClientByEmail","ProductsByClient","EstimatorHostedUsers","EstimatorHostedGroups","Usage","Raw","UsageByDay","UsageByWeek","UsageByMonth","DurationByDay","DurationByWeek","DurationByMonth","getUserFromDto","userDto","isNew","isBeckTechUser","roles","currRole","filter","v","getUserDtoFromUser","user","getUser","get","dto","getUsers","dtos","users","addUser","post","editUser","put","deleteUser","userId","delete","isUserAuthorized","userInformation","userRole","undefined","userRoles","find","populateUserInformationFromLocalStorage","userInfoJSONFromLocalStorage","userInfoFromLocalStorage","React","forwardRef","props","ref","buttonStyleCssClass","color","Button","className","innerRef","onClick","disabled","title","tooltip","type","tabIndex","style","textAlign","align","borderRadius","roundedCorners","icon","text","ConfirmationOverlayContext","createContext","confirmationOverlayDisplayInfo","currentConfirmationOverlayParameters","isDisplayed","hasBeenToggled","showConfirmationOverlay","confirmationOverlayParameters","hideConfirmationOverlay","ConfirmationOverlay","useContext","firstButtonRef","useRef","lastButtonRef","loadingPageOverlayCssClasses","push","useEffect","current","focus","onKeyDown","event","keyCode","shiftKey","document","activeElement","preventDefault","onTab","buttons","currButton","index","length","checkIfLastItem","UserInformationContext","userIsAdmin","userIsInternalUser","userIsClientUser","userIsBidDaySupport","updateUserInformation","newUserInformation","NavigationMenu","t","useTranslation","history","useHistory","useState","mobileNavigationMenuIsOpen","setMobileNavigationMenuIsOpen","pageIsScrolled","setPageIsScrolled","navigationLinks","setNavigationLinks","newNavigationLinks","subLinks","hasDivider","generateNavigationLinks","useLayoutEffect","scrollEventTimer","scrollEventHandler","clearTimeout","setTimeout","pageYOffset","addEventListener","removeEventListener","Navbar","light","fixed","to","src","alt","currLink","NavLink","tag","Link","UncontrolledDropdown","DropdownToggle","nav","caret","DropdownMenu","currSubLink","DropdownItem","divider","NavbarToggler","Collapse","isOpen","navbar","Nav","Layout","children","LoadingPageOverlayContext","pageLoadingOverlayDisplayInfo","showPageLoadingOverlay","hidePageLoadingOverlay","NotificationPanel","popFirstQueuedNotification","NotificationPanelContext","notificationBeingDisplayed","setNotificationBeingDisplayed","setIsDisplayed","hideCurrentNotificationTimeoutPromise","setHideCurrentNotificationTimeoutPromise","setTimeoutToHideCurrentNotification","useCallback","notificationTimeout","testTimeout","queuedNotifications","nextNotification","cssClassesArray","Success","Info","data-testid","showSuccessNotification","showErrorNotification","showInfoNotification","AuthenticatedRoute","useMemo","redirectUser","requiredUserRoles","allUserRoles","allowAnyRoles","some","m","every","getClientOrganizationFromDto","accountExecutive","domains","address","streetAddress","aptSuiteBldg","city","stateOrRegion","country","postalCode","usesCorporateActiveDirectory","getDtoFromAddress","getClientOrganizations","clientOrgs","getClientOrganizationByEmail","clientOrg","addClientOrganization","newClientOrg","editClientOrganization","deleteClientOrganization","clientOrgId","LicensesConstants","DeploymentStatuses","COMPLETED","NONE","IN_PROGRESS","ERROR","REQUESTED","DeploymentStatusesDisplayNames","getLicenseFromDto","licenseDto","clientOrganization","clientOrganizationId","product","productId","features","featureIds","featureId","hasActiveLicenses","deploymentTypeId","userCount","effectiveDate","expirationDate","enforceStrictUserCount","deploymentStatus","deploymentDetails","adminUser","getLicenses","licenses","addLicense","license","f","newLicense","editLicense","updatedLicense","deleteLicense","licenseId","resetDeploymentDetails","requestDeployment","emailDomains","getFeatureFromDto","featureDto","getProductFromDto","productDto","getProducts","products","getProductsByClient","client","addProduct","feature","newProduct","editProduct","featuresToAdd","Promise","all","addFeatureResponses","featuresToEdit","newId","featureIdsToDelete","isDeleted","newFeatures","deleteProduct","getDeploymentTypes","deploymentTypeDto","getDailyBTChartDataFromDto","typeOfUsage","chartSeries","label","day","getPropertyByUsageType","getWeeklyBTChartDataFromDto","week","getMonthlyBTChartDataFromDto","month","usage","isManual","distinctManualCheckouts","distinctAutomaticCheckouts","totalManualCheckouts","totalAutomaticCheckouts","avgManualDuration","_","round","totalHours","avgAutomaticDuration","getRawUsage","fromDate","params","toLocaleDateString","responseType","getUsageByDay","initChartRange","getUsageByWeek","getUsageByMonth","increment","first","last","dataClone","isAfter","unshift","isBefore","scrollToRef","currentRef","newScrollPosition","offsetTop","Scroll","scrollTo","duration","isProductionEnvironment","toLowerCase","BTCardsContainerContext","registerCard","cardRegistrationInfo","unregisterCard","cardId","BTCardsContainer","searchText","setSearchText","filteredCards","setFilteredCards","allCards","setAllCards","existingCards","indexOfCardToUnregister","findIndex","copyOfArray","splice","columnsCssClass","numberOfCardsPerRow","groupCards","cards","sortBy","values","groupBy","groupValue","groupKey","reactElements","sortValue","cardElement","setFilteredCardsArray","newSearchText","filteredCardsArray","currCardData","cardMetadata","metadata","groupedCards","getCardsCountString","flatten","filteredCardsTimeout","cleanedUpSearchText","Provider","enableSearch","Input","autoFocus","placeholder","onChange","target","i","indexOfMatchingCard","copyOfFilteredCards","clone","v2","i2","recordsNotFoundMessage","display","BTFloatingIconButton","buttonIcon","getFormErrorMessages","errors","errorMessages","stringValues","getStringValues","val","FormErrorContainer","containerCssClass","uniqueErrorMessages","from","Set","currErrorMessage","FormFooter","BTIconButton","rest","WrappedInput","field","form","hasErrors","showPassword","setShowPassword","classNames","submitCount","inputType","htmlFor","FormTextInput","validator","validate","component","WrappedDropDownList","defaultItem","placeholderText","onChangeHandler","textField","dataItemKey","setFieldValue","isEqual","FormDropDownList","WrappedFormSwitch","newValue","checked","FormSwitch","ForbiddenDomains","Yup","parent","domain","idx","d","createError","path","FormSchema","shape","required","nullable","countryId","of","unique","ClientEditForm","currentDate","domainsInUseByLicenseAdmin","getRegionsForDropdown","options","defaultOptions","regions","region","FormikEffect","connect","onFormChanged","formik","formValues","countries","c","nameValidator","existingClientNames","domainValidator","cleanedUpDomain","existingClientDomains","initialValues","onSubmit","onSaveClick","validationSchema","render","arrayHelpers","remove","onDiscardClick","generateUuid","crypto","getRandomValues","Uint8Array","toString","BTCard","renderCard","Card","CardHeader","cardIcons","currCardIcon","CardBody","getMetadata","ClientListing","isDisabled","onEditClick","onDeleteClick","setMetadata","doesClientOrganizationHaveLicenses","setDoesClientOrganizationHaveLicenses","cardObject","Countries","Regions","ClientsPage","setLicenses","clientToEdit","setClientToEdit","isPageDataLoaded","setIsPageDataLoaded","clients","setClients","setCountries","setRegions","isEditAreaOpen","setIsEditAreaOpen","adminPageEditAreaRef","ClientApi","licensesApiService","clientData","licenseData","hydrateClientOrganization","fetchData","toggleCollapse","open","onFormSave","closeEditAreaAndClearOutEditModel","clientsClone","updatedClients","l","reduce","previousValue","currentValue","concat","discardChanges","WrappedFormDatePicker","onBlur","FormDatePicker","getValueForMultiSelect","fv","WrappedMultiSelect","autoClose","newValues","FormMultiSelect","WrappedNumericTextInput","FormNumericTextInput","typeError","min","max","LicenseEditForm","getDataForFeatures","selectedProductId","selectedProduct","availableProducts","productHasDeploymentType","p","getAdminPlaceholder","selectedClientOrganizationId","selectedClientOrganization","availableClientOrganizations","x","onSubmitClick","allEditModelValues","yupErrors","validateYupSchema","err","yupToFormErrors","validateWithYup","dateErrors","validateDates","clientOrganizationAndProductErrors","existingLicenses","errorMessage","validateClientOrganizationAndProduct","previousErrors","administratorDomain","validateAdministratorEmail","ProductsConstants","DeploymentTypes","LicenseListing","editLicenseButtonClick","deleteLicenseButtonClick","requestDeploymentButtonClick","redeployButtonClick","deploymentInfoAreaIsDisplayed","setDeploymentInfoAreaIsDisplayed","popoverOpen","setPopoverOpen","getDeploymentDetailValueText","deploymentDetailValueObject","isDate","getDeploymentDetailsStringForKey","input","currFeature","getDeploymentStatusCSSClass","getDeploymentStatusText","Popover","placement","toggle","PopoverHeader","PopoverBody","navigator","clipboard","writeText","LicensesPage","setAvailableProducts","setAvailableClientOrganizations","licenseToEdit","setLicenseToEdit","hydrateLicense","productFeature","LicenseApi","ProductApi","licensesData","availableProductsData","clientOrganizationsData","getAndSetLicensesData","licensesClone","newLicenses","currLicense","mapper","list","size","object","string","boolean","array","ProductEditForm","productIds","setProductIds","productNames","setProductNames","feat","ids","existingProducts","names","saveProduct","updatedFeatures","uuidValidator","uuid","RegExp","productIdValidator","featureIdValidator","productIdWasUpdated","featureIdWasUpdated","deploymentTypes","deletedFeature","featureNames","ProductListing","deleteTooltip","disableButtons","onProductEdit","onProductDelete","ProductsPage","setProducts","setDeploymentTypes","productToEdit","setProductToEdit","productsData","deploymentsData","loadProducts","newProducts","updatedProduct","productsClone","productListings","renderProducts","languages","SiteSettingsPage","currentLang","language","selectedLang","setSelectedLang","defaultValue","changeLanguage","date","number","UserEditForm","allUsers","isEmailAddressBeckTech","setIsEmailAddressBeckTech","rolesBeckTechUser","rolesNonBeckTechUser","currEmailAddress","currRoles","emailIsBechTechEmail","newUserRoles","uniqueEmailValidator","UserListing","editUserButtonClick","deleteUserButtonClick","isUserCurrentUser","UsersPage","userToEdit","setUserToEdit","setUsers","UserApi","usersData","loadPageData","newUsers","u","updatedUserObj","indexOfUserToUpdate","newUsersArray","currUser","EstimatorHostedApi","groupIds","configEnvironment","emailOfUserToCopyFrom","emailsOfUsersToCopyTo","emailAddresses","nameof","GridTextCell","dataValue","dataItem","setText","debouncedOnChange","debounce","syntheticEvent","GridDropdownCell","listValues","valueField","listValue","popupSettings","appendTo","listAnchor","GridDropdownFilterCell","filterOperator","operator","stopPropagation","GridMultiSelectCell","lv","TemporaryPasswordModal","Modal","ModalHeader","ModalBody","passwordInfo","info","password","onCopyPasswordClick","HostedConstants","RSMEANS","DPROFILER","BECK_TECH","CreateDatabaseType","costDatabaseConnectionType","costDatabaseConnection","costDatabaseType","database","server","username","DatabaseConnectionFormSection","namePrefix","arrayName","RSMeansConnectionFormSection","DatabaseConnectionSchema","CostDatabaseConnectionSchema","mixed","environment","oneOf","costDatabases","jobsDatabases","getNewEstimatorConfig","EstimatorConfigurationModal","originalConfiguration","setOriginalConfiguration","configuration","setConfiguration","selectedEnvironment","setSelectedEnvironment","selectedCostDatabaseConnectionType","setSelectedCostDatabaseConnectionType","onEnvironmentDropdownChange","getConfigForUser","closeModal","evt","item","FormSection","EstimatorCopyConfigurationModal","initialFormData","userGroups","getUsersFromFormData","formData","group","displayName","AddUsersModal","colClassNames","sortUsers","EstimatorHostedUserManagementPage","isLoading","setIsLoading","setClientOrgs","setUserGroups","logic","filters","setFilter","showAddUsersModal","setShowAddUsersModal","tempPasswordInfo","setTemporaryPasswordInfo","estimatorConfigState","setEstimatorConfigState","userToCopyConfigFrom","setUserToCopyConfigFrom","gridContainer","filteredUsers","filterBy","selectedUsers","selected","ClientOrganizationsApi","getGroups","groups","hostedUsers","gridUsers","inEdit","loadData","saveUsers","passwordInfoToDisplay","failedUsers","newUser","usersClone","temporaryPassword","updateUser","onAddUsersSaveClick","onAddUsersDiscardClick","linesToCopy","copyText","getEstimatorConfigForUser","onEstimatorConfigSaveClick","originalConfig","updatedConfig","saveEstimatorConfigForUser","onEsimatorCopyConfigSaveClick","displayError","copyEstimatorConfigToUsers","isUserValid","isEmptyString","viewEditEstimatorConfigClick","copyEstimatorConfigClick","onResetPasswordClick","resetPassword","resetUserPassword","tempPassword","removeNewUser","getUserByEmail","savedUser","uneditedUser","resetUser","nameCell","gcp","clientOrgCell","co","clientOrgFilterCell","gfcp","groupCell","groupId","g","groupFilterCell","editField","onItemChange","editedUser","selectedField","onSelectionChange","onHeaderSelectionChange","checkbox","filteredUser","filterable","onFilterChange","headerSelectionValue","editable","cell","filterCell","width","SvgImage","image","getSizeClass","basket","bulb","certificate","clock","estimator","exclamation","stop","tools","users2","verifiedCheck","getSvgImage","GenericErrorPage","PageNotFoundPage","UnauthorizedPage","pageIsDisplayed","setPageIsDisplayed","checkUserAuthenticationStatus","LinksConstants","BeckTechWebsite","BeckTechCommunityWebsite","EstimatorWebsite","HomePage","allLinkCollections","setAllLinkCollections","websiteUrlCommunity","newLinks","svgImage","generateLinksCollections","href","currLinkCollection","currCard","LoginPage","websiteUrl","estimatorWebsite","getUrlForDisplay","saveFile","arrayBuffer","fileType","byteArray","blob","Blob","getFileMimeType","msSaveOrOpenBlob","URL","createObjectURL","link","createElement","download","click","revokeObjectURL","Increments","Day","Week","Month","ProductOptions","All","None","ReportFilterConstants","FILTERINCREMENT_DAY","FILTERINCREMENT_WEEK","FILTERINCREMENT_MONTH","FILTERINCREMENT_DEFAULT_INCREMENTS","PRODUCTOPTION_ALL_PRODUCTS","PRODUCTOPTION_NO_PRODUCTS","Settings","colors","blue","red","chartAreaCeiling","chartAreaFloor","ChartDefaults","getChartCategoryAxisItem","baseUnit","maxDivisions","defaultTooltipRender","point","category","LicenseUsageChart","usageFilters","appliedFilters","specificFilters","position","orientation","cs","aggregate","categoryField","LicenseCheckoutsChart","checkoutFilters","LicenseDurationChart","durationFilters","dateFormat","tooltipLabel","customTooltipRender","ReportsPageCustomChart","exact","ReportNames","applyPartialDateRangeRules","isFromDate","newMomentObj","startOf","endOf","LicenseUsageFilter","reportFilters","usageReportFilters","setReportDataSource","setSpecificReportFilters","setCalendarType","updateReportDataSource","UsageApi","calendarType","updateReportFilterValues","LicenseDurationFilter","durationReportFilters","LicenseCheckoutsFilter","checkoutsReportFilters","RawDataFilter","ReportsPageCustomFilters","allSpecificReportFilters","rawDataReportFilters","ReportsPageFilters","items","availableClients","getProductsForClient","setReportFilters","resetAllDatePickers","defaultToDate","defaultFromDate","resetToDatePicker","resetFromDatePicker","currClient","getProductsForDropdown","currProduct","momentObj","year","ReportsPageReportsListing","availableReports","currReport","reportName","ReportNameRouteMappings","generateReportFiltersObject","localStorageReportFilters","localStorageReportFiltersBase","cachedClientId","cachedProductId","add","saveReportFiltersToLocalStorage","newReportFilters","ReportsPage","location","useLocation","customChartRef","currentChartData","setCurrentChartData","setAvailableClients","clientProductsCache","setClientProductsCache","setAllSpecificReportFilters","allReportsData","setAllReportsData","allReportDataSources","setAllReportDataSources","isLoadingData","setIsLoadingData","chartDataErrorOccurred","setChartDataErrorOccurred","addAllProductsOption","clientProducts","addNoProductsOption","checkAndUpdateProductOptions","updateClientProductsCache","pathname","allProducts","updatedReportFilters","getChartData","currReportDataSource","reportsData","chartData","baseFilters","specificReportFilters","setSpecificReportDataSource","reportDataSource","dataSources","reportFiltersBase","loadProductData","getProduct","cachedProducts","getChartDataAsync","removeItem","baseUrl","getElementsByTagName","getAttribute","browserHistory","createBrowserHistory","basename","reactPlugin","ReactPlugin","instrumentationKey","ApplicationInsights","extensions","extensionConfig","identifier","loadAppInsights","App","setLocale","urlContainsSSOHashData","setUrlContainsSSOHashData","allInitialDataIsLoaded","setAllInitialDataIsLoaded","passwordResetInProgress","setPasswordResetInProgress","lastLocationValue","envName","toUpperCase","ssoPasswordResetCompleted","authTokenFromLocalStorage","accessTokenFromLocalStorage","isTokenExpirationValid","validateTokens","logUserOutAndClearInformation","handleSSOErrors","ssoErrorObj","handleSSOPasswordResetLogic","ssoPasswordResetInitiated","initializePasswordReset","handleAccessTokenError","accessTokenError","urlContainsSSOHash","prototype","urlContainsHash","hash","initializeSignIn","usersApiService","userInfoFromToken","getUserInfoFromAccessToken","parsedUserInfo","onLanguageChanged","lang","on","library","faChartArea","faChevronDown","faClock","faClone","faCog","faCopy","faDatabase","faEdit","faEye","faEyeSlash","faFileAlt","faIdCard","faKey","faLightbulb","faPlus","faSave","faSearch","faServer","faShoppingBasket","faSignOutAlt","faTable","faTimes","faTrash","faUndo","faUsers","faWrench","axiosMiddleware","withAITracking","LoadingIndicator","LoadingPageOverlay","load","weekData","frCaGeneric","frCaGregorian","frCaDateFields","frCaTimeZoneNames","initReactI18next","init","resources","getInitialTranslations","lng","interpolation","escapeValue","toLocaleString","Boolean","hostname","match","rootElement","getElementById","ReactDOM","setPageLoadingOverlayDisplayInfo","setQueuedNotifications","addNotificationToQueue","existingNotifications","copyOfQueuedNotifications","firstElementInArray","shift","setConfirmationOverlayDisplayInfo","setUserInformation","serviceWorker","ready","then","registration","unregister"],"mappings":"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","file":"static/js/main.1bfd1e64.chunk.js","sourcesContent":["module.exports = __webpack_public_path__ + \"static/media/basket.c4f5f274.svg\";","module.exports = __webpack_public_path__ + \"static/media/bulb.b029f5db.svg\";","module.exports = __webpack_public_path__ + \"static/media/certificate.a5b119e8.svg\";","module.exports = __webpack_public_path__ + \"static/media/clock.9075e2c7.svg\";","module.exports = __webpack_public_path__ + \"static/media/database.8f4193d8.svg\";","module.exports = __webpack_public_path__ + \"static/media/error.406d70ca.svg\";","module.exports = __webpack_public_path__ + \"static/media/exclamation.4e0bb1a4.svg\";","module.exports = __webpack_public_path__ + \"static/media/key.b6870872.svg\";","module.exports = __webpack_public_path__ + \"static/media/estimator.bb407f73.svg\";","module.exports = __webpack_public_path__ + \"static/media/stop.a94a5955.svg\";","module.exports = __webpack_public_path__ + \"static/media/tools.ff27b352.svg\";","module.exports = __webpack_public_path__ + \"static/media/users.d1d51217.svg\";","module.exports = __webpack_public_path__ + \"static/media/users2.4b8afc90.svg\";","module.exports = __webpack_public_path__ + \"static/media/verified-check.24460d3b.svg\";","var map = {\n\t\"./general.json\": 250,\n\t\"./reporting.json\": 251\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 = 249;","var map = {\n\t\"./general.json\": 253,\n\t\"./reporting.json\": 254\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 = 252;","import * as Msal from 'msal';\r\nimport { Configuration } from 'msal';\r\nimport LocalStorageKeys from '../../constants/local-storage';\r\nimport { getConfig } from '../../utils/config';\r\n\r\nconst { localStorage } = window;\r\n\r\nexport enum SSOErrorCode {\r\n OtherError = 1,\r\n LicensingAppSSOError = 2,\r\n}\r\n\r\nexport interface SSOError {\r\n message: string;\r\n code: SSOErrorCode;\r\n}\r\n\r\nexport interface AccessTokenUserInfo {\r\n name: string;\r\n emailAddress: string;\r\n}\r\n\r\nexport class AuthenticationService {\r\n public static msalObj: Msal.UserAgentApplication;\r\n private static scope = getConfig('REACT_APP_MSAL_SCOPE') as string;\r\n private static clientId = getConfig('REACT_APP_MSAL_CLIENTID') as string;\r\n private static signInAuthority = getConfig('REACT_APP_MSAL_AUTHORITY_SIGNIN') as string;\r\n private static passwordResetAuthority = getConfig(\r\n 'REACT_APP_MSAL_AUTHORITY_PASSWORDRESET',\r\n ) as string;\r\n private static redirectUri = getConfig('REACT_APP_MSAL_REDIRECT_URL') as string;\r\n private static cacheLocation = 'localStorage' as ('localStorage' | 'sessionStorage' | undefined);\r\n\r\n private static requestObj = {\r\n scopes: [AuthenticationService.scope],\r\n };\r\n\r\n private static signInConfig: Configuration = {\r\n auth: {\r\n clientId: AuthenticationService.clientId,\r\n authority: AuthenticationService.signInAuthority,\r\n validateAuthority: false,\r\n redirectUri: AuthenticationService.redirectUri,\r\n postLogoutRedirectUri: AuthenticationService.redirectUri,\r\n },\r\n cache: {\r\n cacheLocation: AuthenticationService.cacheLocation,\r\n storeAuthStateInCookie: true,\r\n },\r\n };\r\n\r\n private static passwordResetConfig: Configuration = {\r\n auth: {\r\n clientId: AuthenticationService.clientId,\r\n authority: AuthenticationService.passwordResetAuthority,\r\n validateAuthority: false,\r\n redirectUri: AuthenticationService.redirectUri,\r\n },\r\n cache: {\r\n cacheLocation: AuthenticationService.cacheLocation,\r\n storeAuthStateInCookie: true,\r\n },\r\n };\r\n\r\n public static initializeSignIn(): void {\r\n this.msalObj = new Msal.UserAgentApplication(this.signInConfig);\r\n this.setAuthRedirectCallBack();\r\n }\r\n\r\n public static initializePasswordReset(): void {\r\n this.msalObj = new Msal.UserAgentApplication(this.passwordResetConfig);\r\n this.setAuthRedirectCallBack();\r\n }\r\n\r\n // Note: The loginRedirect() method uses the currently configured 'authority' property on the\r\n // msalObj to know whether to navigate to a sign-in or password reset b2c form\r\n public static navigateToSignInOrPasswordReset(): void {\r\n this.msalObj.loginRedirect(this.requestObj);\r\n }\r\n\r\n // Note: The msalObj.logout() method redirects to an SSO logout page so it can clear cookies for that domain, then redirects back to our app\r\n public static logout(): void {\r\n localStorage.clear();\r\n this.msalObj.logout();\r\n }\r\n\r\n public static async getAccessToken(): Promise {\r\n if (this.msalObj.getAccount()) {\r\n try {\r\n const response = await this.msalObj.acquireTokenSilent(this.requestObj);\r\n localStorage.setItem(LocalStorageKeys.AccessToken, response.accessToken);\r\n return true;\r\n } catch (error) {\r\n // NOTE: We do nothing here and let the code continue on and return false\r\n }\r\n }\r\n\r\n return false;\r\n }\r\n\r\n public static isTokenExpirationValid(jwtToken: string): boolean {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const parsedToken: any = AuthenticationService.parseJwtToken(jwtToken);\r\n if (parsedToken && parsedToken.exp) {\r\n // NOTE: The expiration should be a number but parse it as one just in case, or else the logic below will not work correctly\r\n const jwtTokenExpiration = parseInt(parsedToken.exp);\r\n\r\n // NOTE: The expiration date on a JWT token is the date as a number of seconds, NOT milliseconds so we have to adjust it\r\n const tokenExpirationAsDate = new Date(jwtTokenExpiration * 1000);\r\n return new Date() < tokenExpirationAsDate;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n public static getUserInfoFromAccessToken(jwtToken: string): AccessTokenUserInfo | null {\r\n try {\r\n const parsedToken = this.parseJwtToken(jwtToken);\r\n // NOTE: We only require that the email be present\r\n if (parsedToken && parsedToken.email) {\r\n return {\r\n emailAddress: parsedToken.email,\r\n name: parsedToken.name || 'User',\r\n };\r\n }\r\n } catch {}\r\n\r\n return null;\r\n }\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n private static parseJwtToken(jwtToken: string): any | null {\r\n try {\r\n return JSON.parse(atob(jwtToken.split('.')[1]));\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n private static setAuthRedirectCallBack(): void {\r\n this.msalObj.handleRedirectCallback(\r\n (error: Msal.AuthError, response?: Msal.AuthResponse): void => {\r\n if (error) {\r\n // NOTE: There are 3 error codes that require user interaction so we want to redirect the user to\r\n // the SSO login page if this is the case.\r\n // https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-handling-exceptions?tabs=javascript\r\n if (\r\n ['consent_required', 'interaction_required', 'login_required'].includes(error.errorCode)\r\n ) {\r\n this.navigateToSignInOrPasswordReset();\r\n return;\r\n }\r\n\r\n // If we have received an error code, we set necessary local storage\r\n error.message = error.message || '';\r\n if (error.message.indexOf('AADB2C90118') > -1) {\r\n // If we received the password reset error code, set a local storage variable\r\n localStorage.setItem(LocalStorageKeys.SSOPasswordResetInitiated, 'true');\r\n } else if (error.message.indexOf('AADB2C90091') > -1) {\r\n // Else if we received the password reset cancelled error code, we don't need to do anything and can return early\r\n return;\r\n } else {\r\n // Else we set an SSOError based on the error code received\r\n this.setSSOErrors(error.message);\r\n }\r\n } else {\r\n if (response) {\r\n // NOTE: The token claim below indicates that a password change has been completed.\r\n // If it exists, we create a localStorage variable for other code to use.\r\n if (\r\n response.idTokenClaims &&\r\n response.idTokenClaims.acr &&\r\n response.idTokenClaims.acr === 'b2c_1a_passwordreset'\r\n ) {\r\n localStorage.setItem(LocalStorageKeys.SSOPasswordResetCompleted, 'true');\r\n }\r\n const token = response.idToken;\r\n if (token) {\r\n localStorage.setItem(LocalStorageKeys.AuthToken, token.rawIdToken);\r\n localStorage.setItem(LocalStorageKeys.UserName, response.account.name);\r\n return;\r\n }\r\n }\r\n }\r\n },\r\n );\r\n }\r\n\r\n // If SSO errors come into our app, they come in as a URL hash.\r\n // This code will read the errors and then set a local storage variable.\r\n // The MSAL code will then run, strip the hash off the URL, and refresh the page.\r\n private static setSSOErrors(errorDescription: string): void {\r\n let errorCode = SSOErrorCode.OtherError;\r\n\r\n // Certain error codes will need to be handled differently, so here we set an enum value based on the error received\r\n if (errorDescription.indexOf('AADB2C') > -1) {\r\n errorCode = SSOErrorCode.LicensingAppSSOError;\r\n }\r\n\r\n // A typical error message might look as follows so we want to clean it up to make the error message more user-friendly:\r\n // AADB2C: No matching ogranization for 'destiniestimatordev.onmicrosoft.com'\r\n // Correlation ID: be38782a-e576-437e-b449-190ec9756c5e\r\n // Timestamp: 2020-02-11 18:05:50Z\r\n errorDescription = errorDescription.replace(/(\\r\\n|\\r|\\n)/g, '').trim();\r\n errorDescription = errorDescription.replace(/^[\\w]+:/g, '').trim();\r\n errorDescription = errorDescription.replace(/Correlation ID.*$/gi, '').trim();\r\n\r\n // If the error message doesn't have a period at the end, add one\r\n if (!/\\.$/.test(errorDescription)) {\r\n errorDescription += '.';\r\n }\r\n\r\n const ssoError: SSOError = {\r\n message: errorDescription || 'Sorry, but an error occurred.',\r\n code: errorCode,\r\n };\r\n\r\n localStorage.setItem(LocalStorageKeys.SSOError, JSON.stringify(ssoError));\r\n }\r\n}\r\n","const LocalStorageKeys = {\n AccessToken: 'accessToken',\n AccessTokenError: 'accessTokenError',\n AuthToken: 'authToken',\n SSOError: 'SSOError',\n SSOPasswordResetCompleted: 'ssoPasswordResetCompleted',\n SSOPasswordResetInitiated: 'ssoPasswordResetInitiated',\n UserInformation: 'userInformation',\n UserName: 'userName',\n};\n\nexport default LocalStorageKeys;\n","const ADMIN_ROOT = 'admin';\n\n// NOTE: When creating 'full' routes, we use an empty string as the first element in the array we are concatenating so we get a leading forward slash\nconst AdminRoutes = {\n Clients: ['', ADMIN_ROOT, 'clients'].join('/'),\n Products: ['', ADMIN_ROOT, 'products'].join('/'),\n Licenses: ['', ADMIN_ROOT, 'licenses'].join('/'),\n SiteSettings: ['', ADMIN_ROOT, 'settings'].join('/'),\n Users: ['', ADMIN_ROOT, 'users'].join('/'),\n EstimatorHostedUserManagement: ['', ADMIN_ROOT, 'estimator-hosted-user-management'].join('/'),\n};\n\nexport default AdminRoutes;\n","// NOTE: When creating 'full' routes, we use an empty string as the first element in the array we are concatenating so we get a leading forward slash\nconst ErrorRoutes = {\n Error: ['', 'error'].join('/'),\n PageNotFound: ['', 'page-not-found'].join('/'),\n Unauthorized: ['', 'unauthorized'].join('/'),\n};\n\nexport default ErrorRoutes;\n","const REPORTS_ROOT = 'reports';\r\n\r\nconst ReportRoutes = {\r\n Base: ['', REPORTS_ROOT].join('/'),\r\n UsageReport: ['', REPORTS_ROOT, 'usage'].join('/'),\r\n Checkouts: ['', REPORTS_ROOT, 'checkouts'].join('/'),\r\n Duration: ['', REPORTS_ROOT, 'duration'].join('/'),\r\n RawData: ['', REPORTS_ROOT, 'raw-data'].join('/'),\r\n};\r\n\r\nexport default ReportRoutes;\r\n","import AdminRoutes from './admin-routes';\nimport ErrorRoutes from './error-routes';\nimport ReportRoutes from './reports-routes';\n\nconst SITE_ROOT = '/';\nconst HOME = '/home';\n\nconst ApplicationRoutes = {\n SITE_ROOT,\n HOME,\n ADMIN_CLIENTS: AdminRoutes.Clients,\n ADMIN_PRODUCTS: AdminRoutes.Products,\n ADMIN_LICENSES: AdminRoutes.Licenses,\n ADMIN_USERS: AdminRoutes.Users,\n ADMIN_ESTIMATORHOSTED_USERMANAGEMENT: AdminRoutes.EstimatorHostedUserManagement,\n ADMIN_SITESETTINGS: AdminRoutes.SiteSettings,\n ERROR_ERROR: ErrorRoutes.Error,\n ERROR_PAGENOTFOUND: ErrorRoutes.PageNotFound,\n ERROR_UNAUTHORIZED: ErrorRoutes.Unauthorized,\n REPORTS: ReportRoutes.Base,\n REPORTS_USAGE: ReportRoutes.UsageReport,\n REPORTS_DURATION: ReportRoutes.Duration,\n REPORTS_CHECKOUTS: ReportRoutes.Checkouts,\n REPORTS_RAWDATA: ReportRoutes.RawData,\n};\n\nexport default ApplicationRoutes;\n","const UserRolesValues = {\n ClientUser: 'ClientUser',\n InternalUser: 'InternalUser',\n Admin: 'Admin',\n BidDaySupport: 'BidDaySupport',\n};\n\nconst UserRolesDisplayNames = {\n ClientUser: 'Client User',\n InternalUser: 'Internal User',\n Admin: 'Admin',\n BidDaySupport: 'Bid Day Support',\n};\n\nexport { UserRolesValues, UserRolesDisplayNames };\n","import { UserRolesDisplayNames, UserRolesValues } from './user-roles';\n\nconst UserConstants = {\n UserRolesValues: {\n CLIENTUSER: UserRolesValues.ClientUser,\n INTERNALUSER: UserRolesValues.InternalUser,\n ADMIN: UserRolesValues.Admin,\n BIDDAYSUPPORT: UserRolesValues.BidDaySupport,\n },\n UserRolesDisplayNames: {\n CLIENTUSER: UserRolesDisplayNames.ClientUser,\n INTERNALUSER: UserRolesDisplayNames.InternalUser,\n ADMIN: UserRolesDisplayNames.Admin,\n BIDDAYSUPPORT: UserRolesDisplayNames.BidDaySupport,\n },\n};\n\nexport default UserConstants;\n","const getConfig = (key: string): string | undefined => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const env = (window as any).ENV;\n const configVal = env && env[key];\n\n if (configVal) {\n return configVal;\n }\n\n return process.env[key];\n};\n\nexport { getConfig };\n","import moment from 'moment';\r\nimport { cloneDeep } from 'lodash';\r\n\r\nconst getShortDateString = (dateObj: Date): string => {\r\n // NOTE: converting to UTC here because a timezone conversion would give us the wrong date\r\n // NOTE: The \"L\" date format uses the user's locale for the date format\r\n return moment.utc(dateObj).format('L');\r\n};\r\n\r\n// NOTE: using `any` here because of metaprogramming\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nconst getObjectWithDateStringsAsDates = (data: any): any => {\r\n const result = cloneDeep(data);\r\n\r\n if (Array.isArray(data)) {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const resultArray = result as any[];\r\n return resultArray.map(r => getObjectWithDateStringsAsDates(r));\r\n }\r\n\r\n for (const key in result) {\r\n const value = result[key];\r\n\r\n if (typeof value === 'object') {\r\n result[key] = getObjectWithDateStringsAsDates(value);\r\n continue;\r\n }\r\n\r\n const dateValue = moment(value, moment.ISO_8601);\r\n\r\n if (!dateValue.isValid()) {\r\n continue;\r\n }\r\n\r\n result[key] = dateValue.toDate();\r\n }\r\n\r\n return result;\r\n};\r\n\r\nexport { getShortDateString, getObjectWithDateStringsAsDates };\r\n","import axios from 'axios';\nimport LocalStorageKeys from '../constants/local-storage';\nimport { AuthenticationService } from '../services/authentication/authentication-service';\nimport { getObjectWithDateStringsAsDates } from '../utils/dates';\nimport { getConfig } from '../utils/config';\n\nconst enableDateStringToDateResponseMiddleware = (): void => {\n axios.interceptors.response.use(response => {\n if (response && response.data) {\n response.data = getObjectWithDateStringsAsDates(response.data);\n }\n return response;\n });\n\n axios.interceptors.request.use(request => {\n // Attach the authorization headers if they're present\n const accessToken = localStorage.getItem(LocalStorageKeys.AccessToken);\n if (accessToken) {\n request.headers['Authorization'] = `Bearer ${accessToken}`;\n request.headers['Content-Type'] = 'application/json';\n }\n\n request.headers['api-version'] = getConfig('REACT_APP_API_VERSION');\n\n return request;\n });\n\n // Handle 401 responses\n axios.interceptors.response.use(\n async response => response,\n async error => {\n // NOTE: If there was an error and it wasn't from the server (ex. network issues), we want to explicitly\n // throw an exception, otherwise Axios will just return whatever we return from this callback function to\n // the calling code as a regular HTTP response.\n if (error && error.isAxiosError) {\n throw error;\n }\n\n if (error && error.response && error.response.status === 401) {\n try {\n // Try to refresh the access token and retry the AJAX call\n const accessTokenWasAcquired = await AuthenticationService.getAccessToken();\n\n if (!accessTokenWasAcquired) {\n // NOTE: This will trigger a browser redirect\n AuthenticationService.logout();\n return error;\n }\n\n // Now that we have an access token, try to redo the AJAX call without using Axios so we don't trigger this error handler again\n // if we get another 401 response.\n // NOTE: Fetch will not throw an error for error HTTP codes such as 401.\n\n // The AuthenticationService.getAccessToken() call will set the new access token in local storage\n const accessToken = localStorage.getItem(LocalStorageKeys.AccessToken);\n if (!accessToken) {\n // Throw an error so it gets caught below\n throw new Error();\n }\n\n const originalHttpConfig = error.response.config;\n\n const retryResult = await fetch(\n new Request(originalHttpConfig.url, {\n method: originalHttpConfig.method,\n headers: {\n ...originalHttpConfig.headers,\n Authorization: `Bearer ${accessToken}`,\n },\n mode: 'cors',\n cache: 'default',\n }),\n );\n\n if (retryResult.status === 401) {\n // If we got a 401 again, throw an error so it gets caught below\n throw new Error();\n }\n\n return retryResult;\n } catch {\n // NOTE: This will actually trigger a browser redirect\n AuthenticationService.logout();\n return error;\n }\n }\n },\n );\n};\n\nexport default { enableDateStringToDateResponseMiddleware };\n","import React, { useCallback, useState } from 'react';\r\nimport NotificationPanel from './NotificationPanel';\r\n\r\nexport interface NotificationPanelMessage {\r\n title: string;\r\n message: string;\r\n type: NotificationPanelTypes;\r\n}\r\n\r\nexport enum NotificationPanelTypes {\r\n Success = 1,\r\n Error = 2,\r\n Info = 3,\r\n}\r\n\r\nconst NotificationPanelContext = React.createContext({\r\n popFirstQueuedNotification: (): NotificationPanelMessage | null => null,\r\n showSuccessNotification: (title: string, message: string) => {},\r\n showErrorNotification: (title: string, message: string) => {},\r\n showInfoNotification: (title: string, message: string) => {},\r\n});\r\n\r\nconst NotificationPanelContextProvider: React.FC<{}> = props => {\r\n const [queuedNotifications, setQueuedNotifications] = useState([]);\r\n\r\n const addNotificationToQueue = useCallback(\r\n (title: string, message: string, type: NotificationPanelTypes): void => {\r\n // Use the state updater callback pattern so we don't have any dependencies for useCallback\r\n setQueuedNotifications(existingNotifications => {\r\n // Do not allow duplicate messages\r\n if (\r\n existingNotifications.some(\r\n v => v.type === type && v.title === title && v.message === message,\r\n )\r\n ) {\r\n return existingNotifications;\r\n }\r\n\r\n return [\r\n ...existingNotifications,\r\n {\r\n title: title,\r\n message: message,\r\n type: type,\r\n },\r\n ];\r\n });\r\n },\r\n [],\r\n );\r\n\r\n const popFirstQueuedNotification = useCallback((): NotificationPanelMessage | null => {\r\n if (queuedNotifications.length > 0) {\r\n // NOTE: Shift() mutates the array so we want to make a copy of the array and mutate that, and then set the state\r\n const copyOfQueuedNotifications = [...queuedNotifications];\r\n const firstElementInArray = copyOfQueuedNotifications.shift() as NotificationPanelMessage;\r\n setQueuedNotifications(copyOfQueuedNotifications);\r\n return firstElementInArray;\r\n }\r\n\r\n return null;\r\n }, [queuedNotifications]);\r\n\r\n const showSuccessNotification = useCallback(\r\n (title: string, message: string): void => {\r\n addNotificationToQueue(title, message, NotificationPanelTypes.Success);\r\n },\r\n [addNotificationToQueue],\r\n );\r\n\r\n const showErrorNotification = useCallback(\r\n (title: string, message: string): void => {\r\n addNotificationToQueue(title, message, NotificationPanelTypes.Error);\r\n },\r\n [addNotificationToQueue],\r\n );\r\n\r\n const showInfoNotification = useCallback(\r\n (title: string, message: string): void => {\r\n addNotificationToQueue(title, message, NotificationPanelTypes.Info);\r\n },\r\n [addNotificationToQueue],\r\n );\r\n\r\n return (\r\n <>\r\n \r\n \r\n\r\n {props.children}\r\n \r\n \r\n );\r\n};\r\n\r\nexport { NotificationPanelContext, NotificationPanelContextProvider };\r\n","export interface Import {\n name: string;\n translations: Dictionary;\n}\n\nconst getFileNameWithoutExtension = (fileName: string): string => {\n return fileName\n .slice(2) // remove starting ./\n .replace(/\\.[^/.]+$/, ''); // remove file extension\n};\n\n// NOTE: webpack defines a global context rather than a module so we must fully qualify the type\nconst importAll = (requireContext: __WebpackModuleApi.RequireContext): Import[] => {\n return requireContext.keys().map(\n (fileName): Import => ({\n name: getFileNameWithoutExtension(fileName),\n translations: requireContext(fileName),\n }),\n );\n};\n\nexport { importAll };\n","import i18n from 'i18next';\nimport moment from 'moment';\nimport { importAll, Import } from '../utils/imports';\n\nexport const DEFAULT_LANG = 'en-US';\n\nexport const TranslationFilesMap: Dictionary<() => Import[]> = {\n 'en-US': () => importAll(require.context('./translations/en-US', false, /\\.json$/i)),\n 'fr-CA': () => importAll(require.context('./translations/fr-CA', false, /\\.json$/i)),\n};\n\nexport const loadTranslationsForLocale = (locale: string): void => {\n const getTranslationsFunc = TranslationFilesMap[locale] as () => Import[];\n\n if (!getTranslationsFunc) {\n throw new Error(\n `Could not find translations for locale \"${locale}\". Verify that they are added to \"translationFilesMap\" in \"i18n.ts\"`,\n );\n }\n\n const translationFiles = getTranslationsFunc();\n\n translationFiles.forEach(translationFile => {\n i18n.addResourceBundle(locale, translationFile.name, translationFile.translations);\n });\n};\n\n// NOTE: This function declaration is defined by i18n so we must abide by their types\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const format = (value: any, format?: string, lng?: string): string => {\n if (value instanceof Date) {\n if (!lng) {\n throw new Error('`lng` must have a value for date formatting');\n }\n\n const date = moment(value).locale(lng);\n\n if (format === 'shortDate') {\n return date.format('L');\n } else if (format === 'longDate') {\n return date.format('LL');\n }\n\n return date.toString();\n }\n\n if (typeof value === 'number') {\n const num = value as number;\n\n if (format === 'numberFormat') {\n return num.toLocaleString(lng);\n }\n }\n\n return value.toString();\n};\n","import { getConfig } from '../../utils/config';\r\n\r\nconst API_URL = getConfig('REACT_APP_API_URL');\r\n\r\nconst ApiRoutes = {\r\n Clients: [API_URL, 'api', 'clientorganizations'].join('/'),\r\n ClientByEmail: [API_URL, 'api', 'clientorganizations', 'by-email'].join('/'),\r\n Products: [API_URL, 'api', 'products'].join('/'),\r\n ProductsByClient: [API_URL, 'api', 'products', 'by-client-id'].join('/'),\r\n Licenses: [API_URL, 'api', 'licenses'].join('/'),\r\n Users: [API_URL, 'api', 'users'].join('/'),\r\n EstimatorHostedUsers: [API_URL, 'api', 'estimator-hosted', 'users'].join('/'),\r\n EstimatorHostedGroups: [API_URL, 'api', 'estimator-hosted', 'groups'].join('/'),\r\n Usage: [API_URL, 'api', 'usage'].join('/'),\r\n Raw: [API_URL, 'api', 'usage', 'raw'].join('/'),\r\n UsageByDay: [API_URL, 'api', 'usage', 'by-day'].join('/'),\r\n UsageByWeek: [API_URL, 'api', 'usage', 'by-week'].join('/'),\r\n UsageByMonth: [API_URL, 'api', 'usage', 'by-month'].join('/'),\r\n DurationByDay: [API_URL, 'api', 'usage', 'duration-by-day'].join('/'),\r\n DurationByWeek: [API_URL, 'api', 'usage', 'duration-by-week'].join('/'),\r\n DurationByMonth: [API_URL, 'api', 'usage', 'duration-by-month'].join('/'),\r\n};\r\n\r\nexport default ApiRoutes;\r\n","import UserConstants from '../../../constants/users';\r\n\r\nexport interface UserDto {\r\n emailAddress: string;\r\n id: string;\r\n isBeckTechUser: boolean;\r\n name?: string;\r\n roles: string[];\r\n}\r\n\r\n// NOTE: Right now we are not returning everything from the API and must populate later\r\nexport const getUserFromDto = (userDto: UserDto): User => {\r\n const user: User = {\r\n id: userDto.id,\r\n isNew: false,\r\n emailAddress: userDto.emailAddress,\r\n isBeckTechUser: userDto.isBeckTechUser,\r\n roles: userDto.roles\r\n .map((currRole): UserRole | null => {\r\n switch (currRole) {\r\n case UserConstants.UserRolesValues.ADMIN:\r\n return {\r\n id: UserConstants.UserRolesValues.ADMIN,\r\n name: UserConstants.UserRolesDisplayNames.ADMIN,\r\n };\r\n case UserConstants.UserRolesValues.INTERNALUSER:\r\n return {\r\n id: UserConstants.UserRolesValues.INTERNALUSER,\r\n name: UserConstants.UserRolesDisplayNames.INTERNALUSER,\r\n };\r\n case UserConstants.UserRolesValues.CLIENTUSER:\r\n return {\r\n id: UserConstants.UserRolesValues.CLIENTUSER,\r\n name: UserConstants.UserRolesDisplayNames.CLIENTUSER,\r\n };\r\n case UserConstants.UserRolesValues.BIDDAYSUPPORT:\r\n return {\r\n id: UserConstants.UserRolesValues.BIDDAYSUPPORT,\r\n name: UserConstants.UserRolesDisplayNames.BIDDAYSUPPORT,\r\n };\r\n default:\r\n return null;\r\n }\r\n })\r\n .filter(v => v)\r\n .map(v => v!),\r\n };\r\n\r\n return user;\r\n};\r\n\r\nexport const getUserDtoFromUser = (user: User): UserDto => {\r\n return {\r\n emailAddress: user.emailAddress,\r\n id: user.id!,\r\n roles: user.roles.map(v => v.id),\r\n isBeckTechUser: user.isBeckTechUser,\r\n };\r\n};\r\n","import axios from 'axios';\r\nimport ApiRoutes from '../../../constants/routes/api-routes';\r\nimport { getUserDtoFromUser, getUserFromDto, UserDto } from './users-api-service-helper';\r\n\r\nconst getUser = async (): Promise => {\r\n const response = await axios.get(`${ApiRoutes.Users}/current-user`);\r\n const dto: UserDto = response.data;\r\n\r\n const user: User = getUserFromDto(dto);\r\n return user;\r\n};\r\n\r\nconst getUsers = async (): Promise => {\r\n const response = await axios.get(ApiRoutes.Users);\r\n const dtos: UserDto[] = response.data;\r\n\r\n const users: User[] = dtos.map(dto => getUserFromDto(dto));\r\n return users;\r\n};\r\n\r\nconst addUser = async (user: User): Promise => {\r\n const userDto = getUserDtoFromUser(user);\r\n const response = await axios.post(`${ApiRoutes.Users}`, userDto);\r\n const dto: UserDto = response.data;\r\n return getUserFromDto(dto);\r\n};\r\n\r\nconst editUser = async (user: User): Promise => {\r\n const userDto = getUserDtoFromUser(user);\r\n await axios.put(`${ApiRoutes.Users}/${user.id}`, userDto);\r\n};\r\n\r\nconst deleteUser = async (userId: string): Promise => {\r\n await axios.delete(`${ApiRoutes.Users}/${userId}`);\r\n};\r\n\r\nexport default { getUser, getUsers, addUser, editUser, deleteUser };\r\n","import { UserInformation } from '../app/UserInformationContext';\nimport LocalStorageKeys from '../constants/local-storage';\n\nconst isUserAuthenticated = (userInformation: UserInformation): boolean => {\n // TODO - wire this up for real\n return userInformation && (userInformation.name || '').length > 0;\n};\n\nconst isUserAuthorized = (userInformation: UserInformation, userRole: string): boolean => {\n // We require that a user has explicit roles for various things (ie. An \"Admin\" role does\n // not give the user access to everything)\n return userInformation && userInformation.userRoles.find(v => v.id === userRole) !== undefined;\n};\n\nconst populateUserInformationFromLocalStorage = (): UserInformation | null => {\n const userInfoJSONFromLocalStorage = localStorage.getItem(LocalStorageKeys.UserInformation);\n\n if (userInfoJSONFromLocalStorage) {\n try {\n const userInfoFromLocalStorage: UserInformation = JSON.parse(userInfoJSONFromLocalStorage);\n if (userInfoFromLocalStorage && userInfoFromLocalStorage.name) {\n return userInfoFromLocalStorage;\n }\n } catch (error) {}\n }\n\n return null;\n};\n\nexport { isUserAuthenticated, isUserAuthorized, populateUserInformationFromLocalStorage };\n","import { IconProp } from '@fortawesome/fontawesome-svg-core';\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\r\nimport React from 'react';\r\nimport { Button } from 'reactstrap';\r\nimport './BTButton.scss';\r\n\r\ninterface Props {\r\n color?: 'normal' | 'gray';\r\n type?: 'submit' | 'button';\r\n align?: 'left' | 'center' | 'right';\r\n roundedCorners?: boolean;\r\n text: string;\r\n icon?: IconProp;\r\n disabled?: boolean;\r\n onClick?: () => void;\r\n tooltip?: string;\r\n tabIndex?: number;\r\n ref?: React.Ref;\r\n}\r\n\r\nconst BTButton: React.FC = (props, ref: React.Ref) => {\r\n let buttonStyleCssClass = '';\r\n\r\n switch (props.color) {\r\n case 'gray':\r\n buttonStyleCssClass = 'grayButton';\r\n break;\r\n default:\r\n break;\r\n }\r\n\r\n return (\r\n \r\n {props.icon ? : <>}\r\n\r\n {props.text}\r\n \r\n );\r\n};\r\n\r\nexport default React.forwardRef(BTButton);\r\n","import React, { useState, useCallback } from 'react';\r\n\r\ninterface ConfirmationOverlayDisplayInfo {\r\n currentConfirmationOverlayParameters: ConfirmationOverlayParameters | null;\r\n isDisplayed: boolean;\r\n hasBeenToggled: boolean;\r\n}\r\n\r\ninterface ConfirmationOverlayParameters {\r\n title: string;\r\n text: string;\r\n buttons: ConfirmationOverlayButton[];\r\n}\r\n\r\ninterface ConfirmationOverlayButton {\r\n color?: 'normal' | 'gray';\r\n text: string;\r\n onClick: () => void;\r\n}\r\n\r\ninterface ConfirmationOverlayContextInterface {\r\n confirmationOverlayDisplayInfo: ConfirmationOverlayDisplayInfo;\r\n showConfirmationOverlay: (confirmationOverlayParameters: ConfirmationOverlayParameters) => void;\r\n hideConfirmationOverlay: () => void;\r\n}\r\n\r\nconst ConfirmationOverlayContext = React.createContext({\r\n confirmationOverlayDisplayInfo: {\r\n currentConfirmationOverlayParameters: null,\r\n isDisplayed: false,\r\n hasBeenToggled: false,\r\n },\r\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\r\n showConfirmationOverlay: (confirmationOverlayParameters: ConfirmationOverlayParameters) => {},\r\n hideConfirmationOverlay: () => {},\r\n});\r\n\r\nconst ConfirmationOverlayContextProvider: React.FC<{}> = props => {\r\n const [confirmationOverlayDisplayInfo, setConfirmationOverlayDisplayInfo] = useState<\r\n ConfirmationOverlayDisplayInfo\r\n >({\r\n currentConfirmationOverlayParameters: null,\r\n isDisplayed: false,\r\n hasBeenToggled: false,\r\n });\r\n\r\n const showConfirmationOverlay = useCallback(\r\n (confirmationOverlayParameters: ConfirmationOverlayParameters): void => {\r\n setConfirmationOverlayDisplayInfo({\r\n currentConfirmationOverlayParameters: confirmationOverlayParameters,\r\n isDisplayed: true,\r\n hasBeenToggled: true,\r\n });\r\n },\r\n [],\r\n );\r\n\r\n const hideConfirmationOverlay = useCallback((): void => {\r\n setConfirmationOverlayDisplayInfo({\r\n currentConfirmationOverlayParameters: null,\r\n isDisplayed: false,\r\n hasBeenToggled: true,\r\n });\r\n }, []);\r\n\r\n return (\r\n \r\n {props.children}\r\n \r\n );\r\n};\r\n\r\nexport { ConfirmationOverlayContext, ConfirmationOverlayContextProvider };\r\n","import React, { useContext, useRef, useEffect, MutableRefObject } from 'react';\r\nimport BTButton from '../controls/button/BTButton';\r\nimport './ConfirmationOverlay.scss';\r\nimport { ConfirmationOverlayContext } from './ConfirmationOverlayContext';\r\n\r\nconst ConfirmationOverlay: React.FC<{}> = () => {\r\n const { confirmationOverlayDisplayInfo, hideConfirmationOverlay } = useContext(\r\n ConfirmationOverlayContext,\r\n );\r\n\r\n const firstButtonRef: MutableRefObject = useRef(null);\r\n const lastButtonRef: MutableRefObject = useRef(null);\r\n\r\n const loadingPageOverlayCssClasses = ['confirmationOverlay'];\r\n\r\n // Don't even show the overlay if it hasn't explicitly been toggled\r\n if (!confirmationOverlayDisplayInfo.hasBeenToggled) {\r\n loadingPageOverlayCssClasses.push('d-none');\r\n } else if (confirmationOverlayDisplayInfo.isDisplayed) {\r\n loadingPageOverlayCssClasses.push('isDisplayed');\r\n }\r\n\r\n const onTab = (event: React.KeyboardEvent): void => {\r\n if (event.shiftKey) {\r\n if (document.activeElement === firstButtonRef.current) {\r\n event.preventDefault();\r\n (lastButtonRef.current as HTMLButtonElement).focus();\r\n }\r\n } else {\r\n //if tabbing forward\r\n if (document.activeElement === lastButtonRef.current) {\r\n event.preventDefault();\r\n (firstButtonRef.current as HTMLButtonElement).focus();\r\n }\r\n }\r\n };\r\n\r\n // Focus overlay params if not null\r\n useEffect(() => {\r\n if (confirmationOverlayDisplayInfo.currentConfirmationOverlayParameters) {\r\n (firstButtonRef.current as HTMLButtonElement).focus();\r\n }\r\n }, [confirmationOverlayDisplayInfo.currentConfirmationOverlayParameters]);\r\n\r\n return (\r\n confirmationOverlayDisplayInfo.currentConfirmationOverlayParameters && (\r\n {\r\n // Hide the overlay when the escape key is pressed\r\n if (event.keyCode === 27) {\r\n hideConfirmationOverlay();\r\n }\r\n\r\n // Restrict tabbing to the overlay buttons\r\n if (event.keyCode === 9) {\r\n onTab(event);\r\n }\r\n }}\r\n >\r\n
\r\n
\r\n {confirmationOverlayDisplayInfo.currentConfirmationOverlayParameters!.title}\r\n
\r\n
\r\n {confirmationOverlayDisplayInfo.currentConfirmationOverlayParameters!.text}\r\n
\r\n
\r\n {confirmationOverlayDisplayInfo.currentConfirmationOverlayParameters!.buttons.map(\r\n (currButton, index) => {\r\n const checkIfLastItem = (\r\n index: number,\r\n ): MutableRefObject | null => {\r\n if (\r\n index ===\r\n confirmationOverlayDisplayInfo.currentConfirmationOverlayParameters!.buttons\r\n .length -\r\n 1\r\n ) {\r\n return lastButtonRef;\r\n } else {\r\n return null;\r\n }\r\n };\r\n\r\n return (\r\n \r\n );\r\n },\r\n )}\r\n
\r\n
\r\n \r\n )\r\n );\r\n};\r\n\r\nexport default ConfirmationOverlay;\r\n","import React, { useCallback, useState } from 'react';\nimport UserConstants from '../constants/users';\nimport { isUserAuthorized } from '../utils/user-authorization';\nimport LocalStorageKeys from './../constants/local-storage';\n\nexport interface UserInformation {\n id: string;\n emailAddress: string;\n name: string;\n userRoles: UserRole[];\n userIsAdmin?: boolean;\n userIsInternalUser?: boolean;\n userIsClientUser?: boolean;\n userIsBidDaySupport?: boolean;\n}\n\ninterface UserInformationContextData {\n userInformation: UserInformation | null;\n updateUserInformation: (newUserInformation: UserInformation | null) => void;\n}\n\nconst UserInformationContext = React.createContext({\n userInformation: {\n id: '',\n emailAddress: '',\n name: '',\n userRoles: [],\n userIsAdmin: false,\n userIsInternalUser: false,\n userIsClientUser: false,\n userIsBidDaySupport: false,\n },\n updateUserInformation: (newUserInformation: UserInformation | null) => {},\n});\n\nconst UserInformationContextProvider: React.FC<{}> = props => {\n const { localStorage } = window;\n\n const [userInformation, setUserInformation] = useState({\n id: '',\n emailAddress: '',\n name: '',\n userRoles: [],\n userIsAdmin: false,\n userIsInternalUser: false,\n userIsClientUser: false,\n });\n\n const updateUserInformation = useCallback(\n (newUserInformation: UserInformation | null): void => {\n if (newUserInformation) {\n // NOTE: We cannot reference \"userInformation\" in this method, or else we will have to add it as a dependency and we will end up in an infinite loop\n // since we update the \"userInformation\"\n\n // NOTE: Explicitly set the authorization helper properties in this code only\n\n newUserInformation.userIsAdmin = isUserAuthorized(\n newUserInformation,\n UserConstants.UserRolesValues.ADMIN,\n );\n\n newUserInformation.userIsInternalUser = isUserAuthorized(\n newUserInformation,\n UserConstants.UserRolesValues.INTERNALUSER,\n );\n\n newUserInformation.userIsClientUser = isUserAuthorized(\n newUserInformation,\n UserConstants.UserRolesValues.CLIENTUSER,\n );\n\n newUserInformation.userIsBidDaySupport = isUserAuthorized(\n newUserInformation,\n UserConstants.UserRolesValues.BIDDAYSUPPORT,\n );\n\n setUserInformation(newUserInformation);\n\n localStorage.setItem(LocalStorageKeys.UserInformation, JSON.stringify(newUserInformation));\n } else {\n localStorage.removeItem(LocalStorageKeys.UserInformation);\n setUserInformation(null);\n }\n },\n [localStorage],\n );\n\n return (\n \n {props.children}\n \n );\n};\n\nexport { UserInformationContext, UserInformationContextProvider };\n","import React, { useContext, useEffect, useLayoutEffect, useState } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { Link, useHistory } from 'react-router-dom';\r\nimport {\r\n Collapse,\r\n DropdownItem,\r\n DropdownMenu,\r\n DropdownToggle,\r\n Nav,\r\n Navbar,\r\n NavbarToggler,\r\n NavLink,\r\n UncontrolledDropdown,\r\n} from 'reactstrap';\r\nimport { AuthenticationService } from '../../../services/authentication/authentication-service';\r\nimport { UserInformationContext } from '../../UserInformationContext';\r\nimport ApplicationRoutes from './../../../constants/routes';\r\nimport './NavigationMenu.scss';\r\n\r\ninterface CustomNavigationLink {\r\n title: string;\r\n url?: string;\r\n hasDivider?: boolean;\r\n onClick?: () => void;\r\n subLinks?: CustomNavigationLink[];\r\n}\r\n\r\nconst NavigationMenu: React.FC = () => {\r\n const { t } = useTranslation();\r\n const history = useHistory();\r\n const [mobileNavigationMenuIsOpen, setMobileNavigationMenuIsOpen] = useState(false);\r\n const [pageIsScrolled, setPageIsScrolled] = useState(false);\r\n const { userInformation, updateUserInformation } = useContext(UserInformationContext);\r\n\r\n const [navigationLinks, setNavigationLinks] = useState([]);\r\n\r\n // Set the navigation links based on the user's information\r\n useEffect(() => {\r\n const generateNavigationLinks = (): CustomNavigationLink[] => {\r\n const newNavigationLinks: CustomNavigationLink[] = [\r\n { title: t('general:home'), url: ApplicationRoutes.SITE_ROOT },\r\n ];\r\n\r\n if (userInformation && userInformation.id) {\r\n if (\r\n userInformation.userIsClientUser ||\r\n userInformation.userIsInternalUser ||\r\n userInformation.userIsAdmin\r\n ) {\r\n newNavigationLinks.push({\r\n title: t('reporting:reports'),\r\n subLinks: [\r\n {\r\n title: t('reporting:reportNames.usage'),\r\n url: ApplicationRoutes.REPORTS_USAGE,\r\n },\r\n {\r\n title: t('reporting:reportNames.checkouts'),\r\n url: ApplicationRoutes.REPORTS_CHECKOUTS,\r\n },\r\n {\r\n title: t('reporting:reportNames.duration'),\r\n url: ApplicationRoutes.REPORTS_DURATION,\r\n },\r\n {\r\n title: t('reporting:reportNames.rawData'),\r\n url: ApplicationRoutes.REPORTS_RAWDATA,\r\n },\r\n ],\r\n });\r\n }\r\n\r\n if (userInformation.userIsAdmin) {\r\n newNavigationLinks.push({\r\n title: 'Admin',\r\n subLinks: [\r\n {\r\n title: 'Clients',\r\n url: ApplicationRoutes.ADMIN_CLIENTS,\r\n },\r\n {\r\n title: 'Licenses',\r\n url: ApplicationRoutes.ADMIN_LICENSES,\r\n },\r\n {\r\n title: 'Products',\r\n url: ApplicationRoutes.ADMIN_PRODUCTS,\r\n },\r\n {\r\n title: 'Users',\r\n url: ApplicationRoutes.ADMIN_USERS,\r\n },\r\n {\r\n title: 'Estimator Hosted - User Management',\r\n url: ApplicationRoutes.ADMIN_ESTIMATORHOSTED_USERMANAGEMENT,\r\n },\r\n {\r\n title: 'Site Settings',\r\n url: ApplicationRoutes.ADMIN_SITESETTINGS,\r\n hasDivider: true,\r\n },\r\n ],\r\n });\r\n }\r\n\r\n newNavigationLinks.push({\r\n title: userInformation.name,\r\n subLinks: [\r\n {\r\n title: 'Log Out',\r\n onClick: (): void => {\r\n AuthenticationService.logout();\r\n },\r\n },\r\n ],\r\n });\r\n } else {\r\n newNavigationLinks.push({\r\n title: 'Sign In',\r\n onClick: (): void => {\r\n AuthenticationService.navigateToSignInOrPasswordReset();\r\n },\r\n });\r\n }\r\n\r\n return newNavigationLinks;\r\n };\r\n\r\n setNavigationLinks(generateNavigationLinks());\r\n }, [userInformation, history, t, updateUserInformation]);\r\n\r\n const toggleMobileNavigationLinks = (): void => {\r\n setMobileNavigationMenuIsOpen(!mobileNavigationMenuIsOpen);\r\n };\r\n\r\n // Watch when the user scrolls so we can set a property that will dictate a CSS class in the navigation area\r\n useLayoutEffect(() => {\r\n let scrollEventTimer: NodeJS.Timeout;\r\n\r\n const scrollEventHandler = (): void => {\r\n if (scrollEventTimer) {\r\n clearTimeout(scrollEventTimer);\r\n }\r\n\r\n scrollEventTimer = setTimeout(() => {\r\n setPageIsScrolled(window.pageYOffset >= 25);\r\n }, 25);\r\n };\r\n\r\n window.addEventListener('scroll', scrollEventHandler);\r\n\r\n return (): void => {\r\n clearTimeout(scrollEventTimer);\r\n window.removeEventListener('scroll', scrollEventHandler);\r\n };\r\n }, []);\r\n\r\n return (\r\n \r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n\r\n
\r\n {navigationLinks.map(currLink => {\r\n // If the current link has a URL, show it as a regular link.\r\n // If the current link has an array of sublinks, show the current link and sublinks as a dropdown.\r\n // NOTE: This code only handles one level of sublinks for the time being.\r\n if (currLink.url || currLink.onClick) {\r\n return (\r\n
\r\n {\r\n if (currLink.onClick) {\r\n currLink.onClick();\r\n e.preventDefault();\r\n }\r\n }}\r\n >\r\n {currLink.title}\r\n \r\n
\r\n );\r\n } else if (currLink.subLinks && currLink.subLinks.length) {\r\n return (\r\n
\r\n \r\n \r\n {currLink.title}\r\n \r\n\r\n \r\n {currLink.subLinks.map(currSubLink => {\r\n return (\r\n
\r\n {currSubLink.hasDivider && }\r\n \r\n {\r\n if (currSubLink.onClick) {\r\n currSubLink.onClick();\r\n e.preventDefault();\r\n }\r\n }}\r\n >\r\n {currSubLink.title}\r\n \r\n \r\n
\r\n );\r\n })}\r\n
\r\n
\r\n
\r\n );\r\n }\r\n\r\n throw new Error('navigationLinks was not in an expectedFormat');\r\n })}\r\n
\r\n\r\n
\r\n \r\n
\r\n
\r\n\r\n \r\n \r\n \r\n\r\n {/* NOTE: Since this component gets re-rendered when we load a page, the loading progress bar will always animate when it loads */}\r\n
\r\n
\r\n
\r\n \r\n );\r\n};\r\n\r\nexport default NavigationMenu;\r\n","import React from 'react';\r\nimport ConfirmationOverlay from '../confirmation-overlay/ConfirmationOverlay';\r\nimport NavigationMenu from './../navigation-menu/NavigationMenu';\r\nimport './Layout.scss';\r\n\r\nconst Layout: React.FC<{}> = props => {\r\n return (\r\n
\r\n \r\n\r\n \r\n\r\n
{props.children}
\r\n
\r\n );\r\n};\r\n\r\nexport default Layout;\r\n","import React, { useState, useCallback } from 'react';\n\ninterface PageLoadingOverlayDisplayInfo {\n isDisplayed: boolean;\n hasBeenToggled: boolean;\n}\n\nconst LoadingPageOverlayContext = React.createContext({\n pageLoadingOverlayDisplayInfo: {\n isDisplayed: false,\n hasBeenToggled: false,\n },\n showPageLoadingOverlay: () => {},\n hidePageLoadingOverlay: () => {},\n});\n\nconst LoadingPageOverlayContextProvider: React.FC<{}> = props => {\n const [pageLoadingOverlayDisplayInfo, setPageLoadingOverlayDisplayInfo] = useState<\n PageLoadingOverlayDisplayInfo\n >({\n isDisplayed: false,\n hasBeenToggled: false,\n });\n\n const showPageLoadingOverlay = useCallback((): void => {\n setPageLoadingOverlayDisplayInfo({\n isDisplayed: true,\n hasBeenToggled: true,\n });\n }, []);\n\n const hidePageLoadingOverlay = useCallback((): void => {\n setPageLoadingOverlayDisplayInfo({\n isDisplayed: false,\n hasBeenToggled: true,\n });\n }, []);\n\n return (\n \n {props.children}\n \n );\n};\n\nexport { LoadingPageOverlayContext, LoadingPageOverlayContextProvider };\n","import React, { useCallback, useContext, useEffect, useState } from 'react';\r\nimport './NotificationPanel.scss';\r\nimport {\r\n NotificationPanelContext,\r\n NotificationPanelMessage,\r\n NotificationPanelTypes,\r\n} from './NotificationPanelContext';\r\n\r\ninterface Props {\r\n queuedNotifications: NotificationPanelMessage[];\r\n testTimeout?: number;\r\n}\r\n\r\nconst NotificationPanel: React.FC = props => {\r\n const { popFirstQueuedNotification } = useContext(NotificationPanelContext);\r\n\r\n const [\r\n notificationBeingDisplayed,\r\n setNotificationBeingDisplayed,\r\n ] = useState(null);\r\n\r\n const [isDisplayed, setIsDisplayed] = useState(false);\r\n\r\n const [\r\n hideCurrentNotificationTimeoutPromise,\r\n setHideCurrentNotificationTimeoutPromise,\r\n ] = useState(null);\r\n\r\n const setTimeoutToHideCurrentNotification = useCallback(() => {\r\n const notificationTimeout = props.testTimeout || 4000;\r\n hideCurrentNotificationTimeoutPromise && clearTimeout(hideCurrentNotificationTimeoutPromise);\r\n\r\n setHideCurrentNotificationTimeoutPromise(\r\n setTimeout(() => {\r\n setIsDisplayed(false);\r\n\r\n setTimeout(() => {\r\n setNotificationBeingDisplayed(null);\r\n }, 500);\r\n }, notificationTimeout),\r\n );\r\n }, [hideCurrentNotificationTimeoutPromise, props.testTimeout]);\r\n\r\n useEffect(() => {\r\n if (props.queuedNotifications.length > 0 && !notificationBeingDisplayed) {\r\n const nextNotification = popFirstQueuedNotification();\r\n setNotificationBeingDisplayed(nextNotification);\r\n\r\n // Stagger things so the UI has time to animate\r\n setTimeout(() => {\r\n setIsDisplayed(true);\r\n }, 250);\r\n\r\n setTimeoutToHideCurrentNotification();\r\n }\r\n\r\n // NOTE: By having the queued notifications / notification currently displayed as dependencies, we can guarantee that we will cycle through any pending notifications in the queue\r\n }, [\r\n props.queuedNotifications,\r\n notificationBeingDisplayed,\r\n popFirstQueuedNotification,\r\n setTimeoutToHideCurrentNotification,\r\n ]);\r\n\r\n const cssClassesArray = ['notificationPanel', isDisplayed ? 'isDisplayed' : ''];\r\n\r\n if (notificationBeingDisplayed) {\r\n switch (notificationBeingDisplayed.type) {\r\n case NotificationPanelTypes.Success:\r\n cssClassesArray.push('success');\r\n break;\r\n case NotificationPanelTypes.Error:\r\n cssClassesArray.push('error');\r\n break;\r\n case NotificationPanelTypes.Info:\r\n cssClassesArray.push('info');\r\n break;\r\n }\r\n }\r\n\r\n return (\r\n {\r\n setIsDisplayed(false);\r\n\r\n setTimeout(() => {\r\n setNotificationBeingDisplayed(null);\r\n }, 500);\r\n\r\n setTimeoutToHideCurrentNotification();\r\n }}\r\n >\r\n {notificationBeingDisplayed && (\r\n
\r\n

{notificationBeingDisplayed.title}

\r\n
{notificationBeingDisplayed.message}
\r\n
\r\n )}\r\n \r\n );\r\n};\r\n\r\nexport default NotificationPanel;\r\n","import React, { useMemo } from 'react';\r\nimport { Route, RouteProps, useHistory } from 'react-router';\r\nimport ApplicationRoutes from '../../../constants/routes';\r\nimport { populateUserInformationFromLocalStorage } from '../../../utils/user-authorization';\r\n\r\ninterface Props {\r\n requiredUserRoles?: string[];\r\n allowAnyRoles?: boolean; // Specifies that a user having any of the required roles is OK (as opposed to requiring every role)\r\n}\r\n\r\nconst AuthenticatedRoute: React.FC = props => {\r\n const history = useHistory();\r\n\r\n return useMemo(() => {\r\n const redirectUser = (): void => {\r\n // Explicitly replace the current URL\r\n history.replace(ApplicationRoutes.ERROR_UNAUTHORIZED);\r\n };\r\n\r\n // The app does not render any routes until a user is authenticated and their user information is set in the local storage (if they are logged in)\r\n // so we can check that here / get any user information (like their roles) we need for below\r\n const userInfoFromLocalStorage = populateUserInformationFromLocalStorage();\r\n\r\n if (userInfoFromLocalStorage === null) {\r\n redirectUser();\r\n return <>;\r\n }\r\n\r\n // Check authorization if it's required\r\n if (props.requiredUserRoles) {\r\n const allUserRoles = userInfoFromLocalStorage.userRoles.map(v => v.id);\r\n\r\n if (\r\n (props.allowAnyRoles &&\r\n !props.requiredUserRoles.some(v => allUserRoles.some(m => m === v))) ||\r\n (!props.allowAnyRoles &&\r\n !props.requiredUserRoles.every(v => allUserRoles.some(m => m === v)))\r\n ) {\r\n redirectUser();\r\n return <>;\r\n }\r\n }\r\n\r\n return (\r\n
\r\n {' '}\r\n \r\n
\r\n );\r\n\r\n // NOTE: If the URL changes, this component will get re-rendered so we only want to run this useEffect code when the component mounts\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, []);\r\n};\r\n\r\nexport default AuthenticatedRoute;\r\n","interface AddressDto {\n streetAddress: string;\n aptSuiteBldg: string;\n city: string;\n stateOrRegion?: string;\n country?: string;\n postalCode: string;\n}\n\nexport interface ClientOrganizationAddOrEditDto {\n name: string;\n address?: AddressDto;\n accountExecutive: string;\n domains: string[];\n usesCorporateActiveDirectory: boolean;\n}\n\nexport interface ClientOrganizationViewDto extends ClientOrganizationAddOrEditDto {\n id: string;\n}\n\nexport const getClientOrganizationFromDto = (\n dto: ClientOrganizationViewDto,\n): ClientOrganization => {\n const clientOrg: ClientOrganization = {\n id: dto.id,\n name: dto.name,\n accountExecutive: dto.accountExecutive,\n isNew: false,\n domains: dto.domains,\n address: !dto.address\n ? undefined\n : {\n streetAddress: dto.address.streetAddress,\n aptSuiteBldg: dto.address.aptSuiteBldg,\n city: dto.address.city,\n stateOrRegion: !dto.address.stateOrRegion\n ? undefined\n : { name: dto.address.stateOrRegion },\n country: !dto.address.country ? undefined : { name: dto.address.country },\n postalCode: dto.address.postalCode,\n },\n usesCorporateActiveDirectory: dto.usesCorporateActiveDirectory,\n };\n\n return clientOrg;\n};\n\nexport const getDtoFromAddress = (address?: Address): AddressDto | undefined => {\n if (!address) {\n return undefined;\n }\n\n const dto: AddressDto = {\n streetAddress: address.streetAddress,\n aptSuiteBldg: address.aptSuiteBldg,\n city: address.city,\n stateOrRegion: address.stateOrRegion ? address.stateOrRegion.name : undefined,\n country: address.country ? address.country.name : undefined,\n postalCode: address.postalCode,\n };\n\n return dto;\n};\n","import axios from 'axios';\nimport ApiRoutes from '../../../constants/routes/api-routes';\nimport {\n ClientOrganizationViewDto,\n getClientOrganizationFromDto,\n ClientOrganizationAddOrEditDto,\n getDtoFromAddress,\n} from './clients-api-service-helper';\n\nconst getClientOrganizations = async (): Promise => {\n const response = await axios.get(ApiRoutes.Clients);\n const clientOrgs = response.data.map(dto => getClientOrganizationFromDto(dto));\n\n return clientOrgs;\n};\n\nconst getClientOrganizationByEmail = async (email: string): Promise => {\n const url = `${ApiRoutes.ClientByEmail}/${email}`;\n const response = await axios.get(url);\n const clientOrg = getClientOrganizationFromDto(response.data);\n\n return clientOrg;\n};\n\nconst addClientOrganization = async (\n clientOrg: ClientOrganization,\n): Promise => {\n const dto: ClientOrganizationAddOrEditDto = {\n name: clientOrg.name,\n accountExecutive: clientOrg.accountExecutive,\n address: getDtoFromAddress(clientOrg.address),\n domains: clientOrg.domains,\n usesCorporateActiveDirectory: clientOrg.usesCorporateActiveDirectory,\n };\n\n const response = await axios.post(ApiRoutes.Clients, dto);\n const newClientOrg = getClientOrganizationFromDto(response.data);\n\n return newClientOrg;\n};\n\nconst editClientOrganization = async (clientOrg: ClientOrganization): Promise => {\n const dto: ClientOrganizationAddOrEditDto = {\n name: clientOrg.name,\n accountExecutive: clientOrg.accountExecutive,\n address: getDtoFromAddress(clientOrg.address),\n domains: clientOrg.domains,\n usesCorporateActiveDirectory: clientOrg.usesCorporateActiveDirectory,\n };\n\n await axios.put(`${ApiRoutes.Clients}/${clientOrg.id}`, dto);\n};\n\nconst deleteClientOrganization = async (clientOrgId: string): Promise => {\n await axios.delete(`${ApiRoutes.Clients}/${clientOrgId}`);\n};\n\nexport default {\n getClientOrganizations,\n getClientOrganizationByEmail,\n addClientOrganization,\n editClientOrganization,\n deleteClientOrganization,\n};\n","const LicensesConstants = {\r\n DeploymentStatuses: {\r\n COMPLETED: 'Completed',\r\n NONE: 'None',\r\n IN_PROGRESS: 'InProgress',\r\n ERROR: 'Error',\r\n REQUESTED: 'Requested',\r\n },\r\n DeploymentStatusesDisplayNames: {\r\n COMPLETED: 'Completed',\r\n NONE: 'No Deployment Run',\r\n IN_PROGRESS: 'In Progress',\r\n ERROR: 'Error',\r\n REQUESTED: 'Deployment Requested',\r\n },\r\n};\r\n\r\nexport default LicensesConstants;\r\n","export interface LicenseViewDto {\n id: string;\n clientOrganizationId: string;\n productId: string;\n featureIds: string[];\n userCount: number;\n enforceStrictUserCount: boolean;\n effectiveDate: Date;\n expirationDate: Date;\n deploymentStatus: string | null;\n deploymentDetails: Dictionary;\n adminUser: string;\n}\n\nexport interface LicenseAddDto {\n clientOrganizationId: string;\n productId: string;\n featureIds: string[];\n userCount: number;\n enforceStrictUserCount: boolean;\n effectiveDate: Date;\n expirationDate: Date;\n adminUser: string | null;\n}\n\nexport interface LicenseEditDto {\n clientOrganizationId: string;\n productId: string;\n featureIds: string[];\n userCount: number;\n enforceStrictUserCount: boolean;\n effectiveDate: Date;\n expirationDate: Date;\n adminUser: string | null;\n}\n\nexport interface DeploymentRequest {\n licenseId: string;\n adminUser: string;\n emailDomains: string[];\n}\n\n// NOTE: Right now we are not returning everything from the API and must populate later\nexport const getLicenseFromDto = (licenseDto: LicenseViewDto): License => {\n const license: License = {\n id: licenseDto.id,\n clientOrganization: {\n id: licenseDto.clientOrganizationId,\n name: '', // TODO: get from server\n domains: [''], //TODO: get from server\n },\n product: {\n id: licenseDto.productId,\n name: '', // TODO: get from server\n features: licenseDto.featureIds.map(featureId => ({\n id: featureId,\n name: '', // TODO: get from server\n hasActiveLicenses: false, // TODO: get from server\n isNew: false,\n })),\n deploymentTypeId: null,\n },\n userCount: licenseDto.userCount,\n effectiveDate: licenseDto.effectiveDate,\n expirationDate: licenseDto.expirationDate,\n enforceStrictUserCount: licenseDto.enforceStrictUserCount,\n isNew: false,\n deploymentStatus: licenseDto.deploymentStatus,\n deploymentDetails: licenseDto.deploymentDetails,\n adminUser: licenseDto.adminUser,\n };\n\n return license;\n};\n","import axios from 'axios';\r\nimport LicensesConstants from '../../../constants/licenses';\r\nimport ApiRoutes from '../../../constants/routes/api-routes';\r\nimport {\r\n LicenseViewDto,\r\n LicenseAddDto,\r\n LicenseEditDto,\r\n DeploymentRequest,\r\n getLicenseFromDto,\r\n} from './licenses-api-service-helper';\r\n\r\nconst getLicenses = async (): Promise => {\r\n const response = await axios.get(ApiRoutes.Licenses);\r\n const dtos: LicenseViewDto[] = response.data;\r\n\r\n const licenses: License[] = dtos.map(dto => getLicenseFromDto(dto));\r\n return licenses;\r\n};\r\n\r\nconst addLicense = async (license: License): Promise => {\r\n const dto: LicenseAddDto = {\r\n clientOrganizationId: license.clientOrganization.id,\r\n productId: license.product.id,\r\n featureIds: license.product.features.map(f => f.id),\r\n userCount: license.userCount,\r\n enforceStrictUserCount: license.enforceStrictUserCount,\r\n effectiveDate: license.effectiveDate,\r\n expirationDate: license.expirationDate,\r\n adminUser: license.adminUser,\r\n };\r\n\r\n const response = await axios.post(`${ApiRoutes.Licenses}/${license.id}`, dto);\r\n const newLicense = getLicenseFromDto(response.data);\r\n\r\n return newLicense;\r\n};\r\n\r\nconst editLicense = async (license: License): Promise => {\r\n const dto: LicenseEditDto = {\r\n clientOrganizationId: license.clientOrganization.id,\r\n productId: license.product.id,\r\n featureIds: license.product.features.map(f => f.id),\r\n userCount: license.userCount,\r\n enforceStrictUserCount: license.enforceStrictUserCount,\r\n effectiveDate: license.effectiveDate,\r\n expirationDate: license.expirationDate,\r\n adminUser: license.adminUser,\r\n };\r\n\r\n const response = await axios.put(`${ApiRoutes.Licenses}/${license.id}`, dto);\r\n const updatedLicense = getLicenseFromDto(response.data);\r\n\r\n return updatedLicense;\r\n};\r\n\r\nconst deleteLicense = async (licenseId: string): Promise => {\r\n await axios.delete(`${ApiRoutes.Licenses}/${licenseId}`);\r\n};\r\n\r\nconst resetDeploymentDetails = async (licenseId: string): Promise => {\r\n const dto = {\r\n id: licenseId,\r\n deploymentStatus: LicensesConstants.DeploymentStatuses.NONE,\r\n deploymentDetails: {},\r\n };\r\n await axios.put(`${ApiRoutes.Licenses}/update-deployment-details/${licenseId}`, dto);\r\n};\r\n\r\nconst requestDeployment = async (\r\n licenseId: string,\r\n adminUser: string,\r\n emailDomains: string[],\r\n): Promise => {\r\n const dto: DeploymentRequest = {\r\n licenseId: licenseId,\r\n adminUser: adminUser,\r\n emailDomains: emailDomains,\r\n };\r\n await axios.post(`${ApiRoutes.Licenses}/request-deployment/`, dto);\r\n};\r\n\r\nexport default {\r\n getLicenses,\r\n addLicense,\r\n editLicense,\r\n deleteLicense,\r\n resetDeploymentDetails,\r\n requestDeployment,\r\n};\r\n","export interface FeatureViewDto {\n id: string;\n name: string;\n hasActiveLicenses: boolean;\n}\n\nexport interface ProductViewDto {\n id: string;\n name: string;\n deploymentTypeId: string;\n hasActiveLicenses: boolean;\n features: FeatureViewDto[];\n}\n\nexport interface FeatureAddDto {\n name: string;\n}\n\nexport interface ProductAddDto {\n name: string;\n deploymentTypeId: string;\n features: FeatureAddDto[];\n}\n\nexport interface FeatureEditDto {\n id: string;\n newId?: string;\n name: string;\n}\n\nexport interface ProductEditDto {\n id?: string;\n name: string;\n deploymentTypeId: string;\n features: FeatureEditDto[];\n}\n\nexport interface DeploymentTypeDto {\n id: string;\n name: string;\n}\n\nexport const getFeatureFromDto = (featureDto: FeatureViewDto): ProductFeature => {\n const feature: ProductFeature = {\n id: featureDto.id,\n name: featureDto.name,\n hasActiveLicenses: featureDto.hasActiveLicenses,\n isNew: false,\n };\n\n return feature;\n};\n\nexport const getProductFromDto = (productDto: ProductViewDto): Product => {\n const product: Product = {\n id: productDto.id,\n name: productDto.name,\n deploymentTypeId: productDto.deploymentTypeId,\n isNew: false,\n hasActiveLicenses: productDto.hasActiveLicenses,\n features: productDto.features.map(featureDto => getFeatureFromDto(featureDto)),\n };\n\n return product;\n};\n\nexport const getDeploymentTypeFromDto = (deploymentTypeDto: DeploymentTypeDto): DeploymentType => {\n return {\n id: deploymentTypeDto.id,\n name: deploymentTypeDto.name,\n };\n};\n","import axios from 'axios';\nimport ApiRoutes from '../../../constants/routes/api-routes';\nimport {\n DeploymentTypeDto,\n FeatureAddDto,\n FeatureEditDto,\n FeatureViewDto,\n getDeploymentTypeFromDto,\n getFeatureFromDto,\n getProductFromDto,\n ProductAddDto,\n ProductEditDto,\n ProductViewDto,\n} from './products-api-service-helper';\n\nconst getProducts = async (): Promise => {\n const response = await axios.get(ApiRoutes.Products);\n const dtos: ProductViewDto[] = response.data;\n\n const products: Product[] = dtos.map(productDto => getProductFromDto(productDto));\n\n return products;\n};\n\nconst getProductsByClient = async (client: ClientOrganization): Promise => {\n const url = `${ApiRoutes.ProductsByClient}/${client.id}`;\n\n const response = await axios.get(url);\n return response.data;\n};\n\nconst addProduct = async (product: Product): Promise => {\n const productDto: ProductAddDto = {\n name: product.name,\n deploymentTypeId: product.deploymentTypeId,\n features: product.features.map(feature => ({ name: feature.name })),\n };\n\n const response = await axios.post(ApiRoutes.Products, productDto);\n const newProduct: Product = getProductFromDto(response.data);\n\n return newProduct;\n};\n\nconst editProduct = async (product: Product): Promise => {\n const featuresToAdd: FeatureAddDto[] = product.features\n .filter(feature => feature.isNew)\n .map(feature => ({ id: feature.id, name: feature.name }));\n\n const addFeatureResponses = await Promise.all(\n featuresToAdd.map(featureDto =>\n axios.post(`${ApiRoutes.Products}/${product.id}/features`, featureDto),\n ),\n );\n\n const featuresToEdit: FeatureEditDto[] = product.features\n .filter(feature => !feature.isNew)\n .map(feature => ({ id: feature.id, name: feature.name, newId: feature.newId }));\n\n await Promise.all(\n featuresToEdit.map(featureDto =>\n axios.put(`${ApiRoutes.Products}/${product.id}/features/${featureDto.id}`, {\n id: featureDto.newId,\n name: featureDto.name,\n }),\n ),\n );\n\n const featureIdsToDelete: string[] = product.features\n .filter(feature => feature.isDeleted)\n .map(feature => feature.id);\n\n await Promise.all(\n featureIdsToDelete.map(featureId =>\n axios.delete(`${ApiRoutes.Products}/${product.id}/features/${featureId}`),\n ),\n );\n\n const productDto: ProductEditDto = {\n id: product.newId,\n name: product.name,\n deploymentTypeId: product.deploymentTypeId,\n features: [],\n };\n\n await axios.put(`${ApiRoutes.Products}/${product.id}`, productDto);\n\n const newFeatures: ProductFeature[] = product.features\n .filter(feature => feature.isNew)\n .map(feature => {\n const featureDto = addFeatureResponses\n .map(response => response.data)\n .find(featureDto => featureDto.name === feature.name);\n\n if (!featureDto) {\n throw new Error(`Could not find feature with name '${feature.name}' in response`);\n }\n\n return getFeatureFromDto(featureDto);\n });\n\n const features = product.features.filter(feature => !feature.isNew && !feature.isDeleted);\n\n features.forEach(feature => {\n if (!feature.newId || feature.id === feature.newId) {\n return;\n }\n\n feature.id = feature.newId;\n });\n\n const newProduct: Product = {\n ...product,\n features: [...features, ...newFeatures],\n };\n\n return newProduct;\n};\n\nconst deleteProduct = async (productId: string): Promise => {\n await axios.delete(`${ApiRoutes.Products}/${productId}`);\n};\n\nconst getDeploymentTypes = async (): Promise => {\n const response = await axios.get(`${ApiRoutes.Products}/deployment-types`);\n return response.data.map(v => getDeploymentTypeFromDto(v));\n};\n\nexport default {\n getProducts,\n getProductsByClient,\n addProduct,\n editProduct,\n deleteProduct,\n getDeploymentTypes,\n};\n","import _ from 'lodash';\r\n\r\nexport interface LicenseUsageByPeriodDto {\r\n clientOrganizationId: string;\r\n productId: string;\r\n month: string;\r\n week: string;\r\n day: string;\r\n totalAutomaticCheckouts: number;\r\n totalManualCheckouts: number;\r\n distinctAutomaticCheckouts: number;\r\n distinctManualCheckouts: number;\r\n avgManualDuration: TimeSpan;\r\n avgAutomaticDuration: TimeSpan;\r\n}\r\n\r\nexport const getDailyBTChartDataFromDto = (\r\n dtos: LicenseUsageByPeriodDto[],\r\n typeOfUsage: 'distinct' | 'total' | 'duration',\r\n): BTChartData => {\r\n const data: BTChartData = {\r\n chartSeries: [\r\n {\r\n name: 'Automatic',\r\n data: dtos.map((dto: LicenseUsageByPeriodDto) => {\r\n return {\r\n label: new Date(dto.day),\r\n value: getPropertyByUsageType(dto, typeOfUsage, false),\r\n };\r\n }),\r\n },\r\n {\r\n name: 'Manual',\r\n data: dtos.map((dto: LicenseUsageByPeriodDto) => {\r\n return {\r\n label: new Date(dto.day),\r\n value: getPropertyByUsageType(dto, typeOfUsage, true),\r\n };\r\n }),\r\n },\r\n ],\r\n };\r\n return data;\r\n};\r\n\r\nexport const getWeeklyBTChartDataFromDto = (\r\n dtos: LicenseUsageByPeriodDto[],\r\n typeOfUsage: 'distinct' | 'total' | 'duration',\r\n): BTChartData => {\r\n const data: BTChartData = {\r\n chartSeries: [\r\n {\r\n name: 'Automatic',\r\n data: dtos.map((dto: LicenseUsageByPeriodDto) => {\r\n return {\r\n label: new Date(dto.week),\r\n value: getPropertyByUsageType(dto, typeOfUsage, false),\r\n };\r\n }),\r\n },\r\n {\r\n name: 'Manual',\r\n data: dtos.map((dto: LicenseUsageByPeriodDto) => {\r\n return {\r\n label: new Date(dto.week),\r\n value: getPropertyByUsageType(dto, typeOfUsage, true),\r\n };\r\n }),\r\n },\r\n ],\r\n };\r\n return data;\r\n};\r\n\r\nexport const getMonthlyBTChartDataFromDto = (\r\n dtos: LicenseUsageByPeriodDto[],\r\n typeOfUsage: 'distinct' | 'total' | 'duration',\r\n): BTChartData => {\r\n const data: BTChartData = {\r\n chartSeries: [\r\n {\r\n name: 'Automatic',\r\n data: dtos.map((dto: LicenseUsageByPeriodDto) => {\r\n return {\r\n label: new Date(dto.month),\r\n value: getPropertyByUsageType(dto, typeOfUsage, false),\r\n };\r\n }),\r\n },\r\n {\r\n name: 'Manual',\r\n data: dtos.map((dto: LicenseUsageByPeriodDto) => {\r\n return {\r\n label: new Date(dto.month),\r\n value: getPropertyByUsageType(dto, typeOfUsage, true),\r\n };\r\n }),\r\n },\r\n ],\r\n };\r\n return data;\r\n};\r\n\r\nfunction getPropertyByUsageType(\r\n dto: LicenseUsageByPeriodDto,\r\n usage: string,\r\n isManual: boolean,\r\n): number {\r\n switch (usage) {\r\n case 'distinct': {\r\n return isManual ? dto.distinctManualCheckouts : dto.distinctAutomaticCheckouts;\r\n }\r\n case 'total': {\r\n return isManual ? dto.totalManualCheckouts : dto.totalAutomaticCheckouts;\r\n }\r\n case 'duration': {\r\n if (isManual) {\r\n return dto.avgManualDuration ? _.round(dto.avgManualDuration.value.totalHours, 2) : 0;\r\n } else {\r\n return dto.avgAutomaticDuration ? _.round(dto.avgAutomaticDuration.value.totalHours, 2) : 0;\r\n }\r\n }\r\n default: {\r\n return 0;\r\n }\r\n }\r\n}\r\n","import axios from 'axios';\r\nimport {\r\n LicenseUsageByPeriodDto,\r\n getDailyBTChartDataFromDto,\r\n getWeeklyBTChartDataFromDto,\r\n getMonthlyBTChartDataFromDto,\r\n} from './usage-api-service-helper';\r\nimport ApiRoutes from '../../../constants/routes/api-routes';\r\nimport _ from 'lodash';\r\nimport moment from 'moment';\r\n\r\nconst getRawUsage = async (\r\n fromDate: Date,\r\n toDate: Date,\r\n client: ClientOrganization | null,\r\n product: Product | null,\r\n): Promise => {\r\n const params = [\r\n `start=${fromDate.toLocaleDateString()}`,\r\n `end=${toDate.toLocaleDateString()}`,\r\n client ? `clientOrgId=${client.id}` : '',\r\n product ? `productId=${product.id}` : '',\r\n ].filter(v => v);\r\n\r\n const url = `${ApiRoutes.Raw}?${params.join('&')}`;\r\n // NOTE: This api call is expecting to receive binary data\r\n const response = await axios.get(url, {\r\n responseType: 'arraybuffer',\r\n });\r\n return response.data;\r\n};\r\n\r\nconst getUsageByDay = async (\r\n fromDate: Date,\r\n toDate: Date,\r\n client: ClientOrganization | null,\r\n product: Product | null,\r\n typeOfUsage: 'distinct' | 'total' | 'duration',\r\n): Promise => {\r\n const params = [\r\n `start=${fromDate.toLocaleDateString()}`,\r\n `end=${toDate.toLocaleDateString()}`,\r\n client ? `clientOrgId=${client.id}` : '',\r\n product ? `productId=${product.id}` : '',\r\n ].filter(v => v);\r\n const url =\r\n typeOfUsage === 'duration'\r\n ? `${ApiRoutes.DurationByDay}?${params.join('&')}`\r\n : `${ApiRoutes.UsageByDay}?${params.join('&')}`;\r\n const response = await axios.get(url);\r\n const dtos: LicenseUsageByPeriodDto[] = response.data;\r\n const data: BTChartData = getDailyBTChartDataFromDto(dtos, typeOfUsage);\r\n if (data.chartSeries[0]) {\r\n data.chartSeries[0].data = initChartRange(data.chartSeries[0].data, fromDate, toDate, 'days');\r\n }\r\n return data;\r\n};\r\n\r\nconst getUsageByWeek = async (\r\n fromDate: Date,\r\n toDate: Date,\r\n client: ClientOrganization | null,\r\n product: Product | null,\r\n typeOfUsage: 'distinct' | 'total' | 'duration',\r\n): Promise => {\r\n const params = [\r\n `start=${fromDate.toLocaleDateString()}`,\r\n `end=${toDate.toLocaleDateString()}`,\r\n client ? `clientOrgId=${client.id}` : '',\r\n product ? `productId=${product.id}` : '',\r\n ].filter(v => v);\r\n const url =\r\n typeOfUsage === 'duration'\r\n ? `${ApiRoutes.DurationByWeek}?${params.join('&')}`\r\n : `${ApiRoutes.UsageByWeek}?${params.join('&')}`;\r\n const response = await axios.get(url);\r\n\r\n const dtos: LicenseUsageByPeriodDto[] = response.data;\r\n const data: BTChartData = getWeeklyBTChartDataFromDto(dtos, typeOfUsage);\r\n if (data.chartSeries[0]) {\r\n data.chartSeries[0].data = initChartRange(data.chartSeries[0].data, fromDate, toDate, 'weeks');\r\n }\r\n return data;\r\n};\r\n\r\nconst getUsageByMonth = async (\r\n fromDate: Date,\r\n toDate: Date,\r\n client: ClientOrganization | null,\r\n product: Product | null,\r\n typeOfUsage: 'distinct' | 'total' | 'duration',\r\n): Promise => {\r\n const params = [\r\n `start=${fromDate.toLocaleDateString()}`,\r\n `end=${toDate.toLocaleDateString()}`,\r\n client ? `clientOrgId=${client.id}` : '',\r\n product ? `productId=${product.id}` : '',\r\n ].filter(v => v);\r\n const url =\r\n typeOfUsage === 'duration'\r\n ? `${ApiRoutes.DurationByMonth}?${params.join('&')}`\r\n : `${ApiRoutes.UsageByMonth}?${params.join('&')}`;\r\n const response = await axios.get(url);\r\n\r\n const dtos: LicenseUsageByPeriodDto[] = response.data;\r\n const data: BTChartData = getMonthlyBTChartDataFromDto(dtos, typeOfUsage);\r\n if (data.chartSeries[0]) {\r\n data.chartSeries[0].data = initChartRange(data.chartSeries[0].data, fromDate, toDate, 'months');\r\n }\r\n return data;\r\n};\r\n\r\nconst initChartRange = (\r\n data: BTChartSeriesData[],\r\n fromDate: Date,\r\n toDate: Date,\r\n increment: 'days' | 'weeks' | 'months',\r\n): BTChartSeriesData[] => {\r\n const first = _.first(data);\r\n const last = _.last(data);\r\n const dataClone = [...data];\r\n if (first && last) {\r\n //If we have data, check to see if it includes the range specified, hydrate the range if necessary\r\n if (moment(first.label).isAfter(fromDate, increment)) {\r\n dataClone.unshift({\r\n label: fromDate,\r\n value: 0,\r\n });\r\n }\r\n if (moment(last.label).isBefore(toDate, increment)) {\r\n dataClone.push({\r\n label: toDate,\r\n value: 0,\r\n });\r\n }\r\n } else {\r\n //Else, stage the two and from dates as empty records;\r\n dataClone.unshift({\r\n label: fromDate,\r\n value: 0,\r\n });\r\n dataClone.push({\r\n label: toDate,\r\n value: 0,\r\n });\r\n }\r\n return dataClone;\r\n};\r\n\r\nexport default {\r\n getRawUsage,\r\n getUsageByDay,\r\n getUsageByWeek,\r\n getUsageByMonth,\r\n};\r\n","import { MutableRefObject } from 'react';\r\nimport * as Scroll from 'react-scroll';\r\nimport { getConfig } from './config';\r\n\r\nconst scrollToRef = (ref: MutableRefObject): void => {\r\n const currentRef = ref.current as HTMLElement;\r\n if (!currentRef) {\r\n return;\r\n }\r\n\r\n // Subtract 75 to account for the navbar\r\n const newScrollPosition = currentRef.offsetTop - 75;\r\n Scroll.animateScroll.scrollTo(newScrollPosition, { duration: 750 });\r\n};\r\n\r\nconst isDevelopmentEnvironment = !process.env.NODE_ENV || process.env.NODE_ENV === 'development';\r\nconst isProductionEnvironment = (getConfig('REACT_APP_ENVIRONMENT') || '').toLowerCase() === 'prod';\r\n\r\nexport { scrollToRef, isDevelopmentEnvironment, isProductionEnvironment };\r\n","import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { clone, flatten, groupBy, sortBy } from 'lodash';\nimport React, { ReactElement, useCallback, useEffect, useState } from 'react';\nimport { Collapse, Input } from 'reactstrap';\nimport './BTCardsContainer.scss';\n\nexport interface BTCardRegistrationInfo {\n cardId: string;\n metadata: string[];\n sortValue: string;\n groupValue?: string;\n cardElement: ReactElement;\n}\n\nconst BTCardsContainerContext = React.createContext({\n registerCard: (cardRegistrationInfo: BTCardRegistrationInfo) => {},\n unregisterCard: (cardId: string) => {},\n});\n\ninterface Props {\n children?: ReactElement[];\n enableSearch?: boolean;\n numberOfCardsPerRow?: number;\n recordsNotFoundMessage?: string;\n}\n\ninterface GroupedReactElements {\n groupKey: string;\n reactElements: ReactElement[];\n isOpen: boolean;\n}\n\nconst BTCardsContainer: React.FC = props => {\n const [searchText, setSearchText] = useState('');\n\n const [filteredCards, setFilteredCards] = useState([]);\n\n const [allCards, setAllCards] = useState([]);\n\n const registerCard = useCallback((cardRegistrationInfo: BTCardRegistrationInfo): void => {\n setAllCards(existingCards => {\n if (existingCards.some(v => v.cardId === cardRegistrationInfo.cardId)) {\n throw new Error(\n `The card with ID ${cardRegistrationInfo.cardId} has already been registered.`,\n );\n }\n\n return [...existingCards, cardRegistrationInfo];\n });\n }, []);\n\n const unregisterCard = useCallback((cardId: string): void => {\n setAllCards(existingCards => {\n const indexOfCardToUnregister = existingCards.findIndex(v => v.cardId === cardId);\n\n if (indexOfCardToUnregister > -1) {\n const copyOfArray = [...existingCards];\n copyOfArray.splice(indexOfCardToUnregister, 1);\n return copyOfArray;\n }\n\n return existingCards;\n });\n }, []);\n\n let columnsCssClass = '';\n switch (props.numberOfCardsPerRow) {\n case 1:\n columnsCssClass = 'col-lg-12';\n break;\n case 3:\n columnsCssClass = 'col-lg-4';\n break;\n case 4:\n columnsCssClass = 'col-lg-3';\n break;\n case 2:\n default:\n columnsCssClass = 'col-lg-6';\n break;\n }\n\n const groupCards = useCallback((cards: BTCardRegistrationInfo[]): GroupedReactElements[] => {\n return sortBy(\n Object.values(groupBy(cards, v => (v.groupValue || '').toLowerCase())),\n v => v[0].groupValue,\n ).map(\n (v): GroupedReactElements => {\n return {\n groupKey: v[0].groupValue || '',\n reactElements: sortBy(v, m => m.sortValue).map(m => m.cardElement),\n isOpen: true,\n };\n },\n );\n }, []);\n\n const setFilteredCardsArray = useCallback(\n (newSearchText: string): void => {\n if (!newSearchText) {\n const groupedCards = groupCards(allCards);\n setFilteredCards(groupedCards);\n return;\n }\n\n const filteredCardsArray = allCards.filter(currCardData => {\n const cardMetadata = currCardData.metadata;\n\n if (cardMetadata && Array.isArray(cardMetadata)) {\n const flattenedCardMetadata = cardMetadata.join('').toLowerCase();\n return flattenedCardMetadata.indexOf(newSearchText.toLowerCase()) > -1;\n }\n\n return false;\n });\n\n const groupedCards = groupCards(filteredCardsArray);\n setFilteredCards(groupedCards);\n },\n [allCards, groupCards],\n );\n\n const getCardsCountString = useCallback((): string => {\n return `Displaying ${flatten(filteredCards.map(v => v.reactElements)).length} of ${\n allCards.length\n }`;\n }, [allCards, filteredCards]);\n\n // Update the cards when the search text changes\n useEffect(() => {\n let filteredCardsTimeout: NodeJS.Timeout;\n\n const cleanedUpSearchText = searchText.trim();\n\n // Delay the filtering until the user stops typing for a reasonable amount of time so it doesn't flicker with a larger collection of cards\n if (cleanedUpSearchText.length > 0) {\n filteredCardsTimeout = setTimeout(() => {\n setFilteredCardsArray(cleanedUpSearchText);\n }, 250);\n } else {\n setFilteredCardsArray(cleanedUpSearchText);\n }\n\n return (): void => {\n clearTimeout(filteredCardsTimeout);\n };\n }, [searchText, setFilteredCardsArray]);\n\n return (\n \n
\n {props.enableSearch ? (\n
\n
\n {\n const newSearchText = e.target.value;\n setSearchText(newSearchText);\n }}\n value={searchText}\n />\n\n
\n \n
\n
\n\n {allCards.length && (\n
\n \n
\n )}\n
\n ) : (\n <>\n )}\n\n {filteredCards.length ? (\n
\n {filteredCards.map((v, i) => {\n return (\n
\n {v.groupKey && (\n {\n // Make a copy of the cards before updating the open status of the clicked item, then update the state\n const indexOfMatchingCard = filteredCards.findIndex(\n m => m.groupKey === v.groupKey,\n );\n if (indexOfMatchingCard > -1) {\n const copyOfFilteredCards = clone(filteredCards);\n copyOfFilteredCards[indexOfMatchingCard].isOpen = !copyOfFilteredCards[\n indexOfMatchingCard\n ].isOpen;\n setFilteredCards(copyOfFilteredCards);\n }\n }}\n >\n \n \n \n {v.groupKey} • {v.reactElements.length}\n \n )}\n\n \n
\n {v.reactElements.map((v2, i2) => (\n
\n {v2}\n
\n ))}\n
\n
\n
\n );\n })}\n
\n ) : (\n <>\n )}\n\n {(!allCards.length || !filteredCards.length) && (\n
\n {props.recordsNotFoundMessage || 'No records were found.'}\n
\n )}\n
\n\n {/* \n Render the children but don't show them. Any BTCard component that gets rendered anywhere inside of this component will register \n itself with the provided context from this component and we will display them above after applying any applicable filtering.\n */}\n
{props.children}
\n
\n );\n};\n\nexport default BTCardsContainer;\n\nexport { BTCardsContainerContext };\n","import { IconProp } from '@fortawesome/fontawesome-svg-core';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport React from 'react';\nimport { Button } from 'reactstrap';\nimport './BTFloatingIconButton.scss';\n\ninterface Props {\n buttonIcon: IconProp;\n disabled?: boolean;\n onClick: () => void;\n tooltip?: string;\n 'data-testid'?: string;\n}\n\nconst BTFloatingIconButton: React.FC = props => {\n return (\n
\n {/* NOTE: We put the test ID on the button itself, since that is where click events are, etc. */}\n {\n props.onClick();\n }}\n disabled={props.disabled}\n title={props.tooltip}\n data-testid={props['data-testid']}\n >\n \n \n
\n );\n};\n\nexport default BTFloatingIconButton;\n","import { FormikErrors } from 'formik';\r\n\r\n// NOTE: using `any` here because of metaprogramming\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nconst getFormErrorMessages = (errors: FormikErrors): string[] => {\r\n const errorMessages: string[] = [];\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const getStringValues = (values: any[]): string[] => {\r\n const stringValues: string[] = [];\r\n\r\n values.forEach(val => {\r\n if (typeof val === 'string') {\r\n stringValues.push(val);\r\n return;\r\n }\r\n\r\n if (Array.isArray(val)) {\r\n stringValues.push(...getStringValues(val));\r\n return;\r\n }\r\n\r\n if (typeof val === 'object') {\r\n stringValues.push(...getStringValues(Object.values(val)));\r\n return;\r\n }\r\n });\r\n\r\n return stringValues;\r\n };\r\n\r\n const stringValues = getStringValues(Object.values(errors));\r\n errorMessages.push(...stringValues);\r\n\r\n return errorMessages;\r\n};\r\n\r\nexport { getFormErrorMessages };\r\n","import React from 'react';\nimport './FormErrorContainer.scss';\nimport { sortBy } from 'lodash';\n\ninterface Props {\n errorMessages: string[];\n}\n\nconst FormErrorContainer: React.FC = props => {\n const containerCssClass = props.errorMessages && props.errorMessages.length ? 'isDisplayed' : '';\n const uniqueErrorMessages = sortBy(Array.from(new Set(props.errorMessages)), v => v);\n\n return (\n
\n
\n {uniqueErrorMessages.map((currErrorMessage, i) => {\n return (\n
\n {currErrorMessage}\n
\n );\n })}\n
\n
\n );\n};\n\nexport default FormErrorContainer;\n","import React from 'react';\n\nimport './Forms.scss';\n\nconst FormFooter: React.FC<{}> = props => {\n return
{props.children}
;\n};\n\nexport default FormFooter;\n","import { IconProp } from '@fortawesome/fontawesome-svg-core';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport React from 'react';\nimport { Button } from 'reactstrap';\nimport './BTIconButton.scss';\n\ninterface Props {\n icon: IconProp;\n disabled?: boolean;\n onClick: React.MouseEventHandler; // eslint-disable-line @typescript-eslint/no-explicit-any\n tooltip: string;\n tabIndex?: number;\n 'data-testid'?: string;\n}\n\nconst BTIconButton: React.FC = ({ onClick, disabled, tooltip, icon, tabIndex, ...rest }) => {\n return (\n \n \n \n );\n};\n\nexport default BTIconButton;\n","import React, { useState } from 'react';\r\nimport { Input } from '@progress/kendo-react-inputs';\r\nimport { Field, FieldProps } from 'formik';\r\nimport BTIconButton from '../controls/icon-button/BTIconButton';\r\nimport _ from 'lodash';\r\nimport './Forms.scss';\r\n\r\ninterface Props {\r\n label: string;\r\n name: string;\r\n type?: 'text' | 'password';\r\n validator?: (value: string) => string | void;\r\n disabled?: boolean;\r\n tabIndex?: number;\r\n tooltip?: string;\r\n 'data-testid'?: string;\r\n placeholder?: string;\r\n}\r\n\r\nconst WrappedInput: React.FC = ({ field, form, label, type, ...rest }) => {\r\n const errors = _.get(form.errors, field.name);\r\n const hasErrors = !!errors;\r\n const [showPassword, setShowPassword] = useState(false);\r\n\r\n const classNames = ['formInput'];\r\n if (hasErrors && form.submitCount) {\r\n classNames.push('formInputError');\r\n }\r\n\r\n let inputType = type || 'text';\r\n if (inputType === 'password' && showPassword) {\r\n inputType = 'text';\r\n }\r\n\r\n return (\r\n <>\r\n \r\n
\r\n \r\n {type !== 'password' ? (\r\n <>\r\n ) : (\r\n setShowPassword(showPassword => !showPassword)}\r\n />\r\n )}\r\n
\r\n \r\n );\r\n};\r\n\r\nconst FormTextInput: React.FC = ({ name, label, validator, tabIndex, tooltip, ...rest }) => {\r\n return (\r\n // TODO: move tooltip to the Kendo Input in WrappedInput\r\n // Kendo's Input isn't properly displaying a tooltip, but it looks fixed in newer versions\r\n
\r\n \r\n
\r\n );\r\n};\r\n\r\nexport default FormTextInput;\r\n","import { DropDownList } from '@progress/kendo-react-dropdowns';\r\nimport { Field, FieldProps } from 'formik';\r\nimport { get, isEqual, sortBy } from 'lodash';\r\nimport React from 'react';\r\nimport './Forms.scss';\r\n\r\nexport interface FormDropDownListOption {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n value: any;\r\n name: string;\r\n}\r\n\r\ninterface Props {\r\n placeholderText?: string;\r\n label: string;\r\n name: string;\r\n data: FormDropDownListOption[];\r\n validator?: (value: string) => string | void;\r\n onChangeHandler?: (newValue: {}) => void;\r\n disabled?: boolean;\r\n tooltip?: string;\r\n}\r\n\r\nconst WrappedDropDownList: React.FC = ({\r\n field,\r\n form,\r\n placeholderText,\r\n label,\r\n onChangeHandler,\r\n tooltip,\r\n data,\r\n ...rest\r\n}) => {\r\n const errors = get(form.errors, field.name);\r\n const hasErrors = !!errors;\r\n const classNames = ['formInput'];\r\n\r\n let defaultItem: FormDropDownListOption | unknown;\r\n if (placeholderText) {\r\n defaultItem = { name: placeholderText, value: null };\r\n }\r\n\r\n if (hasErrors && form.submitCount) {\r\n classNames.push('formInputError');\r\n }\r\n\r\n data = sortBy(data, v => v.name.toLowerCase());\r\n\r\n const getSelectedValue = (): FormDropDownListOption | undefined => {\r\n return data.find(v => isEqual(v.value, field.value));\r\n };\r\n\r\n // NOTE: Keep the field / rest props at the top so we can override the onChange property\r\n return (\r\n
\r\n \r\n {\r\n form.setFieldValue(field.name, event.target.value.value);\r\n\r\n if (onChangeHandler) {\r\n onChangeHandler(event.target.value.value);\r\n }\r\n }}\r\n value={getSelectedValue()}\r\n />\r\n
\r\n );\r\n};\r\nconst FormDropDownList: React.FC = props => {\r\n return (\r\n
\r\n \r\n
\r\n );\r\n};\r\nexport default FormDropDownList;\r\n","import { Switch } from '@progress/kendo-react-inputs';\r\nimport { Field, FieldProps } from 'formik';\r\nimport _ from 'lodash';\r\nimport React from 'react';\r\nimport './Forms.scss';\r\n\r\ninterface Props {\r\n label: string;\r\n name: string;\r\n validator?: (value: string) => string | void;\r\n}\r\n\r\nconst WrappedFormSwitch: React.FC = ({ field, form, label, ...rest }) => {\r\n const errors = _.get(form.errors, field.name);\r\n const hasErrors = !!errors;\r\n\r\n const classNames = ['formInput'];\r\n if (hasErrors) {\r\n classNames.push('formInputError');\r\n }\r\n\r\n return (\r\n <>\r\n
\r\n \r\n
\r\n {\r\n form.setFieldValue(field.name, newValue.value);\r\n }}\r\n checked={field.value}\r\n />\r\n \r\n );\r\n};\r\n\r\nconst FormSwitch: React.FC = props => {\r\n return (\r\n
\r\n \r\n
\r\n );\r\n};\r\n\r\nexport default FormSwitch;\r\n","const ForbiddenDomains = [\n 'gmail.com',\n 'yahoo.com',\n 'hotmail.com',\n 'aol.com',\n 'msn.com',\n 'live.com',\n 'comcast.net',\n 'live.com',\n];\n\nexport default ForbiddenDomains;\n","import { Form, Formik, FormikProps, connect, FieldArrayRenderProps, FieldArray } from 'formik';\r\nimport React from 'react';\r\nimport * as Yup from 'yup';\r\nimport { getFormErrorMessages } from '../../../../../utils/forms';\r\nimport BTButton from '../../../../common-page-components/controls/button/BTButton';\r\nimport FormErrorContainer from '../../../../common-page-components/forms/form-error-container/FormErrorContainer';\r\nimport FormFooter from '../../../../common-page-components/forms/FormFooter';\r\nimport FormTextInput from '../../../../common-page-components/forms/FormTextInput';\r\nimport FormDropDownList, {\r\n FormDropDownListOption,\r\n} from './../../../../common-page-components/forms/FormDropDownList';\r\nimport FormSwitch from '../../../../common-page-components/forms/FormSwitch';\r\nimport BTIconButton from '../../../../common-page-components/controls/icon-button/BTIconButton';\r\nimport './ClientEditForm.scss';\r\nimport ForbiddenDomains from '../../../../../constants/domains';\r\n\r\nYup.addMethod(Yup.array, 'unique', function(message) {\r\n return this.test('unique', message, function(value) {\r\n if (!value) {\r\n return true;\r\n }\r\n\r\n this.parent.domains.forEach((domain: string, idx: number) => {\r\n if (domain !== undefined) {\r\n const isDuplicate = this.parent.domains.find(\r\n (d: string, i: number) =>\r\n d && idx !== i && d.trim().toLowerCase() === domain.trim().toLowerCase(),\r\n );\r\n\r\n if (isDuplicate) {\r\n throw this.createError({\r\n path: `${this.path}[${idx}]`,\r\n message,\r\n });\r\n }\r\n }\r\n });\r\n return true;\r\n });\r\n});\r\n\r\nconst FormSchema = Yup.object().shape({\r\n id: Yup.string(),\r\n name: Yup.string()\r\n .trim()\r\n .required('Name is required'),\r\n address: Yup.object().shape
({\r\n streetAddress: Yup.string().trim(),\r\n aptSuiteBldg: Yup.string().trim(),\r\n city: Yup.string().trim(),\r\n stateOrRegion: Yup.object().shape({\r\n id: Yup.number().nullable(),\r\n name: Yup.string(),\r\n countryId: Yup.number(),\r\n }),\r\n postalCode: Yup.string().trim(),\r\n country: Yup.object().shape({\r\n id: Yup.number().nullable(),\r\n name: Yup.string(),\r\n }),\r\n }),\r\n accountExecutive: Yup.string()\r\n .trim()\r\n .required('Account executive is required'),\r\n isNew: Yup.boolean(),\r\n domains: Yup.array()\r\n .of(Yup.string().trim())\r\n .unique('Client domain name must be unique', d => d)\r\n .required('Client domain names are required and cannot be empty'),\r\n usesCorporateActiveDirectory: Yup.boolean(),\r\n});\r\n\r\ninterface Props {\r\n client: ClientOrganization;\r\n countries: ClientCountry[];\r\n regions: ClientRegion[];\r\n licenses: License[];\r\n existingClientNames: string[];\r\n existingClientDomains: string[];\r\n onSaveClick: (client: ClientOrganization) => void;\r\n onDiscardClick: (client: ClientOrganization) => void;\r\n}\r\n\r\nconst ClientEditForm: React.FC = props => {\r\n const DEFAULT_COUNTRY_ID = 0;\r\n const currentDate = new Date();\r\n const domainsInUseByLicenseAdmin = props.client.domains.filter(domain => {\r\n if (\r\n props.licenses.find(\r\n license =>\r\n license.expirationDate > currentDate &&\r\n license.adminUser &&\r\n license.adminUser.indexOf(domain) > 0,\r\n )\r\n ) {\r\n return true;\r\n }\r\n return false;\r\n });\r\n\r\n const getCountriesForDropdown = (): FormDropDownListOption[] => {\r\n return props.countries.map(c => {\r\n return {\r\n name: c.name,\r\n value: c.id,\r\n };\r\n });\r\n };\r\n\r\n const getRegionsForDropdown = (values: ClientOrganization): FormDropDownListOption[] => {\r\n let options: ClientRegion[] = [];\r\n const defaultOptions = (options = props.regions.filter(\r\n r => r.countryId === DEFAULT_COUNTRY_ID,\r\n ));\r\n\r\n if (values.address) {\r\n if (values.address.country && values.address.country.id) {\r\n //If we have a valid country, display regions based on the countryId\r\n options = props.regions.filter(r => r.countryId === values.address!.country!.id);\r\n } else if (\r\n (!values.address.country || values.address.country.id === null) &&\r\n (values.address.stateOrRegion && values.address.stateOrRegion.id !== null)\r\n ) {\r\n //If we don't have a valid country, but we have a valid stateOrRegion, display regions based on selected stateOrRegion's countryId\r\n const region = props.regions.find(r => r.id === values!.address!.stateOrRegion!.id);\r\n if (region && region.countryId) {\r\n options = props.regions.filter(r => r.countryId === region.countryId);\r\n } else {\r\n options = defaultOptions;\r\n }\r\n } else {\r\n //Else, display a list of regions based on the DEFAULT_COUNTRY_ID\r\n options = defaultOptions;\r\n }\r\n }\r\n\r\n return options.map(r => {\r\n return {\r\n name: r.name,\r\n value: r.id,\r\n };\r\n });\r\n };\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const FormikEffect = connect((props: any) => {\r\n props.onFormChanged(props.formik);\r\n return null;\r\n });\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const onFormChanged = (form: FormikProps): void => {\r\n if (form && form.values) {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const formValues = form.values as any;\r\n //If both a country and a region are selected\r\n if (\r\n formValues.address &&\r\n formValues.address.country &&\r\n formValues.address.stateOrRegion &&\r\n formValues.address.country.id &&\r\n formValues.address.stateOrRegion.id\r\n ) {\r\n const country = props.countries.find(c => c.id === formValues.address.country.id);\r\n const region = props.regions.find(r => r.id === formValues.address.stateOrRegion.id);\r\n if (country && region && country.id !== region.countryId) {\r\n form.setFieldValue('address.stateOrRegion.id', null);\r\n }\r\n }\r\n }\r\n };\r\n\r\n const nameValidator = (name: string): string | void => {\r\n if (props.client.name === name) {\r\n return;\r\n }\r\n\r\n if (\r\n props.existingClientNames\r\n .map(name => name.toLowerCase().trim())\r\n .includes(name.toLowerCase().trim())\r\n ) {\r\n return 'Client name must be unique';\r\n }\r\n };\r\n\r\n const domainValidator = (domain: string): string | void => {\r\n const domainRegex = /.+\\..+$/;\r\n\r\n //Check each domain to be a valid domain address and for uniqueness with existing client domains\r\n if (!domainRegex.test(domain)) {\r\n return 'Client domain must be a valid domain address (ex. \"abc.com\")';\r\n }\r\n const cleanedUpDomain = domain.toLowerCase().trim();\r\n\r\n if (\r\n props.existingClientDomains\r\n .map(domain => domain.toLowerCase().trim())\r\n .includes(cleanedUpDomain)\r\n ) {\r\n return 'Client domain name must be unique';\r\n }\r\n\r\n if (ForbiddenDomains.includes(cleanedUpDomain)) {\r\n return `Client domain name cannot be a common domain such as ${cleanedUpDomain}.`;\r\n }\r\n };\r\n\r\n return (\r\n
\r\n

{`${props.client && props.client.isNew ? 'Create' : 'Edit'} Client`}

\r\n\r\n \r\n {({ errors, values, submitCount }): JSX.Element => (\r\n <>\r\n \r\n
\r\n {\r\n <>\r\n
\r\n
\r\n \r\n
\r\n\r\n
\r\n \r\n
\r\n\r\n
\r\n \r\n
\r\n\r\n
\r\n \r\n
\r\n\r\n
\r\n \r\n
\r\n\r\n
\r\n \r\n
\r\n\r\n
\r\n \r\n
\r\n\r\n
\r\n \r\n
\r\n
\r\n\r\n (\r\n
\r\n
\r\n
\r\n \r\n
\r\n
\r\n {\r\n arrayHelpers.push('');\r\n }}\r\n tabIndex={-1}\r\n />\r\n
\r\n
\r\n
\r\n
\r\n
\r\n {!values.domains || !values.domains.length ? (\r\n
(No Domain)
\r\n ) : (\r\n <>\r\n )}\r\n\r\n {values.domains.map((domain, idx) => {\r\n return (\r\n
\r\n \r\n
\r\n {\r\n arrayHelpers.remove(idx);\r\n return;\r\n }}\r\n tabIndex={-1}\r\n disabled={domainsInUseByLicenseAdmin.includes(domain)}\r\n data-testid={`domains-${idx}-delete-data-testid`}\r\n />\r\n
\r\n
\r\n );\r\n })}\r\n
\r\n
\r\n )}\r\n />\r\n
\r\n
\r\n \r\n
\r\n
\r\n \r\n }\r\n \r\n
\r\n \r\n {\r\n props.onDiscardClick(values);\r\n }}\r\n />\r\n
\r\n {submitCount > 0 && (\r\n \r\n )}\r\n
\r\n \r\n \r\n )}\r\n \r\n
\r\n );\r\n};\r\n\r\nexport default ClientEditForm;\r\n","// https://stackoverflow.com/a/2117523\nconst uuidv4 = (): string => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (([1e7] as any) + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c: any) =>\n (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16),\n );\n};\n\nconst generateUuid = (): string => uuidv4();\n\n// https://stackoverflow.com/a/13653180/3661319\nconst isValidUuid = (uuid: string): boolean => {\n const regex = new RegExp(\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,\n );\n\n return regex.test(uuid);\n};\n\nexport { generateUuid, isValidUuid };\n","import { IconProp } from '@fortawesome/fontawesome-svg-core';\r\nimport React, { ReactElement, useCallback, useContext, useEffect, useState } from 'react';\r\nimport { Card, CardBody, CardHeader } from 'reactstrap';\r\nimport { getEEClass } from '../../../utils/ee';\r\nimport { isDevelopmentEnvironment } from '../../../utils/general';\r\nimport { generateUuid } from '../../../utils/uuid';\r\nimport { BTCardsContainerContext } from '../cards-container/BTCardsContainer';\r\nimport BTIconButton from '../controls/icon-button/BTIconButton';\r\nimport './BTCard.scss';\r\n\r\nexport type BTCardIcons = {\r\n buttonIcon: IconProp;\r\n tooltip: string;\r\n onClick: () => void;\r\n disabled?: boolean;\r\n 'data-testid'?: string;\r\n};\r\n\r\nexport interface BTCardProps {\r\n cardObject: {}; // Holds a reference to an object so the card knows when to update things in relation to the cards container context\r\n title: string;\r\n cardIcons?: BTCardIcons[];\r\n metadata?: string[];\r\n sortValue: string;\r\n groupValue?: string;\r\n 'data-testid'?: string;\r\n}\r\n\r\nconst BTCard: React.FC = props => {\r\n const { registerCard, unregisterCard } = useContext(BTCardsContainerContext);\r\n\r\n // NOTE: The card ID must be unique for each component so we generate it inside the component\r\n const [cardId] = useState(generateUuid());\r\n\r\n const renderCard = useCallback((): ReactElement => {\r\n return (\r\n \r\n \r\n
\r\n {props.title}\r\n
\r\n
\r\n {props.cardIcons && props.cardIcons.length ? (\r\n props.cardIcons.map((currCardIcon, i) => {\r\n return (\r\n \r\n );\r\n })\r\n ) : (\r\n <>\r\n )}\r\n
\r\n
\r\n {props.children}\r\n \r\n );\r\n }, [props]);\r\n\r\n // Register / unregister the card when this component updates\r\n useEffect(() => {\r\n registerCard({\r\n cardId: cardId,\r\n metadata: props.metadata || [],\r\n sortValue: props.sortValue,\r\n groupValue: props.groupValue,\r\n cardElement: renderCard(),\r\n });\r\n\r\n // Make sure we unregister the card when this component gets updated or unmounted\r\n return (): void => {\r\n unregisterCard(cardId);\r\n };\r\n // When the props for this card changes, we want to unregister / reregister it with the new data, including a new render\r\n }, [props, registerCard, unregisterCard, renderCard, cardId]);\r\n\r\n // Render the card content, in case it isn't wrapped by a BTCardContainer that handles the displaying of the cards\r\n return renderCard();\r\n};\r\n\r\nexport default BTCard;\r\n","import React, { useEffect, useState } from 'react';\r\nimport BTCard from '../../../../common-page-components/card/BTCard';\r\n\r\ninterface Props {\r\n client: ClientOrganization;\r\n licenses: License[];\r\n isDisabled: boolean;\r\n onEditClick: (client: ClientOrganization) => void;\r\n onDeleteClick: (client: ClientOrganization) => void;\r\n}\r\n\r\nconst getMetadata = (client: ClientOrganization): string[] => {\r\n const metadata = [client.id, client.name];\r\n\r\n if (client.address) {\r\n metadata.push(\r\n ...[\r\n client.address.streetAddress,\r\n client.address.aptSuiteBldg,\r\n client.address.city,\r\n client.accountExecutive,\r\n ],\r\n );\r\n }\r\n\r\n return metadata;\r\n};\r\n\r\nconst isAddressBlank = (address: Address): boolean => {\r\n return (\r\n !address ||\r\n (!(address.aptSuiteBldg || '').trim() &&\r\n !(address.city || '').trim() &&\r\n !address.country &&\r\n !(address.streetAddress || '').trim() &&\r\n !address.stateOrRegion &&\r\n !(address.postalCode || '').trim())\r\n );\r\n};\r\n\r\nconst ClientListing: React.FC = ({\r\n client,\r\n licenses,\r\n isDisabled,\r\n onEditClick,\r\n onDeleteClick,\r\n}) => {\r\n const [metadata, setMetadata] = useState(getMetadata(client));\r\n const [doesClientOrganizationHaveLicenses, setDoesClientOrganizationHaveLicenses] = useState<\r\n boolean\r\n >();\r\n\r\n // Update metadata when client changes\r\n useEffect(() => {\r\n setMetadata(getMetadata(client));\r\n }, [client]);\r\n\r\n const getDeleteIconTooltip = (): string => {\r\n if (isDisabled) {\r\n return '';\r\n } else if (doesClientOrganizationHaveLicenses) {\r\n return 'This client organization cannot be deleted because it has active licenses';\r\n }\r\n return 'Delete';\r\n };\r\n\r\n useEffect(() => {\r\n setDoesClientOrganizationHaveLicenses(\r\n licenses &&\r\n licenses.findIndex(v => v.clientOrganization && v.clientOrganization.id === client.id) > -1,\r\n );\r\n }, [client, licenses]);\r\n\r\n return (\r\n {\r\n onEditClick(client);\r\n },\r\n tooltip: isDisabled ? '' : 'Edit',\r\n disabled: isDisabled,\r\n 'data-testid': 'client-edit',\r\n },\r\n {\r\n buttonIcon: 'trash',\r\n onClick: (): void => {\r\n onDeleteClick(client);\r\n },\r\n tooltip: getDeleteIconTooltip(),\r\n disabled: isDisabled || doesClientOrganizationHaveLicenses,\r\n 'data-testid': 'client-delete',\r\n },\r\n ]}\r\n >\r\n
\r\n
\r\n
\r\n \r\n
{client.id}
\r\n
\r\n
\r\n\r\n
\r\n
\r\n \r\n
{client.accountExecutive}
\r\n
\r\n
\r\n \r\n {client.domains && client.domains.length > 0 ? (\r\n client.domains.map(d =>
{d}
)\r\n ) : (\r\n
(No Domains)
\r\n )}\r\n
\r\n
\r\n\r\n
\r\n
\r\n \r\n {!client.address || isAddressBlank(client.address) ? (\r\n
(No Address)
\r\n ) : (\r\n <>\r\n
{client.address.streetAddress}
\r\n
{client.address.aptSuiteBldg}
\r\n
\r\n {!client.address.city ? '' : client.address.city + ', '}\r\n {!client.address.stateOrRegion ? '' : client.address.stateOrRegion.name + ' '}\r\n {client.address.postalCode}\r\n
\r\n {client.address.country &&
{client.address.country.name}
}\r\n \r\n )}\r\n
\r\n
\r\n {' '}\r\n \r\n
{client.usesCorporateActiveDirectory ? 'Yes' : 'No'}
\r\n
\r\n
\r\n
\r\n \r\n );\r\n};\r\n\r\nexport default ClientListing;\r\n","export const Countries: ClientCountry[] = [\n {\n id: 0,\n name: 'United States',\n },\n {\n id: 1,\n name: 'Canada',\n },\n];\n\nexport const Regions: ClientRegion[] = [\n {\n id: 0,\n name: 'Alabama',\n countryId: 0,\n },\n {\n id: 1,\n name: 'Alaska',\n countryId: 0,\n },\n {\n id: 2,\n name: 'Arizona',\n countryId: 0,\n },\n {\n id: 3,\n name: 'Arkansas',\n countryId: 0,\n },\n {\n id: 4,\n name: 'California',\n countryId: 0,\n },\n {\n id: 5,\n name: 'Colorado',\n countryId: 0,\n },\n {\n id: 6,\n name: 'Connecticut',\n countryId: 0,\n },\n {\n id: 7,\n name: 'Delaware',\n countryId: 0,\n },\n {\n id: 8,\n name: 'District of Columbia',\n countryId: 0,\n },\n {\n id: 9,\n name: 'Florida',\n countryId: 0,\n },\n {\n id: 10,\n name: 'Georgia',\n countryId: 0,\n },\n {\n id: 11,\n name: 'Hawaii',\n countryId: 0,\n },\n {\n id: 12,\n name: 'Idaho',\n countryId: 0,\n },\n {\n id: 13,\n name: 'Illinois',\n countryId: 0,\n },\n {\n id: 14,\n name: 'Indiana',\n countryId: 0,\n },\n {\n id: 15,\n name: 'Iowa',\n countryId: 0,\n },\n {\n id: 16,\n name: 'Kansas',\n countryId: 0,\n },\n {\n id: 17,\n name: 'Kentucky',\n countryId: 0,\n },\n {\n id: 18,\n name: 'Louisiana',\n countryId: 0,\n },\n {\n id: 19,\n name: 'Maine',\n countryId: 0,\n },\n {\n id: 20,\n name: 'Maryland',\n countryId: 0,\n },\n {\n id: 21,\n name: 'Massachusetts',\n countryId: 0,\n },\n {\n id: 22,\n name: 'Michigan',\n countryId: 0,\n },\n {\n id: 23,\n name: 'Minnesota',\n countryId: 0,\n },\n {\n id: 24,\n name: 'Mississippi',\n countryId: 0,\n },\n {\n id: 25,\n name: 'Missouri',\n countryId: 0,\n },\n {\n id: 26,\n name: 'Montana',\n countryId: 0,\n },\n {\n id: 27,\n name: 'Nebraska',\n countryId: 0,\n },\n {\n id: 28,\n name: 'Nevada',\n countryId: 0,\n },\n {\n id: 29,\n name: 'New Hampshire',\n countryId: 0,\n },\n {\n id: 30,\n name: 'New Jersey',\n countryId: 0,\n },\n {\n id: 31,\n name: 'New Mexico',\n countryId: 0,\n },\n {\n id: 32,\n name: 'New York',\n countryId: 0,\n },\n {\n id: 33,\n name: 'North Carolina',\n countryId: 0,\n },\n {\n id: 34,\n name: 'North Dakota',\n countryId: 0,\n },\n {\n id: 35,\n name: 'Ohio',\n countryId: 0,\n },\n {\n id: 36,\n name: 'Oklahoma',\n countryId: 0,\n },\n {\n id: 37,\n name: 'Oregon',\n countryId: 0,\n },\n {\n id: 38,\n name: 'Pennsylvania',\n countryId: 0,\n },\n {\n id: 39,\n name: 'Puerto Rico',\n countryId: 0,\n },\n {\n id: 40,\n name: 'Rhode Island',\n countryId: 0,\n },\n {\n id: 41,\n name: 'South Carolina',\n countryId: 0,\n },\n {\n id: 42,\n name: 'South Dakota',\n countryId: 0,\n },\n {\n id: 43,\n name: 'Tennessee',\n countryId: 0,\n },\n {\n id: 44,\n name: 'Texas',\n countryId: 0,\n },\n {\n id: 45,\n name: 'Utah',\n countryId: 0,\n },\n {\n id: 46,\n name: 'Vermont',\n countryId: 0,\n },\n {\n id: 47,\n name: 'Virginia',\n countryId: 0,\n },\n {\n id: 48,\n name: 'Washington',\n countryId: 0,\n },\n {\n id: 49,\n name: 'West Virginia',\n countryId: 0,\n },\n {\n id: 50,\n name: 'Wisconsin',\n countryId: 0,\n },\n {\n id: 51,\n name: 'Wyoming',\n countryId: 0,\n },\n {\n id: 52,\n name: 'Alberta',\n countryId: 1,\n },\n {\n id: 53,\n name: 'British Columbia',\n countryId: 1,\n },\n {\n id: 54,\n name: 'Manitoba',\n countryId: 1,\n },\n {\n id: 55,\n name: 'New Brunswick',\n countryId: 1,\n },\n {\n id: 56,\n name: 'Newfoundland and Labrador',\n countryId: 1,\n },\n {\n id: 57,\n name: 'Northwest Territories',\n countryId: 1,\n },\n {\n id: 58,\n name: 'Nova Scotia',\n countryId: 1,\n },\n {\n id: 59,\n name: 'Nunavut',\n countryId: 1,\n },\n {\n id: 60,\n name: 'Ontario',\n countryId: 1,\n },\n {\n id: 61,\n name: 'Prince Edward Island',\n countryId: 1,\n },\n {\n id: 62,\n name: 'Quebec',\n countryId: 1,\n },\n {\n id: 63,\n name: 'Saskatchewan',\n countryId: 1,\n },\n {\n id: 64,\n name: 'Yukon',\n countryId: 1,\n },\n];\n","import { isEqual } from 'lodash';\r\nimport React, { useContext, useEffect, useRef, useState } from 'react';\r\nimport { useHistory } from 'react-router';\r\nimport { Collapse } from 'reactstrap';\r\nimport { ClientApi } from '../../../../services/api';\r\nimport '../../../../styles/common.scss';\r\nimport { scrollToRef } from '../../../../utils/general';\r\nimport BTCardsContainer from '../../../common-page-components/cards-container/BTCardsContainer';\r\nimport ApplicationRoutes from './../../../../constants/routes';\r\nimport { ConfirmationOverlayContext } from './../../../common-page-components/confirmation-overlay/ConfirmationOverlayContext';\r\nimport BTFloatingIconButton from './../../../common-page-components/controls/floating-icon-button/BTFloatingIconButton';\r\nimport { LoadingPageOverlayContext } from './../../../common-page-components/loading-page-overlay/LoadingPageOverlayContext';\r\nimport { NotificationPanelContext } from './../../../common-page-components/notification-panel/NotificationPanelContext';\r\nimport './ClientsPage.scss';\r\nimport ClientEditForm from './components/ClientEditForm';\r\nimport ClientListing from './components/ClientListing';\r\nimport { Countries, Regions } from './data/LocationData';\r\nimport licensesApiService from '../../../../services/api/licenses/licenses-api-service';\r\n\r\nconst ClientsPage: React.FC = () => {\r\n const { showPageLoadingOverlay, hidePageLoadingOverlay } = useContext(LoadingPageOverlayContext);\r\n const { showConfirmationOverlay, hideConfirmationOverlay } = useContext(\r\n ConfirmationOverlayContext,\r\n );\r\n const { showSuccessNotification, showInfoNotification, showErrorNotification } = useContext(\r\n NotificationPanelContext,\r\n );\r\n\r\n const [licenses, setLicenses] = useState([]);\r\n const [clientToEdit, setClientToEdit] = useState();\r\n const [isPageDataLoaded, setIsPageDataLoaded] = useState(false);\r\n const [clients, setClients] = useState([]);\r\n const [countries, setCountries] = useState(Array());\r\n const [regions, setRegions] = useState(Array());\r\n const [isEditAreaOpen, setIsEditAreaOpen] = useState(false);\r\n const adminPageEditAreaRef = useRef(null);\r\n const history = useHistory();\r\n\r\n // Initial load of data\r\n useEffect(() => {\r\n setCountries(Countries);\r\n setRegions(Regions);\r\n\r\n const fetchData = async (): Promise => {\r\n try {\r\n showPageLoadingOverlay();\r\n\r\n const [clientData, licenseData] = await Promise.all([\r\n await ClientApi.getClientOrganizations(),\r\n await licensesApiService.getLicenses(),\r\n ]);\r\n\r\n setLicenses(licenseData);\r\n\r\n clientData.forEach(client => hydrateClientOrganization(client, Countries, Regions));\r\n\r\n setClients(clientData);\r\n\r\n setIsPageDataLoaded(true);\r\n } catch (error) {\r\n // In this case, we should send the user to an error page since this page isn't very useful without this core data\r\n showErrorNotification('Error', 'An error occurred while loading the page.');\r\n history.push(ApplicationRoutes.ERROR_ERROR);\r\n } finally {\r\n hidePageLoadingOverlay();\r\n }\r\n };\r\n\r\n fetchData();\r\n }, [hidePageLoadingOverlay, history, showPageLoadingOverlay, showErrorNotification]);\r\n\r\n const hydrateClientOrganization = (\r\n clientOrg: ClientOrganization,\r\n countries: ClientCountry[],\r\n regions: ClientRegion[],\r\n ): void => {\r\n if (!clientOrg.address) {\r\n return;\r\n }\r\n\r\n if (clientOrg.address.country) {\r\n const country = countries.find(c => c.name === clientOrg.address!.country!.name);\r\n\r\n if (!country) {\r\n throw new Error(`Could not find country with name '${clientOrg.address.country.name}'`);\r\n }\r\n\r\n clientOrg.address.country = country;\r\n }\r\n\r\n if (clientOrg.address.stateOrRegion) {\r\n const stateOrRegion = regions.find(c => c.name === clientOrg.address!.stateOrRegion!.name);\r\n\r\n if (!stateOrRegion) {\r\n throw new Error(\r\n `Could not find region with name '${clientOrg.address.stateOrRegion.name}'`,\r\n );\r\n }\r\n\r\n clientOrg.address.stateOrRegion = stateOrRegion;\r\n }\r\n };\r\n\r\n const getNewClient = (): ClientOrganization => ({\r\n id: '',\r\n name: '',\r\n address: {\r\n streetAddress: '',\r\n aptSuiteBldg: '',\r\n city: '',\r\n postalCode: '',\r\n stateOrRegion: {\r\n name: '',\r\n },\r\n country: {\r\n name: '',\r\n },\r\n },\r\n accountExecutive: '',\r\n isNew: true,\r\n domains: [],\r\n usesCorporateActiveDirectory: false,\r\n });\r\n\r\n const toggleCollapse = (open: boolean): void => {\r\n setIsEditAreaOpen(open);\r\n\r\n if (open) {\r\n setTimeout(() => {\r\n scrollToRef(adminPageEditAreaRef);\r\n }, 500);\r\n }\r\n };\r\n\r\n const onFormDiscard = (client: ClientOrganization): void => {\r\n const discardChanges = (): void => {\r\n // Delay this slightly so the edit area has time to animate closed\r\n toggleCollapse(false);\r\n setTimeout(() => {\r\n setClientToEdit(null);\r\n }, 250);\r\n };\r\n\r\n if (!isEqual(client, clientToEdit)) {\r\n showConfirmationOverlay({\r\n title: 'Confirm',\r\n text: 'Are you sure you want to discard your changes?',\r\n buttons: [\r\n {\r\n text: 'Yes',\r\n onClick: (): void => {\r\n hideConfirmationOverlay();\r\n discardChanges();\r\n },\r\n },\r\n {\r\n text: 'No',\r\n onClick: (): void => hideConfirmationOverlay(),\r\n color: 'gray',\r\n },\r\n ],\r\n });\r\n } else {\r\n discardChanges();\r\n }\r\n };\r\n\r\n const onFormSave = async (client: ClientOrganization): Promise => {\r\n showPageLoadingOverlay();\r\n\r\n const closeEditAreaAndClearOutEditModel = (): void => {\r\n setIsEditAreaOpen(false);\r\n\r\n // Delay this slightly so the edit area has time to animate closed\r\n setTimeout(() => {\r\n setClientToEdit(null);\r\n }, 250);\r\n };\r\n\r\n // If populated, match up the selected country or stateOrRegion id with appropriate object,\r\n // and clean up the region field if the user has changed the country selection without making a new stateOrRegion\r\n if (client.address) {\r\n if (client.address.country) {\r\n client.address.country = countries.find(c => c.id === client.address!.country.id);\r\n }\r\n if (client.address.stateOrRegion) {\r\n client.address.stateOrRegion = regions.find(r => r.id === client.address!.stateOrRegion.id);\r\n }\r\n }\r\n\r\n if (client.isNew) {\r\n try {\r\n const clientOrg = await ClientApi.addClientOrganization(client);\r\n hydrateClientOrganization(clientOrg, countries, regions);\r\n setClients([...clients, clientOrg]);\r\n\r\n closeEditAreaAndClearOutEditModel();\r\n\r\n showSuccessNotification('Success', 'The client was created successfully.');\r\n } catch {\r\n showErrorNotification('Error', 'An error occurred while attempting to create the client.');\r\n } finally {\r\n hidePageLoadingOverlay();\r\n }\r\n return;\r\n }\r\n\r\n try {\r\n if (isEqual(client, clientToEdit)) {\r\n closeEditAreaAndClearOutEditModel();\r\n\r\n showInfoNotification('No Changes', 'No changes were made to the client.');\r\n return;\r\n }\r\n\r\n await ClientApi.editClientOrganization(client);\r\n const clientsClone = [...clients];\r\n const index = clientsClone.findIndex(c => c.id === client.id);\r\n\r\n if (index === -1) {\r\n throw new Error(`Could not find client with ID '${client.id}'.`);\r\n }\r\n\r\n clientsClone[index] = client;\r\n\r\n setClients(clientsClone);\r\n\r\n closeEditAreaAndClearOutEditModel();\r\n\r\n showSuccessNotification('Success', 'The client was updated successfully.');\r\n } catch {\r\n showErrorNotification('Error', 'An error occurred while attempting to update the client.');\r\n } finally {\r\n hidePageLoadingOverlay();\r\n }\r\n };\r\n\r\n const onAddClick = (): void => {\r\n setClientToEdit(getNewClient());\r\n toggleCollapse(true);\r\n };\r\n\r\n const onEditClick = (client: ClientOrganization): void => {\r\n setClientToEdit(client);\r\n toggleCollapse(true);\r\n };\r\n\r\n const onDeleteClick = (client: ClientOrganization): void => {\r\n // NOTE: The delete button on the card listing should be disabled so if we get to this\r\n // point, we can assume things are OK and the server can confirm any errors\r\n showConfirmationOverlay({\r\n title: 'Confirm',\r\n text: `Are you sure you want to delete the client \"${client.name}\"?`,\r\n buttons: [\r\n {\r\n text: 'Yes',\r\n onClick: async (): Promise => {\r\n hideConfirmationOverlay();\r\n showPageLoadingOverlay();\r\n\r\n try {\r\n await ClientApi.deleteClientOrganization(client.id);\r\n const updatedClients = clients.filter(c => c.id !== client.id);\r\n setClients(updatedClients);\r\n\r\n showSuccessNotification('Success', 'The client was deleted successfully.');\r\n } catch {\r\n showErrorNotification(\r\n 'Error',\r\n 'An error occurred while attempting to delete the client.',\r\n );\r\n } finally {\r\n hidePageLoadingOverlay();\r\n }\r\n },\r\n color: 'normal',\r\n },\r\n {\r\n text: 'No',\r\n onClick: (): void => {\r\n hideConfirmationOverlay();\r\n },\r\n color: 'gray',\r\n },\r\n ],\r\n });\r\n };\r\n\r\n if (!isPageDataLoaded) {\r\n return <>;\r\n }\r\n\r\n return (\r\n <>\r\n
\r\n

Clients

\r\n
\r\n\r\n
\r\n \r\n
\r\n
\r\n {clientToEdit && (\r\n l.clientOrganization.id === clientToEdit.id)}\r\n existingClientNames={clients.map(c => c.name.toLowerCase())}\r\n existingClientDomains={clients\r\n .filter(c => c.id !== clientToEdit.id)\r\n .map(c => c.domains)\r\n .reduce((previousValue, currentValue) =>\r\n previousValue.concat(currentValue.map(domain => domain.toLowerCase())),\r\n )}\r\n onDiscardClick={onFormDiscard}\r\n onSaveClick={onFormSave}\r\n />\r\n )}\r\n
\r\n
\r\n
\r\n
\r\n
\r\n \r\n {clients.map(client => {\r\n return (\r\n \r\n );\r\n })}\r\n \r\n
\r\n\r\n \r\n \r\n );\r\n};\r\n\r\nexport default ClientsPage;\r\n","import { DatePicker } from '@progress/kendo-react-dateinputs';\r\nimport { Field, FieldProps } from 'formik';\r\nimport _ from 'lodash';\r\nimport React from 'react';\r\nimport './Forms.scss';\r\n\r\ninterface Props {\r\n label: string;\r\n name: string;\r\n tabIndex?: number;\r\n validator?: (value: Date) => string | void;\r\n}\r\n\r\nconst WrappedFormDatePicker: React.FC = ({ field, form, label, ...rest }) => {\r\n const errors = _.get(form.errors, field.name);\r\n const hasErrors = !!errors;\r\n\r\n const classNames = ['formInput'];\r\n if (hasErrors && form.submitCount) {\r\n classNames.push('formInputError');\r\n }\r\n\r\n return (\r\n <>\r\n \r\n {\r\n form.setFieldValue(field.name, event.target.value);\r\n }}\r\n onBlur={(): void => {\r\n // We have to override the onBlur event or else the date picker will set the value several times when\r\n // the user clicks to choose a date. The values it sets fluctuate between the old / new values and only once the user\r\n // clicks outside of the date picker will the new value be set.\r\n }}\r\n />\r\n \r\n );\r\n};\r\n\r\nconst FormDatePicker: React.FC = props => {\r\n return (\r\n
\r\n \r\n
\r\n );\r\n};\r\n\r\nexport default FormDatePicker;\r\n","import { MultiSelect } from '@progress/kendo-react-dropdowns';\r\nimport { Field, FieldInputProps, FieldProps } from 'formik';\r\nimport { get, sortBy } from 'lodash';\r\nimport React from 'react';\r\nimport './Forms.scss';\r\n\r\nexport interface FormMultiSelectOption {\r\n id: string;\r\n name: string;\r\n}\r\n\r\ninterface FieldValue {\r\n id: string;\r\n // NOTE: using any here to make a dict type\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n [key: string]: any;\r\n}\r\n\r\ninterface Props {\r\n placeholderText: string;\r\n label: string;\r\n name: string;\r\n data: FormMultiSelectOption[];\r\n validator?: (value: string) => string | void;\r\n}\r\n\r\nconst getValueForMultiSelect = (\r\n data: FormMultiSelectOption[],\r\n field: FieldInputProps,\r\n): FieldValue[] => {\r\n return !field.value\r\n ? []\r\n : sortBy(data.filter(v => field.value.find(fv => fv.id === v.id) !== undefined), v => v.name);\r\n};\r\n\r\nconst WrappedMultiSelect: React.FC = ({\r\n field,\r\n form,\r\n placeholderText,\r\n label,\r\n data,\r\n ...rest\r\n}) => {\r\n const errors = get(form.errors, field.name);\r\n const hasErrors = !!errors;\r\n\r\n const classNames = ['formInput'];\r\n if (hasErrors && form.submitCount) {\r\n classNames.push('formInputError');\r\n }\r\n\r\n // NOTE: Keep the field / rest props at the top so we can override the onChange property\r\n return (\r\n <>\r\n \r\n v.name) : []}\r\n {...field}\r\n {...rest}\r\n value={getValueForMultiSelect(data, field)}\r\n onChange={(newValue): void => {\r\n // Sort the values before we set them, to try to prevent data getting out of order and changing unnecessarily\r\n const newValues = sortBy(newValue.target.value as FormMultiSelectOption[], v => v.name);\r\n form.setFieldValue(field.name, newValues);\r\n }}\r\n />\r\n \r\n );\r\n};\r\n\r\nconst FormMultiSelect: React.FC = props => {\r\n return (\r\n
\r\n \r\n
\r\n );\r\n};\r\n\r\nexport default FormMultiSelect;\r\n","import React from 'react';\r\nimport { NumericTextBox } from '@progress/kendo-react-inputs';\r\nimport { Field, FieldProps } from 'formik';\r\nimport _ from 'lodash';\r\nimport './Forms.scss';\r\n\r\ninterface Props {\r\n label: string;\r\n name: string;\r\n min?: number;\r\n max?: number;\r\n tabIndex?: number;\r\n validator?: (value: string) => string | void;\r\n}\r\n\r\nconst WrappedNumericTextInput: React.FC = ({ field, form, label, ...rest }) => {\r\n const errors = _.get(form.errors, field.name);\r\n const hasErrors = !!errors;\r\n\r\n const classNames = ['formInput'];\r\n if (hasErrors && form.submitCount) {\r\n classNames.push('formInputError');\r\n }\r\n\r\n return (\r\n <>\r\n \r\n \r\n \r\n );\r\n};\r\n\r\nconst FormNumericTextInput: React.FC = props => {\r\n return (\r\n
\r\n \r\n
\r\n );\r\n};\r\n\r\nexport default FormNumericTextInput;\r\n","import { Form, Formik, FormikErrors, validateYupSchema, yupToFormErrors } from 'formik';\nimport { Values } from 'formsy-react/dist/interfaces';\nimport React from 'react';\nimport * as Yup from 'yup';\nimport BTButton from '../../../../common-page-components/controls/button/BTButton';\nimport FormErrorContainer from '../../../../common-page-components/forms/form-error-container/FormErrorContainer';\nimport FormDatePicker from '../../../../common-page-components/forms/FormDatePicker';\nimport FormDropDownList from '../../../../common-page-components/forms/FormDropDownList';\nimport FormFooter from '../../../../common-page-components/forms/FormFooter';\nimport FormMultiSelect from '../../../../common-page-components/forms/FormMultiSelect';\nimport FormNumericTextInput from '../../../../common-page-components/forms/FormNumericTextInput';\nimport FormSwitch from '../../../../common-page-components/forms/FormSwitch';\nimport { getFormErrorMessages } from '../../../../../utils/forms';\nimport FormTextInput from '../../../../common-page-components/forms/FormTextInput';\n\nconst FormSchema = Yup.object().shape({\n id: Yup.string(),\n isNew: Yup.boolean(),\n clientOrganization: Yup.object().shape({\n id: Yup.string().required('The client is required'),\n name: Yup.string(),\n domains: Yup.array().of(Yup.string()),\n }),\n product: Yup.object().shape({\n id: Yup.string().required('The product is required'),\n name: Yup.string(),\n features: Yup.array().of(\n Yup.object().shape({\n id: Yup.string(),\n name: Yup.string(),\n isNew: Yup.boolean(),\n hasActiveLicenses: Yup.boolean(),\n }),\n ),\n deploymentTypeId: Yup.string().nullable(),\n }),\n enforceStrictUserCount: Yup.boolean().required('The unlimited users setting is required'),\n userCount: Yup.number()\n .required()\n .typeError('The user count is required')\n .min(1, 'The user count must be at least 1')\n .max(1000, 'The user count cannot exceed 1000'),\n effectiveDate: Yup.date().required('The effective date is required'),\n expirationDate: Yup.date().required('The effective date is required'),\n deploymentDetails: Yup.object(),\n deploymentStatus: Yup.string().nullable(),\n adminUser: Yup.string()\n .trim()\n .email('The Administrator email address is not valid')\n .nullable(),\n});\n\ninterface Props {\n license: License;\n availableClientOrganizations: ClientOrganization[];\n availableProducts: Product[];\n existingLicenses: License[];\n onSubmitClick: (license: License) => void;\n onDiscardClick: (license: License) => void;\n}\n\nconst LicenseEditForm: React.FC = props => {\n const validateForm = (values: Values): FormikErrors => {\n const allEditModelValues = values as License;\n\n const validateWithYup = (): FormikErrors => {\n try {\n validateYupSchema(values, FormSchema, true, values);\n } catch (err) {\n return yupToFormErrors(err); //for rendering validation errors\n }\n return {};\n };\n\n const validateDates = (): FormikErrors => {\n const dateErrors: FormikErrors = {};\n // Validate that the dates are in order\n if (!(allEditModelValues.effectiveDate < allEditModelValues.expirationDate)) {\n dateErrors.effectiveDate = 'The effective date must come before the expiration date';\n }\n\n return dateErrors;\n };\n\n const validateClientOrganizationAndProduct = (): FormikErrors => {\n const clientOrganizationAndProductErrors: FormikErrors = {};\n // Validate that the selected client organization / product are unique amongst the other licenses on the page\n if (allEditModelValues.clientOrganization.id && allEditModelValues.product.id) {\n const clientOrganizationAndProductComboAlreadyExist = props.existingLicenses.find(\n v =>\n v.id !== allEditModelValues.id &&\n v.clientOrganization.id === allEditModelValues.clientOrganization.id &&\n v.product.id === allEditModelValues.product.id,\n );\n\n if (clientOrganizationAndProductComboAlreadyExist) {\n const errorMessage = 'The selected client organization / product is already in use';\n clientOrganizationAndProductErrors['clientOrganization.id'] = errorMessage;\n clientOrganizationAndProductErrors['product.id'] = errorMessage;\n }\n }\n\n return clientOrganizationAndProductErrors;\n };\n\n const validateAdministratorEmail = (\n previousErrors: FormikErrors,\n ): FormikErrors => {\n const errors: FormikErrors = {};\n\n if (\n productHasDeploymentType(allEditModelValues.product.id) &&\n !allEditModelValues.adminUser\n ) {\n errors.adminUser = 'Administrator is a required field';\n } else if (allEditModelValues.adminUser && !previousErrors.adminUser) {\n const administratorDomain = allEditModelValues.adminUser\n .trim()\n .toLowerCase()\n .split('@')[1];\n const selectedClientOrganization = props.availableClientOrganizations.find(\n x => x.id === allEditModelValues.clientOrganization.id,\n );\n if (\n selectedClientOrganization &&\n !selectedClientOrganization.domains.find(\n d => d.trim().toLowerCase() === administratorDomain,\n )\n ) {\n errors.adminUser = `The Administrator email address must be for one of the following domains: \"${selectedClientOrganization.domains}\".`;\n }\n }\n\n return errors;\n };\n\n const yupErrors = validateWithYup();\n\n return {\n ...yupErrors,\n ...validateDates(),\n ...validateClientOrganizationAndProduct(),\n ...validateAdministratorEmail(yupErrors),\n };\n };\n\n const getDataForFeatures = (selectedProductId: string | null): ProductFeature[] => {\n if (!selectedProductId) {\n return [];\n }\n\n const selectedProduct = props.availableProducts.find(v => v.id === selectedProductId);\n return selectedProduct ? selectedProduct.features : [];\n };\n\n const productHasDeploymentType = (productId: string): boolean => {\n const invalidDeploymentTypes = [null, 'None'];\n const product = props.availableProducts.find(p => p.id === productId);\n return !product ? false : !invalidDeploymentTypes.includes(product.deploymentTypeId);\n };\n\n const getAdminPlaceholder = (selectedClientOrganizationId: string): string => {\n const selectedClientOrganization = props.availableClientOrganizations.find(\n x => x.id === selectedClientOrganizationId,\n );\n return selectedClientOrganization ? `admin@${selectedClientOrganization.domains[0]}` : '';\n };\n\n // NOTE: With Formik, once we set the 'initialValues' property, updating it will not update the form values unless we set the 'enableReinitialize' flag\n // so we do not even render the Formik element unless the object we bind to its initial values is defined\n return (\n
\n

{`${props.license && props.license.isNew ? 'Create' : 'Edit'} License`}

\n\n {props.license && (\n \n {({ errors, values, submitCount }): JSX.Element => (\n
\n {\n <>\n
\n
\n ({\n name: client.name,\n value: client.id,\n }))}\n placeholderText=\"(Select a client)\"\n label=\"Client\"\n name=\"clientOrganization.id\"\n disabled={!props.license.isNew}\n />\n
\n\n
\n ({\n name: product.name,\n value: product.id,\n }))}\n placeholderText=\"(Select a product)\"\n label=\"Product\"\n name=\"product.id\"\n disabled={!props.license.isNew}\n />\n
\n
\n\n
\n
\n \n
\n
\n\n
\n
\n \n
\n\n
\n \n
\n\n {productHasDeploymentType(values.product.id) && (\n
\n \n
\n )}\n
\n\n
\n
\n \n
\n\n
\n \n
\n
\n \n }\n\n \n
\n \n {\n props.onDiscardClick(values);\n }}\n tabIndex={6}\n />\n
\n {submitCount > 0 && (\n \n )}\n
\n
\n )}\n \n )}\n
\n );\n};\n\nexport default LicenseEditForm;\n","const ProductsConstants = {\r\n DeploymentTypes: {\r\n NONE: 'None',\r\n },\r\n};\r\n\r\nexport default ProductsConstants;\r\n","import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { isDate } from 'lodash';\nimport React, { useState } from 'react';\nimport { Collapse, Popover, PopoverBody, PopoverHeader } from 'reactstrap';\nimport { getShortDateString } from '../../../../../utils/dates';\nimport BTCard from '../../../../common-page-components/card/BTCard';\nimport BTButton from '../../../../common-page-components/controls/button/BTButton';\nimport LicensesConstants from './../../../../../constants/licenses';\nimport ProductsConstants from './../../../../../constants/products';\nimport './LicenseListing.scss';\n\ninterface Props {\n editLicenseButtonClick: (productLicense: License) => void;\n deleteLicenseButtonClick: (productLicense: License) => void;\n requestDeploymentButtonClick: (productLicense: License) => void;\n redeployButtonClick: (productLicense: License) => void;\n isEditAreaOpen: boolean;\n license: License;\n}\n\nconst LicenseListing: React.FC = ({\n license,\n isEditAreaOpen,\n editLicenseButtonClick,\n deleteLicenseButtonClick,\n requestDeploymentButtonClick,\n redeployButtonClick,\n}) => {\n const title = `${license.clientOrganization.name} - ${license.product.name}`;\n\n const [deploymentInfoAreaIsDisplayed, setDeploymentInfoAreaIsDisplayed] = useState(\n false,\n );\n\n const [popoverOpen, setPopoverOpen] = useState>({});\n\n const toggle = (target: string): void => {\n if (!popoverOpen[target]) {\n setPopoverOpen({\n ...popoverOpen,\n [target]: true,\n });\n } else {\n setPopoverOpen({\n ...popoverOpen,\n [target]: !popoverOpen[target],\n });\n }\n };\n\n const shouldShowDeploymentInfo = (): boolean => {\n return (\n license.product.deploymentTypeId !== null &&\n license.product.deploymentTypeId.length > 0 &&\n license.product.deploymentTypeId !== ProductsConstants.DeploymentTypes.NONE\n );\n };\n\n const isDeploymentComplete = (): boolean =>\n license.deploymentStatus === LicensesConstants.DeploymentStatuses.COMPLETED;\n\n const isDeploymentError = (): boolean =>\n license.deploymentStatus === LicensesConstants.DeploymentStatuses.ERROR;\n\n const canDeploymentBeRequested = (): boolean =>\n [null, LicensesConstants.DeploymentStatuses.NONE].includes(license.deploymentStatus);\n\n const getDeploymentStatusCSSClass = (): string => {\n switch (license.deploymentStatus) {\n case LicensesConstants.DeploymentStatuses.COMPLETED:\n return 'completed';\n\n case LicensesConstants.DeploymentStatuses.ERROR:\n return 'error';\n\n case LicensesConstants.DeploymentStatuses.REQUESTED:\n return 'requested';\n\n default:\n return '';\n }\n };\n\n const getDeploymentStatusText = (): string => {\n switch (license.deploymentStatus) {\n case LicensesConstants.DeploymentStatuses.COMPLETED:\n return LicensesConstants.DeploymentStatusesDisplayNames.COMPLETED;\n\n case LicensesConstants.DeploymentStatuses.ERROR:\n return LicensesConstants.DeploymentStatusesDisplayNames.ERROR;\n\n case LicensesConstants.DeploymentStatuses.IN_PROGRESS:\n return LicensesConstants.DeploymentStatusesDisplayNames.IN_PROGRESS;\n\n case LicensesConstants.DeploymentStatuses.REQUESTED:\n return LicensesConstants.DeploymentStatusesDisplayNames.REQUESTED;\n\n case LicensesConstants.DeploymentStatuses.NONE:\n default:\n return LicensesConstants.DeploymentStatusesDisplayNames.NONE;\n }\n };\n\n // A deployment detail can contain a date string.\n // Our axios middleware recognizes and converts date strings to date objects, for convenience, so\n // we need to handle formatting the date strings (when applicable).\n const getDeploymentDetailValueText = (deploymentDetailValueObject: string | Date): string => {\n return isDate(deploymentDetailValueObject)\n ? getShortDateString(deploymentDetailValueObject)\n : deploymentDetailValueObject;\n };\n\n const getDeploymentDetailsStringForKey = (input: string): string => {\n return input.replace(/\\s/g, '');\n };\n\n return (\n {\n editLicenseButtonClick(license);\n },\n tooltip: isEditAreaOpen ? '' : 'Edit',\n disabled: isEditAreaOpen,\n 'data-testid': 'license-edit',\n },\n {\n buttonIcon: 'trash',\n onClick: (): void => {\n deleteLicenseButtonClick(license);\n },\n tooltip: isEditAreaOpen ? '' : 'Delete',\n disabled: isEditAreaOpen,\n 'data-testid': 'license-delete',\n },\n ]}\n >\n
\n
\n
\n \n
{license.product.name}
\n
\n\n
\n \n\n
\n {license.enforceStrictUserCount\n ? `${license.userCount} User` + (license.userCount === 1 ? '' : 's')\n : 'Unlimited'}\n
\n
\n
\n\n
\n
\n \n\n {!license.product.features.length ? (\n
(No Features)
\n ) : (\n
\n {license.product.features.map(currFeature => {\n return (\n
\n {currFeature.name}\n
\n );\n })}\n
\n )}\n
\n\n
\n \n
\n {getShortDateString(license.effectiveDate)}\n \n {getShortDateString(license.expirationDate)}\n
\n
\n
\n\n {shouldShowDeploymentInfo() && (\n
\n {\n setDeploymentInfoAreaIsDisplayed(!deploymentInfoAreaIsDisplayed);\n }}\n >\n \n \n \n\n Deployment Info\n \n \n\n \n
\n
\n
\n \n \n {getDeploymentStatusText()}\n
\n\n {canDeploymentBeRequested() && (\n
\n requestDeploymentButtonClick(license)}\n />\n
\n )}\n
\n\n {(isDeploymentComplete() || isDeploymentError()) && (\n <>\n
\n
\n \n
\n {Object.keys(license.deploymentDetails).map(v => (\n
\n
{v}
\n
\n {getDeploymentDetailValueText(license.deploymentDetails[v])}\n
\n \n toggle(`view-${getDeploymentDetailsStringForKey(v)}`)\n }\n >\n {v}\n \n {getDeploymentDetailValueText(license.deploymentDetails[v])}\n \n \n \n \n
\n {\n navigator.clipboard.writeText(\n getDeploymentDetailValueText(license.deploymentDetails[v]),\n );\n }}\n >\n \n
\n
\n ))}\n
\n
\n
\n\n
\n \n
\n redeployButtonClick(license)}\n />\n
\n
\n \n )}\n
\n \n \n \n )}\n \n \n );\n};\n\nexport default LicenseListing;\n","import { isEqual } from 'lodash';\r\nimport React, { useContext, useEffect, useRef, useState } from 'react';\r\nimport { useHistory } from 'react-router';\r\nimport { Collapse } from 'reactstrap';\r\nimport { scrollToRef } from '../../../../utils/general';\r\nimport BTCardsContainer from '../../../common-page-components/cards-container/BTCardsContainer';\r\nimport BTFloatingIconButton from '../../../common-page-components/controls/floating-icon-button/BTFloatingIconButton';\r\nimport { NotificationPanelContext } from '../../../common-page-components/notification-panel/NotificationPanelContext';\r\nimport ApplicationRoutes from './../../../../constants/routes';\r\nimport { ClientApi, LicenseApi, ProductApi } from './../../../../services/api';\r\nimport { ConfirmationOverlayContext } from './../../../common-page-components/confirmation-overlay/ConfirmationOverlayContext';\r\nimport { LoadingPageOverlayContext } from './../../../common-page-components/loading-page-overlay/LoadingPageOverlayContext';\r\nimport LicenseEditForm from './components/LicenseEditForm';\r\nimport LicenseListing from './components/LicenseListing';\r\nimport './LicensesPage.scss';\r\nimport licensesApiService from '../../../../services/api/licenses/licenses-api-service';\r\nimport LicensesConstants from '../../../../constants/licenses';\r\n\r\nconst LicensesPage: React.FC<{}> = () => {\r\n const history = useHistory();\r\n\r\n const { showPageLoadingOverlay, hidePageLoadingOverlay } = useContext(LoadingPageOverlayContext);\r\n const { showConfirmationOverlay, hideConfirmationOverlay } = useContext(\r\n ConfirmationOverlayContext,\r\n );\r\n const { showSuccessNotification, showInfoNotification, showErrorNotification } = useContext(\r\n NotificationPanelContext,\r\n );\r\n\r\n const [licenses, setLicenses] = useState([]);\r\n const [availableProducts, setAvailableProducts] = useState([]);\r\n const [availableClientOrganizations, setAvailableClientOrganizations] = useState<\r\n ClientOrganization[]\r\n >([]);\r\n const [isEditAreaOpen, setIsEditAreaOpen] = useState(false);\r\n const [licenseToEdit, setLicenseToEdit] = useState();\r\n const [isPageDataLoaded, setIsPageDataLoaded] = useState(false);\r\n\r\n const adminPageEditAreaRef = useRef(null);\r\n\r\n // TODO: we are not currently getting enough data back from the `getLicenses` API call so we\r\n // must hydrate manually. This should be removed once we update the API call.\r\n const hydrateLicense = (\r\n license: License,\r\n clientOrgs: ClientOrganization[],\r\n products: Product[],\r\n ): void => {\r\n const clientOrg = clientOrgs.find(clientOrg => clientOrg.id === license.clientOrganization.id);\r\n\r\n if (!clientOrg) {\r\n throw new Error(\r\n `Could not find Client Organization with ID '${license.clientOrganization.id}'`,\r\n );\r\n }\r\n\r\n license.clientOrganization.name = clientOrg.name;\r\n license.clientOrganization.domains = clientOrg.domains;\r\n\r\n const product = products.find(product => product.id === license.product.id);\r\n\r\n if (!product) {\r\n throw new Error(`Could not find Product with ID '${license.product.id}'`);\r\n }\r\n\r\n license.product.name = product.name;\r\n\r\n license.product.features.forEach(feature => {\r\n const productFeature = product.features.find(\r\n productFeature => productFeature.id === feature.id,\r\n );\r\n\r\n if (!productFeature) {\r\n throw new Error(\r\n `Could not find Feature with ID '${feature.id}' on Product with ID '${product.id}'`,\r\n );\r\n }\r\n\r\n feature.name = productFeature.name;\r\n feature.hasActiveLicenses = productFeature.hasActiveLicenses;\r\n });\r\n\r\n license.product.deploymentTypeId = product.deploymentTypeId;\r\n };\r\n\r\n // Initial load of data\r\n useEffect(() => {\r\n const getAndSetLicensesData = async (): Promise => {\r\n try {\r\n showPageLoadingOverlay();\r\n\r\n const [licensesData, availableProductsData, clientOrganizationsData] = await Promise.all([\r\n LicenseApi.getLicenses(),\r\n ProductApi.getProducts(),\r\n ClientApi.getClientOrganizations(),\r\n ]);\r\n\r\n // TODO: we are not currently getting enough data back from the `getLicenses` API call so we\r\n // must hydrate manually. This should be removed once we update the API call.\r\n licensesData.forEach(license =>\r\n hydrateLicense(license, clientOrganizationsData, availableProductsData),\r\n );\r\n\r\n setAvailableProducts(availableProductsData);\r\n setAvailableClientOrganizations(clientOrganizationsData);\r\n setLicenses(licensesData);\r\n\r\n setIsPageDataLoaded(true);\r\n } catch (error) {\r\n // In this case, we should send the user to an error page since this page isn't very useful without this core data\r\n showErrorNotification('Error', 'An error occurred while loading the page.');\r\n history.push(ApplicationRoutes.ERROR_ERROR);\r\n } finally {\r\n hidePageLoadingOverlay();\r\n }\r\n };\r\n\r\n getAndSetLicensesData();\r\n }, [hidePageLoadingOverlay, history, showPageLoadingOverlay, showErrorNotification]);\r\n\r\n const onSubmit = async (license: License): Promise => {\r\n showPageLoadingOverlay();\r\n\r\n const closeEditAreaAndClearOutEditModel = (): void => {\r\n setIsEditAreaOpen(false);\r\n\r\n // Delay this slightly so the edit area has time to animate closed\r\n setTimeout(() => {\r\n setLicenseToEdit(null);\r\n }, 250);\r\n };\r\n\r\n try {\r\n if (license.isNew) {\r\n try {\r\n const newLicense = await LicenseApi.addLicense(license);\r\n hydrateLicense(newLicense, availableClientOrganizations, availableProducts);\r\n setLicenses([...licenses, newLicense]);\r\n\r\n closeEditAreaAndClearOutEditModel();\r\n\r\n showSuccessNotification('Success', 'The license was created successfully.');\r\n } catch {\r\n showErrorNotification(\r\n 'Error',\r\n 'An error occurred while attempting to create the license.',\r\n );\r\n }\r\n } else {\r\n try {\r\n if (isEqual(license, licenseToEdit)) {\r\n closeEditAreaAndClearOutEditModel();\r\n\r\n showInfoNotification('No Changes', 'No changes were made to the license.');\r\n return;\r\n }\r\n\r\n await LicenseApi.editLicense(license);\r\n const licensesClone = [...licenses];\r\n\r\n const index = licensesClone.findIndex(l => l.id === license.id);\r\n\r\n if (index === -1) {\r\n throw new Error(`Could not find license with ID '${license.id}'.`);\r\n }\r\n\r\n licensesClone[index] = license;\r\n\r\n setLicenses(licensesClone);\r\n\r\n closeEditAreaAndClearOutEditModel();\r\n\r\n showSuccessNotification('Success', 'The license was updated successfully.');\r\n } catch {\r\n showErrorNotification(\r\n 'Error',\r\n 'An error occurred while attempting to update the license.',\r\n );\r\n }\r\n }\r\n } finally {\r\n hidePageLoadingOverlay();\r\n }\r\n };\r\n\r\n const onDiscard = (license: License): void => {\r\n const discardChanges = (): void => {\r\n setIsEditAreaOpen(false);\r\n\r\n // Delay this slightly so the edit area has time to animate closed\r\n setTimeout(() => {\r\n setLicenseToEdit(null);\r\n }, 250);\r\n };\r\n\r\n if (!isEqual(license, licenseToEdit)) {\r\n showConfirmationOverlay({\r\n title: 'Confirm',\r\n text: 'Are you sure you want to discard your unsaved changes?',\r\n buttons: [\r\n {\r\n text: 'Yes',\r\n onClick: (): void => {\r\n discardChanges();\r\n hideConfirmationOverlay();\r\n },\r\n color: 'normal',\r\n },\r\n {\r\n text: 'No',\r\n onClick: (): void => {\r\n hideConfirmationOverlay();\r\n },\r\n color: 'gray',\r\n },\r\n ],\r\n });\r\n } else {\r\n discardChanges();\r\n }\r\n };\r\n\r\n const editLicenseButtonClick = (license: License | null): void => {\r\n if (isEditAreaOpen) {\r\n return;\r\n }\r\n\r\n if (!license) {\r\n license = {\r\n id: '',\r\n clientOrganization: { id: '', name: '', domains: [] },\r\n product: { id: '', name: '', features: [], deploymentTypeId: null },\r\n effectiveDate: new Date(),\r\n expirationDate: new Date(),\r\n enforceStrictUserCount: false,\r\n userCount: 1,\r\n isNew: true,\r\n deploymentDetails: {},\r\n deploymentStatus: null,\r\n adminUser: '',\r\n };\r\n }\r\n\r\n setLicenseToEdit({ ...license });\r\n\r\n // Delay this slightly so the edit area has time to animate in\r\n setTimeout(() => {\r\n scrollToRef(adminPageEditAreaRef);\r\n }, 500);\r\n\r\n setIsEditAreaOpen(true);\r\n };\r\n\r\n const deleteLicenseButtonClick = (license: License): void => {\r\n showConfirmationOverlay({\r\n title: 'Confirm',\r\n text: `Are you sure you want to delete the license for \"${license.clientOrganization.name}\" / \"${license.product.name}\"?`,\r\n buttons: [\r\n {\r\n text: 'Yes',\r\n onClick: async (): Promise => {\r\n try {\r\n hideConfirmationOverlay();\r\n showPageLoadingOverlay();\r\n\r\n await LicenseApi.deleteLicense(license.id);\r\n const newLicenses = licenses.filter(l => l.id !== license.id);\r\n setLicenses(newLicenses);\r\n\r\n showSuccessNotification('Success', 'The license was deleted successfully.');\r\n } catch {\r\n showErrorNotification(\r\n 'Error',\r\n 'An error occurred while attempting to delete the license.',\r\n );\r\n } finally {\r\n hidePageLoadingOverlay();\r\n }\r\n },\r\n color: 'normal',\r\n },\r\n {\r\n text: 'No',\r\n onClick: (): void => {\r\n hideConfirmationOverlay();\r\n },\r\n color: 'gray',\r\n },\r\n ],\r\n });\r\n };\r\n\r\n const requestDeploymentButtonClick = async (license: License): Promise => {\r\n if (![null, LicensesConstants.DeploymentStatuses.NONE].includes(license.deploymentStatus)) {\r\n return;\r\n }\r\n\r\n showConfirmationOverlay({\r\n title: 'Confirm',\r\n text: `Are you sure you want to run a deployment to set up \"${license.product.name}\" for \"${license.clientOrganization.name}\"?`,\r\n buttons: [\r\n {\r\n text: 'Yes',\r\n onClick: async (): Promise => {\r\n try {\r\n hideConfirmationOverlay();\r\n\r\n showPageLoadingOverlay();\r\n\r\n await licensesApiService.requestDeployment(\r\n license.id,\r\n license.adminUser!,\r\n license.clientOrganization.domains,\r\n );\r\n\r\n license.deploymentStatus = LicensesConstants.DeploymentStatuses.REQUESTED;\r\n\r\n showSuccessNotification(\r\n 'Success',\r\n 'The deployment was successfully requested. Refresh to view status.',\r\n );\r\n } catch {\r\n showErrorNotification('Error', 'The deployment request could not complete.');\r\n } finally {\r\n hidePageLoadingOverlay();\r\n }\r\n },\r\n },\r\n {\r\n text: 'No',\r\n onClick: (): void => hideConfirmationOverlay(),\r\n color: 'gray',\r\n },\r\n ],\r\n });\r\n };\r\n\r\n const redeployButtonClick = async (license: License): Promise => {\r\n if (\r\n ![\r\n LicensesConstants.DeploymentStatuses.COMPLETED,\r\n LicensesConstants.DeploymentStatuses.ERROR,\r\n ].includes(license.deploymentStatus || '')\r\n ) {\r\n return;\r\n }\r\n\r\n showConfirmationOverlay({\r\n title: 'Confirm',\r\n text: `Are you sure you want to redeploy \"${license.product.name}\" for \"${license.clientOrganization.name}\"?`,\r\n buttons: [\r\n {\r\n text: 'Yes',\r\n onClick: async (): Promise => {\r\n try {\r\n hideConfirmationOverlay();\r\n\r\n showPageLoadingOverlay();\r\n\r\n // Reset deployment details\r\n await licensesApiService.resetDeploymentDetails(license.id);\r\n\r\n // Request new deployment\r\n await licensesApiService.requestDeployment(\r\n license.id,\r\n license.adminUser!,\r\n license.clientOrganization.domains,\r\n );\r\n license.deploymentStatus = LicensesConstants.DeploymentStatuses.REQUESTED;\r\n\r\n showSuccessNotification(\r\n 'Success',\r\n 'The deployment was successfully requested. Refresh to view status.',\r\n );\r\n } catch {\r\n showErrorNotification('Error', 'The deployment request could not complete.');\r\n } finally {\r\n hidePageLoadingOverlay();\r\n }\r\n },\r\n },\r\n {\r\n text: 'No',\r\n onClick: (): void => hideConfirmationOverlay(),\r\n color: 'gray',\r\n },\r\n ],\r\n });\r\n };\r\n\r\n if (!isPageDataLoaded) {\r\n return <>;\r\n }\r\n\r\n return (\r\n <>\r\n
\r\n

Licenses

\r\n
\r\n\r\n
\r\n \r\n
\r\n
\r\n {licenseToEdit && (\r\n \r\n )}\r\n
\r\n
\r\n
\r\n
\r\n\r\n
\r\n \r\n {licenses.map(currLicense => {\r\n return (\r\n \r\n );\r\n })}\r\n \r\n
\r\n\r\n {\r\n editLicenseButtonClick(null);\r\n }}\r\n tooltip={'Add new license'}\r\n disabled={isEditAreaOpen}\r\n />\r\n \r\n );\r\n};\r\n\r\nexport default LicensesPage;\r\n","import * as Yup from 'yup';\n\n// eslint-disable-next-line\nYup.addMethod(Yup.array, 'unique', function(message: string, mapper = (a: any) => a) {\n return this.test('unique', message, list => {\n return list.length === new Set(list.map(mapper)).size;\n });\n});\n\nexport default Yup;\n","import { FieldArray, Form, Formik, FormikValues } from 'formik';\nimport { isEqual } from 'lodash';\nimport React, { useContext, useEffect, useState } from 'react';\nimport { getFormErrorMessages } from '../../../../../utils/forms';\nimport { isProductionEnvironment } from '../../../../../utils/general';\nimport { generateUuid, isValidUuid } from '../../../../../utils/uuid';\nimport Yup from '../../../../../utils/yup';\nimport { ConfirmationOverlayContext } from '../../../../common-page-components/confirmation-overlay/ConfirmationOverlayContext';\nimport BTButton from '../../../../common-page-components/controls/button/BTButton';\nimport BTIconButton from '../../../../common-page-components/controls/icon-button/BTIconButton';\nimport FormErrorContainer from '../../../../common-page-components/forms/form-error-container/FormErrorContainer';\nimport FormFooter from '../../../../common-page-components/forms/FormFooter';\nimport FormTextInput from '../../../../common-page-components/forms/FormTextInput';\nimport './ProductEditForm.scss';\nimport FormDropDownList from '../../../../common-page-components/forms/FormDropDownList';\n\nconst FormSchema = Yup.object().shape({\n id: Yup.string(),\n name: Yup.string()\n .trim()\n .required('Name is required'),\n isNew: Yup.boolean().required(),\n hasActiveLicenses: Yup.boolean().required(),\n deploymentTypeId: Yup.string().required('Deployment type is required'),\n newId: Yup.string(),\n features: Yup.array()\n .of(\n Yup.object().shape({\n id: Yup.string(),\n name: Yup.string()\n .trim()\n .required('Feature name is required'),\n isNew: Yup.boolean(),\n hasActiveLicenses: Yup.boolean().required(),\n }),\n )\n .unique('Feature IDs must be unique', f => f.newId && f.newId.toLowerCase()),\n});\n\ninterface Props {\n product: Product;\n deploymentTypes: DeploymentType[];\n existingProducts: Product[];\n onSaveClick: (product: Product) => void;\n onDiscardClick: (product: Product) => void;\n}\n\nconst ProductEditForm: React.FC = props => {\n const [productIds, setProductIds] = useState([]);\n const [productNames, setProductNames] = useState([]);\n\n const { showConfirmationOverlay, hideConfirmationOverlay } = useContext(\n ConfirmationOverlayContext,\n );\n\n const product = {\n ...props.product,\n newId: props.product.id,\n features: props.product.features.map(feat => ({ ...feat, newId: feat.id })),\n };\n\n // Keep list of lowercase IDs and Names so we don't have to transform every time\n useEffect(() => {\n const ids = props.existingProducts.map(product => product.id.toLowerCase().trim());\n const names = props.existingProducts.map(product => product.name.toLowerCase().trim());\n\n setProductIds(ids);\n setProductNames(names);\n }, [props.existingProducts]);\n\n const saveProduct = (values: FormikValues): void => {\n const features = values.features as ProductFeature[];\n\n const newFeatures = features.filter(feature => feature.isNew);\n\n const updatedFeatures = features\n .filter((feature, index) => !feature.isNew && product.features[index])\n .map((feature, index) => {\n const updatedFeature = values.features[index];\n return { ...feature, name: updatedFeature.name };\n });\n\n const newProduct: Product = {\n id: values.id,\n newId: values.newId,\n name: values.name,\n deploymentTypeId: values.deploymentTypeId,\n isNew: product.isNew,\n hasActiveLicenses: false,\n features: [...newFeatures, ...updatedFeatures],\n };\n\n props.onSaveClick(newProduct);\n };\n\n const submit = (values: FormikValues): void => {\n const newProduct = values as Product;\n\n const productIdWasUpdated = product.id !== values.newId;\n const featureIdWasUpdated = newProduct.features.some(\n (feature, index) => !feature.isNew && feature.newId !== product.features[index].id,\n );\n\n if (product.isNew || (!productIdWasUpdated && !featureIdWasUpdated)) {\n saveProduct(values);\n return;\n }\n\n let messageSection: string;\n\n if (productIdWasUpdated && featureIdWasUpdated) {\n messageSection = 'both product and feature IDs';\n } else if (productIdWasUpdated) {\n messageSection = 'the product ID';\n } else {\n messageSection = 'a feature ID';\n }\n\n showConfirmationOverlay({\n title: 'Confirm',\n text: `You have edited ${messageSection}. This could cause errors for anything mapped to the current ID. Are you sure you'd like to continue?`,\n buttons: [\n {\n text: 'Yes',\n onClick: async (): Promise => {\n hideConfirmationOverlay();\n saveProduct(values);\n },\n },\n {\n text: 'No',\n onClick: (): void => hideConfirmationOverlay(),\n color: 'gray',\n },\n ],\n });\n };\n\n const onDiscardClick = (values: FormikValues): void => {\n const newProduct = values as Product;\n\n if (!isEqual(product, newProduct)) {\n showConfirmationOverlay({\n title: 'Confirm',\n text: 'Are you sure you want to discard your changes?',\n buttons: [\n {\n text: 'Yes',\n onClick: (): void => {\n hideConfirmationOverlay();\n props.onDiscardClick(newProduct);\n },\n },\n {\n text: 'No',\n onClick: (): void => hideConfirmationOverlay(),\n color: 'gray',\n },\n ],\n });\n } else {\n props.onDiscardClick(newProduct);\n }\n };\n\n const uuidValidator = (id: string): string | void => {\n if (!isValidUuid(id)) {\n return 'ID must be in the format \"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\"';\n }\n };\n\n const productIdValidator = (id: string): string | void => {\n if (product.id === id) {\n return;\n }\n\n if (productIds.includes(id.toLowerCase().trim())) {\n return 'ID must be unique';\n }\n\n return uuidValidator(id);\n };\n\n const nameValidator = (name: string): string | void => {\n if (product.name === name) {\n return;\n }\n\n if (productNames.includes(name.toLowerCase().trim())) {\n return 'Name must be unique';\n }\n };\n\n const featureIdValidator = (id: string): string | void => {\n return uuidValidator(id);\n };\n\n return (\n
\n

{`${product && product.isNew ? 'Create' : 'Edit'} Product`}

\n\n \n {({ errors, values, submitCount, setFieldValue }): JSX.Element => (\n
\n
\n
\n \n
\n\n
\n ({\n name: v.name,\n value: v.id,\n }))}\n label=\"Deployment Type\"\n name=\"deploymentTypeId\"\n disabled={product.hasActiveLicenses}\n tooltip={\n product.hasActiveLicenses\n ? 'The deployment type cannot be updated because active licenses exist for this product'\n : ''\n }\n />\n
\n
\n\n {!product.isNew && (\n
\n
\n
\n \n
\n\n
\n setFieldValue('newId', product.id)}\n tabIndex={-1}\n data-testid=\"product-id-undo\"\n />\n
\n
\n
\n )}\n\n (\n
\n
\n
\n \n
\n {\n const id = generateUuid();\n\n const feature: ProductFeature = {\n id: id,\n name: '',\n isNew: true,\n hasActiveLicenses: false,\n newId: id,\n };\n\n arrayHelpers.push(feature);\n }}\n tabIndex={-1}\n />\n
\n
\n
\n
\n {!values.features || !values.features.length ? (\n
(No Features)
\n ) : (\n <>\n )}\n\n {values.features.map((feature, index) => {\n // Must use original ID as the key since it is editable in the form\n const key = !feature.isNew ? product.features[index].id : feature.id;\n\n if (feature.isDeleted) {\n return
;\n }\n\n const classNames = ['feature'];\n\n // If it is an existing product, we will be showing the ID as well as the name so we want them side by side\n if (product.isNew) {\n classNames.push('col-12 col-md-6');\n } else {\n classNames.push('col-12');\n }\n\n return (\n
\n {!product.isNew && (\n
\n \n
\n {\n arrayHelpers.replace(index, {\n ...feature,\n newId: product.features[index].newId,\n });\n }}\n disabled={feature.isNew}\n tabIndex={-1}\n data-testid={`feature-${index}-id-undo`}\n />\n
\n
\n )}\n \n
\n {\n if (feature.isNew) {\n arrayHelpers.remove(index);\n return;\n }\n\n const deletedFeature: ProductFeature = {\n ...feature,\n isDeleted: true,\n };\n\n arrayHelpers.replace(index, deletedFeature);\n }}\n tabIndex={-1}\n data-testid={`feature-${index}-delete`}\n />\n
\n
\n );\n })}\n
\n
\n )}\n />\n\n \n
\n \n onDiscardClick(values)}\n tabIndex={5}\n />\n
\n {submitCount > 0 && (\n \n )}\n
\n \n )}\n \n
\n );\n};\n\nexport default ProductEditForm;\n","import React, { useEffect, useState } from 'react';\nimport BTCard from '../../../../common-page-components/card/BTCard';\nimport './ProductListing.scss';\n\ninterface Props {\n product: Product;\n disableButtons: boolean;\n onProductEdit: (product: Product) => void;\n onProductDelete: (product: Product) => void;\n}\n\nconst getMetadata = (product: Product): string[] => {\n const featureNames = product.features.map(f => f.name);\n return [product.id, product.name, ...featureNames];\n};\n\nconst ProductListing: React.FC = props => {\n const { product } = props;\n\n const [metadata, setMetadata] = useState(getMetadata(product));\n\n // Update metadata when product changes\n useEffect(() => {\n setMetadata(getMetadata(product));\n }, [product]);\n\n const onEditClick = (): void => {\n props.onProductEdit(product);\n };\n\n const onDeleteClick = (): void => {\n props.onProductDelete(product);\n };\n\n let deleteTooltip = props.disableButtons ? '' : 'Delete';\n if (product.hasActiveLicenses) {\n deleteTooltip = 'Cannot delete a product with active licenses';\n }\n\n return (\n \n
\n \n\n {!product.features || product.features.length === 0 ? (\n
(No Features)
\n ) : (\n
\n {product.features.map(feature => (\n \n {feature.name}\n
\n ))}\n
\n )}\n
\n\n
\n
\n \n
{product.id}
\n
\n\n
\n \n
{product.deploymentTypeId || '(Not Selected)'}
\n
\n
\n \n );\n};\n\nexport default ProductListing;\n","import { isEqual } from 'lodash';\r\nimport React, { useContext, useEffect, useState } from 'react';\r\nimport { useHistory } from 'react-router';\r\nimport { Collapse } from 'reactstrap';\r\nimport ApplicationRoutes from '../../../../constants/routes';\r\nimport { ProductApi } from '../../../../services/api/';\r\nimport BTCardsContainer from '../../../common-page-components/cards-container/BTCardsContainer';\r\nimport { ConfirmationOverlayContext } from '../../../common-page-components/confirmation-overlay/ConfirmationOverlayContext';\r\nimport { NotificationPanelContext } from '../../../common-page-components/notification-panel/NotificationPanelContext';\r\nimport BTFloatingIconButton from './../../../common-page-components/controls/floating-icon-button/BTFloatingIconButton';\r\nimport { LoadingPageOverlayContext } from './../../../common-page-components/loading-page-overlay/LoadingPageOverlayContext';\r\nimport ProductEditForm from './components/ProductEditForm';\r\nimport ProductListing from './components/ProductListing';\r\n\r\nconst getNewProduct = (deploymentType: DeploymentType): Product => ({\r\n id: '',\r\n name: '',\r\n isNew: true,\r\n hasActiveLicenses: false,\r\n features: [],\r\n deploymentTypeId: deploymentType.id,\r\n});\r\n\r\nconst ProductsPage: React.FC = () => {\r\n const { showPageLoadingOverlay, hidePageLoadingOverlay } = useContext(LoadingPageOverlayContext);\r\n\r\n const { showConfirmationOverlay, hideConfirmationOverlay } = useContext(\r\n ConfirmationOverlayContext,\r\n );\r\n\r\n const { showSuccessNotification, showInfoNotification, showErrorNotification } = useContext(\r\n NotificationPanelContext,\r\n );\r\n\r\n const history = useHistory();\r\n\r\n const [isPageDataLoaded, setIsPageDataLoaded] = useState(false);\r\n const [products, setProducts] = useState([]);\r\n const [deploymentTypes, setDeploymentTypes] = useState([]);\r\n const [isEditAreaOpen, setIsEditAreaOpen] = useState(false);\r\n const [productToEdit, setProductToEdit] = useState();\r\n\r\n // Initial load of data\r\n useEffect(() => {\r\n const loadProducts = async (): Promise => {\r\n try {\r\n showPageLoadingOverlay();\r\n\r\n const [productsData, deploymentsData] = await Promise.all([\r\n await ProductApi.getProducts(),\r\n await ProductApi.getDeploymentTypes(),\r\n ]);\r\n\r\n setProducts(productsData);\r\n setDeploymentTypes(deploymentsData);\r\n\r\n setIsPageDataLoaded(true);\r\n } catch (error) {\r\n // In this case, we should send the user to an error page since this page isn't very useful without this core data\r\n showErrorNotification('Error', 'An error occurred while loading the page.');\r\n history.push(ApplicationRoutes.ERROR_ERROR);\r\n } finally {\r\n hidePageLoadingOverlay();\r\n }\r\n };\r\n\r\n loadProducts();\r\n }, [hidePageLoadingOverlay, history, showPageLoadingOverlay, showErrorNotification]);\r\n\r\n const onProductAdd = (): void => {\r\n // NOTE: We will always have at least one deployment type\r\n setProductToEdit(getNewProduct(deploymentTypes[0]));\r\n setIsEditAreaOpen(true);\r\n };\r\n\r\n const onProductEdit = (product: Product): void => {\r\n // Set the deployment type if it doesn't exist\r\n if (!product.deploymentTypeId) {\r\n product.deploymentTypeId = deploymentTypes[0].id;\r\n }\r\n\r\n setProductToEdit(product);\r\n setIsEditAreaOpen(true);\r\n };\r\n\r\n const onProductDelete = (product: Product): void => {\r\n const deleteProduct = async (): Promise => {\r\n showPageLoadingOverlay();\r\n\r\n try {\r\n await ProductApi.deleteProduct(product.id);\r\n\r\n const newProducts = products.filter(p => p.id !== product.id);\r\n setProducts(newProducts);\r\n\r\n showSuccessNotification('Success', 'The product was deleted successfully.');\r\n } catch {\r\n showErrorNotification('Error', 'An error occurred while attempting to delete the product.');\r\n } finally {\r\n hidePageLoadingOverlay();\r\n }\r\n };\r\n\r\n showConfirmationOverlay({\r\n title: 'Confirm',\r\n text: `Are you sure you want to delete the product \"${product.name}\"?`,\r\n buttons: [\r\n {\r\n text: 'Yes',\r\n onClick: async (): Promise => {\r\n hideConfirmationOverlay();\r\n await deleteProduct();\r\n },\r\n },\r\n {\r\n text: 'No',\r\n onClick: (): void => hideConfirmationOverlay(),\r\n color: 'gray',\r\n },\r\n ],\r\n });\r\n };\r\n\r\n const onFormDiscard = (product: Product): void => {\r\n // Delay this slightly so the edit area has time to animate closed\r\n setTimeout(() => {\r\n setProductToEdit(null);\r\n }, 250);\r\n\r\n setIsEditAreaOpen(false);\r\n };\r\n\r\n const onFormSave = async (product: Product): Promise => {\r\n showPageLoadingOverlay();\r\n\r\n const closeEditAreaAndClearOutEditModel = (): void => {\r\n setIsEditAreaOpen(false);\r\n\r\n // Delay this slightly so the edit area has time to animate closed\r\n setTimeout(() => {\r\n setProductToEdit(null);\r\n }, 250);\r\n };\r\n\r\n try {\r\n if (product.isNew) {\r\n const newProduct: Product = await ProductApi.addProduct(product);\r\n setProducts([...products, newProduct]);\r\n\r\n closeEditAreaAndClearOutEditModel();\r\n } else {\r\n if (isEqual(product, productToEdit)) {\r\n closeEditAreaAndClearOutEditModel();\r\n\r\n showInfoNotification('No Changes', 'No changes were made to the product.');\r\n return;\r\n }\r\n\r\n const updatedProduct = await ProductApi.editProduct(product);\r\n const productsClone = [...products];\r\n\r\n const index = productsClone.findIndex(product => product.id === updatedProduct.id);\r\n\r\n if (index === -1) {\r\n throw new Error(`Could not find product with ID '${updatedProduct.id}'.`);\r\n }\r\n\r\n // Update product with new ID\r\n if (updatedProduct.newId && updatedProduct.newId !== updatedProduct.id) {\r\n updatedProduct.id = updatedProduct.newId;\r\n delete updatedProduct.newId;\r\n }\r\n\r\n productsClone[index] = updatedProduct;\r\n\r\n setProducts(productsClone);\r\n }\r\n\r\n setIsEditAreaOpen(false);\r\n\r\n // Delay this slightly so the edit area has time to animate closed\r\n setTimeout(() => {\r\n setProductToEdit(null);\r\n }, 250);\r\n\r\n showSuccessNotification(\r\n 'Success',\r\n `The product was ${product.isNew ? 'created' : 'updated'} successfully.`,\r\n );\r\n } catch {\r\n showErrorNotification(\r\n 'Error',\r\n `An error occurred while attempting to ${product.isNew ? 'create' : 'update'} the product.`,\r\n );\r\n } finally {\r\n hidePageLoadingOverlay();\r\n }\r\n };\r\n\r\n const renderProducts = (): JSX.Element => {\r\n const productListings = products.map(product => (\r\n \r\n ));\r\n\r\n return (\r\n
\r\n \r\n {productListings}\r\n \r\n
\r\n );\r\n };\r\n\r\n if (!isPageDataLoaded) {\r\n return <>;\r\n }\r\n\r\n return (\r\n <>\r\n
\r\n

Products

\r\n
\r\n
\r\n \r\n
\r\n
\r\n {productToEdit && (\r\n \r\n )}\r\n
\r\n
\r\n
\r\n
\r\n\r\n
{renderProducts()}
\r\n\r\n \r\n \r\n );\r\n};\r\n\r\nexport default ProductsPage;\r\n","import React, { useState, useContext } from 'react';\nimport { DropDownList } from '@progress/kendo-react-dropdowns';\nimport BTButton from '../../../common-page-components/controls/button/BTButton';\nimport { NotificationPanelContext } from '../../../common-page-components/notification-panel/NotificationPanelContext';\nimport { loadTranslationsForLocale } from '../../../../internationalization/i18n';\nimport './SiteSettingsPage.scss';\nimport { useTranslation } from 'react-i18next';\n\ninterface Language {\n name: string;\n value: string;\n}\n\nconst languages: Language[] = [\n { name: 'English (US)', value: 'en-US' },\n { name: 'French (Canada)', value: 'fr-CA' },\n];\n\nconst SiteSettingsPage: React.FC = () => {\n const { t, i18n } = useTranslation();\n const { showSuccessNotification, showErrorNotification } = useContext(NotificationPanelContext);\n\n // NOTE: it's okay if this is undefined, there just won't be a lang selected in the dropdown\n const currentLang = languages.find(l => l.value === i18n.language);\n\n const [selectedLang, setSelectedLang] = useState(currentLang);\n\n return (\n <>\n
\n

Site Settings

\n
\n\n
\n

Change Language

\n setSelectedLang(event.target.value)}\n />\n => {\n try {\n // NOTE: button is only enabled when `selectedLang` has a value\n const locale = selectedLang!.value;\n\n await i18n.changeLanguage(locale);\n loadTranslationsForLocale(locale);\n showSuccessNotification('Success', 'The language was updated successfully.');\n } catch (ex) {\n showErrorNotification(\n 'Error',\n 'An error occurred while attempting to update the language.',\n );\n }\n }}\n />\n\n
\n {t('general:shortDateFormat', { date: new Date() })}\n
\n\n
\n {t('general:longDateFormat', { date: new Date() })}\n
\n\n
\n {t('general:numberFormat', { number: 1234567 })}\n
\n\n
\n {t('general:numberFormat', { number: 1234567.89 })}\n
\n
\n \n );\n};\n\nexport default SiteSettingsPage;\n","import { connect, Form, Formik, FormikProps } from 'formik';\r\nimport { isEqual, sortBy } from 'lodash';\r\nimport React, { useState } from 'react';\r\nimport * as Yup from 'yup';\r\nimport { UserRolesDisplayNames, UserRolesValues } from '../../../../../constants/users/user-roles';\r\nimport { getFormErrorMessages } from '../../../../../utils/forms';\r\nimport BTButton from '../../../../common-page-components/controls/button/BTButton';\r\nimport FormErrorContainer from '../../../../common-page-components/forms/form-error-container/FormErrorContainer';\r\nimport FormFooter from '../../../../common-page-components/forms/FormFooter';\r\nimport FormMultiSelect, {\r\n FormMultiSelectOption,\r\n} from '../../../../common-page-components/forms/FormMultiSelect';\r\nimport FormTextInput from '../../../../common-page-components/forms/FormTextInput';\r\n\r\nconst FormSchema = Yup.object().shape({\r\n id: Yup.string().nullable(),\r\n isNew: Yup.boolean().required(),\r\n isBeckTechUser: Yup.boolean(),\r\n emailAddress: Yup.string()\r\n .trim()\r\n .email('The email address is not valid')\r\n .required('Email address is a required field'),\r\n roles: Yup.array()\r\n .of(\r\n Yup.object().shape({\r\n id: Yup.string(),\r\n name: Yup.string(),\r\n }),\r\n )\r\n .min(1, 'At least one role must be specified'),\r\n});\r\n\r\ninterface Props {\r\n user: User;\r\n allUsers: User[];\r\n onSubmitClick: (user: User) => void;\r\n onDiscardClick: (user: User) => void;\r\n}\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nconst FormikEffect = connect((props: any) => {\r\n props.onFormChanged(props.formik);\r\n return null;\r\n});\r\n\r\nconst isBeckTechEmailAddress = (emailAddress: string): boolean => {\r\n return /@beck-technology\\.com$/i.test(emailAddress);\r\n};\r\n\r\nconst UserEditForm: React.FC = ({ user, allUsers, onSubmitClick, onDiscardClick }) => {\r\n const [isEmailAddressBeckTech, setIsEmailAddressBeckTech] = useState();\r\n\r\n const rolesBeckTechUser: UserRole[] = [\r\n { id: UserRolesValues.ClientUser, name: UserRolesDisplayNames.ClientUser },\r\n { id: UserRolesValues.InternalUser, name: UserRolesDisplayNames.InternalUser },\r\n { id: UserRolesValues.Admin, name: UserRolesDisplayNames.Admin },\r\n { id: UserRolesValues.BidDaySupport, name: UserRolesDisplayNames.BidDaySupport },\r\n ];\r\n const rolesNonBeckTechUser: UserRole[] = [\r\n { id: UserRolesValues.ClientUser, name: UserRolesDisplayNames.ClientUser },\r\n ];\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const onFormChanged = (form: FormikProps): void => {\r\n if (form && form.values) {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const formValues = form.values as any;\r\n const currEmailAddress = formValues.emailAddress || '';\r\n // Order the roles first, so we have consistent behavior between runs of this code\r\n const currRoles: UserRole[] = sortBy(formValues.roles || [], (v: UserRole) => v.id);\r\n\r\n // The roles the user can select depend on the entered email address.\r\n // If we are going down to a more restrictive set of available roles because the email address is not a Beck Tech email,\r\n // we need to adjust the already selected roles.\r\n const emailIsBechTechEmail = isBeckTechEmailAddress(currEmailAddress);\r\n setIsEmailAddressBeckTech(emailIsBechTechEmail);\r\n\r\n if (!emailIsBechTechEmail) {\r\n // Order the roles first, so we have consistent behavior between runs of this code\r\n const newUserRoles = sortBy(\r\n rolesNonBeckTechUser.filter(v => currRoles.some(m => m.id === v.id)),\r\n v => v.id,\r\n );\r\n\r\n // NOTE: Setting the form value will trigger this function to run again so we have to make sure we only set it when it's different,\r\n // otherwise we'll trigger an infinite loop, and who knows how long that'll take to run....\r\n if (!isEqual(newUserRoles, currRoles)) {\r\n form.setFieldValue('roles', newUserRoles);\r\n }\r\n }\r\n }\r\n };\r\n\r\n const getAvailableUserRoles = (): FormMultiSelectOption[] => {\r\n return isEmailAddressBeckTech ? rolesBeckTechUser : rolesNonBeckTechUser;\r\n };\r\n\r\n const uniqueEmailValidator = (emailAddress: string): string | void => {\r\n emailAddress = emailAddress.trim().toLowerCase();\r\n\r\n // NOTE: When we are editing a user, the email address is not editable so we don't have to worry about\r\n // checking to make sure the user with the same email address isn't the user being edited or if the\r\n // user object is new\r\n if (allUsers.find(v => v.emailAddress.trim().toLowerCase() === emailAddress)) {\r\n return 'The email address must be unique.';\r\n }\r\n };\r\n\r\n return (\r\n
\r\n

{`${user && user.isNew ? 'Create' : 'Edit'} User`}

\r\n\r\n {user && (\r\n <>\r\n \r\n {({ errors, values, submitCount }): JSX.Element => (\r\n <>\r\n \r\n
\r\n {\r\n <>\r\n
\r\n {!user.isNew ? (\r\n <>\r\n
\r\n \r\n
{user.emailAddress}
\r\n
\r\n \r\n ) : (\r\n
\r\n \r\n
\r\n )}\r\n\r\n
\r\n \r\n
\r\n
\r\n \r\n }\r\n\r\n \r\n
\r\n \r\n {\r\n onDiscardClick(values);\r\n }}\r\n />\r\n
\r\n {submitCount > 0 && (\r\n \r\n )}\r\n
\r\n
\r\n \r\n )}\r\n
\r\n \r\n )}\r\n
\r\n );\r\n};\r\n\r\nexport default UserEditForm;\r\n","import React, { useContext } from 'react';\nimport BTCard from '../../../../common-page-components/card/BTCard';\nimport { UserInformationContext } from '../../../../UserInformationContext';\nimport './UserListing.scss';\n\ninterface Props {\n editUserButtonClick: (user: User) => void;\n deleteUserButtonClick: (user: User) => void;\n isEditAreaOpen: boolean;\n user: User;\n}\n\nconst UserListing: React.FC = ({\n user,\n isEditAreaOpen,\n editUserButtonClick,\n deleteUserButtonClick,\n}) => {\n const { userInformation } = useContext(UserInformationContext);\n\n const isUserCurrentUser = (): boolean => {\n return userInformation !== null && userInformation.id === user.id;\n };\n\n const getTooltipForEditButton = (): string => {\n if (isUserCurrentUser()) {\n return 'You cannot edit your own user';\n } else if (isEditAreaOpen) {\n return '';\n }\n return 'Edit';\n };\n\n const getTooltipForDeleteButton = (): string => {\n if (isUserCurrentUser()) {\n return 'You cannot delete your own user';\n } else if (isEditAreaOpen) {\n return '';\n }\n return 'Delete';\n };\n\n return (\n v.name).join(' ')]}\n cardIcons={[\n {\n buttonIcon: 'edit',\n onClick: (): void => {\n editUserButtonClick(user);\n },\n tooltip: getTooltipForEditButton(),\n disabled: isUserCurrentUser() || isEditAreaOpen,\n 'data-testid': `user-edit`,\n },\n {\n buttonIcon: 'trash',\n onClick: (): void => {\n deleteUserButtonClick(user);\n },\n tooltip: getTooltipForDeleteButton(),\n disabled: isUserCurrentUser() || isEditAreaOpen,\n 'data-testid': `user-delete`,\n },\n ]}\n >\n
\n
\n \n\n {!user.roles || user.roles.length === 0 ? (\n
(No Roles)
\n ) : (\n
\n {user.roles.map(currRole => (\n
{currRole.name}
\n ))}\n\n {!user.roles &&
(No Roles)
}\n
\n )}\n
\n
\n \n );\n};\n\nexport default UserListing;\n","import { isEqual } from 'lodash';\nimport React, { useContext, useEffect, useRef, useState } from 'react';\nimport { useHistory } from 'react-router';\nimport { Collapse } from 'reactstrap';\nimport ApplicationRoutes from '../../../../constants/routes';\nimport { UserApi } from '../../../../services/api';\nimport { scrollToRef } from '../../../../utils/general';\nimport BTCardsContainer from '../../../common-page-components/cards-container/BTCardsContainer';\nimport { ConfirmationOverlayContext } from '../../../common-page-components/confirmation-overlay/ConfirmationOverlayContext';\nimport BTFloatingIconButton from '../../../common-page-components/controls/floating-icon-button/BTFloatingIconButton';\nimport { LoadingPageOverlayContext } from '../../../common-page-components/loading-page-overlay/LoadingPageOverlayContext';\nimport { NotificationPanelContext } from '../../../common-page-components/notification-panel/NotificationPanelContext';\nimport UserEditForm from './components/UserEditForm';\nimport UserListing from './components/UserListing';\n\nconst UsersPage: React.FC = () => {\n const history = useHistory();\n\n const { showPageLoadingOverlay, hidePageLoadingOverlay } = useContext(LoadingPageOverlayContext);\n const { showConfirmationOverlay, hideConfirmationOverlay } = useContext(\n ConfirmationOverlayContext,\n );\n const { showSuccessNotification, showInfoNotification, showErrorNotification } = useContext(\n NotificationPanelContext,\n );\n\n const [isEditAreaOpen, setIsEditAreaOpen] = useState(false);\n const [isPageDataLoaded, setIsPageDataLoaded] = useState(false);\n const [userToEdit, setUserToEdit] = useState();\n const [users, setUsers] = useState([]);\n const adminPageEditAreaRef = useRef(null);\n\n // Initial load of data\n useEffect(() => {\n const loadPageData = async (): Promise => {\n try {\n showPageLoadingOverlay();\n\n const usersData = await UserApi.getUsers();\n setUsers(usersData);\n\n setIsPageDataLoaded(true);\n } catch (error) {\n // In this case, we should send the user to an error page since this page isn't very useful without this core data\n showErrorNotification('Error', 'An error occurred while loading the page.');\n history.push(ApplicationRoutes.ERROR_ERROR);\n } finally {\n hidePageLoadingOverlay();\n }\n };\n\n loadPageData();\n }, [hidePageLoadingOverlay, history, showPageLoadingOverlay, showErrorNotification]);\n\n const editUserButtonClick = (user: User | null): void => {\n if (isEditAreaOpen) {\n return;\n }\n\n if (!user) {\n user = {\n emailAddress: '',\n isNew: true,\n id: null,\n isBeckTechUser: false,\n roles: [],\n };\n }\n\n setUserToEdit({ ...user });\n\n // Delay this slightly so the edit area has time to animate in\n setTimeout(() => {\n scrollToRef(adminPageEditAreaRef);\n }, 500);\n\n setIsEditAreaOpen(true);\n };\n\n const deleteUserButtonClick = (user: User): void => {\n if (isEditAreaOpen) {\n return;\n }\n\n const deleteUser = async (): Promise => {\n showPageLoadingOverlay();\n\n try {\n if (!user.id) {\n showErrorNotification('Error', 'An error occurred while attempting to delete the user.');\n return;\n }\n\n await UserApi.deleteUser(user.id);\n\n const newUsers = users.filter(u => u.id !== user.id);\n setUsers(newUsers);\n\n showSuccessNotification('Success', 'The user was deleted successfully.');\n } catch {\n showErrorNotification('Error', 'An error occurred while attempting to delete the user.');\n } finally {\n hidePageLoadingOverlay();\n }\n };\n\n showConfirmationOverlay({\n title: 'Confirm',\n text: `Are you sure you want to delete the user \"${user.emailAddress}\"?`,\n buttons: [\n {\n text: 'Yes',\n onClick: async (): Promise => {\n hideConfirmationOverlay();\n await deleteUser();\n },\n },\n {\n text: 'No',\n onClick: (): void => hideConfirmationOverlay(),\n color: 'gray',\n },\n ],\n });\n };\n\n const onDiscard = (user: User): void => {\n const discardChanges = (): void => {\n setIsEditAreaOpen(false);\n\n // Delay this slightly so the edit area has time to animate closed\n setTimeout(() => {\n setUserToEdit(null);\n }, 250);\n };\n\n if (!isEqual(user, userToEdit)) {\n showConfirmationOverlay({\n title: 'Confirm',\n text: 'Are you sure you want to discard your unsaved changes?',\n buttons: [\n {\n text: 'Yes',\n onClick: (): void => {\n discardChanges();\n hideConfirmationOverlay();\n },\n color: 'normal',\n },\n {\n text: 'No',\n onClick: (): void => {\n hideConfirmationOverlay();\n },\n color: 'gray',\n },\n ],\n });\n } else {\n discardChanges();\n }\n };\n\n const onSubmit = async (user: User): Promise => {\n showPageLoadingOverlay();\n\n const closeEditAreaAndClearOutEditModel = (): void => {\n setIsEditAreaOpen(false);\n\n // Delay this slightly so the edit area has time to animate closed\n setTimeout(() => {\n setUserToEdit(null);\n }, 250);\n };\n\n try {\n if (isEqual(user, userToEdit)) {\n closeEditAreaAndClearOutEditModel();\n\n showInfoNotification('No Changes', 'No changes were made to the user.');\n return;\n }\n\n // NOTE: The add / edit functionality hits the same API endpoint\n\n if (user.isNew) {\n const updatedUserObj = await UserApi.addUser(user);\n setUsers([...users, updatedUserObj]);\n } else {\n await UserApi.editUser(user);\n\n const indexOfUserToUpdate = users.findIndex(v => v.id === user.id);\n if (indexOfUserToUpdate === -1) {\n throw new Error(`Could not find user with id '${user.id}'.`);\n }\n const newUsersArray = [...users];\n newUsersArray.splice(indexOfUserToUpdate, 1, user);\n setUsers(newUsersArray);\n }\n\n closeEditAreaAndClearOutEditModel();\n\n showSuccessNotification('Success', 'The user was updated successfully.');\n } catch (error) {\n showErrorNotification(\n 'Error',\n `An error occurred while attempting to ${user.isNew ? 'add' : 'update'} the user.`,\n );\n } finally {\n hidePageLoadingOverlay();\n }\n };\n\n if (!isPageDataLoaded) {\n return <>;\n }\n\n return (\n <>\n
\n

Users

\n
\n\n
\n \n
\n
\n {userToEdit && (\n \n )}\n
\n
\n
\n
\n\n
\n \n {users.map(currUser => {\n return (\n \n );\n })}\n \n
\n\n editUserButtonClick(null)}\n tooltip=\"Add new user\"\n disabled={isEditAreaOpen}\n />\n \n );\n};\n\nexport default UsersPage;\n","import axios from 'axios';\nimport ApiRoutes from '../../../constants/routes/api-routes';\n\nexport class EstimatorHostedApi {\n public static async getUsers(): Promise {\n const response = await axios.get(ApiRoutes.EstimatorHostedUsers);\n return response.data;\n }\n\n public static async getUserByEmail(email: string): Promise {\n const url = ApiRoutes.EstimatorHostedUsers + '/' + email;\n const response = await axios.get(url);\n return response.data;\n }\n\n public static async addUser(\n name: string,\n clientOrganizationId: string,\n groupIds: string[],\n ): Promise {\n const response = await axios.post(\n ApiRoutes.EstimatorHostedUsers,\n {\n name: name,\n clientOrganizationId: clientOrganizationId,\n groupIds: groupIds,\n },\n );\n return response.data;\n }\n\n public static async updateUser(\n email: string,\n name: string,\n clientOrganizationId: string,\n groupIds: string[],\n ): Promise {\n const url = ApiRoutes.EstimatorHostedUsers + '/' + email;\n await axios.put(url, {\n name: name,\n clientOrganizationId: clientOrganizationId,\n groupIds: groupIds,\n });\n }\n\n public static async resetUserPassword(email: string): Promise {\n const url = `${ApiRoutes.EstimatorHostedUsers}/${email}/reset-password`;\n const response = await axios.post(url);\n return response.data;\n }\n\n public static async deleteUser(email: string): Promise {\n await axios.delete(ApiRoutes.EstimatorHostedUsers + '/' + email);\n }\n\n public static async getGroups(): Promise {\n const response = await axios.get(ApiRoutes.EstimatorHostedGroups);\n return response.data;\n }\n\n public static async getEstimatorConfigForUser(\n email: string,\n configEnvironment: EstimatorHostedConfigurationEnvironment,\n ): Promise {\n const url = `${ApiRoutes.EstimatorHostedUsers}/${email}/configuration/${configEnvironment}`;\n const response = await axios.get(url);\n return response.data;\n }\n\n public static async saveEstimatorConfigForUser(\n email: string,\n config: EstimatorHostedConfiguration,\n ): Promise {\n const url = `${ApiRoutes.EstimatorHostedUsers}/${email}/configuration`;\n await axios.post(url, config);\n }\n\n public static async copyEstimatorConfigToUsers(\n emailOfUserToCopyFrom: string,\n configEnvironment: EstimatorHostedConfigurationEnvironment,\n emailsOfUsersToCopyTo: string[],\n ): Promise {\n const url = `${ApiRoutes.EstimatorHostedUsers}/${emailOfUserToCopyFrom}/configuration/${configEnvironment}/copy`;\n await axios.post(url, { emailAddresses: emailsOfUsersToCopyTo });\n }\n}\n","export const nameof = (name: keyof T): keyof T => name;\n","import React, { useCallback, useState } from 'react';\nimport { GridCellProps } from '@progress/kendo-react-grid';\nimport { Input, InputChangeEvent } from '@progress/kendo-react-inputs';\nimport { debounce } from 'lodash';\n\ninterface Props extends GridCellProps {\n required?: boolean;\n}\n\nconst GridTextCell: React.FC = props => {\n const dataValue = props.field && props.dataItem[props.field] ? props.dataItem[props.field] : '';\n const [text, setText] = useState(dataValue);\n\n const debouncedOnChange = useCallback(debounce(props.onChange!, 250), [props.onChange]);\n\n const onChange = (e: InputChangeEvent): void => {\n setText(e.target.value as string);\n\n debouncedOnChange({\n ...props,\n value: e.target.value,\n syntheticEvent: e.syntheticEvent,\n });\n };\n\n return (\n \n \n \n );\n};\n\nexport default GridTextCell;\n","import React, { RefObject } from 'react';\nimport { GridCellProps } from '@progress/kendo-react-grid';\nimport { DropDownList, DropDownListChangeEvent } from '@progress/kendo-react-dropdowns';\n\ninterface Props extends GridCellProps {\n listAnchor: RefObject;\n required?: boolean;\n listValues: any[]; // eslint-disable-line @typescript-eslint/no-explicit-any\n textField?: string;\n dataItemKey?: string;\n valueField?: string;\n}\n\nconst GridDropdownCell: React.FC = props => {\n const onChange = (event: DropDownListChangeEvent): void => {\n if (props.onChange) {\n props.onChange({\n ...props,\n value: props.valueField ? event.target.value[props.valueField] : event.target.value,\n syntheticEvent: event.syntheticEvent,\n });\n }\n };\n\n const value = props.field ? props.dataItem[props.field] : '';\n\n return (\n \n listValue[props.valueField!] === value)\n : value\n }\n onChange={onChange}\n required={props.required}\n popupSettings={{ appendTo: props.listAnchor.current || undefined }}\n />\n \n );\n};\n\nexport default GridDropdownCell;\n","import { DropDownList, DropDownListChangeEvent } from '@progress/kendo-react-dropdowns';\nimport { GridFilterCellProps } from '@progress/kendo-react-grid';\nimport React from 'react';\n\ninterface Props extends GridFilterCellProps {\n listValues: any[]; // eslint-disable-line @typescript-eslint/no-explicit-any\n textField?: string;\n dataItemKey?: string;\n valueField?: string;\n filterOperator?: 'eq' | 'contains';\n}\n\nconst GridDropdownFilterCell: React.FC = props => {\n const filterOperator = props.filterOperator || 'eq';\n\n const onChange = (e: DropDownListChangeEvent): void => {\n props.onChange({\n value: props.valueField ? e.target.value[props.valueField] : e.target.value,\n operator: e.target.value ? filterOperator : '',\n syntheticEvent: e.syntheticEvent,\n });\n };\n\n const onClearClick = (event: React.MouseEvent): void => {\n event.preventDefault();\n event.stopPropagation();\n props.onChange({\n value: '',\n operator: '',\n syntheticEvent: event,\n });\n };\n\n return (\n
\n listValue[props.valueField!] === props.value) || ''\n : props.value\n }\n />\n \n \n \n
\n );\n};\n\nexport default GridDropdownFilterCell;\n","import React, { RefObject } from 'react';\nimport { GridCellProps } from '@progress/kendo-react-grid';\nimport { MultiSelect, MultiSelectChangeEvent } from '@progress/kendo-react-dropdowns';\n\ninterface Props extends GridCellProps {\n listAnchor: RefObject;\n required?: boolean;\n listValues: any[]; // eslint-disable-line @typescript-eslint/no-explicit-any\n dataItemKey?: string;\n valueField?: string;\n textField?: string;\n}\n\nconst GridMultiSelectCell: React.FC = props => {\n const onChange = (event: MultiSelectChangeEvent): void => {\n if (props.onChange) {\n props.onChange({\n ...props,\n value: props.valueField\n ? event.target.value.map(v => v[props.valueField!])\n : event.target.value,\n syntheticEvent: event.syntheticEvent,\n });\n }\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const value: any[] = props.field ? props.dataItem[props.field] : [];\n\n return (\n \n value.includes(lv[props.valueField!]))\n : value\n }\n onChange={onChange}\n required={props.required}\n popupSettings={{ appendTo: props.listAnchor.current || undefined }}\n />\n \n );\n};\n\nexport default GridMultiSelectCell;\n","import React from 'react';\nimport { Modal, ModalBody, ModalHeader } from 'reactstrap';\nimport BTButton from '../../../../common-page-components/controls/button/BTButton';\n\nexport interface TemporaryPasswordInfo {\n name: string;\n email: string;\n password: string;\n}\n\ninterface Props {\n passwordInfo: TemporaryPasswordInfo[];\n onCopyPasswordClick: () => Promise;\n}\n\nconst TemporaryPasswordModal: React.FC = props => {\n return (\n \n Temporary Password Info\n \n
\n {props.passwordInfo.map(info => (\n
\n
\n Name: {info.name}\n
\n
\n Email: {info.email}\n
\n
\n Password: {info.password}\n
\n
\n ))}\n\n
\n \n
\n
\n
\n
\n );\n};\n\nexport default TemporaryPasswordModal;\n","export const HostedConstants = {\r\n CostDatabaseTypes: {\r\n RSMEANS: 'RSMEANS',\r\n DPROFILER: 'DPROFILER',\r\n },\r\n CostDatabaseConnectionTypes: {\r\n RSMEANS: 'RSMeans',\r\n BECK_TECH: 'Beck Tech',\r\n },\r\n} as const;\r\n\r\nexport type CostDatabaseConnectionType =\r\n | typeof HostedConstants.CostDatabaseConnectionTypes.BECK_TECH\r\n | typeof HostedConstants.CostDatabaseConnectionTypes.RSMEANS;\r\n\r\nexport type CostDatabaseType =\r\n | typeof HostedConstants.CostDatabaseTypes.DPROFILER\r\n | typeof HostedConstants.CostDatabaseTypes.RSMEANS;\r\n","import React, { useState } from 'react';\nimport { Modal, ModalBody, ModalHeader } from 'reactstrap';\nimport BTButton from '../../../../common-page-components/controls/button/BTButton';\nimport Yup from '../../../../../utils/yup';\nimport { Form, Formik, FieldArray } from 'formik';\nimport FormFooter from '../../../../common-page-components/forms/FormFooter';\nimport FormErrorContainer from '../../../../common-page-components/forms/form-error-container/FormErrorContainer';\nimport { getFormErrorMessages } from '../../../../../utils/forms';\nimport FormTextInput from '../../../../common-page-components/forms/FormTextInput';\nimport { nameof } from '../../../../../utils/nameof';\nimport BTIconButton from '../../../../common-page-components/controls/icon-button/BTIconButton';\nimport { DropDownList, DropDownListChangeEvent } from '@progress/kendo-react-dropdowns';\nimport './EstimatorConfigurationModal.scss';\nimport {\n CostDatabaseConnectionType,\n CostDatabaseType,\n HostedConstants,\n} from '../../../../../constants/hosted-estimator-user-management';\n\ninterface Props {\n users: EstimatorHostedUser[];\n getConfigForUser: (\n environment: EstimatorHostedConfigurationEnvironment,\n user: EstimatorHostedUser,\n ) => Promise;\n closeModal: () => void;\n onSaveClick: (\n originalConfig: EstimatorHostedConfiguration,\n updatedConfig: EstimatorHostedConfiguration,\n ) => Promise;\n onDiscardClick: (\n originalConfig: EstimatorHostedConfiguration,\n updatedConfig: EstimatorHostedConfiguration,\n ) => void;\n}\n\nconst EstimatorConfigurationModal: React.FC = props => {\n // State\n const [originalConfiguration, setOriginalConfiguration] = useState<\n EstimatorHostedConfiguration\n >();\n const [configuration, setConfiguration] = useState();\n const [selectedEnvironment, setSelectedEnvironment] = useState<\n EstimatorHostedConfigurationEnvironment\n >();\n\n const [selectedCostDatabaseConnectionType, setSelectedCostDatabaseConnectionType] = useState<\n CostDatabaseConnectionType\n >(HostedConstants.CostDatabaseConnectionTypes.BECK_TECH);\n\n const onEnvironmentDropdownChange = async (event: DropDownListChangeEvent): Promise => {\n const environment = event.target.value as EstimatorHostedConfigurationEnvironment;\n setSelectedEnvironment(environment);\n\n if (props.users.length === 1) {\n const user = props.users[0];\n const config = await props.getConfigForUser(environment, user);\n\n if (!config) {\n props.closeModal();\n return;\n }\n\n setOriginalConfiguration(config);\n setConfiguration(config);\n } else {\n const config = getNewEstimatorConfig(environment);\n setOriginalConfiguration(config);\n setConfiguration(config);\n }\n };\n\n const onSubmit = async (values: EstimatorHostedConfiguration): Promise => {\n await props.onSaveClick(originalConfiguration!, values);\n };\n\n return (\n \n Estimator Configuration\n \n {!configuration ? (\n
\n \n \n
\n ) : (\n \n {({ errors, values, submitCount }): JSX.Element => (\n
\n
\n \n {({ push, remove }): JSX.Element => (\n
\n
\n
Cost Databases
\n
\n \n setSelectedCostDatabaseConnectionType(evt.value)\n }\n />\n
\n
\n \n push(CreateDatabaseType(selectedCostDatabaseConnectionType))\n }\n tabIndex={-1}\n />\n
\n
\n\n {values.costDatabases.map((item, index) => {\n const FormSection =\n item.costDatabaseType === HostedConstants.CostDatabaseTypes.RSMEANS\n ? RSMeansConnectionFormSection\n : DatabaseConnectionFormSection;\n\n return (\n (\n 'costDatabases',\n )}.${index}`}\n arrayName={nameof('costDatabases')}\n index={index}\n remove={(): void => remove(index)}\n />\n );\n })}\n
\n )}\n
\n\n ('jobsDatabases')}>\n {({ push, remove }): JSX.Element => (\n
\n
\n
Jobs Databases
\n
\n push({})}\n tabIndex={-1}\n />\n
\n
\n\n {values.jobsDatabases.map((_, index) => {\n return (\n (\n 'jobsDatabases',\n )}.${index}`}\n arrayName={nameof('jobsDatabases')}\n index={index}\n remove={(): void => remove(index)}\n />\n );\n })}\n
\n )}\n
\n
\n\n \n
\n \n
\n {\n props.onDiscardClick(originalConfiguration!, values);\n }}\n />\n
\n
\n {submitCount > 0 && (\n \n )}\n
\n
\n )}\n
\n )}\n
\n
\n );\n};\n\nconst CreateDatabaseType = (\n costDatabaseConnectionType: CostDatabaseConnectionType,\n): CostDatabaseConnection => {\n const costDatabaseConnection: CostDatabaseConnection = {\n costDatabaseType: HostedConstants.CostDatabaseTypes.DPROFILER,\n database: '',\n name: '',\n password: '',\n server: '',\n username: '',\n };\n\n if (costDatabaseConnectionType === HostedConstants.CostDatabaseConnectionTypes.RSMEANS) {\n costDatabaseConnection.costDatabaseType = HostedConstants.CostDatabaseTypes.RSMEANS;\n costDatabaseConnection.database = 'RSMeans Database';\n costDatabaseConnection.server = 'RSMeans Server';\n }\n\n return costDatabaseConnection;\n};\n\nconst DatabaseConnectionFormSection: React.FC<{\n arrayName: string;\n index: number;\n remove: () => void;\n}> = props => {\n const namePrefix = `${props.arrayName}.${props.index}`;\n\n return (\n
\n
\n
\n ('name')}`}\n />\n
\n
\n \n
\n
\n
\n
\n ('server')}`}\n />\n
\n
\n ('database')}`}\n />\n
\n
\n
\n
\n ('username')}`}\n />\n
\n
\n ('password')}`}\n type=\"password\"\n />\n
\n
\n
\n );\n};\n\nconst RSMeansConnectionFormSection: React.FC<{\n arrayName: string;\n index: number;\n remove: () => void;\n}> = props => {\n const namePrefix = `${props.arrayName}.${props.index}`;\n\n return (\n
\n
\n
\n ('name')}`}\n />\n
\n
\n \n
\n
\n
\n
\n ('username')}`}\n />\n
\n
\n ('password')}`}\n type=\"password\"\n />\n
\n
\n
\n );\n};\n\nconst DatabaseConnectionSchema = Yup.object().shape({\n name: Yup.string().required('Name is required'),\n server: Yup.string().required('Server is required'),\n database: Yup.string().required('Database is required'),\n username: Yup.string().required('Username is required'),\n password: Yup.string().required('Password is required'),\n});\n\nconst CostDatabaseConnectionSchema = Yup.object().shape({\n name: Yup.string().required('Name is required'),\n server: Yup.string().required('Server is required'),\n database: Yup.string().required('Database is required'),\n username: Yup.string().required('Username is required'),\n password: Yup.string().required('Password is required'),\n costDatabaseType: Yup.mixed(),\n});\n\nconst FormSchema = Yup.object().shape({\n environment: Yup.mixed().oneOf(['Test', 'Production']),\n costDatabases: Yup.array().of(CostDatabaseConnectionSchema),\n jobsDatabases: Yup.array().of(DatabaseConnectionSchema),\n});\n\nconst getNewEstimatorConfig = (\n environment: EstimatorHostedConfigurationEnvironment,\n): EstimatorHostedConfiguration => ({\n environment: environment,\n costDatabases: [\n {\n name: '',\n server: '',\n database: '',\n username: '',\n password: '',\n costDatabaseType: HostedConstants.CostDatabaseTypes.DPROFILER,\n },\n ],\n jobsDatabases: [{ name: '', server: '', database: '', username: '', password: '' }],\n});\n\nexport default EstimatorConfigurationModal;\n","import React, { useState } from 'react';\nimport { Modal, ModalBody, ModalHeader } from 'reactstrap';\nimport BTButton from '../../../../common-page-components/controls/button/BTButton';\nimport { DropDownList, DropDownListChangeEvent } from '@progress/kendo-react-dropdowns';\nimport './EstimatorConfigurationModal.scss';\n\ninterface Props {\n onSaveClick: (environment: EstimatorHostedConfigurationEnvironment) => Promise;\n onDiscardClick: () => void;\n}\n\nconst EstimatorCopyConfigurationModal: React.FC = props => {\n // State\n const [selectedEnvironment, setSelectedEnvironment] = useState<\n EstimatorHostedConfigurationEnvironment\n >();\n\n const onEnvironmentDropdownChange = async (event: DropDownListChangeEvent): Promise => {\n const environment = event.target.value as EstimatorHostedConfigurationEnvironment;\n setSelectedEnvironment(environment);\n };\n\n return (\n \n Copy Estimator Configuration\n \n
\n \n \n
\n => await props.onSaveClick(selectedEnvironment!)}\n disabled={!selectedEnvironment}\n />\n
\n \n
\n
\n
\n
\n
\n );\n};\n\nexport default EstimatorCopyConfigurationModal;\n","import React from 'react';\nimport { Modal, ModalBody, ModalHeader } from 'reactstrap';\nimport { nameof } from '../../../../../utils/nameof';\nimport { FieldArray, Form, Formik } from 'formik';\nimport FormFooter from '../../../../common-page-components/forms/FormFooter';\nimport BTButton from '../../../../common-page-components/controls/button/BTButton';\nimport Yup from '../../../../../utils/yup';\nimport FormDropDownList from '../../../../common-page-components/forms/FormDropDownList';\nimport FormMultiSelect from '../../../../common-page-components/forms/FormMultiSelect';\nimport FormErrorContainer from '../../../../common-page-components/forms/form-error-container/FormErrorContainer';\nimport { getFormErrorMessages } from '../../../../../utils/forms';\nimport BTIconButton from '../../../../common-page-components/controls/icon-button/BTIconButton';\nimport FormTextInput from '../../../../common-page-components/forms/FormTextInput';\nimport { isEqual } from 'lodash';\n\ninterface FormData {\n clientOrg: ClientOrganization | null;\n userGroups: EstimatorHostedUserGroup[];\n names: string[];\n}\n\ninterface Props {\n clientOrgs: ClientOrganization[];\n userGroups: EstimatorHostedUserGroup[];\n onSaveClick: (users: EstimatorHostedUser[]) => Promise;\n onDiscardClick: (users: EstimatorHostedUser[]) => void;\n}\n\nconst AddUsersModal: React.FC = props => {\n const onSaveClick = (formData: FormData): void => {\n const users = getUsersFromFormData(formData);\n props.onSaveClick(users);\n };\n\n const onDiscardClick = (formData: FormData): void => {\n if (isEqual(formData, initialFormData)) {\n props.onDiscardClick([]);\n } else {\n const users = getUsersFromFormData(formData);\n props.onDiscardClick(users);\n }\n };\n\n return (\n \n Add Users\n \n \n {({ errors, values, submitCount }): JSX.Element => (\n
\n
\n
\n
\n ('clientOrg')}\n data={props.clientOrgs.map(clientOrg => ({\n name: clientOrg.name,\n value: clientOrg,\n }))}\n />\n
\n\n
\n ('userGroups')}\n data={props.userGroups.map(group => ({\n id: group.id,\n name: group.displayName,\n }))}\n />\n
\n
\n\n ('names')}>\n {({ push, remove }): JSX.Element => (\n
\n
\n
Names
\n
\n push('')}\n tabIndex={-1}\n />\n
\n
\n\n
\n {values.names.map((_, index) => {\n const name = `${nameof('names')}.${index}`;\n const colClassNames =\n values.names.length === 1 ? 'col-12' : 'col-lg-6 col-md-12';\n\n return (\n
\n
\n \n
\n
\n remove(index)}\n tabIndex={-1}\n />\n
\n
\n );\n })}\n
\n
\n )}\n
\n
\n\n \n
\n \n
\n onDiscardClick(values)}\n />\n
\n
\n {submitCount > 0 && (\n \n )}\n
\n
\n )}\n \n
\n
\n );\n};\n\nconst initialFormData: FormData = {\n clientOrg: null,\n userGroups: [],\n names: [],\n};\n\nconst getUsersFromFormData = (formData: FormData): EstimatorHostedUser[] => {\n const groupIds = formData.userGroups.map(group => group.id);\n const clientOrgId = formData.clientOrg ? formData.clientOrg.id : '';\n const users: EstimatorHostedUser[] = formData.names.map(name => ({\n displayName: name,\n emailAddress: '',\n clientOrganizationId: clientOrgId,\n groupIds: groupIds,\n }));\n return users;\n};\n\nconst FormSchema = Yup.object().shape({\n clientOrg: Yup.object()\n .shape({\n id: Yup.string(),\n name: Yup.string(),\n address: Yup.object().shape
({\n streetAddress: Yup.string(),\n aptSuiteBldg: Yup.string(),\n city: Yup.string(),\n stateOrRegion: Yup.object().shape({\n id: Yup.number().nullable(),\n name: Yup.string(),\n countryId: Yup.number(),\n }),\n postalCode: Yup.string(),\n country: Yup.object().shape({\n id: Yup.number().nullable(),\n name: Yup.string(),\n }),\n }),\n accountExecutive: Yup.string(),\n isNew: Yup.boolean(),\n domains: Yup.array().of(Yup.string()),\n usesCorporateActiveDirectory: Yup.boolean(),\n })\n .required('Client Organization is required'),\n userGroups: Yup.array().of(\n Yup.object().shape({\n id: Yup.string(),\n displayName: Yup.string(),\n }),\n ),\n names: Yup.array().of(Yup.string().required('Name is required')),\n});\n\nexport default AddUsersModal;\n","import React, { useState, useEffect, useRef, useContext, useCallback } from 'react';\nimport ClientOrganizationsApi from '../../../../services/api/clients/clients-api-service';\nimport { EstimatorHostedApi } from '../../../../services/api/estimator-hosted/estimator-hosted-service';\nimport {\n Grid,\n GridCellProps,\n GridColumn,\n GridFilterCellProps,\n GridFilterChangeEvent,\n GridHeaderSelectionChangeEvent,\n GridItemChangeEvent,\n GridSelectionChangeEvent,\n GridToolbar,\n} from '@progress/kendo-react-grid';\nimport { CompositeFilterDescriptor, filterBy } from '@progress/kendo-data-query';\nimport { nameof } from '../../../../utils/nameof';\nimport { isEqual, sortBy } from 'lodash';\nimport BTButton from '../../../common-page-components/controls/button/BTButton';\nimport BTIconButton from '../../../common-page-components/controls/icon-button/BTIconButton';\nimport GridTextCell from './components/GridTextCell';\nimport GridDropdownCell from './components/GridDropdownCell';\nimport GridDropdownFilterCell from './components/GridDropdownFilterCell';\nimport GridMultiSelectCell from './components/GridMultiSelectCell';\nimport TemporaryPasswordModal, { TemporaryPasswordInfo } from './components/TemporaryPasswordModal';\nimport EstimatorConfigurationModal from './components/EstimatorConfigurationModal';\nimport { LoadingPageOverlayContext } from '../../../common-page-components/loading-page-overlay/LoadingPageOverlayContext';\nimport { ConfirmationOverlayContext } from '../../../common-page-components/confirmation-overlay/ConfirmationOverlayContext';\nimport { NotificationPanelContext } from '../../../common-page-components/notification-panel/NotificationPanelContext';\nimport './EstimatorHostedUserManagementPage.scss';\nimport { useHistory } from 'react-router-dom';\nimport ApplicationRoutes from '../../../../constants/routes';\nimport EstimatorCopyConfigurationModal from './components/EstimatorCopyConfigurationModal';\nimport AddUsersModal from './components/AddUsersModal';\n\ninterface GridHostedUser extends EstimatorHostedUser {\n inEdit: boolean;\n isNew: boolean;\n selected: boolean;\n}\n\ninterface EstimatorConfigState {\n users: EstimatorHostedUser[];\n}\n\nconst EstimatorHostedUserManagementPage: React.FC = () => {\n // Hooks\n const history = useHistory();\n\n // Contexts\n const { showPageLoadingOverlay, hidePageLoadingOverlay } = useContext(LoadingPageOverlayContext);\n const { showConfirmationOverlay, hideConfirmationOverlay } = useContext(\n ConfirmationOverlayContext,\n );\n const { showSuccessNotification, showErrorNotification, showInfoNotification } = useContext(\n NotificationPanelContext,\n );\n\n // State\n const [isLoading, setIsLoading] = useState(true);\n const [clientOrgs, setClientOrgs] = useState([]);\n const [userGroups, setUserGroups] = useState([]);\n const [users, setUsers] = useState([]);\n const [filter, setFilter] = useState({ logic: 'and', filters: [] });\n const [showAddUsersModal, setShowAddUsersModal] = useState(false);\n const [tempPasswordInfo, setTemporaryPasswordInfo] = useState();\n const [estimatorConfigState, setEstimatorConfigState] = useState();\n const [userToCopyConfigFrom, setUserToCopyConfigFrom] = useState();\n\n // Ref to the grid container div\n // Used as the element to anchor any droplist elements on\n const gridContainer = useRef(null);\n\n // Apply filter on users for each render\n const filteredUsers = filterBy(users, filter);\n\n // Selected users\n const selectedUsers = filteredUsers.filter(user => user.selected && !user.isNew);\n\n // Initial data load\n useEffect(() => {\n const loadData = async (): Promise => {\n try {\n showPageLoadingOverlay();\n\n // Get clients\n const clients = await ClientOrganizationsApi.getClientOrganizations();\n setClientOrgs(sortBy(clients, client => client.name));\n\n // Get groups\n const groups = await EstimatorHostedApi.getGroups();\n setUserGroups(groups);\n\n // Get users\n const hostedUsers = await EstimatorHostedApi.getUsers();\n const gridUsers: GridHostedUser[] = hostedUsers.map(user => ({\n ...user,\n inEdit: false,\n isNew: false,\n selected: false,\n }));\n setUsers(sortUsers(gridUsers));\n\n setIsLoading(false);\n } catch {\n showErrorNotification('Error', 'Failed to load data.');\n history.push(ApplicationRoutes.ERROR_ERROR);\n } finally {\n hidePageLoadingOverlay();\n }\n };\n\n loadData();\n }, [hidePageLoadingOverlay, history, showErrorNotification, showPageLoadingOverlay]);\n\n const saveUsers = async (users: GridHostedUser[]): Promise => {\n showPageLoadingOverlay();\n\n const passwordInfoToDisplay: TemporaryPasswordInfo[] = [];\n const failedUsers: GridHostedUser[] = [];\n\n try {\n for (const user of users) {\n try {\n if (user.isNew) {\n // Add user via API\n const newUser = await EstimatorHostedApi.addUser(\n user.displayName,\n user.clientOrganizationId,\n user.groupIds,\n );\n\n // Update state\n setUsers(users => {\n const usersClone = [...users];\n usersClone.push({ ...newUser, inEdit: false, isNew: false, selected: false });\n return sortUsers(usersClone);\n });\n\n // Save password info to display later\n passwordInfoToDisplay.push({\n name: newUser.displayName,\n email: newUser.emailAddress,\n password: newUser.temporaryPassword,\n });\n } else {\n // Update user via API\n await EstimatorHostedApi.updateUser(\n user.emailAddress,\n user.displayName,\n user.clientOrganizationId,\n user.groupIds,\n );\n\n // Set State\n setUsers(users => {\n const usersClone = [...users];\n const index = usersClone.findIndex(u => u.emailAddress === user.emailAddress);\n usersClone[index] = { ...usersClone[index], inEdit: false };\n return usersClone;\n });\n }\n } catch {\n failedUsers.push(user);\n }\n }\n\n // Notify of success/failure\n if (failedUsers.length === 0) {\n showSuccessNotification('Success', 'The save was successful');\n } else {\n showErrorNotification(\n 'Error',\n `The following users failed to save: ${failedUsers\n .map(user => user.displayName)\n .join(', ')}`,\n );\n }\n\n // Display password info if necessary\n if (passwordInfoToDisplay.length > 0) {\n if (failedUsers.length === 0) {\n setTemporaryPasswordInfo(passwordInfoToDisplay);\n } else {\n // Allow enough time to read error message\n setTimeout(() => setTemporaryPasswordInfo(passwordInfoToDisplay), 2000);\n }\n }\n } finally {\n hidePageLoadingOverlay();\n }\n };\n\n const onAddUsersSaveClick = async (users: EstimatorHostedUser[]): Promise => {\n setShowAddUsersModal(false);\n\n const gridUsers: GridHostedUser[] = users.map(user => ({\n ...user,\n isNew: true,\n inEdit: false,\n selected: false,\n }));\n\n await saveUsers(gridUsers);\n };\n\n const onAddUsersDiscardClick = async (users: EstimatorHostedUser[]): Promise => {\n if (users.length === 0) {\n setShowAddUsersModal(false);\n return;\n }\n\n showConfirmationOverlay({\n title: 'Confirm',\n text: 'Are you sure you want to discard your unsaved changes?',\n buttons: [\n {\n text: 'Yes',\n onClick: (): void => {\n setShowAddUsersModal(false);\n hideConfirmationOverlay();\n },\n color: 'normal',\n },\n {\n text: 'No',\n onClick: (): void => {\n hideConfirmationOverlay();\n },\n color: 'gray',\n },\n ],\n });\n };\n\n const onCopyPasswordClick = async (): Promise => {\n if (!tempPasswordInfo || tempPasswordInfo.length === 0) {\n return;\n }\n\n const linesToCopy = tempPasswordInfo.map(\n info => `Name: ${info.name}\\nEmail: ${info.email}\\nPassword: ${info.password}`,\n );\n const copyText = linesToCopy.join('\\n\\n');\n await navigator.clipboard.writeText(copyText);\n\n setTemporaryPasswordInfo(undefined);\n };\n\n const getConfigForUser = async (\n environment: EstimatorHostedConfigurationEnvironment,\n user: EstimatorHostedUser,\n ): Promise => {\n try {\n showPageLoadingOverlay();\n const config = await EstimatorHostedApi.getEstimatorConfigForUser(\n user.emailAddress,\n environment,\n );\n return config;\n } catch {\n showErrorNotification('Error', 'Failed to retrieve the user configuration.');\n return null;\n } finally {\n hidePageLoadingOverlay();\n }\n };\n\n const onEstimatorConfigSaveClick = async (\n originalConfig: EstimatorHostedConfiguration,\n updatedConfig: EstimatorHostedConfiguration,\n ): Promise => {\n if (!estimatorConfigState) {\n return;\n }\n\n if (isEqual(updatedConfig, originalConfig)) {\n showInfoNotification('Info', 'There were no changes to save.');\n setEstimatorConfigState(undefined);\n return;\n }\n\n try {\n showPageLoadingOverlay();\n\n for (const user of estimatorConfigState.users) {\n await EstimatorHostedApi.saveEstimatorConfigForUser(user.emailAddress, updatedConfig);\n }\n\n setEstimatorConfigState(undefined);\n showSuccessNotification('Success', 'Configuration saved successfully.');\n } catch {\n showErrorNotification('Errror', 'Failed to save configuration.');\n } finally {\n hidePageLoadingOverlay();\n }\n };\n\n const onEstimatorConfigDiscardClick = (\n originalConfig: EstimatorHostedConfiguration,\n updatedConfig: EstimatorHostedConfiguration,\n ): void => {\n if (estimatorConfigState && isEqual(updatedConfig, originalConfig)) {\n setEstimatorConfigState(undefined);\n return;\n }\n\n showConfirmationOverlay({\n title: 'Confirm',\n text: 'Are you sure you want to discard your unsaved changes?',\n buttons: [\n {\n text: 'Yes',\n onClick: async (): Promise => {\n setEstimatorConfigState(undefined);\n hideConfirmationOverlay();\n },\n color: 'normal',\n },\n {\n text: 'No',\n onClick: (): void => {\n hideConfirmationOverlay();\n },\n color: 'gray',\n },\n ],\n });\n };\n\n const onEsimatorCopyConfigSaveClick = async (\n environment: EstimatorHostedConfigurationEnvironment,\n ): Promise => {\n const displayError = (): void => {\n showErrorNotification('Error', 'Failed to copy user configuration.');\n };\n\n if (!userToCopyConfigFrom) {\n displayError();\n return;\n }\n\n showConfirmationOverlay({\n title: 'Confirm',\n text: `Are you sure you want to copy the ${environment} config from \"${\n userToCopyConfigFrom.displayName\n }\" to the following users? ${selectedUsers.map(u => u.displayName).join(', ')}`,\n buttons: [\n {\n text: 'Yes',\n onClick: async (): Promise => {\n try {\n hideConfirmationOverlay();\n showPageLoadingOverlay();\n\n await EstimatorHostedApi.copyEstimatorConfigToUsers(\n userToCopyConfigFrom.emailAddress,\n environment,\n selectedUsers.map(u => u.emailAddress),\n );\n\n setUserToCopyConfigFrom(undefined);\n showSuccessNotification('Success', 'User configuration copied successfully.');\n } catch {\n displayError();\n } finally {\n hidePageLoadingOverlay();\n }\n },\n color: 'normal',\n },\n {\n text: 'No',\n onClick: (): void => {\n hideConfirmationOverlay();\n },\n color: 'gray',\n },\n ],\n });\n };\n\n const onEsimatorCopyConfigDiscardClick = (): void => {\n setUserToCopyConfigFrom(undefined);\n };\n\n const isUserValid = (user: GridHostedUser): boolean => {\n const isEmptyString = (text: string): boolean => text.trim().length === 0;\n return !isEmptyString(user.displayName) && !isEmptyString(user.clientOrganizationId);\n };\n\n const onItemChanged = (event: GridItemChangeEvent): void => {\n const editedUser = event.dataItem as GridHostedUser;\n\n setUsers(users => {\n const editedUsers = users.map(user => {\n if (user.emailAddress !== editedUser.emailAddress) {\n return user;\n }\n return { ...user, [event.field!]: event.value };\n });\n\n return editedUsers;\n });\n };\n\n const onSelectionChange = (event: GridSelectionChangeEvent): void => {\n const user = event.dataItem as GridHostedUser;\n setUsers(users => {\n const usersClone = [...users];\n const userToEdit = getUser(user.emailAddress, usersClone);\n userToEdit.selected = !user.selected;\n return usersClone;\n });\n };\n\n const onHeaderSelectionChange = (event: GridHeaderSelectionChangeEvent): void => {\n const checkbox = event.syntheticEvent.target as HTMLInputElement;\n\n setUsers(users => {\n const usersClone = [...users];\n\n filteredUsers.forEach(filteredUser => {\n const user = getUser(filteredUser.emailAddress, usersClone);\n user.selected = checkbox.checked;\n });\n\n return usersClone;\n });\n };\n\n const onFilterChange = (event: GridFilterChangeEvent): void => {\n setFilter(event.filter);\n };\n\n const onAddUsersClick = (): void => {\n setShowAddUsersModal(true);\n };\n\n const onUpdateConfigForSelectedUsersClick = (): void => {\n const selectedClientOrgIds = new Set(selectedUsers.map(u => u.clientOrganizationId));\n\n if (selectedClientOrgIds.size > 1) {\n showErrorNotification(\n 'Error',\n 'The selected users are from different Client Organizations. We only support bulk editing for users in the same Client Organization.',\n );\n return;\n }\n\n setEstimatorConfigState({ users: selectedUsers });\n };\n\n const onEditClick = (user: GridHostedUser): void => {\n setUsers(users => {\n const usersClone = [...users];\n const userToEdit = getUser(user.emailAddress, usersClone);\n userToEdit.inEdit = true;\n return usersClone;\n });\n };\n\n const viewEditEstimatorConfigClick = async (user: GridHostedUser): Promise => {\n setEstimatorConfigState({ users: [user] });\n };\n\n const copyEstimatorConfigClick = async (user: GridHostedUser): Promise => {\n if (selectedUsers.some(u => u.clientOrganizationId !== user.clientOrganizationId)) {\n showErrorNotification(\n 'Error',\n 'The selected users are from different Client Organizations. We only support copying configuration for users in the same Client Organization.',\n );\n return;\n }\n\n setUserToCopyConfigFrom(user);\n };\n\n const onResetPasswordClick = async (user: GridHostedUser): Promise => {\n const resetPassword = async (): Promise => {\n const tempPassword: string = await EstimatorHostedApi.resetUserPassword(user.emailAddress);\n setTemporaryPasswordInfo([\n {\n name: user.displayName,\n email: user.emailAddress,\n password: tempPassword,\n },\n ]);\n };\n\n showConfirmationOverlay({\n title: 'Confirm',\n text: `Are you sure you want to reset the password for user \"${user.displayName}\"?`,\n buttons: [\n {\n text: 'Yes',\n onClick: async (): Promise => {\n try {\n hideConfirmationOverlay();\n showPageLoadingOverlay();\n await resetPassword();\n } catch {\n showErrorNotification('Error', \"Failed to reset the user's password\");\n } finally {\n hidePageLoadingOverlay();\n }\n },\n color: 'normal',\n },\n {\n text: 'No',\n onClick: (): void => {\n hideConfirmationOverlay();\n },\n color: 'gray',\n },\n ],\n });\n };\n\n const onDeleteClick = async (user: GridHostedUser): Promise => {\n const deleteUser = async (): Promise => {\n await EstimatorHostedApi.deleteUser(user.emailAddress);\n setUsers(users => {\n const usersClone = [...users];\n const index = usersClone.findIndex(u => u.emailAddress === user.emailAddress);\n usersClone.splice(index, 1);\n return usersClone;\n });\n };\n\n showConfirmationOverlay({\n title: 'Confirm',\n text: `Are you sure you want to delete the user \"${user.displayName}\"?`,\n buttons: [\n {\n text: 'Yes',\n onClick: async (): Promise => {\n try {\n hideConfirmationOverlay();\n showPageLoadingOverlay();\n await deleteUser();\n showSuccessNotification('Success', 'User deleted successfully');\n } catch {\n showErrorNotification('Error', 'Failed to delete the user.');\n } finally {\n hidePageLoadingOverlay();\n }\n },\n color: 'normal',\n },\n {\n text: 'No',\n onClick: (): void => {\n hideConfirmationOverlay();\n },\n color: 'gray',\n },\n ],\n });\n };\n\n const onSaveClick = async (user: GridHostedUser): Promise => {\n await saveUsers([user]);\n };\n\n const onDiscardClick = async (user: GridHostedUser): Promise => {\n if (user.isNew) {\n const removeNewUser = (): void => {\n setUsers(users => {\n const usersClone = [...users];\n const index = usersClone.findIndex(u => u.emailAddress === user.emailAddress);\n usersClone.splice(index, 1);\n return usersClone;\n });\n };\n\n if (!user.displayName && !user.clientOrganizationId) {\n removeNewUser();\n } else {\n showConfirmationOverlay({\n title: 'Confirm',\n text: 'Are you sure you want to discard your unsaved changes?',\n buttons: [\n {\n text: 'Yes',\n onClick: (): void => {\n hideConfirmationOverlay();\n removeNewUser();\n },\n color: 'normal',\n },\n {\n text: 'No',\n onClick: (): void => {\n hideConfirmationOverlay();\n },\n color: 'gray',\n },\n ],\n });\n }\n } else {\n try {\n const savedUser = await EstimatorHostedApi.getUserByEmail(user.emailAddress);\n const uneditedUser: GridHostedUser = {\n ...savedUser,\n isNew: user.isNew,\n inEdit: user.inEdit,\n selected: user.selected,\n };\n\n const resetUser = (): void => {\n setUsers(users => {\n const usersClone = [...users];\n const index = usersClone.findIndex(u => u.emailAddress === user.emailAddress);\n usersClone[index] = { ...uneditedUser, inEdit: false };\n return usersClone;\n });\n };\n\n if (isEqual(uneditedUser, user)) {\n resetUser();\n } else {\n showConfirmationOverlay({\n title: 'Confirm',\n text: 'Are you sure you want to discard your unsaved changes?',\n buttons: [\n {\n text: 'Yes',\n onClick: (): void => {\n hideConfirmationOverlay();\n resetUser();\n },\n color: 'normal',\n },\n {\n text: 'No',\n onClick: (): void => {\n hideConfirmationOverlay();\n },\n color: 'gray',\n },\n ],\n });\n }\n } catch {\n showErrorNotification('Error', 'Failed to load user.');\n history.push(ApplicationRoutes.ERROR_ERROR);\n }\n }\n };\n\n const commandCell = (gcp: GridCellProps): JSX.Element => {\n const user = gcp.dataItem as GridHostedUser;\n return (\n \n
\n {user.inEdit ? (\n <>\n => await onSaveClick(user)}\n disabled={!isUserValid(user)}\n />\n => await onDiscardClick(user)}\n />\n \n ) : (\n <>\n onEditClick(user)} />\n => await viewEditEstimatorConfigClick(user)}\n />\n => await copyEstimatorConfigClick(user)}\n disabled={\n selectedUsers.length === 1\n ? selectedUsers[0].emailAddress === user.emailAddress\n : selectedUsers.length === 0\n }\n />\n => await onResetPasswordClick(user)}\n />\n => await onDeleteClick(user)}\n />\n \n )}\n
\n \n );\n };\n\n const emailCell = (gcp: GridCellProps): JSX.Element => {\n const user = gcp.dataItem as GridHostedUser;\n return {user.isNew ? <>{''} : <>{user.emailAddress}};\n };\n\n const nameCell = useCallback((gcp: GridCellProps): JSX.Element => {\n const user = gcp.dataItem as GridHostedUser;\n if (user.inEdit) {\n return ;\n } else {\n return {user.displayName};\n }\n }, []);\n\n const clientOrgCell = useCallback(\n (gcp: GridCellProps): JSX.Element => {\n const user = gcp.dataItem as GridHostedUser;\n\n if (user.inEdit) {\n return (\n ('id')}\n valueField={nameof('id')}\n textField={nameof('name')}\n listAnchor={gridContainer}\n />\n );\n }\n\n const clientOrg = clientOrgs.find(co => co.id === user.clientOrganizationId);\n if (!clientOrg) {\n return (\n \n
    \n
  • {'ERROR: Client Organization ID not set'}
  • \n
  • {`Value: ${user.clientOrganizationId}`}
  • \n
\n \n );\n }\n\n return {clientOrg.name};\n },\n [clientOrgs],\n );\n\n const clientOrgFilterCell = useCallback(\n (gfcp: GridFilterCellProps): JSX.Element => {\n return (\n ('id')}\n valueField={nameof('id')}\n textField={nameof('name')}\n />\n );\n },\n [clientOrgs],\n );\n\n const groupCell = useCallback(\n (gcp: GridCellProps): JSX.Element => {\n const user = gcp.dataItem as GridHostedUser;\n if (user.inEdit) {\n return (\n ('id')}\n valueField={nameof('id')}\n textField={nameof('displayName')}\n listAnchor={gridContainer}\n />\n );\n }\n\n return (\n \n
    \n {user.groupIds.map(groupId => {\n const group = userGroups.find(g => g.id === groupId);\n return
  • {group ? group.displayName : groupId}
  • ;\n })}\n
\n \n );\n },\n [userGroups],\n );\n\n const groupFilterCell = useCallback(\n (gfcp: GridFilterCellProps): JSX.Element => {\n return (\n ('id')}\n valueField={nameof('id')}\n textField={nameof('displayName')}\n filterOperator=\"contains\"\n />\n );\n },\n [userGroups],\n );\n\n if (isLoading) {\n return <>;\n }\n\n return (\n
\n
\n

Estimator Hosted - User Management

\n
\n\n {!showAddUsersModal ? (\n <>\n ) : (\n \n )}\n\n {!tempPasswordInfo ? (\n <>\n ) : (\n \n )}\n\n {!estimatorConfigState ? (\n <>\n ) : (\n setEstimatorConfigState(undefined)}\n onSaveClick={onEstimatorConfigSaveClick}\n onDiscardClick={onEstimatorConfigDiscardClick}\n />\n )}\n\n {!userToCopyConfigFrom ? (\n <>\n ) : (\n \n )}\n\n
\n ('emailAddress')}\n editField={nameof('inEdit')}\n onItemChange={onItemChanged}\n selectedField={nameof('selected')}\n onSelectionChange={onSelectionChange}\n onHeaderSelectionChange={onHeaderSelectionChange}\n filterable={true}\n filter={filter}\n onFilterChange={onFilterChange}\n >\n \n
\n \n
\n \n
\n
\n
\n ('selected')}\n filterable={false}\n headerSelectionValue={\n filteredUsers.length > 0 && filteredUsers.every(user => user.selected)\n }\n />\n ('emailAddress')}\n editable={false}\n cell={emailCell}\n />\n ('displayName')} cell={nameCell} />\n ('clientOrganizationId')}\n cell={clientOrgCell}\n filterCell={clientOrgFilterCell}\n />\n ('groupIds')}\n cell={groupCell}\n filterCell={groupFilterCell}\n />\n \n \n
\n
\n );\n};\n\nconst getUser = (email: string, users: GridHostedUser[]): GridHostedUser => {\n const user = users.find(u => u.emailAddress === email);\n\n if (!user) {\n throw new Error(`Could not find user with email: ${email}`);\n }\n\n return user;\n};\n\nconst sortUsers = (users: GridHostedUser[]): GridHostedUser[] => {\n return sortBy(users, user => user.displayName);\n};\n\nexport default EstimatorHostedUserManagementPage;\n","import React from 'react';\nimport basket from './../../assets/icons/basket.svg';\nimport bulb from './../../assets/icons/bulb.svg';\nimport certificate from './../../assets/icons/certificate.svg';\nimport clock from './../../assets/icons/clock.svg';\nimport database from './../../assets/icons/database.svg';\nimport error from './../../assets/icons/error.svg';\nimport exclamation from './../../assets/icons/exclamation.svg';\nimport key from './../../assets/icons/key.svg';\nimport estimator from './../../assets/icons/products/estimator.svg';\nimport stop from './../../assets/icons/stop.svg';\nimport tools from './../../assets/icons/tools.svg';\nimport users from './../../assets/icons/users.svg';\nimport users2 from './../../assets/icons/users2.svg';\nimport verifiedCheck from './../../assets/icons/verified-check.svg';\nimport './SvgImage.scss';\n\nexport type SvgImages =\n | 'basket'\n | 'bulb'\n | 'certificate'\n | 'clock'\n | 'error'\n | 'database'\n | 'estimator'\n | 'exclamation'\n | 'key'\n | 'stop'\n | 'tools'\n | 'users'\n | 'users2'\n | 'verified-check';\ntype SvgImageSizes = 'sm' | 'lg' | 'xl';\n\ninterface Props {\n image: SvgImages;\n size?: SvgImageSizes;\n}\n\nconst SvgImage: React.FC = ({ image, size }) => {\n const getSvgImage = (): string => {\n switch (image) {\n case 'basket':\n return basket;\n case 'bulb':\n return bulb;\n case 'certificate':\n return certificate;\n case 'clock':\n return clock;\n case 'database':\n return database;\n case 'error':\n return error;\n case 'estimator':\n return estimator;\n case 'exclamation':\n return exclamation;\n case 'key':\n return key;\n case 'stop':\n return stop;\n case 'tools':\n return tools;\n case 'users':\n return users;\n case 'users2':\n return users2;\n case 'verified-check':\n return verifiedCheck;\n default:\n return '';\n }\n };\n\n const getSizeClass = (): string => {\n switch (size) {\n case 'sm':\n return 'sm';\n case 'xl':\n return 'xl';\n case 'lg':\n default:\n return 'lg';\n }\n };\n\n return (\n
\n {image}\n
\n );\n};\n\nexport default SvgImage;\n","import React from 'react';\nimport { useHistory } from 'react-router';\nimport ApplicationRoutes from '../../../../../constants/routes';\nimport { isDevelopmentEnvironment } from '../../../../../utils/general';\nimport SvgImage from '../../../../common-page-components/svg-image/SvgImage';\n\nconst GenericErrorPage: React.FC = () => {\n const history = useHistory();\n\n return (\n
\n
\n
\n
\n \n
\n
\n\n
\n

We're sorry, but an error occurred.

\n
\n\n {isDevelopmentEnvironment ? (\n
\n history.push(ApplicationRoutes.SITE_ROOT)}\n title=\"Click here to go home, Forrest\"\n />\n
\n ) : (\n <>\n )}\n
\n
\n );\n};\n\nexport default GenericErrorPage;\n","import React from 'react';\nimport { useHistory } from 'react-router';\nimport ApplicationRoutes from '../../../../../constants/routes';\nimport { isDevelopmentEnvironment } from '../../../../../utils/general';\nimport SvgImage from '../../../../common-page-components/svg-image/SvgImage';\n\nconst PageNotFoundPage: React.FC = () => {\n const history = useHistory();\n\n return (\n
\n
\n
\n
\n \n
\n
\n\n
\n

\n Sorry, but we can't find that page.\n {isDevelopmentEnvironment && (\n <>\n
\n
\n Maybe if we had used DESTINI Estimator during site preconstruction, we could have\n made enough money to build all the pages.\n \n )}\n

\n
\n\n {isDevelopmentEnvironment ? (\n
\n history.push(ApplicationRoutes.SITE_ROOT)}\n title=\"Click here to go home, Forrest\"\n />\n
\n ) : (\n <>\n )}\n
\n
\n );\n};\n\nexport default PageNotFoundPage;\n","import React, { useContext, useEffect, useState } from 'react';\nimport { useHistory } from 'react-router';\nimport ApplicationRoutes from '../../../../../constants/routes';\nimport { AuthenticationService } from '../../../../../services/authentication/authentication-service';\nimport { isDevelopmentEnvironment } from '../../../../../utils/general';\nimport { LoadingPageOverlayContext } from '../../../../common-page-components/loading-page-overlay/LoadingPageOverlayContext';\nimport SvgImage from '../../../../common-page-components/svg-image/SvgImage';\n\nconst UnauthorizedPage: React.FC = () => {\n const history = useHistory();\n const { showPageLoadingOverlay, hidePageLoadingOverlay } = useContext(LoadingPageOverlayContext);\n\n const [pageIsDisplayed, setPageIsDisplayed] = useState(false);\n\n useEffect(() => {\n // If the user is logged in, we want to redirect them to the home page\n const checkUserAuthenticationStatus = async (): Promise => {\n try {\n showPageLoadingOverlay();\n\n const accessTokenWasRetrieved = await AuthenticationService.getAccessToken();\n if (accessTokenWasRetrieved) {\n history.push(ApplicationRoutes.HOME);\n return;\n }\n\n // Display the page as usual if the user is not logged in\n setPageIsDisplayed(true);\n } catch {\n // Display the page as usual if an error occurred\n setPageIsDisplayed(true);\n } finally {\n hidePageLoadingOverlay();\n }\n };\n\n checkUserAuthenticationStatus();\n }, [showPageLoadingOverlay, hidePageLoadingOverlay, history]);\n\n if (!pageIsDisplayed) {\n return <>;\n }\n\n return (\n
\n
\n
\n
\n \n
\n
\n\n
\n

We're sorry, but you are not authorized to view the requested page.

\n
\n\n {isDevelopmentEnvironment ? (\n
\n history.push(ApplicationRoutes.SITE_ROOT)}\n title=\"Click here to go home, Forrest\"\n />\n
\n ) : (\n <>\n )}\n
\n
\n );\n};\n\nexport default UnauthorizedPage;\n","const LinksConstants = {\r\n BeckTechWebsite: 'http://www.beck-technology.com',\r\n BeckTechCommunityWebsite: 'http://community.beck-technology.com',\r\n EstimatorWebsite: 'https://beck-technology.com/destini-estimator',\r\n};\r\n\r\nexport default LinksConstants;\r\n","import React, { useContext, useEffect, useState } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { Link } from 'react-router-dom';\r\nimport ApplicationRoutes from '../../../../constants/routes';\r\nimport { UserInformationContext } from '../../../UserInformationContext';\r\nimport { getEEClass } from './../../../../utils/ee';\r\nimport { isDevelopmentEnvironment } from './../../../../utils/general';\r\nimport SvgImage, { SvgImages } from './../../../common-page-components/svg-image/SvgImage';\r\nimport './HomePage.scss';\r\nimport { getConfig } from '../../../../utils/config';\r\nimport LinksConstants from '../../../../constants/links';\r\n\r\ninterface HomePageNavigationCardsCollection {\r\n title: string;\r\n cards: HomePageNavigationCard[];\r\n}\r\n\r\ninterface HomePageNavigationCard {\r\n title: string;\r\n url: string;\r\n svgImage?: SvgImages;\r\n}\r\n\r\nconst HomePage: React.FC = () => {\r\n const { t } = useTranslation();\r\n\r\n const { userInformation } = useContext(UserInformationContext);\r\n const [allLinkCollections, setAllLinkCollections] = useState(\r\n [],\r\n );\r\n\r\n const websiteUrlCommunity =\r\n getConfig('REACT_APP_BECKTECH_COMMUNITY_URL') || LinksConstants.BeckTechCommunityWebsite;\r\n\r\n const getUrlForDisplay = (url: string): string => {\r\n return url.replace('http://', '');\r\n };\r\n\r\n useEffect(() => {\r\n const generateLinksCollections = (): HomePageNavigationCardsCollection[] => {\r\n const newLinks: HomePageNavigationCardsCollection[] = [];\r\n\r\n if (userInformation) {\r\n if (\r\n userInformation.userIsClientUser ||\r\n userInformation.userIsInternalUser ||\r\n userInformation.userIsAdmin\r\n ) {\r\n newLinks.push({\r\n title: t('reporting:reports'),\r\n cards: [\r\n {\r\n title: t('reporting:reportNames.usage'),\r\n url: ApplicationRoutes.REPORTS_USAGE,\r\n svgImage: 'tools',\r\n },\r\n\r\n {\r\n title: t('reporting:reportNames.checkouts'),\r\n url: ApplicationRoutes.REPORTS_CHECKOUTS,\r\n svgImage: 'basket',\r\n },\r\n\r\n {\r\n title: t('reporting:reportNames.duration'),\r\n url: ApplicationRoutes.REPORTS_DURATION,\r\n svgImage: 'clock',\r\n },\r\n\r\n {\r\n title: t('reporting:reportNames.rawData'),\r\n url: ApplicationRoutes.REPORTS_RAWDATA,\r\n svgImage: 'database',\r\n },\r\n ],\r\n });\r\n }\r\n\r\n if (userInformation.userIsAdmin) {\r\n newLinks.unshift({\r\n title: 'Admin',\r\n cards: [\r\n { title: 'Clients', url: ApplicationRoutes.ADMIN_CLIENTS, svgImage: 'users2' },\r\n {\r\n title: 'Licenses',\r\n url: ApplicationRoutes.ADMIN_LICENSES,\r\n svgImage: 'certificate',\r\n },\r\n { title: 'Products', url: ApplicationRoutes.ADMIN_PRODUCTS, svgImage: 'bulb' },\r\n // NOTE: The page this navigates to is the users page but for clarity as to what that page actually is, we use a slightly different label\r\n {\r\n title: 'Users',\r\n url: ApplicationRoutes.ADMIN_USERS,\r\n svgImage: 'key',\r\n },\r\n ],\r\n });\r\n }\r\n }\r\n return newLinks;\r\n };\r\n setAllLinkCollections(generateLinksCollections());\r\n }, [t, userInformation]);\r\n\r\n return (\r\n
\r\n
\r\n {!allLinkCollections.length && (\r\n
\r\n
\r\n
\r\n \r\n
\r\n\r\n
\r\n
Your license is valid and we think that is awesome!
\r\n\r\n
\r\n Keep using Estimator, keep telling us how we can continue to make preconstruction\r\n technology better, and keep revolutionizing the construction industry.\r\n
\r\n
\r\n We also encourage you to join our community at{' '}\r\n \r\n {getUrlForDisplay(websiteUrlCommunity)}\r\n {' '}\r\n to get the latest updates and interact with other Estimator users.\r\n
\r\n
\r\n
\r\n
\r\n )}\r\n\r\n {allLinkCollections.map((currLinkCollection, i) => (\r\n
\r\n

{currLinkCollection.title}

\r\n\r\n
\r\n {currLinkCollection.cards.map(currCard => {\r\n return (\r\n \r\n \r\n \r\n
\r\n {currCard.svgImage && }\r\n
\r\n
{currCard.title}
\r\n
\r\n \r\n
\r\n );\r\n })}\r\n
\r\n
\r\n ))}\r\n \r\n \r\n );\r\n};\r\n\r\nexport default HomePage;\r\n","import React, { useEffect } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { useHistory } from 'react-router-dom';\r\nimport LinksConstants from '../../../../constants/links';\r\nimport LocalStorageKeys from '../../../../constants/local-storage';\r\nimport ApplicationRoutes from '../../../../constants/routes';\r\nimport { AuthenticationService } from '../../../../services/authentication/authentication-service';\r\nimport { getConfig } from '../../../../utils/config';\r\nimport BTButton from '../../../common-page-components/controls/button/BTButton';\r\nimport SvgImage from '../../../common-page-components/svg-image/SvgImage';\r\nimport './LoginPage.scss';\r\n\r\nconst LoginPage: React.FC = () => {\r\n const { t } = useTranslation();\r\n const history = useHistory();\r\n\r\n useEffect(() => {\r\n const accessTokenFromLocalStorage = localStorage.getItem(LocalStorageKeys.AccessToken);\r\n\r\n if (accessTokenFromLocalStorage) {\r\n // NOTE: We explicitly replace the history entry, not push onto it\r\n history.replace(ApplicationRoutes.HOME);\r\n }\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, []);\r\n\r\n const websiteUrl = getConfig('REACT_APP_BECKTECH_URL') || LinksConstants.BeckTechWebsite;\r\n const websiteUrlCommunity =\r\n getConfig('REACT_APP_BECKTECH_COMMUNITY_URL') || LinksConstants.BeckTechCommunityWebsite;\r\n const estimatorWebsite = getConfig('REACT_APP_ESTIMATOR_URL') || LinksConstants.EstimatorWebsite;\r\n\r\n const getUrlForDisplay = (url: string): string => {\r\n return url.replace('http://', '');\r\n };\r\n\r\n const signIn = (): void => {\r\n AuthenticationService.navigateToSignInOrPasswordReset();\r\n };\r\n\r\n return (\r\n
\r\n
\r\n
\r\n\r\n
\r\n
\r\n

{t('general:Welcome to the Beck Technology Licensing Portal')}

\r\n
\r\n\r\n
\r\n \r\n
\r\n
\r\n
\r\n\r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n
\r\n
\r\n
\r\n To learn more about DESTINI Estimator and preconstruction lifecycle data please visit\r\n our website at{' '}\r\n \r\n {getUrlForDisplay(websiteUrl)}\r\n \r\n .\r\n
\r\n
\r\n If you need assistance with Estimator, visit our online community at{' '}\r\n \r\n {getUrlForDisplay(websiteUrlCommunity)}\r\n \r\n .\r\n
\r\n
\r\n
\r\n
\r\n
\r\n );\r\n};\r\n\r\nexport default LoginPage;\r\n","export type FileType = 'csv';\r\n\r\nconst saveFile = (arrayBuffer: ArrayBuffer, fileName: string, fileType: FileType): void => {\r\n // Source: https://expertcodeblog.wordpress.com/2018/08/13/asp-net-core-angular-download-file/\r\n const byteArray = new Uint8Array(arrayBuffer);\r\n const blob = new Blob([byteArray], { type: getFileMimeType(fileType) });\r\n const name = fileName + '.' + fileType;\r\n // IE doesn't allow using a blob object directly as link href\r\n // instead it is necessary to use msSaveOrOpenBlob\r\n if (window.navigator && window.navigator.msSaveOrOpenBlob) {\r\n window.navigator.msSaveOrOpenBlob(blob, name);\r\n return;\r\n }\r\n\r\n // For other browsers:\r\n // Create a link pointing to the ObjectURL containing the blob.\r\n const data = window.URL.createObjectURL(blob);\r\n const link = document.createElement('a');\r\n link.href = data;\r\n link.download = name;\r\n link.click();\r\n setTimeout(() => {\r\n // For Firefox it is necessary to delay revoking the ObjectURL\r\n window.URL.revokeObjectURL(data);\r\n }, 100);\r\n};\r\n\r\nconst getFileMimeType = (fileType: FileType): string => {\r\n switch (fileType) {\r\n case 'csv':\r\n return 'text/csv';\r\n default:\r\n return 'text/plain';\r\n }\r\n};\r\n\r\nexport { saveFile };\r\n","export const Increments = {\r\n Day: 'Day',\r\n Week: 'Week',\r\n Month: 'Month',\r\n};\r\n\r\nexport default { Increments };\r\n","export const ProductOptions = {\r\n All: 'All Products',\r\n None: 'No Products',\r\n};\r\n\r\nexport default { ProductOptions };\r\n","import { Increments } from './increments';\r\nimport { ProductOptions } from './products';\r\n\r\nconst ReportFilterConstants = {\r\n FILTERINCREMENT_DAY: Increments.Day,\r\n FILTERINCREMENT_WEEK: Increments.Week,\r\n FILTERINCREMENT_MONTH: Increments.Month,\r\n FILTERINCREMENT_DEFAULT_INCREMENTS: [Increments.Day, Increments.Week, Increments.Month],\r\n PRODUCTOPTION_ALL_PRODUCTS: ProductOptions.All,\r\n PRODUCTOPTION_NO_PRODUCTS: ProductOptions.None,\r\n};\r\n\r\nexport default ReportFilterConstants;\r\n","export const Settings = {\r\n colors: {\r\n blue: '#0033a0',\r\n red: 'rgba(239, 47, 33, 0.9)',\r\n },\r\n chartAreaCeiling: 10,\r\n chartAreaFloor: 1,\r\n};\r\n\r\nexport default { Settings };\r\n","import { Settings } from './chart-defaults';\r\n\r\nconst ChartDefaults = {\r\n colors: Settings.colors,\r\n chartAreaCeiling: Settings.chartAreaCeiling,\r\n chartAreaFloor: Settings.chartAreaFloor,\r\n};\r\n\r\nexport default ChartDefaults;\r\n","import React from 'react';\nimport {\n ChartCategoryAxisItem,\n TooltipContext,\n SharedTooltipContext,\n} from '@progress/kendo-react-charts';\nimport { CategoryBaseUnit } from '@progress/kendo-react-charts/dist/npm/common/property-types';\nimport moment from 'moment';\n\nconst getChartCategoryAxisItem = (increment: string): JSX.Element => {\n switch (increment) {\n case 'Day':\n case 'Week':\n case 'Month': {\n const baseUnit = (increment.toLowerCase() + 's') as CategoryBaseUnit;\n return ;\n }\n\n default: {\n return ;\n }\n }\n};\n\nconst defaultTooltipRender = (props: TooltipContext | SharedTooltipContext): React.ReactNode => {\n return (\n
\n {`${moment(new Date((props as TooltipContext).point.category)).format(\n 'M/D/YYYY',\n )} - Checkouts: ${(props as TooltipContext).point.value}`}\n
\n );\n};\n\nconst customTooltipRender = (\n props: TooltipContext | SharedTooltipContext,\n dateFormat: string,\n tooltipLabel: string,\n): React.ReactNode => {\n return (\n
\n {`${moment(new Date((props as TooltipContext).point.category)).format(\n dateFormat,\n )} - ${tooltipLabel}: ${(props as TooltipContext).point.value}`}\n
\n );\n};\n\nexport { getChartCategoryAxisItem, defaultTooltipRender, customTooltipRender };\n","import {\r\n Chart,\r\n ChartCategoryAxis,\r\n ChartLegend,\r\n ChartSeries,\r\n ChartSeriesItem,\r\n ChartTitle,\r\n ChartTooltip,\r\n} from '@progress/kendo-react-charts';\r\nimport React from 'react';\r\nimport ChartDefaults from '../../../../../constants/charts';\r\nimport { defaultTooltipRender, getChartCategoryAxisItem } from '../../../../../utils/charts';\r\n\r\nconst LicenseUsageChart: React.FC = props => {\r\n const {\r\n data: {\r\n chartSeries,\r\n appliedFilters: { specificFilters },\r\n },\r\n } = props;\r\n\r\n const usageFilters = specificFilters as ReportFiltersWithIncrement;\r\n return (\r\n
\r\n \r\n \r\n \r\n \r\n \r\n {chartSeries.map((cs, idx) => {\r\n return (\r\n \r\n );\r\n })}\r\n \r\n {getChartCategoryAxisItem(usageFilters.increment)}\r\n \r\n
\r\n );\r\n};\r\n\r\nexport default LicenseUsageChart;\r\n","import {\n Chart,\n ChartCategoryAxis,\n ChartLegend,\n ChartSeries,\n ChartSeriesItem,\n ChartTitle,\n ChartTooltip,\n} from '@progress/kendo-react-charts';\nimport React from 'react';\nimport ChartDefaults from '../../../../../constants/charts';\nimport { defaultTooltipRender, getChartCategoryAxisItem } from '../../../../../utils/charts';\n\nconst LicenseCheckoutsChart: React.FC = props => {\n const {\n data: {\n chartSeries,\n appliedFilters: { specificFilters },\n },\n } = props;\n\n const checkoutFilters = specificFilters as ReportFiltersWithIncrement;\n\n return (\n
\n \n \n \n \n \n {chartSeries.map((cs, idx) => {\n return (\n \n );\n })}\n \n {getChartCategoryAxisItem(checkoutFilters.increment)}\n \n
\n );\n};\n\nexport default LicenseCheckoutsChart;\n","import {\r\n Chart,\r\n ChartCategoryAxis,\r\n ChartLegend,\r\n ChartSeries,\r\n ChartSeriesItem,\r\n ChartTitle,\r\n ChartTooltip,\r\n SharedTooltipContext,\r\n TooltipContext,\r\n} from '@progress/kendo-react-charts';\r\nimport React from 'react';\r\nimport ChartDefaults from '../../../../../constants/charts';\r\nimport { customTooltipRender, getChartCategoryAxisItem } from '../../../../../utils/charts';\r\n\r\nconst LicenseDurationChart: React.FC = props => {\r\n const {\r\n data: {\r\n chartSeries,\r\n appliedFilters: { specificFilters },\r\n },\r\n } = props;\r\n\r\n const durationFilters = specificFilters as ReportFiltersWithIncrement;\r\n\r\n const tooltipRender = (props: TooltipContext | SharedTooltipContext): React.ReactNode => {\r\n return customTooltipRender(props, 'M/D/YYYY', 'Hours');\r\n };\r\n\r\n return (\r\n
\r\n \r\n \r\n \r\n \r\n \r\n {chartSeries.map((cs, idx) => {\r\n return (\r\n \r\n );\r\n })}\r\n \r\n {getChartCategoryAxisItem(durationFilters.increment)}\r\n \r\n
\r\n );\r\n};\r\n\r\nexport default LicenseDurationChart;\r\n","import React, { useMemo } from 'react';\r\nimport { Route, Switch } from 'react-router';\r\nimport ApplicationRoutes from '../../../../constants/routes';\r\nimport LicenseUsageChart from './../charts/LicenseUsage/LicenseUsageChart';\r\nimport LicenseCheckoutsChart from './../charts/LicenseCheckouts/LicenseCheckoutsChart';\r\nimport LicenseDurationChart from './../charts/LicenseDuration/LicenseDurationChart';\r\n\r\nconst ReportsPageCustomChart: React.FC = props => {\r\n // NOTE: This is required so that the chart doesn't re-render with filter changes\r\n return useMemo(\r\n () => (\r\n \r\n }\r\n />\r\n }\r\n />\r\n }\r\n />\r\n \r\n ),\r\n [props.data],\r\n );\r\n};\r\n\r\nexport default ReportsPageCustomChart;\r\n","const REPORT_USAGE = 'Usage';\r\nconst REPORT_CHECKOUTS = 'Checkouts';\r\nconst REPORT_DURATION = 'Duration';\r\nconst REPORT_RAWDATA = 'Raw Data';\r\n\r\nexport const ReportNames = {\r\n Usage: REPORT_USAGE,\r\n Checkouts: REPORT_CHECKOUTS,\r\n Duration: REPORT_DURATION,\r\n RawData: REPORT_RAWDATA,\r\n};\r\n","import moment from 'moment';\r\n\r\nexport const applyPartialDateRangeRules = (\r\n date: Date,\r\n increment: string,\r\n isFromDate: boolean,\r\n): Date => {\r\n let newMomentObj = moment(date);\r\n switch (increment) {\r\n case 'Week': {\r\n if (isFromDate) {\r\n newMomentObj = newMomentObj.startOf('week');\r\n } else {\r\n newMomentObj = newMomentObj.endOf('week');\r\n }\r\n break;\r\n }\r\n case 'Month': {\r\n if (isFromDate) {\r\n newMomentObj = newMomentObj.startOf('month');\r\n } else {\r\n newMomentObj = newMomentObj.endOf('month');\r\n }\r\n break;\r\n }\r\n }\r\n\r\n return newMomentObj.toDate();\r\n};\r\n","import { DropDownList } from '@progress/kendo-react-dropdowns';\r\nimport React, { useEffect, useCallback } from 'react';\r\nimport { ReportNames } from '../../reports';\r\nimport { UsageApi } from '../../../../../services/api';\r\nimport { useHistory } from 'react-router';\r\nimport ApplicationRoutes from '../../../../../constants/routes';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { applyPartialDateRangeRules } from '../../../../../utils/calendars';\r\nimport ReportFilterConstants from './../../../../../constants/reports/filters';\r\n\r\ninterface Props {\r\n usageReportFilters: ReportFiltersWithIncrement;\r\n}\r\n\r\nconst LicenseUsageFilter: React.FC = ({\r\n reportFilters,\r\n usageReportFilters,\r\n setReportDataSource,\r\n setSpecificReportFilters,\r\n setCalendarType,\r\n}) => {\r\n const { t } = useTranslation();\r\n const history = useHistory();\r\n\r\n const updateReportDataSource = useCallback((): void => {\r\n setReportDataSource(ReportNames.Usage, () => {\r\n switch (usageReportFilters.increment) {\r\n case ReportFilterConstants.FILTERINCREMENT_DAY: {\r\n return UsageApi.getUsageByDay(\r\n reportFilters.fromDate,\r\n reportFilters.toDate,\r\n reportFilters.client,\r\n reportFilters.product &&\r\n reportFilters.product.id === ReportFilterConstants.PRODUCTOPTION_ALL_PRODUCTS\r\n ? null\r\n : reportFilters.product,\r\n 'distinct',\r\n );\r\n }\r\n case ReportFilterConstants.FILTERINCREMENT_WEEK: {\r\n return UsageApi.getUsageByWeek(\r\n applyPartialDateRangeRules(reportFilters.fromDate, reportFilters.calendarType, true),\r\n applyPartialDateRangeRules(reportFilters.toDate, reportFilters.calendarType, false),\r\n reportFilters.client,\r\n reportFilters.product &&\r\n reportFilters.product.id === ReportFilterConstants.PRODUCTOPTION_ALL_PRODUCTS\r\n ? null\r\n : reportFilters.product,\r\n 'distinct',\r\n );\r\n }\r\n case ReportFilterConstants.FILTERINCREMENT_MONTH: {\r\n return UsageApi.getUsageByMonth(\r\n applyPartialDateRangeRules(reportFilters.fromDate, reportFilters.calendarType, true),\r\n applyPartialDateRangeRules(reportFilters.toDate, reportFilters.calendarType, false),\r\n reportFilters.client,\r\n reportFilters.product &&\r\n reportFilters.product.id === ReportFilterConstants.PRODUCTOPTION_ALL_PRODUCTS\r\n ? null\r\n : reportFilters.product,\r\n 'distinct',\r\n );\r\n }\r\n default: {\r\n // NOTE: This is based on a fixed dropdown, so this case should never be hit. Returning\r\n // an empty promise to satisfy the return type, but the redirect will run prior.\r\n history.push(ApplicationRoutes.ERROR_ERROR);\r\n return new Promise((): void => {});\r\n }\r\n }\r\n });\r\n }, [setReportDataSource, usageReportFilters, reportFilters, history]);\r\n\r\n const updateReportFilterValues = useCallback(\r\n (usageReportFilters: ReportFiltersWithIncrement): void => {\r\n setSpecificReportFilters(ReportNames.Usage, usageReportFilters);\r\n setCalendarType(usageReportFilters.increment);\r\n updateReportDataSource();\r\n },\r\n [setSpecificReportFilters, setCalendarType, updateReportDataSource],\r\n );\r\n\r\n // Set the data source values for this component when the generic report filters provided to this component change\r\n useEffect(() => {\r\n updateReportDataSource();\r\n }, [reportFilters, updateReportDataSource]);\r\n\r\n // If the usage report filters are not initialized, initialize them\r\n useEffect(() => {\r\n if (!usageReportFilters) {\r\n updateReportFilterValues({\r\n increment: ReportFilterConstants.FILTERINCREMENT_DAY,\r\n });\r\n }\r\n }, [updateReportFilterValues, usageReportFilters]);\r\n\r\n return (\r\n
\r\n
\r\n \r\n {\r\n updateReportFilterValues({\r\n ...usageReportFilters,\r\n increment: event.target.value,\r\n });\r\n }}\r\n value={(usageReportFilters && usageReportFilters.increment) || ''}\r\n />\r\n
\r\n
\r\n );\r\n};\r\n\r\nexport default LicenseUsageFilter;\r\n","import React, { useEffect, useCallback } from 'react';\r\nimport { DropDownList } from '@progress/kendo-react-dropdowns';\r\nimport { ReportNames } from '../../reports';\r\nimport { useHistory } from 'react-router';\r\nimport { UsageApi } from '../../../../../services/api';\r\nimport ApplicationRoutes from '../../../../../constants/routes';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { applyPartialDateRangeRules } from '../../../../../utils/calendars';\r\nimport ReportFilterConstants from './../../../../../constants/reports/filters';\r\n\r\ninterface Props {\r\n durationReportFilters: ReportFiltersWithIncrement;\r\n}\r\n\r\nconst LicenseDurationFilter: React.FC = ({\r\n reportFilters,\r\n durationReportFilters,\r\n setSpecificReportFilters,\r\n setReportDataSource,\r\n setCalendarType,\r\n}) => {\r\n const { t } = useTranslation();\r\n const history = useHistory();\r\n\r\n const updateReportDataSource = useCallback((): void => {\r\n setReportDataSource(ReportNames.Duration, () => {\r\n switch (durationReportFilters.increment) {\r\n case ReportFilterConstants.FILTERINCREMENT_DAY: {\r\n return UsageApi.getUsageByDay(\r\n reportFilters.fromDate,\r\n reportFilters.toDate,\r\n reportFilters.client,\r\n reportFilters.product &&\r\n reportFilters.product.id === ReportFilterConstants.PRODUCTOPTION_ALL_PRODUCTS\r\n ? null\r\n : reportFilters.product,\r\n 'duration',\r\n );\r\n }\r\n\r\n case ReportFilterConstants.FILTERINCREMENT_WEEK: {\r\n return UsageApi.getUsageByWeek(\r\n applyPartialDateRangeRules(reportFilters.fromDate, reportFilters.calendarType, true),\r\n applyPartialDateRangeRules(reportFilters.toDate, reportFilters.calendarType, false),\r\n reportFilters.client,\r\n reportFilters.product &&\r\n reportFilters.product.id === ReportFilterConstants.PRODUCTOPTION_ALL_PRODUCTS\r\n ? null\r\n : reportFilters.product,\r\n 'duration',\r\n );\r\n }\r\n\r\n case ReportFilterConstants.FILTERINCREMENT_MONTH: {\r\n return UsageApi.getUsageByMonth(\r\n applyPartialDateRangeRules(reportFilters.fromDate, reportFilters.calendarType, true),\r\n applyPartialDateRangeRules(reportFilters.toDate, reportFilters.calendarType, false),\r\n reportFilters.client,\r\n reportFilters.product &&\r\n reportFilters.product.id === ReportFilterConstants.PRODUCTOPTION_ALL_PRODUCTS\r\n ? null\r\n : reportFilters.product,\r\n 'duration',\r\n );\r\n }\r\n\r\n default: {\r\n // NOTE: This is based on a fixed dropdown, so this case should never be hit. Returning\r\n // an empty promise to satisfy the return type, but the redirect will run prior.\r\n history.push(ApplicationRoutes.ERROR_ERROR);\r\n return new Promise((): void => {});\r\n }\r\n }\r\n });\r\n }, [setReportDataSource, durationReportFilters, reportFilters, history]);\r\n\r\n const updateReportFilterValues = useCallback(\r\n (durationReportFilters: ReportFiltersWithIncrement): void => {\r\n setSpecificReportFilters(ReportNames.Duration, durationReportFilters);\r\n setCalendarType(durationReportFilters.increment);\r\n updateReportDataSource();\r\n },\r\n [setSpecificReportFilters, setCalendarType, updateReportDataSource],\r\n );\r\n\r\n // Set the data source values for this component when the generic report filters provided to this component change\r\n useEffect(() => {\r\n updateReportDataSource();\r\n }, [reportFilters, updateReportDataSource]);\r\n\r\n // If the duration report filters are not initialized, initialize them\r\n useEffect(() => {\r\n if (!durationReportFilters) {\r\n updateReportFilterValues({\r\n increment: ReportFilterConstants.FILTERINCREMENT_DAY,\r\n });\r\n }\r\n }, [updateReportFilterValues, durationReportFilters]);\r\n\r\n return (\r\n
\r\n
\r\n \r\n {\r\n updateReportFilterValues({\r\n ...durationReportFilters,\r\n increment: event.target.value,\r\n });\r\n }}\r\n value={(durationReportFilters && durationReportFilters.increment) || ''}\r\n />\r\n
\r\n
\r\n );\r\n};\r\n\r\nexport default LicenseDurationFilter;\r\n","import React, { useEffect, useCallback } from 'react';\nimport { DropDownList } from '@progress/kendo-react-dropdowns';\nimport { ReportNames } from '../../reports';\nimport { useHistory } from 'react-router';\nimport { UsageApi } from '../../../../../services/api';\nimport ApplicationRoutes from '../../../../../constants/routes';\nimport { useTranslation } from 'react-i18next';\nimport { applyPartialDateRangeRules } from '../../../../../utils/calendars';\nimport ReportFilterConstants from './../../../../../constants/reports/filters';\n\ninterface Props {\n checkoutsReportFilters: ReportFiltersWithIncrement;\n}\n\nconst LicenseCheckoutsFilter: React.FC = ({\n reportFilters,\n checkoutsReportFilters,\n setSpecificReportFilters,\n setReportDataSource,\n setCalendarType,\n}) => {\n const { t } = useTranslation();\n const history = useHistory();\n\n const updateReportDataSource = useCallback((): void => {\n setReportDataSource(ReportNames.Checkouts, () => {\n switch (checkoutsReportFilters.increment) {\n case ReportFilterConstants.FILTERINCREMENT_DAY: {\n return UsageApi.getUsageByDay(\n reportFilters.fromDate,\n reportFilters.toDate,\n reportFilters.client,\n reportFilters.product &&\n reportFilters.product.id === ReportFilterConstants.PRODUCTOPTION_ALL_PRODUCTS\n ? null\n : reportFilters.product,\n 'total',\n );\n }\n\n case ReportFilterConstants.FILTERINCREMENT_WEEK: {\n return UsageApi.getUsageByWeek(\n applyPartialDateRangeRules(reportFilters.fromDate, reportFilters.calendarType, true),\n applyPartialDateRangeRules(reportFilters.toDate, reportFilters.calendarType, false),\n reportFilters.client,\n reportFilters.product &&\n reportFilters.product.id === ReportFilterConstants.PRODUCTOPTION_ALL_PRODUCTS\n ? null\n : reportFilters.product,\n 'total',\n );\n }\n\n case ReportFilterConstants.FILTERINCREMENT_MONTH: {\n return UsageApi.getUsageByMonth(\n applyPartialDateRangeRules(reportFilters.fromDate, reportFilters.calendarType, true),\n applyPartialDateRangeRules(reportFilters.toDate, reportFilters.calendarType, false),\n reportFilters.client,\n reportFilters.product &&\n reportFilters.product.id === ReportFilterConstants.PRODUCTOPTION_ALL_PRODUCTS\n ? null\n : reportFilters.product,\n 'total',\n );\n }\n\n default: {\n // NOTE: This is based on a fixed dropdown, so this case should never be hit. Returning\n // an empty promise to satisfy the return type, but the redirect will run prior.\n history.push(ApplicationRoutes.ERROR_ERROR);\n return new Promise((): void => {});\n }\n }\n });\n }, [setReportDataSource, checkoutsReportFilters, reportFilters, history]);\n\n const updateReportFilterValues = useCallback(\n (checkoutsReportFilters: ReportFiltersWithIncrement): void => {\n setSpecificReportFilters(ReportNames.Checkouts, checkoutsReportFilters);\n setCalendarType(checkoutsReportFilters.increment);\n updateReportDataSource();\n },\n [setSpecificReportFilters, setCalendarType, updateReportDataSource],\n );\n\n // Set the data source values for this component when the generic report filters provided to this component change\n useEffect(() => {\n updateReportDataSource();\n }, [reportFilters, updateReportDataSource]);\n\n // If the checkouts report filters are not initialized, initialize them\n useEffect(() => {\n if (!checkoutsReportFilters) {\n updateReportFilterValues({\n increment: ReportFilterConstants.FILTERINCREMENT_DAY,\n });\n }\n }, [updateReportFilterValues, checkoutsReportFilters]);\n\n return (\n
\n
\n \n {\n updateReportFilterValues({\n ...checkoutsReportFilters,\n increment: event.target.value,\n });\n }}\n value={(checkoutsReportFilters && checkoutsReportFilters.increment) || ''}\n />\n
\n
\n );\n};\n\nexport default LicenseCheckoutsFilter;\n","import React, { useEffect, useCallback } from 'react';\r\nimport { ReportNames } from '../../reports';\r\nimport { UsageApi } from '../../../../../services/api';\r\nimport ReportFilterConstants from '../../../../../constants/reports/filters';\r\n\r\ninterface Props {\r\n rawDataReportFilters: ReportFiltersWithIncrement;\r\n}\r\n\r\nconst RawDataFilter: React.FC = ({\r\n reportFilters,\r\n setReportDataSource,\r\n}) => {\r\n const updateReportDataSource = useCallback((): void => {\r\n setReportDataSource(ReportNames.RawData, () => {\r\n return UsageApi.getRawUsage(\r\n reportFilters.fromDate,\r\n reportFilters.toDate,\r\n reportFilters.client,\r\n reportFilters.product &&\r\n reportFilters.product.id === ReportFilterConstants.PRODUCTOPTION_ALL_PRODUCTS\r\n ? null\r\n : reportFilters.product,\r\n );\r\n });\r\n }, [setReportDataSource, reportFilters]);\r\n\r\n // Set the data source values for this component when the generic report filters provided to this component change\r\n useEffect(() => {\r\n updateReportDataSource();\r\n }, [reportFilters, updateReportDataSource]);\r\n\r\n return <>;\r\n};\r\n\r\nexport default RawDataFilter;\r\n","import React from 'react';\r\nimport { Route, Switch } from 'react-router';\r\nimport ApplicationRoutes from '../../../../constants/routes';\r\nimport LicenseUsageFilter from '../charts/LicenseUsage/LicenseUsageFilter';\r\nimport LicenseDurationFilter from '../charts/LicenseDuration/LicenseDurationFilter';\r\nimport LicenseCheckoutsFilter from '../charts/LicenseCheckouts/LicenseCheckoutsFilter';\r\nimport { ReportNames } from '../reports';\r\nimport RawDataFilter from '../charts/RawData/RawDataFilter';\r\n\r\ninterface Props {\r\n allSpecificReportFilters: Dictionary;\r\n}\r\n\r\nconst ReportsPageCustomFilters: React.FC = props => {\r\n return (\r\n \r\n (\r\n \r\n )}\r\n />\r\n (\r\n \r\n )}\r\n />\r\n (\r\n \r\n )}\r\n />\r\n (\r\n \r\n )}\r\n />\r\n \r\n );\r\n};\r\n\r\nexport default ReportsPageCustomFilters;\r\n","import { DatePicker } from '@progress/kendo-react-dateinputs';\r\nimport { DropDownList } from '@progress/kendo-react-dropdowns';\r\nimport moment from 'moment';\r\nimport React, { useContext } from 'react';\r\nimport { FormDropDownListOption } from '../../../common-page-components/forms/FormDropDownList';\r\nimport { NotificationPanelContext } from '../../../common-page-components/notification-panel/NotificationPanelContext';\r\nimport { UserInformationContext } from '../../../UserInformationContext';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { applyPartialDateRangeRules } from '../../../../utils/calendars';\r\nimport ReportFilterConstants from './../../../../constants/reports/filters';\r\nimport { sortBy } from 'lodash';\r\n\r\ninterface Props {\r\n availableClients: ClientOrganization[];\r\n availableProducts: Product[];\r\n reportFilters: ReportFiltersBase;\r\n getProductsForClient: (clientId: string) => void;\r\n setReportFilters: (reportFilters: ReportFiltersBase) => void;\r\n}\r\n\r\nconst ReportsPageFilters: React.FC = ({\r\n availableClients,\r\n availableProducts,\r\n reportFilters,\r\n getProductsForClient,\r\n setReportFilters,\r\n}) => {\r\n const { t } = useTranslation();\r\n const { userInformation } = useContext(UserInformationContext);\r\n\r\n const { showInfoNotification } = useContext(NotificationPanelContext);\r\n\r\n const resetAllDatePickers = (): void => {\r\n setReportFilters({\r\n ...reportFilters,\r\n toDate: applyPartialDateRangeRules(\r\n reportFilters.defaultToDate,\r\n reportFilters.calendarType,\r\n false,\r\n ),\r\n fromDate: applyPartialDateRangeRules(\r\n reportFilters.defaultFromDate,\r\n reportFilters.calendarType,\r\n true,\r\n ),\r\n });\r\n };\r\n\r\n const resetToDatePicker = (): void => {\r\n setReportFilters({\r\n ...reportFilters,\r\n toDate: applyPartialDateRangeRules(\r\n reportFilters.defaultToDate,\r\n reportFilters.calendarType,\r\n false,\r\n ),\r\n });\r\n };\r\n\r\n const resetFromDatePicker = (): void => {\r\n setReportFilters({\r\n ...reportFilters,\r\n fromDate: applyPartialDateRangeRules(\r\n reportFilters.defaultFromDate,\r\n reportFilters.calendarType,\r\n true,\r\n ),\r\n });\r\n };\r\n\r\n const getClientsForDropdown = (items: ClientOrganization[]): FormDropDownListOption[] => {\r\n return sortBy(\r\n items.map(v => {\r\n return {\r\n name: v.name,\r\n value: v.id,\r\n };\r\n }),\r\n v => v.name,\r\n );\r\n };\r\n\r\n const getProductsForDropdown = (items: Product[]): FormDropDownListOption[] => {\r\n return sortBy(\r\n items.map(v => {\r\n return {\r\n name: v.name,\r\n value: v.id,\r\n };\r\n }),\r\n v => v.name,\r\n );\r\n };\r\n\r\n return (\r\n
\r\n {userInformation && (userInformation.userIsAdmin || userInformation.userIsInternalUser) && (\r\n
\r\n \r\n\r\n {\r\n const id = (event.target.value as FormDropDownListOption).value;\r\n //Avoid triggering a reload of product data if the user reselects the same value\r\n if (\r\n !reportFilters.client ||\r\n (reportFilters.client && id !== reportFilters.client.id)\r\n ) {\r\n setReportFilters({\r\n ...reportFilters,\r\n client: availableClients.find(v => v.id === id)!,\r\n });\r\n getProductsForClient(id);\r\n }\r\n }}\r\n value={\r\n availableClients.find(\r\n currClient => reportFilters.client && reportFilters.client.name === currClient.name,\r\n ) ||\r\n availableClients[0] ||\r\n null\r\n }\r\n />\r\n
\r\n )}\r\n
\r\n \r\n\r\n {\r\n setReportFilters({\r\n ...reportFilters,\r\n product: availableProducts.find(\r\n v => v.id === (event.target.value as FormDropDownListOption).value,\r\n )!,\r\n });\r\n }}\r\n value={\r\n availableProducts.find(\r\n currProduct =>\r\n reportFilters.product && reportFilters.product.name === currProduct.name,\r\n ) ||\r\n availableProducts[0] ||\r\n null\r\n }\r\n />\r\n
\r\n {/*\r\n * The DatePickers below are using the onChange and onBlur hooks to modify and validate their values.\r\n * Keying the date manually will trigger onChange events until the user clicks away, which triggers an onBlur,\r\n * while selecting a date from the calendar control will trigger both an onChange, then an onBlur.\r\n * ----------------------------------------------------------------------------------------------------\r\n * onChange is handling modification of the data before setting it on the reportFilters state object.\r\n * We won't be validating here since manually keyed dates can fail validation prior to being completely typed\r\n * ----------------------------------------------------------------------------------------------------\r\n * onBlur is ensuring the provided value is a fully keyed date and that it conforms to typical date range rules\r\n */}\r\n
\r\n
\r\n \r\n {\r\n const momentObj = moment(reportFilters.fromDate).startOf('day');\r\n if (momentObj.isValid() && momentObj.year().toString().length === 4) {\r\n if (momentObj.toDate() > reportFilters.toDate) {\r\n if (reportFilters.toDate >= reportFilters.defaultFromDate) {\r\n resetFromDatePicker();\r\n } else {\r\n resetAllDatePickers();\r\n }\r\n showInfoNotification(\r\n 'Invalid From Date',\r\n 'The from date must come before the to date.',\r\n );\r\n } else {\r\n if (\r\n [\r\n ReportFilterConstants.FILTERINCREMENT_WEEK,\r\n ReportFilterConstants.FILTERINCREMENT_MONTH,\r\n ].includes(reportFilters.calendarType)\r\n ) {\r\n const fromDate = applyPartialDateRangeRules(\r\n momentObj.toDate(),\r\n reportFilters.calendarType,\r\n true,\r\n );\r\n // Due to a conflict between react re-renders and how the onBlur is firing,\r\n // a timeout is necessary to allow the calendar to toggle correctly while\r\n // also applying the partialDateRange logic\r\n setTimeout(() => {\r\n setReportFilters({\r\n ...reportFilters,\r\n fromDate: fromDate,\r\n });\r\n });\r\n }\r\n }\r\n } else {\r\n resetFromDatePicker();\r\n }\r\n }}\r\n onChange={(event): void => {\r\n const newValue = event.target.value!;\r\n if (newValue) {\r\n setReportFilters({\r\n ...reportFilters,\r\n fromDate: applyPartialDateRangeRules(newValue, reportFilters.calendarType, true),\r\n });\r\n }\r\n }}\r\n value={applyPartialDateRangeRules(\r\n reportFilters.fromDate,\r\n reportFilters.calendarType,\r\n true,\r\n )}\r\n />\r\n
\r\n
\r\n \r\n {\r\n const momentObj = moment(reportFilters.toDate).startOf('day');\r\n if (momentObj.isValid() && momentObj.year().toString().length === 4) {\r\n if (momentObj.toDate() < reportFilters.fromDate) {\r\n if (reportFilters.fromDate <= reportFilters.defaultToDate) {\r\n resetToDatePicker();\r\n } else {\r\n resetAllDatePickers();\r\n }\r\n showInfoNotification(\r\n 'Invalid To Date',\r\n 'The to date must come after the from date.',\r\n );\r\n } else {\r\n if (\r\n [\r\n ReportFilterConstants.FILTERINCREMENT_WEEK,\r\n ReportFilterConstants.FILTERINCREMENT_MONTH,\r\n ].includes(reportFilters.calendarType)\r\n ) {\r\n const toDate = applyPartialDateRangeRules(\r\n momentObj.toDate(),\r\n reportFilters.calendarType,\r\n false,\r\n );\r\n // Due to a conflict between react re-renders and how the onBlur is firing,\r\n // a timeout is necessary to allow the calendar to toggle correctly while\r\n // also applying the partialDateRange logic\r\n setTimeout(() => {\r\n setReportFilters({\r\n ...reportFilters,\r\n toDate: toDate,\r\n });\r\n });\r\n }\r\n }\r\n } else {\r\n resetToDatePicker();\r\n }\r\n }}\r\n onChange={(event): void => {\r\n const newValue = event.target.value!;\r\n if (newValue) {\r\n setReportFilters({\r\n ...reportFilters,\r\n toDate: applyPartialDateRangeRules(newValue, reportFilters.calendarType, false),\r\n });\r\n }\r\n }}\r\n value={applyPartialDateRangeRules(\r\n reportFilters.toDate,\r\n reportFilters.calendarType,\r\n false,\r\n )}\r\n />\r\n
\r\n
\r\n
\r\n );\r\n};\r\n\r\nexport default ReportsPageFilters;\r\n","import React from 'react';\nimport { useHistory } from 'react-router';\nimport BTButton from '../../../common-page-components/controls/button/BTButton';\nimport { useTranslation } from 'react-i18next';\n\ninterface Props {\n availableReports: Report[];\n reportFilters: ReportFiltersBase;\n setReportFilters: (reportFiltersBase: ReportFiltersBase) => void; // NOTE: We have this function so this component doesn't explicitly update the parent component's state\n onClick?: () => void;\n}\n\nconst ReportsPageReportsListing: React.FC = ({\n availableReports,\n reportFilters,\n setReportFilters,\n onClick,\n}) => {\n const { t } = useTranslation();\n const history = useHistory();\n\n return (\n
\n

{t('reporting:availableReports')}

\n\n
\n {availableReports.map(currReport => (\n {\n if (onClick) {\n onClick();\n }\n\n // NOTE: Since we match multiple routes to get to this page, this page component will not reinitialize and will retain its state if the URL changes to one that it matches\n history.push(currReport.url);\n\n setReportFilters({\n ...reportFilters,\n reportName: currReport.name,\n });\n }}\n >\n {\n // NOTE: Since we match multiple routes to get to this page, this page component will not reinitialize and will retain its state if the URL changes to one that it matches\n history.push(currReport.url);\n\n setReportFilters({\n ...reportFilters,\n reportName: currReport.name,\n });\n }}\n roundedCorners={true}\n align=\"left\"\n />\n
\n ))}\n
\n \n );\n};\n\nexport default ReportsPageReportsListing;\n","import 'hammerjs'; //For KendoCharts event handling\r\nimport moment from 'moment';\r\nimport React, { useCallback, useContext, useEffect, useRef, useState } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { useHistory, useLocation } from 'react-router';\r\nimport ApplicationRoutes from '../../../constants/routes';\r\nimport UserConstants from '../../../constants/users';\r\nimport { ProductApi } from '../../../services/api';\r\nimport { saveFile } from '../../../utils/file';\r\nimport { isDevelopmentEnvironment, scrollToRef } from '../../../utils/general';\r\nimport { populateUserInformationFromLocalStorage } from '../../../utils/user-authorization';\r\nimport BTButton from '../../common-page-components/controls/button/BTButton';\r\nimport { LoadingPageOverlayContext } from '../../common-page-components/loading-page-overlay/LoadingPageOverlayContext';\r\nimport { NotificationPanelContext } from '../../common-page-components/notification-panel/NotificationPanelContext';\r\nimport ReportFilterConstants from './../../../constants/reports/filters';\r\nimport ClientApi from './../../../services/api/clients/clients-api-service';\r\nimport { UserInformationContext } from './../../UserInformationContext';\r\nimport ReportsPageCustomChart from './components/ReportsPageCustomChart';\r\nimport ReportsPageCustomFilters from './components/ReportsPageCustomFilters';\r\nimport ReportsPageFilters from './components/ReportsPageFilters';\r\nimport ReportsPageReportsListing from './components/ReportsPageReportsListing';\r\nimport { ReportNames } from './reports';\r\nimport './ReportsPage.scss';\r\n\r\nconst LOCAL_STORAGE_REPORT_FILTERS = 'ModifiedBaseReportFilters';\r\n\r\nconst ReportNameRouteMappings = {\r\n [ApplicationRoutes.REPORTS_USAGE.toLowerCase()]: ReportNames.Usage,\r\n [ApplicationRoutes.REPORTS_DURATION.toLowerCase()]: ReportNames.Duration,\r\n [ApplicationRoutes.REPORTS_CHECKOUTS.toLowerCase()]: ReportNames.Checkouts,\r\n [ApplicationRoutes.REPORTS_RAWDATA.toLowerCase()]: ReportNames.RawData,\r\n};\r\n\r\nconst generateReportFiltersObject = (\r\n clients: ClientOrganization[],\r\n products: Product[],\r\n): ReportFiltersBase => {\r\n // Attempt to return existing filter settings from local storage.\r\n const localStorageReportFilters = localStorage.getItem(LOCAL_STORAGE_REPORT_FILTERS);\r\n if (localStorageReportFilters) {\r\n try {\r\n const localStorageReportFiltersBase: ReportFiltersBase = JSON.parse(\r\n localStorageReportFilters,\r\n );\r\n\r\n const cachedClientId =\r\n localStorageReportFiltersBase.client === null\r\n ? null\r\n : localStorageReportFiltersBase.client.id;\r\n\r\n const cachedProductId =\r\n localStorageReportFiltersBase.product === null\r\n ? null\r\n : localStorageReportFiltersBase.product.id;\r\n\r\n const filters: ReportFiltersBase = {\r\n client: !cachedClientId ? null : clients.find(c => c.id === cachedClientId) || null,\r\n product: !cachedProductId ? null : products.find(p => p.id === cachedProductId) || null,\r\n defaultFromDate: new Date(localStorageReportFiltersBase.defaultFromDate),\r\n defaultToDate: new Date(localStorageReportFiltersBase.defaultToDate),\r\n fromDate: new Date(localStorageReportFiltersBase.fromDate),\r\n toDate: new Date(localStorageReportFiltersBase.toDate),\r\n reportName: localStorageReportFiltersBase.reportName,\r\n calendarType: localStorageReportFiltersBase.calendarType,\r\n };\r\n\r\n return filters;\r\n } catch {\r\n // We intentionally leave this catch empty and allow the code to continue\r\n }\r\n }\r\n\r\n const defaultFromDate = moment()\r\n .add(-7, 'days')\r\n .startOf('day')\r\n .toDate();\r\n\r\n const defaultToDate = moment()\r\n .startOf('day')\r\n .toDate();\r\n\r\n const defaultFilters = {\r\n client: clients[0] || null,\r\n product: products[0] || null,\r\n defaultFromDate: defaultFromDate,\r\n defaultToDate: defaultToDate,\r\n fromDate: defaultFromDate,\r\n toDate: defaultToDate,\r\n reportName: ReportNames.Usage,\r\n calendarType: ReportFilterConstants.FILTERINCREMENT_DAY,\r\n };\r\n\r\n return defaultFilters;\r\n};\r\n\r\nconst saveReportFiltersToLocalStorage = (newReportFilters: ReportFiltersBase): void => {\r\n localStorage.setItem(LOCAL_STORAGE_REPORT_FILTERS, JSON.stringify(newReportFilters));\r\n};\r\n\r\nconst removeReportFiltersFromLocalStorage = (): void => {\r\n localStorage.removeItem(LOCAL_STORAGE_REPORT_FILTERS);\r\n};\r\n\r\nconst ReportsPage: React.FC<{}> = () => {\r\n const { t } = useTranslation();\r\n const location = useLocation();\r\n const history = useHistory();\r\n const customChartRef = useRef(null);\r\n const [isPageDataLoaded, setIsPageDataLoaded] = useState(false);\r\n\r\n const availableReports: Report[] = [\r\n {\r\n icon: 'wrench',\r\n name: t('reporting:reportNames.usage'),\r\n url: ApplicationRoutes.REPORTS_USAGE,\r\n },\r\n {\r\n icon: 'shopping-basket',\r\n name: t('reporting:reportNames.checkouts'),\r\n url: ApplicationRoutes.REPORTS_CHECKOUTS,\r\n },\r\n {\r\n icon: 'clock',\r\n name: t('reporting:reportNames.duration'),\r\n url: ApplicationRoutes.REPORTS_DURATION,\r\n },\r\n {\r\n icon: 'database',\r\n name: t('reporting:reportNames.rawData'),\r\n url: ApplicationRoutes.REPORTS_RAWDATA,\r\n },\r\n ];\r\n\r\n const { showPageLoadingOverlay, hidePageLoadingOverlay } = useContext(LoadingPageOverlayContext);\r\n\r\n const { userInformation } = useContext(UserInformationContext);\r\n\r\n const { showErrorNotification, showInfoNotification } = useContext(NotificationPanelContext);\r\n\r\n const [currentChartData, setCurrentChartData] = useState(null);\r\n\r\n const [availableClients, setAvailableClients] = useState([]);\r\n\r\n const [availableProducts, setAvailableProducts] = useState([]);\r\n\r\n const [clientProductsCache, setClientProductsCache] = useState>({});\r\n\r\n const [reportFilters, setReportFilters] = useState();\r\n\r\n // Use state for all of the reports filters so the user can jump between reports while retaining previously selected filter values\r\n const [allSpecificReportFilters, setAllSpecificReportFilters] = useState<\r\n Dictionary\r\n >({});\r\n\r\n // Maintain a list of reports chart data\r\n const [allReportsData, setAllReportsData] = useState>({});\r\n\r\n // Maintain a list of report data sources\r\n const [allReportDataSources, setAllReportDataSources] = useState<\r\n Dictionary<() => Promise>\r\n >({});\r\n\r\n const [isLoadingData, setIsLoadingData] = useState(false);\r\n const [chartDataErrorOccurred, setChartDataErrorOccurred] = useState(false);\r\n\r\n const addAllProductsOption = useCallback(\r\n (clientProducts: Product[]): Product[] => {\r\n clientProducts.unshift({\r\n id: ReportFilterConstants.PRODUCTOPTION_ALL_PRODUCTS,\r\n name: t('reporting:filters.productOptionAllProducts'),\r\n isNew: false,\r\n hasActiveLicenses: true,\r\n features: [],\r\n deploymentTypeId: '',\r\n });\r\n return clientProducts;\r\n },\r\n [t],\r\n );\r\n\r\n const addNoProductsOption = useCallback(\r\n (clientProducts: Product[]): Product[] => {\r\n clientProducts.unshift({\r\n id: ReportFilterConstants.PRODUCTOPTION_NO_PRODUCTS,\r\n name: t('reporting:filters.productOptionNoProducts'),\r\n isNew: false,\r\n hasActiveLicenses: false,\r\n features: [],\r\n deploymentTypeId: '',\r\n });\r\n return clientProducts;\r\n },\r\n [t],\r\n );\r\n\r\n const checkAndUpdateProductOptions = useCallback(\r\n (clientProducts: Product[]): Product[] => {\r\n if (clientProducts.length < 1) {\r\n return addNoProductsOption(clientProducts);\r\n } else if (clientProducts.length > 1) {\r\n return addAllProductsOption(clientProducts);\r\n }\r\n return clientProducts;\r\n },\r\n [addAllProductsOption, addNoProductsOption],\r\n );\r\n\r\n const updateClientProductsCache = useCallback(\r\n (clientId: string, clientProducts: Product[]): void => {\r\n setClientProductsCache({\r\n ...clientProductsCache,\r\n [clientId]: clientProducts,\r\n });\r\n },\r\n [clientProductsCache, setClientProductsCache],\r\n );\r\n\r\n useEffect(() => {\r\n const loadPageData = async (): Promise => {\r\n showPageLoadingOverlay();\r\n\r\n const reportName =\r\n ReportNameRouteMappings[location.pathname.toLowerCase()] ||\r\n ReportNameRouteMappings[ApplicationRoutes.REPORTS_USAGE];\r\n\r\n if (userInformation && (userInformation.userIsAdmin || userInformation.userIsInternalUser)) {\r\n try {\r\n const [clients, allProducts] = await Promise.all([\r\n await ClientApi.getClientOrganizations(),\r\n await ProductApi.getProducts(),\r\n ]);\r\n\r\n if (!clients.length) {\r\n throw new Error();\r\n }\r\n setAvailableClients(clients);\r\n\r\n const reportFilters = generateReportFiltersObject(clients, allProducts);\r\n\r\n const client = reportFilters.client || clients[0];\r\n let clientProducts = await ProductApi.getProductsByClient(client);\r\n clientProducts = checkAndUpdateProductOptions(clientProducts);\r\n setAvailableProducts(clientProducts);\r\n\r\n const updatedReportFilters = {\r\n ...reportFilters,\r\n client: reportFilters.client || clients[0] || null,\r\n product: reportFilters.product || clientProducts[0] || null,\r\n reportName: reportName,\r\n };\r\n\r\n setReportFilters(updatedReportFilters);\r\n\r\n // If the calendar type was populated, set it as the increment for the specific report filter\r\n if (updatedReportFilters.calendarType) {\r\n setAllSpecificReportFilters(v => ({\r\n ...v,\r\n [updatedReportFilters.reportName]: {\r\n increment: updatedReportFilters.calendarType,\r\n },\r\n }));\r\n }\r\n\r\n setIsPageDataLoaded(true);\r\n } catch (error) {\r\n showErrorNotification('Error', 'An error occurred while loading the page.');\r\n history.push(ApplicationRoutes.ERROR_ERROR);\r\n } finally {\r\n hidePageLoadingOverlay();\r\n }\r\n } else {\r\n try {\r\n const user = populateUserInformationFromLocalStorage();\r\n if (user) {\r\n const client = await ClientApi.getClientOrganizationByEmail(user.emailAddress);\r\n let clientProducts = await ProductApi.getProductsByClient(client);\r\n clientProducts = checkAndUpdateProductOptions(clientProducts);\r\n setAvailableProducts(clientProducts);\r\n\r\n const reportFilters = generateReportFiltersObject([client], clientProducts);\r\n\r\n const updatedReportFilters = {\r\n ...reportFilters,\r\n client: client || null,\r\n reportName: reportName,\r\n };\r\n\r\n setReportFilters(updatedReportFilters);\r\n\r\n // If the calendar type was populated, set it as the increment for the specific report filter\r\n if (updatedReportFilters.calendarType) {\r\n setAllSpecificReportFilters(v => {\r\n return {\r\n ...v,\r\n [updatedReportFilters.reportName]: {\r\n increment: updatedReportFilters.calendarType,\r\n },\r\n };\r\n });\r\n }\r\n\r\n setIsPageDataLoaded(true);\r\n } else {\r\n throw new Error('Unable to pull user information from local storage.');\r\n }\r\n } catch (error) {\r\n showErrorNotification('Error', 'An error occurred while loading the page.');\r\n history.push(ApplicationRoutes.ERROR_ERROR);\r\n } finally {\r\n hidePageLoadingOverlay();\r\n }\r\n }\r\n };\r\n\r\n loadPageData();\r\n }, [\r\n history,\r\n userInformation,\r\n addAllProductsOption,\r\n addNoProductsOption,\r\n checkAndUpdateProductOptions,\r\n hidePageLoadingOverlay,\r\n showErrorNotification,\r\n showInfoNotification,\r\n showPageLoadingOverlay,\r\n location.pathname,\r\n ]);\r\n\r\n const getChartData = async (): Promise => {\r\n if (!reportFilters) {\r\n return;\r\n }\r\n\r\n setIsLoadingData(true);\r\n\r\n showPageLoadingOverlay();\r\n\r\n try {\r\n const currReportDataSource = allReportDataSources[reportFilters.reportName];\r\n\r\n if (currReportDataSource) {\r\n const reportsData = await currReportDataSource();\r\n\r\n // For the raw data, the promise we await will actually return binary data, not JSON,\r\n // so we don't want to put this in the state variable that holds our chart data\r\n if (reportFilters.reportName === ReportNames.RawData) {\r\n saveFile(reportsData, 'Export', 'csv');\r\n return;\r\n }\r\n\r\n setAllReportsData({\r\n ...allReportsData,\r\n [reportFilters.reportName]: reportsData,\r\n });\r\n\r\n const chartData: BTChartDataWithFilters = {\r\n ...reportsData,\r\n appliedFilters: {\r\n baseFilters: reportFilters,\r\n specificFilters: allSpecificReportFilters[reportFilters.reportName],\r\n },\r\n };\r\n\r\n setCurrentChartData(chartData);\r\n }\r\n } catch (error) {\r\n setChartDataErrorOccurred(true);\r\n } finally {\r\n setIsLoadingData(false);\r\n hidePageLoadingOverlay();\r\n }\r\n };\r\n\r\n const getProductsForClient = (clientId: string): void => {\r\n if (!reportFilters) {\r\n return;\r\n }\r\n\r\n const loadProductData = async (): Promise => {\r\n try {\r\n const getProduct = (products: Product[], filters: ReportFiltersBase): Product | null => {\r\n if (!filters || !filters.product || products.length === 0) {\r\n return null;\r\n }\r\n const product = products.find(p => p.id === filters!.product!.id);\r\n return product || products[0];\r\n };\r\n\r\n const client = availableClients.find(c => c.id === clientId);\r\n if (client) {\r\n //Attempt to use cached products first and avoid a round trip\r\n const cachedProducts: Product[] = clientProductsCache[client.id];\r\n if (cachedProducts) {\r\n setAvailableProducts(cachedProducts);\r\n setReportFilters(filters => {\r\n if (!filters) {\r\n return filters;\r\n }\r\n\r\n return {\r\n ...filters,\r\n product: getProduct(cachedProducts, filters),\r\n };\r\n });\r\n } else {\r\n //Else fetch products for the client and cache the results\r\n showPageLoadingOverlay();\r\n let clientProducts = await ProductApi.getProductsByClient(client);\r\n clientProducts = checkAndUpdateProductOptions(clientProducts);\r\n setAvailableProducts(clientProducts);\r\n updateClientProductsCache(client.id, clientProducts);\r\n setReportFilters(filters => {\r\n if (!filters) {\r\n return filters;\r\n }\r\n\r\n return {\r\n ...filters,\r\n product: getProduct(clientProducts, filters),\r\n };\r\n });\r\n }\r\n }\r\n } catch (error) {\r\n showErrorNotification('Error', 'An error occurred while loading products.');\r\n history.push(ApplicationRoutes.ERROR_ERROR);\r\n } finally {\r\n hidePageLoadingOverlay();\r\n }\r\n };\r\n if (reportFilters.client) {\r\n loadProductData();\r\n }\r\n };\r\n\r\n const setSpecificReportFilters = useCallback(\r\n (reportName: string, specificReportFilters: SpecificReportFiltersBase): void => {\r\n if (!reportFilters) {\r\n return;\r\n }\r\n\r\n // Update our internal state collection for the rendered report\r\n setAllSpecificReportFilters(reportFilters => ({\r\n ...reportFilters,\r\n [reportName]: specificReportFilters,\r\n }));\r\n\r\n const newReportFilters = {\r\n ...reportFilters,\r\n calendarType: (specificReportFilters as ReportFiltersWithIncrement).increment,\r\n };\r\n setReportFilters(newReportFilters);\r\n\r\n saveReportFiltersToLocalStorage(newReportFilters);\r\n },\r\n [reportFilters, setAllSpecificReportFilters, setReportFilters],\r\n );\r\n\r\n const setCalendarType = useCallback(\r\n (calendarType: string): void => {\r\n setReportFilters(reportFilters => {\r\n if (!reportFilters) {\r\n return reportFilters;\r\n }\r\n\r\n return {\r\n ...reportFilters,\r\n calendarType: calendarType,\r\n };\r\n });\r\n },\r\n [setReportFilters],\r\n );\r\n\r\n const setSpecificReportDataSource = useCallback(\r\n (reportName: string, reportDataSource: () => Promise<{}>): void => {\r\n // Update our internal state collection for the rendered report\r\n setAllReportDataSources(dataSources => ({\r\n ...dataSources,\r\n [reportName]: reportDataSource,\r\n }));\r\n },\r\n [setAllReportDataSources],\r\n );\r\n\r\n if (!isPageDataLoaded || !reportFilters) {\r\n return <>;\r\n }\r\n\r\n return (\r\n
\r\n
\r\n

{t('reporting:reports')}

\r\n\r\n {\r\n setReportFilters(reportFiltersBase);\r\n }}\r\n onClick={(): void => setCurrentChartData(null)}\r\n />\r\n\r\n
\r\n

{t('reporting:filters.filters')}

\r\n\r\n {\r\n setReportFilters({\r\n ...reportFilters,\r\n ...newReportFilters,\r\n // Only let the client be updated if the user has correct permissions, as an extra layer of security\r\n client:\r\n userInformation &&\r\n userInformation.userRoles.find(\r\n v =>\r\n v.id === UserConstants.UserRolesValues.ADMIN ||\r\n v.id === UserConstants.UserRolesValues.INTERNALUSER,\r\n )\r\n ? newReportFilters.client\r\n : reportFilters.client,\r\n product: newReportFilters.product,\r\n });\r\n saveReportFiltersToLocalStorage(newReportFilters);\r\n }}\r\n />\r\n\r\n \r\n
\r\n\r\n
\r\n {/* Only show the 'apply' button if the current report provided a data source. If not, it can handle things itself. */}\r\n {allReportDataSources[reportFilters.reportName] && (\r\n {\r\n setChartDataErrorOccurred(false);\r\n if (reportFilters.reportName === ReportNames.RawData) {\r\n showInfoNotification('Downloading', 'Your download will begin shortly...');\r\n //Adding a slight delay to allow the user time to process the notification before actually serving the data\r\n setTimeout(() => {\r\n getChartData();\r\n }, 1500);\r\n } else {\r\n const getChartDataAsync = async (): Promise => {\r\n await getChartData();\r\n setTimeout(() => {\r\n scrollToRef(customChartRef);\r\n }, 500);\r\n };\r\n getChartDataAsync();\r\n }\r\n }}\r\n />\r\n )}\r\n\r\n {\r\n removeReportFiltersFromLocalStorage();\r\n setReportFilters({\r\n ...generateReportFiltersObject(availableClients, availableProducts),\r\n reportName: reportFilters.reportName, // Keep the report name the same\r\n });\r\n\r\n // Remove the specific report filters object from state -- the active filter component should regenerate its state\r\n setAllSpecificReportFilters({\r\n ...allSpecificReportFilters,\r\n [reportFilters.reportName]: undefined,\r\n });\r\n }}\r\n />\r\n
\r\n\r\n {chartDataErrorOccurred ? (\r\n
\r\n

We're sorry, but an error occurred while loading data.

\r\n\r\n {isDevelopmentEnvironment ? (\r\n
\r\n \"Error\"\r\n
\r\n ) : (\r\n <>\r\n )}\r\n
\r\n ) : (\r\n currentChartData && ( // There is a known issue with the chart below that causes additional redraws of the chart when the client changes or filters are applied\r\n
\r\n \r\n
\r\n )\r\n )}\r\n
\r\n
\r\n );\r\n};\r\n\r\nexport default ReportsPage;\r\n","import { library } from '@fortawesome/fontawesome-svg-core';\r\nimport {\r\n faChartArea,\r\n faChevronDown,\r\n faClock,\r\n faClone,\r\n faCog,\r\n faCopy,\r\n faDatabase,\r\n faEdit,\r\n faEye,\r\n faEyeSlash,\r\n faFileAlt,\r\n faIdCard,\r\n faKey,\r\n faLightbulb,\r\n faPlus,\r\n faSave,\r\n faSearch,\r\n faServer,\r\n faShoppingBasket,\r\n faSignOutAlt,\r\n faTable,\r\n faTimes,\r\n faTrash,\r\n faUndo,\r\n faUsers,\r\n faWrench,\r\n} from '@fortawesome/free-solid-svg-icons';\r\nimport { ReactPlugin, withAITracking } from '@microsoft/applicationinsights-react-js';\r\nimport { ApplicationInsights } from '@microsoft/applicationinsights-web';\r\nimport { IntlProvider } from '@progress/kendo-react-intl';\r\nimport { createBrowserHistory } from 'history';\r\nimport i18n from 'i18next';\r\nimport * as moment from 'moment';\r\nimport * as Msal from 'msal';\r\nimport { default as React, useCallback, useContext, useEffect, useRef, useState } from 'react';\r\nimport { Redirect, Route, Switch } from 'react-router';\r\nimport { BrowserRouter, useHistory, useLocation } from 'react-router-dom';\r\nimport LocalStorageKeys from '../constants/local-storage';\r\nimport ApplicationRoutes from '../constants/routes';\r\nimport UserConstants from '../constants/users';\r\nimport axiosMiddleware from '../extensions/axiosMiddleware';\r\nimport { DEFAULT_LANG } from '../internationalization/i18n';\r\nimport usersApiService from '../services/api/users/users-api-service';\r\nimport {\r\n AuthenticationService,\r\n SSOError,\r\n SSOErrorCode,\r\n} from '../services/authentication/authentication-service';\r\nimport '../styles/kendo/all.css';\r\nimport '../styles/kendo/variables.scss';\r\nimport { getConfig } from '../utils/config';\r\nimport { populateUserInformationFromLocalStorage } from '../utils/user-authorization';\r\nimport Layout from './common-page-components/layout/Layout';\r\nimport { LoadingPageOverlayContext } from './common-page-components/loading-page-overlay/LoadingPageOverlayContext';\r\nimport { NotificationPanelContext } from './common-page-components/notification-panel/NotificationPanelContext';\r\nimport AuthenticatedRoute from './common-page-components/routes/AuthenticatedRoute';\r\nimport ClientsPage from './pages/admin/clients/ClientsPage';\r\nimport LicensesPage from './pages/admin/licenses/LicensesPage';\r\nimport ProductsPage from './pages/admin/products/ProductsPage';\r\nimport SiteSettingsPage from './pages/admin/settings/SiteSettingsPage';\r\nimport UsersPage from './pages/admin/users/UsersPage';\r\nimport EstimatorHostedUserManagementPage from './pages/admin/hosted-estimator-user-management/EstimatorHostedUserManagementPage';\r\nimport GenericErrorPage from './pages/common/error/generic-error/GenericErrorPage';\r\nimport PageNotFoundPage from './pages/common/error/page-not-found/PageNotFoundPage';\r\nimport UnauthorizedPage from './pages/common/error/unauthorized/UnauthorizedPage';\r\nimport HomePage from './pages/common/home/HomePage';\r\nimport LoginPage from './pages/common/login/LoginPage';\r\nimport ReportsPage from './pages/reports/ReportsPage';\r\nimport { UserInformationContext } from './UserInformationContext';\r\n\r\nconst baseUrl = document.getElementsByTagName('base')[0].getAttribute('href') || '/';\r\nconst browserHistory = createBrowserHistory({ basename: baseUrl });\r\n\r\nconst reactPlugin = new ReactPlugin();\r\n\r\nconst instrumentationKey = getConfig('REACT_APP_APPINSIGHTS_INSTRUMENTATIONKEY');\r\n\r\nif (instrumentationKey) {\r\n const appInsights = new ApplicationInsights({\r\n config: {\r\n instrumentationKey: instrumentationKey,\r\n extensions: [reactPlugin],\r\n extensionConfig: {\r\n [reactPlugin.identifier]: { history: browserHistory },\r\n },\r\n },\r\n });\r\n\r\n appInsights.loadAppInsights();\r\n}\r\n\r\nconst App: React.FC = () => {\r\n const [locale, setLocale] = useState(DEFAULT_LANG);\r\n const { updateUserInformation } = useContext(UserInformationContext);\r\n const { showSuccessNotification, showErrorNotification } = useContext(NotificationPanelContext);\r\n const history = useHistory();\r\n const location = useLocation();\r\n\r\n const { showPageLoadingOverlay, hidePageLoadingOverlay } = useContext(LoadingPageOverlayContext);\r\n\r\n // Assume this is true so we don't display anything until we are sure the URL doesn't contain SSO hash data\r\n const [urlContainsSSOHashData, setUrlContainsSSOHashData] = useState(true);\r\n\r\n const [allInitialDataIsLoaded, setAllInitialDataIsLoaded] = useState(false);\r\n const [passwordResetInProgress, setPasswordResetInProgress] = useState(false);\r\n const lastLocationValue = useRef('');\r\n\r\n // Set tab title\r\n useEffect(() => {\r\n const envName = (getConfig('REACT_APP_ENVIRONMENT') || '').toUpperCase();\r\n document.title = envName.includes('PROD')\r\n ? 'DESTINI Licensing'\r\n : `DESTINI Licensing - ${envName}`;\r\n }, []);\r\n\r\n useEffect(() => {\r\n const checkUserAuthenticationStatus = async (): Promise => {\r\n // Since this can fire several times because of its dependencies, we only want to take action when the location changes\r\n if (lastLocationValue.current === location.pathname) {\r\n return;\r\n }\r\n\r\n const ssoPasswordResetCompleted = localStorage.getItem(\r\n LocalStorageKeys.SSOPasswordResetCompleted,\r\n );\r\n let authTokenFromLocalStorage = localStorage.getItem(LocalStorageKeys.AuthToken);\r\n let accessTokenFromLocalStorage = localStorage.getItem(LocalStorageKeys.AccessToken);\r\n\r\n const validateTokens = (): void => {\r\n // If the expiration date is not valid for the auth token or the access token, do some housekeeping and clear them out\r\n if (\r\n authTokenFromLocalStorage &&\r\n !AuthenticationService.isTokenExpirationValid(authTokenFromLocalStorage)\r\n ) {\r\n authTokenFromLocalStorage = null;\r\n localStorage.removeItem(LocalStorageKeys.AuthToken);\r\n }\r\n\r\n if (\r\n accessTokenFromLocalStorage &&\r\n !AuthenticationService.isTokenExpirationValid(accessTokenFromLocalStorage)\r\n ) {\r\n accessTokenFromLocalStorage = null;\r\n localStorage.removeItem(LocalStorageKeys.AccessToken);\r\n }\r\n };\r\n\r\n validateTokens();\r\n\r\n const logUserOutAndClearInformation = (): void => {\r\n updateUserInformation(null);\r\n AuthenticationService.logout();\r\n };\r\n\r\n const handleSSOErrors = (): boolean => {\r\n const ssoErrorObj = localStorage.getItem(LocalStorageKeys.SSOError);\r\n if (ssoErrorObj) {\r\n const ssoError: SSOError = JSON.parse(ssoErrorObj);\r\n localStorage.removeItem(LocalStorageKeys.SSOError);\r\n showErrorNotification('Error', ssoError.message);\r\n\r\n switch (ssoError.code) {\r\n case SSOErrorCode.OtherError:\r\n history.push(ApplicationRoutes.ERROR_ERROR);\r\n break;\r\n case SSOErrorCode.LicensingAppSSOError:\r\n history.push(ApplicationRoutes.ERROR_UNAUTHORIZED);\r\n break;\r\n }\r\n return true;\r\n }\r\n\r\n return false;\r\n };\r\n\r\n // When the user initiates a password reset flow, they get redirected to an SSO page, then back to our app with query string parameters.\r\n // The MSAL library then runs and sets local storage flags, which we then have to check and redirect the user again to a different SSO page.\r\n // This code will check the local storage flags and take whatever actions it needs to based on their values.\r\n const handleSSOPasswordResetLogic = (): boolean => {\r\n const ssoPasswordResetInitiated = localStorage.getItem(\r\n LocalStorageKeys.SSOPasswordResetInitiated,\r\n );\r\n\r\n // We conditionally control the AuthenticationService flow based on whether the ssoPasswordResetInitiated flag is set.\r\n // While both flags below should never be set at the same time, if we do end up in this state we need to wipe out user information and local storage.\r\n if (ssoPasswordResetInitiated && ssoPasswordResetCompleted) {\r\n logUserOutAndClearInformation();\r\n return true;\r\n }\r\n // If only ssoPasswordResetInitiated is set, we initialize the service to a password-reset flow and redirect the user to a password reset screen\r\n else if (ssoPasswordResetInitiated) {\r\n localStorage.removeItem(LocalStorageKeys.SSOPasswordResetInitiated);\r\n setPasswordResetInProgress(true);\r\n AuthenticationService.initializePasswordReset();\r\n AuthenticationService.navigateToSignInOrPasswordReset();\r\n return true;\r\n } else if (ssoPasswordResetCompleted) {\r\n showSuccessNotification(\r\n 'Success',\r\n 'Your password was changed successfully. Please log in using your new credentials.',\r\n );\r\n }\r\n\r\n return false;\r\n };\r\n\r\n // In some instances, if we fail to get an access token, we set an error message in local storage and then log the user out via the MSAL library,\r\n // which involves some redirects. Once we get back to our app, we want to show the user the error message.\r\n const handleAccessTokenError = (): void => {\r\n const accessTokenError = localStorage.getItem(LocalStorageKeys.AccessTokenError);\r\n if (accessTokenError) {\r\n localStorage.removeItem(LocalStorageKeys.AccessTokenError);\r\n showErrorNotification('Error', accessTokenError);\r\n }\r\n };\r\n\r\n const getAccessToken = async (): Promise => {\r\n // If the password reset just completed, we don't want to get an access token, we want the user to have to log in again\r\n if (ssoPasswordResetCompleted) {\r\n return false;\r\n }\r\n\r\n // If we already have an access token, return true\r\n if (accessTokenFromLocalStorage) {\r\n return true;\r\n }\r\n\r\n // NOTE: If we don't have an auth token, that's ok, we can still get a new access token silently as long as we have the MSAL\r\n // specific stuff in local storage - there is no harm in trying to get a new access token at this point\r\n\r\n try {\r\n showPageLoadingOverlay();\r\n return await AuthenticationService.getAccessToken();\r\n } catch {\r\n // NOTE: We want to catch the error but not do anything else here\r\n } finally {\r\n hidePageLoadingOverlay();\r\n }\r\n\r\n return false;\r\n };\r\n\r\n // If the URL changed, reset the flag so we don't render any page routes until we get all of the user's authorization info\r\n setAllInitialDataIsLoaded(false);\r\n lastLocationValue.current = location.pathname;\r\n\r\n // If the URL contains hash data, it is because of a successful SSO login or an error. In either case, the hash data will get removed from the URL\r\n // and the page redirected -- in this situation, we conditionally do not render certain parts of the application, like page components, using a state variable\r\n // to dictate that.\r\n const urlContainsSSOHash = Msal.UserAgentApplication.prototype.urlContainsHash(location.hash);\r\n setUrlContainsSSOHashData(urlContainsSSOHash);\r\n\r\n AuthenticationService.initializeSignIn();\r\n\r\n if (!urlContainsSSOHash) {\r\n // Handle SSO error logic -- if the function returned true, it triggered a redirect so we want to return early from this code in that case.\r\n if (handleSSOErrors()) {\r\n return;\r\n }\r\n\r\n // Handle SSO password reset logic -- if the function returned true, it triggered a redirect so we want to return early from this code in that case.\r\n if (handleSSOPasswordResetLogic()) {\r\n return;\r\n }\r\n\r\n // If we have just completed a password reset, return early and load the app as usual\r\n if (ssoPasswordResetCompleted) {\r\n localStorage.removeItem(LocalStorageKeys.SSOPasswordResetCompleted);\r\n setAllInitialDataIsLoaded(true);\r\n return;\r\n }\r\n\r\n // Handle access token errors\r\n handleAccessTokenError();\r\n\r\n const accessTokenWasAcquired = await getAccessToken();\r\n\r\n // If we don't have a valid access token at this point, the user needs to take explicit action in order to acquire one since the authentication\r\n // service tried to refresh it silently and couldn't for whatever reason.\r\n if (!accessTokenWasAcquired) {\r\n // Clear out the user's info from local storage if we couldn't get an access token\r\n updateUserInformation(null);\r\n\r\n // If we had an auth token but couldn't get an access token, wipe everything and log the user out\r\n if (authTokenFromLocalStorage) {\r\n logUserOutAndClearInformation();\r\n return;\r\n } else {\r\n // If we never had an auth token to begin with, load the app as usual\r\n setAllInitialDataIsLoaded(true);\r\n }\r\n } else {\r\n const userInformationFromLocalStorage = localStorage.getItem(\r\n LocalStorageKeys.UserInformation,\r\n );\r\n\r\n if (!userInformationFromLocalStorage) {\r\n try {\r\n showPageLoadingOverlay();\r\n\r\n // Try to get the current user's information - if the AJAX call returns a NotFound status, it means the user does not have\r\n // a user record in our database\r\n try {\r\n const user = await usersApiService.getUser();\r\n\r\n updateUserInformation({\r\n id: user.id!,\r\n emailAddress: user.emailAddress,\r\n name: localStorage.getItem(LocalStorageKeys.UserName) as string,\r\n userRoles: user.roles,\r\n });\r\n } catch (error) {\r\n if (error && error.response && error.response.status === 404) {\r\n // Since we could not get the user's info from the server, we want to get what we can by reading in the data from the access token\r\n // and populate the UserInformation object\r\n const userInfoFromToken = AuthenticationService.getUserInfoFromAccessToken(\r\n localStorage.getItem(LocalStorageKeys.AccessToken)!,\r\n );\r\n\r\n if (!userInfoFromToken) {\r\n throw new Error('The user could not be logged in.');\r\n }\r\n\r\n updateUserInformation({\r\n id: '0', // NOTE: We use a placeholder ID in this case\r\n emailAddress: userInfoFromToken.emailAddress,\r\n name: userInfoFromToken.name,\r\n userRoles: [],\r\n });\r\n } else {\r\n // If the error wasn't what we want to handle, rethrow it\r\n throw error;\r\n }\r\n }\r\n\r\n setAllInitialDataIsLoaded(true);\r\n } catch {\r\n // If we couldn't get the user's info (or it didn't exist on the server), we want to log them out\r\n // and set an error message in local storage that our app will show the next time it loads\r\n logUserOutAndClearInformation();\r\n\r\n // NOTE: We have to set the local storage after we call the logUserOutAndClearInformation() method\r\n // because that method wipes local storage\r\n localStorage.setItem(\r\n LocalStorageKeys.AccessTokenError,\r\n 'Sorry, but we could not log you in at this time.',\r\n );\r\n } finally {\r\n hidePageLoadingOverlay();\r\n }\r\n } else {\r\n const parsedUserInfo = populateUserInformationFromLocalStorage();\r\n updateUserInformation(parsedUserInfo);\r\n setAllInitialDataIsLoaded(true);\r\n }\r\n }\r\n }\r\n };\r\n\r\n checkUserAuthenticationStatus();\r\n }, [\r\n location,\r\n hidePageLoadingOverlay,\r\n showPageLoadingOverlay,\r\n history,\r\n updateUserInformation,\r\n showSuccessNotification,\r\n showErrorNotification,\r\n ]);\r\n\r\n const onLanguageChanged = useCallback((lang: string) => {\r\n moment.locale(lang); // Update moment locale globally\r\n setLocale(lang); // Update locale state for kendo provider\r\n }, []);\r\n\r\n i18n.on('languageChanged', onLanguageChanged);\r\n\r\n // Add commonly used icons to the library collection so they're available\r\n // in every component without explicit imports\r\n library.add(\r\n faChartArea,\r\n faChevronDown,\r\n faClock,\r\n faClone,\r\n faCog,\r\n faCopy,\r\n faDatabase,\r\n faEdit,\r\n faEye,\r\n faEyeSlash,\r\n faFileAlt,\r\n faIdCard,\r\n faKey,\r\n faLightbulb,\r\n faPlus,\r\n faSave,\r\n faSearch,\r\n faServer,\r\n faShoppingBasket,\r\n faSignOutAlt,\r\n faTable,\r\n faTimes,\r\n faTrash,\r\n faUndo,\r\n faUsers,\r\n faWrench,\r\n );\r\n\r\n // Convert date strings to dates in axios responses\r\n axiosMiddleware.enableDateStringToDateResponseMiddleware();\r\n\r\n return (\r\n
\r\n \r\n <>\r\n {/* We wait until all initial data is loaded before we render any page components */}\r\n {allInitialDataIsLoaded && (\r\n \r\n \r\n {/* Login page */}\r\n \r\n\r\n {/* Home page */}\r\n \r\n\r\n {/* Admin pages */}\r\n \r\n\r\n \r\n\r\n \r\n\r\n \r\n\r\n \r\n\r\n \r\n\r\n {/* Report pages */}\r\n {/* Redirect the user to the usage report page if the user hit the root reports page */}\r\n\r\n \r\n \r\n \r\n\r\n \r\n\r\n \r\n\r\n \r\n\r\n \r\n\r\n {/* Error pages */}\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n )}\r\n \r\n \r\n
\r\n );\r\n};\r\n\r\nconst BrowserApp = (): JSX.Element => (\r\n \r\n \r\n \r\n);\r\n\r\nexport default withAITracking(reactPlugin, BrowserApp, 'App');\r\n","import React from 'react';\nimport './LoadingIndicator.scss';\n\nconst LoadingIndicator: React.FC = () => {\n return
;\n};\n\nexport default LoadingIndicator;\n","import React, { useContext } from 'react';\nimport LoadingIndicator from '../loading-indicator/LoadingIndicator';\nimport './LoadingPageOverlay.scss';\nimport { LoadingPageOverlayContext } from './LoadingPageOverlayContext';\n\nconst LoadingPageOverlay: React.FC = () => {\n const { pageLoadingOverlayDisplayInfo } = useContext(LoadingPageOverlayContext);\n\n const loadingPageOverlayCssClasses = ['loadingPageOverlay'];\n\n // Don't even show the loading overlay if it hasn't explicitly been toggled\n if (!pageLoadingOverlayDisplayInfo.hasBeenToggled) {\n loadingPageOverlayCssClasses.push('d-none');\n } else if (pageLoadingOverlayDisplayInfo.isDisplayed) {\n loadingPageOverlayCssClasses.push('isDisplayed');\n }\n\n return (\n
\n
\n \n
\n
\n );\n};\n\nexport default LoadingPageOverlay;\n","//\n// NOTE: TO ADD SUPPORT FOR ANOTHER LOCALE, REFER TO THE WIKI ARTICLE FOR INSTRUCTIONS\n//\n\nimport { load } from '@progress/kendo-react-intl';\nimport { initReactI18next } from 'react-i18next';\nimport i18n from 'i18next';\nimport { TranslationFilesMap, DEFAULT_LANG, format } from './i18n';\nimport { Import } from '../utils/imports';\nimport moment from 'moment';\n\nimport 'moment/locale/fr-ca';\n\nimport weekData from 'cldr-core/supplemental/weekData.json';\nimport frCaGeneric from 'cldr-dates-full/main/fr-CA/ca-generic.json';\nimport frCaGregorian from 'cldr-dates-full/main/fr-CA/ca-gregorian.json';\nimport frCaDateFields from 'cldr-dates-full/main/fr-CA/dateFields.json';\nimport frCaTimeZoneNames from 'cldr-dates-full/main/fr-CA/timeZoneNames.json';\n\nload(weekData, frCaGeneric, frCaGregorian, frCaDateFields, frCaTimeZoneNames);\n\nconst getInitialTranslations = (): Dictionary => {\n const resources: Dictionary = { [DEFAULT_LANG]: {} };\n const getTranslationsFunc = TranslationFilesMap[DEFAULT_LANG] as () => Import[];\n const translationFiles = getTranslationsFunc();\n\n translationFiles.forEach(translationFile => {\n resources[DEFAULT_LANG][translationFile.name] = translationFile.translations;\n });\n\n return resources;\n};\n\ni18n\n .use(initReactI18next) // passes i18n down to react-i18next\n .init({\n resources: getInitialTranslations(),\n lng: DEFAULT_LANG,\n interpolation: {\n escapeValue: false, // react already safes from xss\n format: format,\n },\n });\n\n// Set initial moment locale to the default language\nmoment.locale(DEFAULT_LANG);\n","// This optional code is used to register a service worker.\n// register() is not called by default.\n\n// This lets the app load faster on subsequent visits in production, and gives\n// it offline capabilities. However, it also means that developers (and users)\n// will only see deployed updates on subsequent visits to a page, after all the\n// existing tabs open on the page have been closed, since previously cached\n// resources are updated in the background.\n\n// To learn more about the benefits of this model and instructions on how to\n// opt-in, read https://bit.ly/CRA-PWA\n\nconst isLocalhost = Boolean(\n window.location.hostname === 'localhost' ||\n // [::1] is the IPv6 localhost address.\n window.location.hostname === '[::1]' ||\n // 127.0.0.1/8 is considered localhost for IPv4.\n window.location.hostname.match(/^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/),\n);\n\ntype Config = {\n onSuccess?: (registration: ServiceWorkerRegistration) => void;\n onUpdate?: (registration: ServiceWorkerRegistration) => void;\n};\n\nfunction registerValidSW(swUrl: string, config?: Config): void {\n navigator.serviceWorker\n .register(swUrl)\n .then(registration => {\n registration.onupdatefound = (): void => {\n const installingWorker = registration.installing;\n if (installingWorker == null) {\n return;\n }\n installingWorker.onstatechange = (): void => {\n if (installingWorker.state === 'installed') {\n if (navigator.serviceWorker.controller) {\n // At this point, the updated precached content has been fetched,\n // but the previous service worker will still serve the older\n // content until all client tabs are closed.\n\n // eslint-disable-next-line no-console\n console.log(\n 'New content is available and will be used when all ' +\n 'tabs for this page are closed. See https://bit.ly/CRA-PWA.',\n );\n\n // Execute callback\n if (config && config.onUpdate) {\n config.onUpdate(registration);\n }\n } else {\n // At this point, everything has been precached.\n // It's the perfect time to display a\n // \"Content is cached for offline use.\" message.\n\n // eslint-disable-next-line no-console\n console.log('Content is cached for offline use.');\n\n // Execute callback\n if (config && config.onSuccess) {\n config.onSuccess(registration);\n }\n }\n }\n };\n };\n })\n .catch(error => {\n // eslint-disable-next-line no-console\n console.error('Error during service worker registration:', error);\n });\n}\n\nfunction checkValidServiceWorker(swUrl: string, config?: Config): void {\n // Check if the service worker can be found. If it can't reload the page.\n fetch(swUrl)\n .then(response => {\n // Ensure service worker exists, and that we really are getting a JS file.\n const contentType = response.headers.get('content-type');\n if (\n response.status === 404 ||\n (contentType != null && contentType.indexOf('javascript') === -1)\n ) {\n // No service worker found. Probably a different app. Reload the page.\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister().then(() => {\n window.location.reload();\n });\n });\n } else {\n // Service worker found. Proceed as normal.\n registerValidSW(swUrl, config);\n }\n })\n .catch(() => {\n // eslint-disable-next-line no-console\n console.log('No internet connection found. App is running in offline mode.');\n });\n}\n\nexport function register(config?: Config): void {\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\n // The URL constructor is available in all browsers that support SW.\n const publicUrl = new URL(\n (process as { env: { [key: string]: string } }).env.PUBLIC_URL,\n window.location.href,\n );\n if (publicUrl.origin !== window.location.origin) {\n // Our service worker won't work if PUBLIC_URL is on a different origin\n // from what our page is served on. This might happen if a CDN is used to\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\n return;\n }\n\n window.addEventListener('load', () => {\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\n\n if (isLocalhost) {\n // This is running on localhost. Let's check if a service worker still exists or not.\n checkValidServiceWorker(swUrl, config);\n\n // Add some additional logging to localhost, pointing developers to the\n // service worker/PWA documentation.\n navigator.serviceWorker.ready.then(() => {\n // eslint-disable-next-line no-console\n console.log(\n 'This web app is being served cache-first by a service ' +\n 'worker. To learn more, visit https://bit.ly/CRA-PWA',\n );\n });\n } else {\n // Is not localhost. Just register service worker\n registerValidSW(swUrl, config);\n }\n });\n }\n}\n\nexport function unregister(): void {\n if ('serviceWorker' in navigator) {\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister();\n });\n }\n}\n","import 'bootstrap/dist/css/bootstrap.css';\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport App from './app/App';\nimport { ConfirmationOverlayContextProvider } from './app/common-page-components/confirmation-overlay/ConfirmationOverlayContext';\nimport LoadingPageOverlay from './app/common-page-components/loading-page-overlay/LoadingPageOverlay';\nimport { LoadingPageOverlayContextProvider } from './app/common-page-components/loading-page-overlay/LoadingPageOverlayContext';\nimport { NotificationPanelContextProvider } from './app/common-page-components/notification-panel/NotificationPanelContext';\nimport { UserInformationContextProvider } from './app/UserInformationContext';\nimport './internationalization/setup';\nimport * as serviceWorker from './registerServiceWorker';\n\nconst rootElement = document.getElementById('root');\n\nReactDOM.render(\n \n \n \n \n \n\n \n \n \n \n ,\n rootElement,\n);\n\n// If you want your app to work offline and load faster, you can change\n// unregister() to register() below. Note this comes with some pitfalls.\n// Learn more about service workers: https://bit.ly/CRA-PWA\nserviceWorker.unregister();\n"],"sourceRoot":""}