{"version":3,"sources":["api/Config.js","api/i18n.js","api/restApi.js","store/Login/ActionCreators.js","store/ProjectStore.js","util/callOnceAfterInterval.js","store/RecommendationState/updateRecommendations.js","store/RecommendationState/ActionCreators.js","store/AddCamerasStore.js","api/ConfigSummary.js","api/prettifyNumbers.js","store/ProductRecommendations/Reducer.js","store/OrderSummary/Reducer.js","store/RecommendationState/Reducer.js","util/arrayHelpers.js","attribute-handling/parseAttributes.js","store/ProductOptions/Reducer.js","store/Login/Reducer.js","store/ProjectList/ActionCreators.js","store/ProjectList/Reducer.js","components/ConfigSummaryTable.jsx","components/EditableTable2.jsx","components/AddCameras.jsx","components/ProductAttribute.jsx","components/ProductOptions.jsx","components/ProductDescription.jsx","components/Product.jsx","components/Disclaimer.jsx","components/ProductRecommendations.jsx","hooks/useRoleTranslation.js","components/OrderSummaryPdf.jsx","components/Loading.jsx","components/Project/Project.jsx","components/Project/ProjectReferenceInput.jsx","components/Project/DeleteProjectModal.jsx","components/ProjectList/Pagination.jsx","components/ProjectMenu.jsx","util/filterCaseInsensitive.js","components/ProjectList/ProjectListColumns.jsx","components/ProjectList/ProjectList.jsx","hooks/useIsAdmin.js","components/User.jsx","CookiePolicyPage/CookiePolicyPage.jsx","App.js","registerServiceWorker.js","postFrameHeight.js","components/Header/burgerMenu.js","components/Header/device.js","components/Header/headersectionblock.js","components/Header/Header.jsx","components/Footer/Footer.jsx","index.js","store/configureStore.js"],"names":["environment","CONFIG","MILESTONE_URL","localhost","getMilestoneUrl","i18n","use","initReactI18next","init","resources","en","translations","STORAGE_CONFIGURATION_JBOD","STORAGE_CONFIGURATION_RAID0","STORAGE_CONFIGURATION_RAID1","STORAGE_CONFIGURATION_RAID5","STORAGE_CONFIGURATION_RAID6","STORAGE_CONFIGURATION_RAID10","SERVER_CPU_SINGLE","SERVER_CPU_DUAL","SERVER_GPU_NVIDIAP2000","SERVER_GPU_NONE","SERVER_FEATURE_GPUDECODING","SERVER_NETWORK_TENGBITSFPPLUS","SERVER_NETWORK_ONEGBIT","FORM_FACTOR_TWOURACK","FORM_FACTOR_FOURURACK","FORM_FACTOR_TOWER","CAMERA_CODEC_MJPEG","CAMERA_CODEC_H265","CAMERA_CODEC_H264","IMAGE_COMPLEXITY_LOW","IMAGE_COMPLEXITY_MEDIUM","IMAGE_COMPLEXITY_HIGH","CAMERA_RESOLUTION_CIF","CAMERA_RESOLUTION_VGA","CAMERA_RESOLUTION_SEVENTWENTYP","CAMERA_RESOLUTION_ONEPOINTTHREEMP","CAMERA_RESOLUTION_TENEIGHTYP","CAMERA_RESOLUTION_TWOMP","CAMERA_RESOLUTION_THREEMP","CAMERA_RESOLUTION_FOURMP","CAMERA_RESOLUTION_FIVEMP","CAMERA_RESOLUTION_SIXMP","CAMERA_RESOLUTION_EIGHTHMP","CAMERA_RESOLUTION_TWELVEMP","CAMERA_RESOLUTION_FOURK","FEATURE_GPU_HEADER","FEATURE_CPU_HEADER","FEATURE_NETWORK_HEADER","FEATURE_FORM_FACTOR_HEADER","lng","fallbackLng","debug","ns","defaultNS","keySeparator","interpolation","escapeValue","formatSeparator","react","wait","axios","defaults","withCredentials","serverUri","path","window","hostName","location","hostname","getApiUrl","get","result","data","cameraLine","post","redirectUri","top","replace","console","error","href","projectId","project","put","map","header","created","Date","modified","delete","newReference","encodeURIComponent","actionCreators","userRoleChanged","userRole","type","role","userChanged","user","authenticationChanged","isAuthenticated","types","loadModels","dispatch","getState","a","restApi","getModels","skus","serverFilter","recommendationState","loadProject","getProject","updateRecommendations","updateProjectDetails","projectDetails","updateProject","initialState","modelsLoading","projectLoading","loadingRecommendations","projectReference","message","telephoneNumber","distributor","timeFrameEndDate","toISOString","slice","projectCustomerId","currentCustomerId","reducer","state","action","recommendations","loading","id","customerId","callback","intervalMs","updateTaskId","args","clearTimeout","setTimeout","updateAfterOneSecond","callOnceAfterInterval","cameraLines","length","calculateRecommendations","appTypes","fullState","updateReq","resourceUsage","diskStoragePercentageUpdated","newPercentage","isEditingDisabled","dataRatePercentageUpdated","numberOfCamerasPercentageUpdated","cameraLineAdded","cameraLineRemoved","index","cameraLineUpdated","serverModelsUpdated","models","storageConfigurationUpdated","newStorageConfig","serverAttributeUpdated","attributeId","selectedOptions","getDefaultCameraRow","codecList","imageComplexityList","resolutionList","cameras","operation","recording","days","codec","imageComplexity","resolution","fps","dataRate","notes","fetchConfig","updateAfterDelay","rowIndex","updatedRow","shouldUpdateDataRate","rowToApi","toString","parseFloat","calculateCameraDataRate","rowToState","recommendationsActions","addFirstRow","addRow","getCameraSelectLists","lists","row","removeRow","fieldUpdated","field","newValue","oldRow","hasOwnProperty","Object","assign","selected","recommendationsTypes","indexOf","getConfigSummary","dataRows","sum","prev","next","numberOfCameras","cr","reduce","totalBitrate","totalStorage","prettifyStorage","storageKbit","storageKbyte","Math","pow","toFixed","round","camTypes","calculateTotalBitrateAndStorage","projectTypes","summary","diskStoragePercentage","recTypes","storageConfiguration","attributes","dataRatePercentage","numberOfCamerasPercentage","filter","_","item","newAttributes","updatedItem","options","find","deduplicate","arrayWithDuplicates","Set","flatten","features","f","current","concat","groupBy","xs","key","rv","x","v","Function","el","r","values","push","optionToSelectItem","option","name","enabled","storageConfigurations","projTypes","updateSelectedModels","collator","Intl","Collator","undefined","numeric","sensitivity","sku","model","sort","compare","mapSelectItem","parsedAttributes","restAttributes","attributeIds","ra","currentId","restAttributesWithCurrentId","allOptions","parsedAttribute","title","parseAttributes","filterAttributes","aggregate","attribute","attributeInFilters","updateSelectedAttributes","m","s","i","newModels","sc","modelsInState","includes","modelsToChange","Array","isArray","mtc","attributesInState","oldAttribute","newAttribute","showAllProjects","showOwnProjects","ConfigSummaryTable","props","bitrateKbps","cameraRows","useSelector","store","productOptions","style","fontWeight","width","align","columns","t","useTranslation","Table","className","size","c","fontSize","paddingLeft","accessor","maxWidth","Header","column","value","editable","columnId","cellOptions","onChange","otherOptions","FormControl","as","e","target","o","renderSelect","Button","variant","borderRadius","onClick","renderButton","minvalue","maxvalue","cellId","cellInfo","event","Number","MIN_VALUE","MAX_VALUE","isNaN","callIfWithinRange","renderEditable","renderCell","editingDisabled","useDispatch","useState","addingFirstRow","setAddingFirstRow","useEffect","configLoaded","getColumns","margin","xlinkHref","sprites","EditableTable2","ProductAttribute","toggleChange","setState","isChecked","clearAll","bind","renderAll","renderSelected","renderSingle","isTruncated","onSelectOption","this","showRadio","padding","truncateList","optionsToRender","ButtonGroup","vertical","renderedItems","defaultChecked","htmlFor","Component","withTranslation","poweredByAttribute","remainingAttributes","optionName","parseInt","names","min","max","evt","valueAsNumber","marginLeft","getAttributeValue","storageSize","join","replaceAll","powerSupply","attributeName","formatDescription","description","Product","product","original","Container","fluid","Row","Col","maxHeight","src","image","alt","dangerouslySetInnerHTML","__html","ProductDescription","Card","Body","StorageBar","count","position","ProgressBar","now","background","height","lineHeight","color","textAlign","NumberOfResultsButton","isSelected","children","textDecoration","showOrderSummary","login","useMemo","tr","textId","toLowerCase","useRoleTranslation","productRecommendations","sortingFunction","numberOfResults","setNumberOfResults","filteredRecommendations","filtered","groupedByPoweredBy","rec","attr","group","resultObject","accu","Cell","isExpanded","techSheetLink","minWidth","show","Disclaimer","md","span","pageSize","minRows","showPagination","showPageJump","showPageSizeOptions","noDataText","SubComponent","orderedProduct","hide","orderSummary","headerStyle","Modal","onHide","dialogClassName","minHeight","resolveData","resolveCameraLines","defaultPageSize","marginTop","document","onafterprint","print","headerClassName","text","Spinner","animation","Project","showModal","documentElement","overflow","hideModal","removeAttribute","showAddCameras","loadingProject","match","params","history","Loading","Accordion","defaultActiveKey","Toggle","eventKey","Collapse","AddCameras","closeButton","Title","ProductOptions","lg","ProductRecommendations","ProjectWithRouter","withRouter","connect","bindActionCreators","handleClose","handleCreated","doCreate","labelText","buttonText","defaultValue","inputProjectName","useRef","setProjectReference","focus","close","create","handleKeyup","Form","sm","ref","onKeyUp","placeholder","handleDeleted","doDelete","deleteProject","Footer","canPreviousPage","pageCount","canNextPage","nextPage","previousPage","pageIndex","disabled","CustomToggle","React","forwardRef","preventDefault","onClickDelete","onClickDuplicate","onClickEditReference","useHistory","Dropdown","alignRight","icon","faEllipsisV","Menu","Item","faArrowCircleRight","Divider","faEdit","faClone","faTrash","rows","filterValue","rowValue","String","toUpperCase","CellText","setLoading","setData","showAddRow","setShowAddRow","showDeleteModal","setShowDeleteModal","selectedProjectReference","setSelectedProjectReference","selectedProjectId","setSelectedProjectId","projectList","isAdmin","useIsAdmin","editedRowId","setEditedRowId","updateProjectReference","changeProjectReference","formatLocal","format","reference","showEdit","ProjectReferenceInput","newProjectReference","to","Filter","setFilter","InputGroup","Prepend","Text","filterCaseInsensitive","sortType","sortable","ProjectMenu","stopPropagation","duplicateProject","listAdminProjects","listProjects","projects","fetchData","then","sortBy","desc","hiddenColumns","hidden","tableInstance","useTable","useFilters","useSortBy","usePagination","getTableBodyProps","headerGroups","prepareRow","page","gotoPage","setPageSize","projectNameHeader","headerGroup","headers","total","h","createProject","defaultProject","DeleteProjectModal","border","render","getHeaderGroupProps","getHeaderProps","getSortByToggleProps","borderTop","isSorted","isSortedDesc","faCaretDown","faCaretUp","getRowProps","cells","cell","getCellProps","Pagination","User","setUser","getUserInfo","userInfo","logInToWebsite","whiteSpace","UserClass","CookiePolicyPage","script","createElement","async","cookiebotContainer","getElementById","appendChild","removeChild","go","ProjectList","Boolean","resizeObserver","ResizeObserver","entries","newHeight","getElementsByTagName","scrollHeight","parent","postMessage","frameHeight","BurgerMenu","navigation","navigationMenuItems","bodyElement","burgerMenuLink","closeButtonElement","burgerMenuLinkToggle","classList","toggle","updatePageScrolling","onBurgerMenuClick","onBurgerMenuIconClick","closest","closeBurgerMenu","contains","remove","querySelectorAll","forEach","element","isOpened","add","initialize","querySelector","addEventListener","bindEvents","bindBurgerMenuClick","navigationMenuItem","navigationMenuItemIcon","unbindBurgerMenuClick","removeEventListener","onOutsideBurgerMenuClick","onBurgerMenuWindowResize","Device","isXSmall","clientWidth","isSmall","isMedium","isLarge","isXLarge","isXXLarge","isDesktop","innerWidth","body","isAndroid","navigator","userAgent","isCurrentClientWidth","headerSectionBlock","device","navigationMenus","burgerMenu","currentOpenedComponent","isInitialized","updateHeaderLayout","checkOpenedComponent","cacheDom","onOutsideDesktopUIClick","counter","checkMultipleComponentsAreOpened","onOutsideMobileUIClick","onWindowClick","milestoneUrl","logInEvent","logOutEvent","logOut","viewBox","version","xmlns","xmlnsXlink","fill","d","fillRule","aboutUsLink","contactUsLink","officesLink","careersLink","termsOfUseLink","privacyPolicyLink","cookiePolicyLink","mapPolicyLink","makeAWhistleblowerReportLink","modernSlaveryActLink","currentYear","getFullYear","rel","host","split","reducers","OrderSummary","RecommendationState","Login","middleware","thunk","enhancers","rootReducer","combineReducers","createStore","compose","applyMiddleware","configureStore","initialReduxState","rootElement","serviceWorker","ready","registration","unregister","observe","ReactDOM","App"],"mappings":"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","file":"static/js/main.c5a319b0.chunk.js","sourcesContent":["let environment = \"localhost\";\r\n\r\nconst CONFIG = {\r\n \"huskycalculator.milestonesys.wdev\": {\r\n MILESTONE_URL: \"https://www.milestonesys.wdev\"\r\n },\r\n \"huskycalculator.milestonesys.wtst\": {\r\n MILESTONE_URL: \"https://www.milestonesys.wtst\"\r\n },\r\n \"huskycalculator.milestonesys.xyz\": {\r\n MILESTONE_URL: \"https://www.milestonesys.xyz\"\r\n },\r\n \"huskycalculator.milestonesys.com\": {\r\n MILESTONE_URL: \"https://www.milestonesys.com\"\r\n },\r\n localhost: {\r\n MILESTONE_URL: \"https://www.milestonesys.wdev\"\r\n }\r\n};\r\n\r\n// Ensure the environment is correctly set based on the host\r\nexport const loadConfig = () => {\r\n environment = window.location.host.split(\":\")[0];\r\n};\r\n\r\n// Return the correct URL based on the environment\r\nexport const getMilestoneUrl = () => CONFIG[environment].MILESTONE_URL;\r\n","import i18n from 'i18next'\r\nimport { initReactI18next } from 'react-i18next'\r\n\r\ni18n.use(initReactI18next).init({\r\n // we init with resources\r\n resources: {\r\n en: {\r\n translations: {\r\n STORAGE_CONFIGURATION_JBOD: 'JBOD',\r\n STORAGE_CONFIGURATION_RAID0: 'RAID 0',\r\n STORAGE_CONFIGURATION_RAID1: 'RAID 1',\r\n STORAGE_CONFIGURATION_RAID5: 'RAID 5',\r\n STORAGE_CONFIGURATION_RAID6: 'RAID 6',\r\n STORAGE_CONFIGURATION_RAID10: 'RAID 10',\r\n SERVER_CPU_SINGLE: 'Single CPU',\r\n SERVER_CPU_DUAL: 'Dual CPU',\r\n SERVER_GPU_NVIDIAP2000: 'NVIDIA P2000',\r\n SERVER_GPU_NONE: 'None',\r\n SERVER_FEATURE_GPUDECODING: 'GPU Decoding',\r\n SERVER_NETWORK_TENGBITSFPPLUS: '10Gbit SFP+',\r\n SERVER_NETWORK_ONEGBIT: '1Gbit',\r\n FORM_FACTOR_TWOURACK: '2U Rackmount',\r\n FORM_FACTOR_FOURURACK: '4U Rackmount',\r\n FORM_FACTOR_TOWER: 'Tower',\r\n CAMERA_CODEC_MJPEG: 'MJPEG',\r\n CAMERA_CODEC_H265: 'H265',\r\n CAMERA_CODEC_H264: 'H264',\r\n IMAGE_COMPLEXITY_LOW: 'Low',\r\n IMAGE_COMPLEXITY_MEDIUM: 'Medium',\r\n IMAGE_COMPLEXITY_HIGH: 'High',\r\n CAMERA_RESOLUTION_CIF: 'CIF (352x240)',\r\n CAMERA_RESOLUTION_VGA: 'VGA (640x480)',\r\n CAMERA_RESOLUTION_SEVENTWENTYP: '720p (1280x720)',\r\n CAMERA_RESOLUTION_ONEPOINTTHREEMP: '1.3 MP (1280x1024)',\r\n CAMERA_RESOLUTION_TENEIGHTYP: 'Full HD (1920x1080)',\r\n CAMERA_RESOLUTION_TWOMP: '2 MP (1600x1200)',\r\n CAMERA_RESOLUTION_THREEMP: '3 MP (2048x1536)',\r\n CAMERA_RESOLUTION_FOURMP: '4 MP (2592x1520)',\r\n CAMERA_RESOLUTION_FIVEMP: '5 MP (2592x1944)',\r\n CAMERA_RESOLUTION_SIXMP: '6 MP (4800x1280)',\r\n CAMERA_RESOLUTION_EIGHTHMP: '8 MP (6400x1200)',\r\n CAMERA_RESOLUTION_TWELVEMP: '12 MP (8192x1536)',\r\n CAMERA_RESOLUTION_FOURK: '4K (3840x2160)',\r\n FEATURE_GPU_HEADER: 'GPU',\r\n FEATURE_CPU_HEADER: 'CPU',\r\n FEATURE_NETWORK_HEADER: 'Network',\r\n FEATURE_FORM_FACTOR_HEADER: 'Form factor',\r\n },\r\n },\r\n },\r\n lng: 'en',\r\n fallbackLng: 'en',\r\n debug: false,\r\n\r\n // have a common namespace used around the full app\r\n ns: ['translations'],\r\n defaultNS: 'translations',\r\n\r\n keySeparator: false, // we use content as keys\r\n\r\n interpolation: {\r\n escapeValue: false, // not needed for react!!\r\n formatSeparator: ',',\r\n },\r\n\r\n react: {\r\n wait: true,\r\n },\r\n})\r\n\r\nexport default i18n\r\n","// @flow\r\n/* eslint no-restricted-globals: [\"error\", \"location\"] */\r\n\r\nimport axios from 'axios'\r\nimport type {\r\n CameraLine,\r\n DataForRecommendations,\r\n ProjectHeader,\r\n ServerProject,\r\n} from './restTypes'\r\n\r\naxios.defaults.withCredentials = true\r\n\r\nfunction getApiUrl() {\r\n let path = ''\r\n if (typeof window !== 'undefined') {\r\n let hostName = window.location.hostname\r\n if (hostName === 'localhost') {\r\n return `http://localhost:5000/api`\r\n }\r\n\r\n path = `https://${hostName}/api`\r\n }\r\n\r\n return path\r\n}\r\n\r\nconst serverUri = getApiUrl()\r\n\r\nclass RestApi {\r\n async getModels() {\r\n const result = await axios.get(`${serverUri}/Configurations/GetModels`)\r\n return result.data || []\r\n }\r\n\r\n async getCameraSelectLists() {\r\n const result = await axios.get(`${serverUri}/CameraLine/GetSelectLists`)\r\n return result.data || []\r\n }\r\n\r\n async calculateCameraDataRate(cameraLine: CameraLine) {\r\n const result = await axios.post(\r\n `${serverUri}/CameraLine/CalculateDataRate`,\r\n cameraLine\r\n )\r\n return result.data\r\n }\r\n\r\n async calculateRecommendations(data: DataForRecommendations) {\r\n const result = await axios.post(\r\n `${serverUri}/Configurations/CalculateRecommendations`,\r\n data\r\n )\r\n return result.data || []\r\n }\r\n\r\n async logInToWebsite() {\r\n try {\r\n const result = await axios.get(\r\n `${serverUri}/authentication/client-redirect-url`\r\n )\r\n const redirectUri = result.data\r\n window.top.location.replace(redirectUri)\r\n } catch (error) {\r\n console.error(error)\r\n }\r\n }\r\n\r\n async getUserInfo() {\r\n const result = await axios.get(`${serverUri}/authentication/me`)\r\n return result.data || {}\r\n }\r\n\r\n async logOut() {\r\n const result = await axios.get(`${serverUri}/authentication/logout`)\r\n window.location.href = `https://${window.location.hostname.replace('huskycalculator', 'www')}/my-milestone`\r\n return result.data || {}\r\n }\r\n\r\n async getProject(projectId: string) {\r\n try {\r\n const result = await axios.get(`${serverUri}/projects/${projectId}`)\r\n return result.data\r\n } catch (error) {\r\n console.error(error)\r\n throw error\r\n }\r\n }\r\n\r\n async updateProject(project: ServerProject) {\r\n try {\r\n const result = await axios.put(`${serverUri}/projects`, project)\r\n return result.data\r\n } catch (error) {\r\n console.error(error)\r\n throw error\r\n }\r\n }\r\n\r\n async listProjects(): Promise<ProjectHeader[]> {\r\n try {\r\n const result = await axios.get(`${serverUri}/projects`)\r\n\r\n return result.data.map(header => ({\r\n ...header,\r\n created: new Date(header.created),\r\n modified: new Date(header.modified),\r\n }))\r\n } catch (error) {\r\n console.error(error)\r\n return []\r\n }\r\n }\r\n\r\n async deleteProject(projectId: string): Promise<void> {\r\n try {\r\n await axios.delete(`${serverUri}/projects/${projectId}`)\r\n } catch (error) {\r\n console.error(error)\r\n }\r\n }\r\n\r\n async duplicateProject(projectId: string): Promise<void> {\r\n try {\r\n await axios.post(`${serverUri}/projects/duplicate/${projectId}`)\r\n } catch (error) {\r\n console.error(error)\r\n }\r\n }\r\n\r\n async listAdminProjects(): Promise<ProjectHeader[]> {\r\n try {\r\n const result = await axios.get(`${serverUri}/projectsadmin`)\r\n\r\n return result.data.map(header => ({\r\n ...header,\r\n created: new Date(header.created),\r\n modified: new Date(header.modified),\r\n }))\r\n } catch (error) {\r\n console.error(error)\r\n return []\r\n }\r\n }\r\n\r\n async changeProjectReference(\r\n projectId: string,\r\n newReference: string\r\n ): Promise<void> {\r\n newReference = encodeURIComponent(newReference)\r\n await axios.post(`${serverUri}/projects/${projectId}/name/${newReference}`)\r\n }\r\n}\r\n\r\nexport default new RestApi()\r\n","// @flow\r\n\r\nexport const userRoleChangedType = 'USER_ROLE_CHANGED'\r\nexport type UserRoleChangedAction = {\r\n type: 'USER_ROLE_CHANGED',\r\n role: string,\r\n}\r\n\r\ntype User = {\r\n id: number,\r\n role: string,\r\n}\r\n\r\nexport const userChangedType = 'USER_CHANGED'\r\nexport type UserChangedAction = {\r\n type: 'USER_CHANGED',\r\n user: User,\r\n}\r\n\r\nexport const authenticationChangedType = 'AUTHENTICATION_CHANGED'\r\nexport type AuthenticationChangedAction = {\r\n type: authenticationChangedType,\r\n isAuthenticated: boolean,\r\n}\r\n\r\nexport const actionCreators = {\r\n userRoleChanged(userRole: string): UserRoleChangedAction {\r\n return { type: userRoleChangedType, role: userRole }\r\n },\r\n userChanged(user: User) {\r\n return { type: userChangedType, user }\r\n },\r\n authenticationChanged(isAuthenticated: boolean): AuthenticationChangedAction {\r\n return { type: authenticationChangedType, isAuthenticated }\r\n },\r\n}\r\n","// @flow\r\n\r\nimport restApi from '../api/restApi'\r\nimport {\r\n updateRecommendations,\r\n updateProject,\r\n} from './RecommendationState/updateRecommendations'\r\nimport { userChangedType } from './Login/ActionCreators'\r\n\r\nimport type {\r\n DataForRecommendations,\r\n NvrAttribute,\r\n ProjectDetails,\r\n ServerProject,\r\n ServerFilter,\r\n} from '../api/restTypes'\r\n\r\nexport type Sku = {\r\n model: string,\r\n storageConfigurations: string[],\r\n attributes: NvrAttribute[],\r\n}\r\n\r\nconst updateRecommendationsType = 'UPDATE_RECOMMENDATIONS'\r\nexport type RecommendationsAction = {\r\n type: 'UPDATE_RECOMMENDATIONS',\r\n recommendations: any,\r\n}\r\n\r\nconst modelsLoadingType = 'PRODUCT_OPTIONS_MODELS_LOADING'\r\ntype LoadingAction = {\r\n type: 'PRODUCT_OPTIONS_MODELS_LOADING',\r\n}\r\n\r\nconst modelsLoadedType = 'PRODUCT_OPTIONS_MODELS_LOADED'\r\ntype ModelsLoadedAction = {\r\n type: 'PRODUCT_OPTIONS_MODELS_LOADED',\r\n skus: Sku[],\r\n serverFilter: ServerFilter,\r\n}\r\n\r\nconst recommendationsLoadingType = 'LOADING_RECOMMENDATIONS'\r\nexport type RecommendationsLoadingAction = {\r\n type: 'LOADING_RECOMMENDATIONS',\r\n}\r\n\r\nconst projectLoadingType = 'PROJECT_LOADING'\r\nexport type ProjectLoadingAction = {\r\n type: 'PROJECT_LOADING',\r\n}\r\n\r\nconst projectLoadedType = 'PROJECT_LOADED'\r\nexport type ProjectLoadedAction = {\r\n type: 'PROJECT_LOADED',\r\n project: ServerProject,\r\n}\r\n\r\nconst updateProjectDetailsType = 'UPDATE_PROJECT_DETAILS'\r\nexport type UpdateProjectDetailsAction = {\r\n type: 'UPDATE_PROJECT_DETAILS',\r\n projectDetails: ProjectDetails,\r\n}\r\n\r\nexport const types = {\r\n updateRecommendationsType,\r\n modelsLoadingType,\r\n modelsLoadedType,\r\n recommendationsLoadingType,\r\n projectLoadingType,\r\n projectLoadedType,\r\n updateProjectDetailsType,\r\n}\r\n\r\nexport type ProjectAction =\r\n | RecommendationsAction\r\n | LoadingAction\r\n | ModelsLoadedAction\r\n | RecommendationsLoadingAction\r\n | ProjectLoadedAction\r\n | ProjectLoadingAction\r\n | UpdateProjectDetailsAction\r\n\r\nexport type ProjectState = {\r\n skus: Sku[],\r\n modelsLoading: boolean,\r\n projectLoading: boolean,\r\n loadingRecommendations: boolean,\r\n projectId: ?string,\r\n projectDetails: ProjectDetails,\r\n projectCustomerId: ?number,\r\n currentCustomerId: ?number,\r\n}\r\n\r\ntype GetState = () => {\r\n recommendationState: DataForRecommendations,\r\n project: ProjectState,\r\n}\r\ntype PromiseAction = Promise<ProjectAction>\r\ntype Dispatch = (action: ProjectAction | ThunkAction | PromiseAction) => any // eslint-disable-line no-use-before-define\r\ntype ThunkAction = (dispatch: Dispatch, getState: GetState) => any\r\n\r\nexport const actionCreators = {\r\n loadModels(): ThunkAction {\r\n return async (dispatch, getState) => {\r\n dispatch({ type: modelsLoadingType })\r\n\r\n const skus = await restApi.getModels()\r\n const serverFilter = getState().recommendationState.serverFilter\r\n\r\n dispatch({ type: modelsLoadedType, skus, serverFilter })\r\n }\r\n },\r\n loadProject: (projectId: string) => async (\r\n dispatch: Dispatch,\r\n getState: GetState\r\n ) => {\r\n dispatch({ type: projectLoadingType })\r\n\r\n const project = await restApi.getProject(projectId)\r\n\r\n dispatch({ type: projectLoadedType, project })\r\n updateRecommendations(dispatch, getState)\r\n },\r\n updateProjectDetails: (projectDetails: ProjectDetails) => async (\r\n dispatch: Dispatch,\r\n getState: GetState\r\n ) => {\r\n dispatch({ type: updateProjectDetailsType, projectDetails })\r\n await updateProject(getState)\r\n },\r\n}\r\n\r\nconst initialState: ProjectState = {\r\n modelsLoading: true,\r\n projectLoading: false,\r\n loadingRecommendations: true,\r\n skus: [],\r\n projectId: null,\r\n projectDetails: {\r\n projectReference: '',\r\n message: '',\r\n telephoneNumber: '',\r\n distributor: 'Other',\r\n timeFrameEndDate: new Date().toISOString().slice(0, 10),\r\n },\r\n projectCustomerId: null,\r\n currentCustomerId: null,\r\n}\r\n\r\nexport function reducer(\r\n state: ProjectState,\r\n action: ProjectAction\r\n): ProjectState {\r\n state = state || initialState\r\n\r\n if (action.type === recommendationsLoadingType) {\r\n return {\r\n ...state,\r\n loadingRecommendations: true,\r\n }\r\n } else if (action.type === updateRecommendationsType) {\r\n return {\r\n ...state,\r\n recommendations: action.recommendations,\r\n loadingRecommendations: false,\r\n }\r\n } else if (action.type === modelsLoadingType) {\r\n return {\r\n ...state,\r\n modelsLoading: true,\r\n loading: true,\r\n }\r\n } else if (action.type === modelsLoadedType) {\r\n return {\r\n ...state,\r\n modelsLoading: false,\r\n loading: state.projectLoading,\r\n skus: action.skus,\r\n }\r\n } else if (action.type === projectLoadingType) {\r\n return {\r\n ...state,\r\n projectLoading: true,\r\n loading: true,\r\n }\r\n } else if (action.type === projectLoadedType) {\r\n return {\r\n ...state,\r\n projectLoading: false,\r\n loading: state.modelsLoading,\r\n projectId: action.project.id,\r\n projectDetails: action.project.projectDetails,\r\n projectCustomerId: action.project.customerId,\r\n }\r\n } else if (action.type === updateProjectDetailsType) {\r\n return {\r\n ...state,\r\n projectDetails: action.projectDetails,\r\n }\r\n } else if (action.type === userChangedType) {\r\n return {\r\n ...state,\r\n currentCustomerId: action.user.id,\r\n }\r\n }\r\n\r\n return state\r\n}\r\n","export default function (callback, intervalMs) {\r\n let updateTaskId\r\n\r\n return (...args) => {\r\n clearTimeout(updateTaskId)\r\n updateTaskId = setTimeout(() => callback(...args), intervalMs)\r\n }\r\n}\r\n","// @flow\r\n\r\nimport type {\r\n RecommendationsLoadingAction,\r\n RecommendationsAction,\r\n} from '../ProjectStore'\r\nimport type { DataForRecommendations } from '../../api/restTypes'\r\nimport type { ProjectState } from '../ProjectStore'\r\n\r\nimport restApi from '../../api/restApi'\r\nimport { types as appTypes } from '../ProjectStore'\r\nimport callOnceAfterInterval from '../../util/callOnceAfterInterval'\r\n\r\ntype UpdateRecommendationsAction =\r\n | RecommendationsAction\r\n | RecommendationsLoadingAction\r\n\r\ntype GetState = () => {\r\n recommendationState: DataForRecommendations,\r\n project: ProjectState,\r\n}\r\ntype PromiseAction = Promise<UpdateRecommendationsAction>\r\n// eslint-disable-next-line no-use-before-define\r\ntype ThunkAction = (dispatch: Dispatch, getState: GetState) => any\r\ntype Dispatch = (\r\n action: UpdateRecommendationsAction | ThunkAction | PromiseAction\r\n) => any\r\n\r\nconst updateAfterOneSecond = callOnceAfterInterval(\r\n async (\r\n data: DataForRecommendations,\r\n dispatch: Dispatch,\r\n getState: GetState\r\n ) => {\r\n let recommendations = []\r\n if (data.cameraLines != null && data.cameraLines.length > 0) {\r\n recommendations = await restApi.calculateRecommendations(data)\r\n }\r\n\r\n await updateProject(getState)\r\n\r\n const recommendationsAction: RecommendationsAction = {\r\n type: appTypes.updateRecommendationsType,\r\n recommendations,\r\n }\r\n dispatch(recommendationsAction)\r\n },\r\n 1000\r\n)\r\n\r\nexport const updateRecommendations = (\r\n dispatch: Dispatch,\r\n getState: GetState\r\n) => {\r\n dispatch({ type: appTypes.recommendationsLoadingType })\r\n\r\n const data = getState().recommendationState\r\n updateAfterOneSecond(data, dispatch, getState)\r\n}\r\n\r\nexport const updateProject = async (getState: GetState) => {\r\n const fullState = getState()\r\n\r\n if (\r\n fullState.project.projectCustomerId !== fullState.project.currentCustomerId\r\n ) {\r\n return\r\n }\r\n\r\n const updateReq = {\r\n id: fullState.project.projectId,\r\n cameraLines: fullState.recommendationState.cameraLines,\r\n serverFilter: fullState.recommendationState.serverFilter,\r\n resourceUsage: fullState.recommendationState.resourceUsage,\r\n projectDetails: fullState.project.projectDetails,\r\n }\r\n\r\n await restApi.updateProject(updateReq)\r\n}\r\n","// @flow\r\n\r\nimport type { DataForRecommendations, CameraLine } from '../../api/restTypes'\r\nimport type {\r\n RecommendationsLoadingAction,\r\n RecommendationsAction,\r\n ProjectState,\r\n} from '../ProjectStore'\r\n\r\nimport { updateRecommendations } from './updateRecommendations'\r\n\r\nconst updateDiskStoragePercentage = 'UPDATE_DISK_STORAGE_PERCENTAGE'\r\nexport type UpdateDiskStoragePercentageAction = {\r\n type: 'UPDATE_DISK_STORAGE_PERCENTAGE',\r\n newPercentage: number,\r\n}\r\n\r\nconst updateDataRatePercentage = 'UPDATE_DATA_RATE_PERCENTAGE'\r\nexport type UpdateDataRatePercentageAction = {\r\n type: 'UPDATE_DATA_RATE_PERCENTAGE',\r\n newPercentage: number,\r\n}\r\n\r\nconst updateNumberOfCamerasPercentage = 'UPDATE_NUMBER_OF_CAMERAS_PERCENTAGE'\r\nexport type UpdateNumberOfCamerasPercentageAction = {\r\n type: 'UPDATE_NUMBER_OF_CAMERAS_PERCENTAGE',\r\n newPercentage: number,\r\n}\r\n\r\nconst addCameraLine = 'ADD_CAMERA_LINE'\r\nexport type AddCameraLineAction = {\r\n type: 'ADD_CAMERA_LINE',\r\n cameraLine: CameraLine,\r\n}\r\n\r\nconst removeCameraLine = 'REMOVE_CAMERA_LINE'\r\nexport type RemoveCameraLineAction = {\r\n type: 'REMOVE_CAMERA_LINE',\r\n index: number,\r\n}\r\n\r\nconst updateCameraLine = 'UPDATE_CAMERA_LINE'\r\nexport type UpdateCameraLineAction = {\r\n type: 'UPDATE_CAMERA_LINE',\r\n index: number,\r\n cameraLine: CameraLine,\r\n}\r\n\r\nconst updateServerModels = 'UPDATE_SERVER_MODEL_FILTER'\r\nexport type UpdateServerModelsAction = {\r\n type: 'UPDATE_SERVER_MODEL_FILTER',\r\n models: string[],\r\n}\r\n\r\nconst removeServerModel = 'REMOVE_SERVER_MODEL_FILTER'\r\nexport type RemoveServerModelAction = {\r\n type: 'REMOVE_SERVER_MODEL_FILTER',\r\n index: number,\r\n}\r\n\r\nconst updateStorageConfiguration = 'UPDATE_STORAGE_CONFIGURATION'\r\nexport type UpdateStorageConfigurationAction = {\r\n type: 'UPDATE_STORAGE_CONFIGURATION',\r\n newStorageConfig: string,\r\n}\r\n\r\nconst updateServerAttribute = 'UPDATE_SERVER_ATTRIBUTE'\r\nexport type UpdateServerAttributeAction = {\r\n type: 'UPDATE_SERVER_ATTRIBUTE',\r\n attributeId: number,\r\n selectedOptions: string[],\r\n}\r\n\r\nexport type RecommendationStateAction =\r\n | UpdateDiskStoragePercentageAction\r\n | UpdateDataRatePercentageAction\r\n | UpdateNumberOfCamerasPercentageAction\r\n | AddCameraLineAction\r\n | RemoveCameraLineAction\r\n | UpdateCameraLineAction\r\n | UpdateServerModelsAction\r\n | RemoveServerModelAction\r\n | UpdateStorageConfigurationAction\r\n | UpdateServerAttributeAction\r\n | RecommendationsAction\r\n | RecommendationsLoadingAction\r\n\r\ntype GetState = () => {\r\n recommendationState: DataForRecommendations,\r\n project: ProjectState,\r\n}\r\ntype PromiseAction = Promise<RecommendationStateAction>\r\n// eslint-disable-next-line no-use-before-define\r\ntype ThunkAction = (dispatch: Dispatch, getState: GetState) => any | void\r\ntype Dispatch = (\r\n action: RecommendationStateAction | ThunkAction | PromiseAction\r\n) => any\r\n\r\nexport const types = {\r\n updateDiskStoragePercentage,\r\n updateDataRatePercentage,\r\n updateNumberOfCamerasPercentage,\r\n addCameraLine,\r\n removeCameraLine,\r\n updateCameraLine,\r\n updateServerModels,\r\n removeServerModel,\r\n updateStorageConfiguration,\r\n updateServerAttribute,\r\n}\r\n\r\nexport const actionCreators = {\r\n diskStoragePercentageUpdated(newPercentage: number): ThunkAction {\r\n return (dispatch, getState) => {\r\n if (isEditingDisabled(getState())) return\r\n\r\n dispatch({ type: updateDiskStoragePercentage, newPercentage })\r\n updateRecommendations(dispatch, getState)\r\n }\r\n },\r\n dataRatePercentageUpdated(newPercentage: number): ThunkAction {\r\n return (dispatch, getState) => {\r\n if (isEditingDisabled(getState())) return\r\n\r\n dispatch({ type: updateDataRatePercentage, newPercentage })\r\n updateRecommendations(dispatch, getState)\r\n }\r\n },\r\n numberOfCamerasPercentageUpdated(newPercentage: number): ThunkAction {\r\n return (dispatch, getState) => {\r\n if (isEditingDisabled(getState())) return\r\n\r\n dispatch({ type: updateNumberOfCamerasPercentage, newPercentage })\r\n updateRecommendations(dispatch, getState)\r\n }\r\n },\r\n cameraLineAdded(cameraLine: CameraLine): ThunkAction {\r\n return (dispatch, getState) => {\r\n if (isEditingDisabled(getState())) return\r\n\r\n dispatch({ type: addCameraLine, cameraLine })\r\n updateRecommendations(dispatch, getState)\r\n }\r\n },\r\n cameraLineRemoved(index: number): ThunkAction {\r\n return (dispatch, getState) => {\r\n if (isEditingDisabled(getState())) return\r\n\r\n dispatch({ type: removeCameraLine, index })\r\n updateRecommendations(dispatch, getState)\r\n }\r\n },\r\n cameraLineUpdated(index: number, cameraLine: CameraLine): ThunkAction {\r\n return (dispatch, getState) => {\r\n if (isEditingDisabled(getState())) return\r\n\r\n dispatch({ type: updateCameraLine, index, cameraLine })\r\n updateRecommendations(dispatch, getState)\r\n }\r\n },\r\n serverModelsUpdated(models: string[]): ThunkAction {\r\n return (dispatch, getState) => {\r\n if (isEditingDisabled(getState())) return\r\n\r\n dispatch({ type: updateServerModels, models })\r\n updateRecommendations(dispatch, getState)\r\n }\r\n },\r\n storageConfigurationUpdated(newStorageConfig: string): ThunkAction {\r\n return (dispatch, getState) => {\r\n if (isEditingDisabled(getState())) return\r\n\r\n dispatch({ type: updateStorageConfiguration, newStorageConfig })\r\n updateRecommendations(dispatch, getState)\r\n }\r\n },\r\n serverAttributeUpdated(\r\n attributeId: number,\r\n selectedOptions: string[]\r\n ): ThunkAction {\r\n return (dispatch, getState) => {\r\n if (isEditingDisabled(getState())) return\r\n\r\n dispatch({ type: updateServerAttribute, attributeId, selectedOptions })\r\n updateRecommendations(dispatch, getState)\r\n }\r\n },\r\n}\r\n\r\nfunction isEditingDisabled(state) {\r\n return state.project.projectCustomerId !== state.project.currentCustomerId\r\n}\r\n","import restApi from '../api/restApi'\r\n\r\nimport {\r\n actionCreators as recommendationsActions,\r\n types as recommendationsTypes,\r\n} from './RecommendationState/ActionCreators'\r\nimport { types as appTypes } from './ProjectStore'\r\nimport callOnceAfterInterval from '../util/callOnceAfterInterval'\r\n\r\nconst getConfigurationLoadingType = 'GET_SELECT_LISTS_LOADING'\r\nconst getConfigurationLoadedType = 'GET_SELECT_LISTS_LOADED'\r\nconst loadingType = 'CAMERA_LINE_LOADING'\r\nconst cameraLinesUpdatedType = 'CAMERA_LINES_UPDATED'\r\n\r\nexport const types = {\r\n cameraLinesUpdatedType,\r\n}\r\n\r\nconst getDefaultCameraRow = ({\r\n codecList,\r\n imageComplexityList,\r\n resolutionList,\r\n}) => ({\r\n cameras: 1,\r\n operation: 24,\r\n recording: 20,\r\n days: 30,\r\n codec: codecList[1] || '',\r\n imageComplexity: imageComplexityList[1] || '',\r\n resolution: resolutionList[2] || '',\r\n fps: 10,\r\n dataRate: 0,\r\n notes: '',\r\n})\r\n\r\nconst initialState = {\r\n fetchConfig: true,\r\n loading: true,\r\n codecList: [],\r\n resolutionList: [],\r\n imageComplexityList: [],\r\n}\r\n\r\nconst updateAfterDelay = callOnceAfterInterval(\r\n async (dispatch, rowIndex, updatedRow, shouldUpdateDataRate, getState) => {\r\n if (shouldUpdateDataRate) {\r\n const rowToApi = {\r\n ...updatedRow,\r\n imageComplexity: updatedRow.imageComplexity.toString(),\r\n resolution: updatedRow.resolution.toString(),\r\n dataRate: parseFloat(updatedRow.dataRate),\r\n }\r\n\r\n const dataRate = await restApi.calculateCameraDataRate(rowToApi)\r\n const rowToState = { ...updatedRow, dataRate }\r\n dispatch(recommendationsActions.cameraLineUpdated(rowIndex, rowToState))\r\n } else {\r\n dispatch(recommendationsActions.cameraLineUpdated(rowIndex, updatedRow))\r\n }\r\n\r\n dispatch({\r\n type: cameraLinesUpdatedType,\r\n cameraLines: getState().recommendationState.cameraLines,\r\n })\r\n },\r\n 500\r\n)\r\n\r\nexport const actionCreators = {\r\n addFirstRow: () => async (dispatch, getState) => {\r\n if (getState().recommendationState.cameraLines.length > 0) {\r\n return\r\n }\r\n\r\n await actionCreators.addRow()(dispatch, getState)\r\n },\r\n fetchConfig: () => async (dispatch, getState) => {\r\n dispatch({ type: getConfigurationLoadingType })\r\n\r\n const lists = await restApi.getCameraSelectLists()\r\n const {\r\n codecList = [],\r\n resolutionList = [],\r\n imageComplexityList = [],\r\n } = lists\r\n\r\n dispatch({\r\n type: getConfigurationLoadedType,\r\n codecList,\r\n resolutionList,\r\n imageComplexityList,\r\n })\r\n },\r\n addRow: () => async (dispatch, getState) => {\r\n const state = getState().cameras\r\n\r\n const row = getDefaultCameraRow({\r\n codecList: state.codecList ?? [],\r\n resolutionList: state.resolutionList ?? [],\r\n imageComplexityList: state.imageComplexityList ?? [],\r\n })\r\n\r\n const dataRate = await restApi.calculateCameraDataRate(row)\r\n row.dataRate = dataRate\r\n\r\n dispatch(recommendationsActions.cameraLineAdded(row))\r\n\r\n dispatch({\r\n type: cameraLinesUpdatedType,\r\n cameraLines: getState().recommendationState.cameraLines,\r\n })\r\n },\r\n removeRow: index => async (dispatch, getState) => {\r\n dispatch(recommendationsActions.cameraLineRemoved(index))\r\n\r\n dispatch({\r\n type: cameraLinesUpdatedType,\r\n cameraLines: getState().recommendationState.cameraLines,\r\n })\r\n },\r\n fieldUpdated: (rowIndex, field, newValue) => async (dispatch, getState) => {\r\n const state = getState().recommendationState\r\n const oldRow = state.cameraLines[rowIndex]\r\n const updatedRow = { ...oldRow }\r\n if (oldRow.hasOwnProperty(field)) {\r\n if (oldRow[field].hasOwnProperty('selected')) {\r\n updatedRow[field] = Object.assign(oldRow[field], { selected: newValue })\r\n } else {\r\n updatedRow[field] = newValue\r\n }\r\n }\r\n\r\n dispatch({\r\n type: recommendationsTypes.updateCameraLine,\r\n index: rowIndex,\r\n cameraLine: updatedRow,\r\n })\r\n dispatch({ type: appTypes.recommendationsLoadingType })\r\n\r\n const shouldUpdateDataRate =\r\n ['resolution', 'codec', 'imageComplexity', 'fps'].indexOf(field) !== -1\r\n updateAfterDelay(\r\n dispatch,\r\n rowIndex,\r\n updatedRow,\r\n shouldUpdateDataRate,\r\n getState\r\n )\r\n },\r\n}\r\n\r\nexport const reducer = (state, action) => {\r\n state = state || initialState\r\n\r\n if (action.type === loadingType) {\r\n return {\r\n ...state,\r\n loading: true,\r\n }\r\n }\r\n\r\n if (action.type === getConfigurationLoadingType) {\r\n if (state.fetchConfig) {\r\n return {\r\n ...state,\r\n codecList: [],\r\n resolutionList: [],\r\n imageComplexityList: [],\r\n loading: true,\r\n fetchConfig: false,\r\n }\r\n }\r\n }\r\n\r\n if (action.type === getConfigurationLoadedType) {\r\n const { codecList, resolutionList, imageComplexityList } = action\r\n return {\r\n ...state,\r\n codecList,\r\n resolutionList,\r\n imageComplexityList,\r\n loading: false,\r\n }\r\n }\r\n\r\n return state\r\n}\r\n","// @flow\r\n\r\nimport type { CameraLine } from './restTypes'\r\n\r\nexport const getConfigSummary = (dataRows: CameraLine[]) => {\r\n const sum = (prev, next) => prev + next\r\n const numberOfCameras = dataRows\r\n .map(cr => cr.cameras)\r\n .reduce(sum, 0)\r\n const totalBitrate = dataRows\r\n .map(cr => cr.dataRate * cr.cameras)\r\n .reduce(sum, 0)\r\n const totalStorage = dataRows\r\n .map(\r\n cr =>\r\n cr.dataRate *\r\n cr.cameras *\r\n (cr.operation * 60 * 60) *\r\n (cr.recording / 100) *\r\n cr.days\r\n )\r\n .reduce(sum, 0)\r\n\r\n return {\r\n numberOfCameras,\r\n totalBitrate,\r\n totalStorage,\r\n }\r\n}\r\n","export const CONVERSION_BASE = 1000\r\n\r\nexport function prettifyBitrate(bitrateKbps) {\r\n if (bitrateKbps / CONVERSION_BASE / CONVERSION_BASE >= 1) {\r\n return `${(bitrateKbps / CONVERSION_BASE / CONVERSION_BASE).toFixed(\r\n 2\r\n )} Gbit/sec`\r\n } else if (bitrateKbps / CONVERSION_BASE >= 1) {\r\n return `${(bitrateKbps / CONVERSION_BASE).toFixed(2)} Mbit/sec`\r\n } else {\r\n return `${Math.round(bitrateKbps)} kbit/sec`\r\n }\r\n}\r\n\r\nexport function prettifyStorage(storageKbit) {\r\n const storageKbyte = storageKbit / 8\r\n if (storageKbyte / Math.pow(CONVERSION_BASE, 3) >= 1) {\r\n return `${(storageKbyte / Math.pow(CONVERSION_BASE, 3)).toFixed(2)} TB`\r\n } else if (storageKbyte / Math.pow(CONVERSION_BASE, 2) >= 1) {\r\n return `${(storageKbyte / Math.pow(CONVERSION_BASE, 2)).toFixed(2)} GB`\r\n } else {\r\n return `${Math.round(storageKbyte / CONVERSION_BASE)} MB`\r\n }\r\n}\r\n\r\nexport function prettifyPrice(price) {\r\n if (typeof price !== 'number') {\r\n return ''\r\n }\r\n\r\n const formattedPrice = price.toLocaleString(undefined, {\r\n style: 'currency',\r\n currency: 'EUR',\r\n currencyDisplay: 'symbol',\r\n useGrouping: true,\r\n })\r\n return formattedPrice\r\n}\r\n","import type { UserRoleChangedAction } from '../Login/ActionCreators'\r\nimport type { CameraLine } from '../../api/restTypes'\r\nimport { userRoleChangedType } from '../Login/ActionCreators'\r\nimport { types as camTypes } from '../AddCamerasStore'\r\nimport { types as projectTypes } from '../ProjectStore'\r\nimport { getConfigSummary } from '../../api/ConfigSummary'\r\nimport { CONVERSION_BASE } from '../../api/prettifyNumbers'\r\ntype ProductRecommendationAction = UserRoleChangedAction\r\ntype ProductRecommendationsState = {\r\n totalBitrate: number,\r\n totalStorage: number,\r\n}\r\nconst initialState = {\r\n totalBitrate: 0,\r\n totalStorage: 0,\r\n}\r\nexport function reducer(\r\n state: ProductRecommendationsState,\r\n action: ProductRecommendationAction\r\n): ProductRecommendationsState {\r\n state = state || initialState\r\n if (action.type === userRoleChangedType) {\r\n return {\r\n ...state,\r\n }\r\n }\r\n if (action.type === camTypes.cameraLinesUpdatedType) {\r\n const { totalBitrate, totalStorage } = calculateTotalBitrateAndStorage(\r\n action.cameraLines\r\n )\r\n return {\r\n ...state,\r\n totalBitrate,\r\n totalStorage,\r\n }\r\n }\r\n if (action.type === projectTypes.projectLoadedType) {\r\n const { totalBitrate, totalStorage } = calculateTotalBitrateAndStorage(\r\n action.project.cameraLines\r\n )\r\n return {\r\n ...state,\r\n totalBitrate,\r\n totalStorage,\r\n }\r\n }\r\n return state\r\n}\r\nfunction calculateTotalBitrateAndStorage(cameraLines: CameraLine[]) {\r\n const summary = getConfigSummary(cameraLines)\r\n const totalBitrate = summary.totalBitrate / CONVERSION_BASE\r\n const totalStorage = summary.totalStorage / 8 / Math.pow(CONVERSION_BASE, 3)\r\n return {\r\n totalBitrate,\r\n totalStorage,\r\n }\r\n}\r\n","// @flow\r\n\r\nimport type { UserRoleChangedAction } from '../Login/ActionCreators'\r\nimport type { CameraLine } from '../../api/restTypes'\r\n\r\nimport { userRoleChangedType } from '../Login/ActionCreators'\r\nimport { types as recTypes } from '../RecommendationState/ActionCreators'\r\n\r\ntype OrderStatusAction = UserRoleChangedAction\r\n\r\ntype OrderStatusState = {\r\n cameraLines: CameraLine[],\r\n diskStoragePercentage: number,\r\n}\r\n\r\nconst initialState = {\r\n diskStoragePercentage: 90,\r\n}\r\n\r\nexport function reducer(\r\n state: OrderStatusState,\r\n action: OrderStatusAction\r\n): OrderStatusState {\r\n state = state || initialState\r\n\r\n if (action.type === userRoleChangedType) {\r\n return {\r\n ...state,\r\n }\r\n }\r\n\r\n if (action.type === recTypes.updateDiskStoragePercentage) {\r\n return {\r\n ...state,\r\n diskStoragePercentage: action.newPercentage,\r\n }\r\n }\r\n\r\n return state\r\n}\r\n","// @flow\r\n\r\nimport type { DataForRecommendations } from '../../api/restTypes'\r\nimport type { RecommendationStateAction } from './ActionCreators'\r\nimport type { ProjectAction } from '../ProjectStore'\r\n\r\nimport { types } from './ActionCreators'\r\nimport { types as projectTypes } from '../ProjectStore'\r\n\r\nexport const initialState: DataForRecommendations = {\r\n cameraLines: [],\r\n serverFilter: {\r\n models: [],\r\n storageConfiguration: 'STORAGE_CONFIGURATION_JBOD',\r\n attributes: [],\r\n },\r\n resourceUsage: {\r\n diskStoragePercentage: 90,\r\n dataRatePercentage: 90,\r\n numberOfCamerasPercentage: 100,\r\n },\r\n}\r\n\r\nexport function reducer(\r\n state: DataForRecommendations,\r\n action: RecommendationStateAction | ProjectAction\r\n): DataForRecommendations {\r\n state = state || initialState\r\n\r\n if (state.serverFilter.storageConfiguration == null) {\r\n state = {\r\n ...state,\r\n serverFilter: {\r\n ...state.serverFilter,\r\n storageConfiguration: 'STORAGE_CONFIGURATION_JBOD',\r\n },\r\n }\r\n }\r\n\r\n if (action.type === types.updateDiskStoragePercentage) {\r\n return {\r\n ...state,\r\n resourceUsage: {\r\n ...state.resourceUsage,\r\n diskStoragePercentage: action.newPercentage,\r\n },\r\n }\r\n }\r\n\r\n if (action.type === types.updateDataRatePercentage) {\r\n return {\r\n ...state,\r\n resourceUsage: {\r\n ...state.resourceUsage,\r\n dataRatePercentage: action.newPercentage,\r\n },\r\n }\r\n }\r\n\r\n if (action.type === types.updateNumberOfCamerasPercentage) {\r\n return {\r\n ...state,\r\n resourceUsage: {\r\n ...state.resourceUsage,\r\n numberOfCamerasPercentage: action.newPercentage,\r\n },\r\n }\r\n }\r\n\r\n if (action.type === types.addCameraLine) {\r\n return {\r\n ...state,\r\n cameraLines: [...state.cameraLines, action.cameraLine],\r\n }\r\n }\r\n\r\n if (action.type === types.removeCameraLine) {\r\n return {\r\n ...state,\r\n cameraLines: state.cameraLines.filter(\r\n (_, index) => index !== action.index\r\n ),\r\n }\r\n }\r\n\r\n if (action.type === types.updateCameraLine) {\r\n return {\r\n ...state,\r\n cameraLines: state.cameraLines.map((item, index) =>\r\n index !== action.index ? item : action.cameraLine\r\n ),\r\n }\r\n }\r\n\r\n if (action.type === types.updateServerModels) {\r\n return {\r\n ...state,\r\n serverFilter: {\r\n ...state.serverFilter,\r\n models: action.models.slice(),\r\n },\r\n }\r\n }\r\n\r\n if (action.type === types.removeServerModel) {\r\n return {\r\n ...state,\r\n serverFilter: {\r\n ...state.serverFilter,\r\n models: state.serverFilter.models.filter(\r\n (_, index) => index !== action.index\r\n ),\r\n },\r\n }\r\n }\r\n\r\n if (action.type === types.updateStorageConfiguration) {\r\n return {\r\n ...state,\r\n serverFilter: {\r\n ...state.serverFilter,\r\n storageConfiguration: action.newStorageConfig,\r\n },\r\n }\r\n }\r\n\r\n if (action.type === types.updateServerAttribute) {\r\n const updatedItem = {\r\n attributeId: action.attributeId,\r\n options: action.selectedOptions,\r\n }\r\n\r\n let newAttributes\r\n if (\r\n state.serverFilter.attributes.find(\r\n a => a.attributeId === action.attributeId\r\n ) == null\r\n ) {\r\n newAttributes = [...state.serverFilter.attributes, updatedItem]\r\n } else {\r\n newAttributes = state.serverFilter.attributes.map(item =>\r\n item.attributeId !== action.attributeId ? item : updatedItem\r\n )\r\n }\r\n\r\n return {\r\n ...state,\r\n serverFilter: {\r\n ...state.serverFilter,\r\n attributes: newAttributes,\r\n },\r\n }\r\n }\r\n\r\n if (action.type === projectTypes.projectLoadedType) {\r\n return {\r\n ...state,\r\n cameraLines: action.project.cameraLines,\r\n serverFilter: action.project.serverFilter,\r\n resourceUsage: action.project.resourceUsage,\r\n }\r\n }\r\n\r\n return state\r\n}\r\n","// @flow\r\n\r\nexport function deduplicate<T>(arrayWithDuplicates: T[]): T[] {\r\n return [...new Set(arrayWithDuplicates)]\r\n}\r\n\r\nexport function flatten<T>(features: T[][]): T[] {\r\n return features\r\n .filter(f => f != null && f.length > 0)\r\n .reduce((prev, current) => prev.concat(current), [])\r\n}\r\n\r\nexport function groupBy(xs: any, key: any) {\r\n return xs.reduce(function (rv, x) {\r\n const v = key instanceof Function ? key(x) : x[key]\r\n const el = rv.find(r => r && r.key === v)\r\n if (el) {\r\n el.values.push(x)\r\n } else {\r\n rv.push({\r\n key: v,\r\n values: [x],\r\n })\r\n }\r\n return rv\r\n }, [])\r\n}\r\n","// @flow\r\n\r\nimport { deduplicate, flatten } from '../util/arrayHelpers'\r\n\r\nimport type { ProductAttributeType } from '../components/ProductAttribute'\r\nimport type { NvrAttribute } from '../api/restTypes'\r\nimport type { SelectItem } from '../components/Project/Project'\r\n\r\nexport function parseAttributes(\r\n restAttributes: NvrAttribute[]\r\n): ProductAttributeType[] {\r\n const collator = new Intl.Collator(undefined, {\r\n numeric: true,\r\n sensitivity: 'base',\r\n })\r\n\r\n const parsedAttributes: ProductAttributeType[] = []\r\n const attributeIds = deduplicate(restAttributes.map(ra => ra.attributeId))\r\n\r\n for (const currentId of attributeIds) {\r\n const restAttributesWithCurrentId = restAttributes.filter(\r\n ra => ra.attributeId === currentId\r\n )\r\n const allOptions = flatten(\r\n restAttributesWithCurrentId.map(ra => ra.options)\r\n )\r\n\r\n const parsedAttribute = {\r\n attributeId: currentId.toString(),\r\n title: restAttributesWithCurrentId[0].name || '',\r\n options: deduplicate(allOptions)\r\n .sort(collator.compare)\r\n .map(optionToSelectItem),\r\n }\r\n\r\n parsedAttributes.push(parsedAttribute)\r\n }\r\n\r\n return parsedAttributes\r\n}\r\n\r\nfunction optionToSelectItem(option: string): SelectItem {\r\n return {\r\n name: option,\r\n enabled: true,\r\n selected: false,\r\n }\r\n}\r\n","// @flow\r\nimport type { Sku } from '../ProjectStore'\r\nimport type { ProductAttributeType } from '../../components/ProductAttribute'\r\nimport type { RecommendationStateAction } from '../RecommendationState/ActionCreators'\r\nimport type { ProjectAction } from '../ProjectStore'\r\n\r\nimport { flatten, deduplicate } from '../../util/arrayHelpers'\r\nimport { parseAttributes } from '../../attribute-handling/parseAttributes'\r\n\r\nimport { types as projTypes } from '../ProjectStore'\r\nimport { types as recTypes } from '../RecommendationState/ActionCreators'\r\n\r\nexport type ProductOptionsAction = ProjectAction | RecommendationStateAction\r\n\r\ntype SelectItem = {\r\n name: string,\r\n enabled: boolean,\r\n selected: boolean,\r\n}\r\n\r\nexport type ProductOptionsState = {\r\n attributes: ProductAttributeType[],\r\n storageConfigurations: SelectItem[],\r\n models: SelectItem[],\r\n loading: boolean,\r\n diskStoragePercentage: number,\r\n}\r\n\r\nconst initialState: ProductOptionsState = {\r\n attributes: [],\r\n storageConfigurations: [],\r\n models: [],\r\n loading: true,\r\n diskStoragePercentage: 90,\r\n}\r\n\r\nexport function reducer(\r\n state: ProductOptionsState,\r\n action: ProductOptionsAction\r\n): ProductOptionsState {\r\n state = state ?? initialState\r\n\r\n if (action.type === projTypes.modelsLoadedType) {\r\n const { skus } = action\r\n const models = updateSelectedModels(\r\n action.serverFilter.models,\r\n getModels(skus)\r\n )\r\n\r\n const attributesFromApi = flatten(skus.map(sku => sku.attributes))\r\n\r\n const parsedAttributes = parseAttributes(attributesFromApi)\r\n const filterAttributes = action.serverFilter.attributes.map(a => ({\r\n ...a,\r\n attributeId: a.attributeId.toString(),\r\n }))\r\n const attributes: ProductAttributeType[] = parsedAttributes.reduce(\r\n (aggregate, attribute) => {\r\n const attributeInFilters = filterAttributes.find(\r\n a => a.attributeId.toString() === attribute.attributeId\r\n )\r\n if (attributeInFilters == null) {\r\n return aggregate\r\n }\r\n\r\n return updateSelectedAttributes(attributeInFilters, aggregate)\r\n },\r\n parsedAttributes\r\n )\r\n\r\n const uniqueStorages = deduplicate(\r\n flatten(skus.map(m => m.storageConfigurations))\r\n )\r\n const storageConfigurations: SelectItem[] = uniqueStorages.map((s, i) => ({\r\n name: s,\r\n selected: false,\r\n enabled: true,\r\n }))\r\n\r\n return {\r\n ...state,\r\n loading: false,\r\n storageConfigurations,\r\n attributes,\r\n models,\r\n }\r\n }\r\n\r\n if (action.type === recTypes.updateServerModels) {\r\n const { models } = action\r\n\r\n const newModels = updateSelectedModels(models, state.models)\r\n\r\n return {\r\n ...state,\r\n models: newModels,\r\n }\r\n }\r\n\r\n if (action.type === recTypes.updateDiskStoragePercentage) {\r\n return {\r\n ...state,\r\n diskStoragePercentage: action.newPercentage,\r\n }\r\n }\r\n\r\n if (action.type === recTypes.updateServerAttribute) {\r\n const attributeId = action.attributeId.toString()\r\n\r\n const attribute: ?ProductAttributeType = state.attributes.find(\r\n a => a.attributeId === attributeId\r\n )\r\n if (attribute != null) {\r\n return {\r\n ...state,\r\n attributes: updateSelectedAttributes(\r\n { attributeId, options: action.selectedOptions },\r\n state.attributes\r\n ),\r\n }\r\n }\r\n }\r\n\r\n if (action.type === recTypes.updateStorageConfiguration) {\r\n return {\r\n ...state,\r\n storageConfigurations: state.storageConfigurations.map(sc => ({\r\n ...sc,\r\n selected: sc.name === action.newStorageConfig,\r\n })),\r\n }\r\n }\r\n\r\n if (action.type === projTypes.projectLoadedType) {\r\n const { serverFilter, resourceUsage } = action.project\r\n\r\n const newModels = updateSelectedModels(\r\n serverFilter?.models ?? [],\r\n state.models\r\n )\r\n\r\n const filterAttributes = (serverFilter?.attributes ?? []).map(a => ({\r\n ...a,\r\n attributeId: a.attributeId.toString(),\r\n }))\r\n const attributes: ProductAttributeType[] = state.attributes.reduce(\r\n (aggregate, attribute) => {\r\n const attributeInFilters = filterAttributes.find(\r\n a => a.attributeId.toString() === attribute.attributeId\r\n )\r\n if (attributeInFilters == null) {\r\n return aggregate\r\n }\r\n\r\n return updateSelectedAttributes(attributeInFilters, aggregate)\r\n },\r\n state.attributes\r\n )\r\n\r\n const storageConfigurations = state.storageConfigurations.map(sc => ({\r\n ...sc,\r\n selected: sc.name === serverFilter?.storageConfiguration,\r\n }))\r\n\r\n return {\r\n ...state,\r\n models: newModels,\r\n attributes,\r\n diskStoragePercentage:\r\n resourceUsage?.diskStoragePercentage ??\r\n initialState.diskStoragePercentage,\r\n storageConfigurations,\r\n }\r\n }\r\n\r\n return state\r\n}\r\n\r\nfunction mapSelectItem(name: string): SelectItem {\r\n return { name, enabled: true, selected: false }\r\n}\r\n\r\nfunction getModels(skus: Sku[]): SelectItem[] {\r\n const collator = new Intl.Collator(undefined, {\r\n numeric: true,\r\n sensitivity: 'base',\r\n })\r\n const uniqueModels = deduplicate(skus.map(sku => sku.model))\r\n return uniqueModels.sort(collator.compare).map(mapSelectItem)\r\n}\r\n\r\nfunction updateSelectedModels(models, modelsInState): SelectItem[] {\r\n const model = modelsInState.filter(model => models.includes(model.name))\r\n let modelsToChange: SelectItem[] = []\r\n if (Array.isArray(model)) {\r\n modelsToChange = model\r\n } else {\r\n modelsToChange = [model]\r\n }\r\n\r\n return modelsInState.map(model => {\r\n if (modelsToChange?.length === 0) {\r\n return {\r\n ...model,\r\n selected: false,\r\n }\r\n } else if (\r\n modelsToChange.filter(mtc => mtc.name === model.name).length > 0\r\n ) {\r\n return {\r\n ...model,\r\n selected: true,\r\n }\r\n } else {\r\n return model\r\n }\r\n })\r\n}\r\n\r\nfunction updateSelectedAttributes(\r\n attribute,\r\n attributesInState: ProductAttributeType[]\r\n) {\r\n const { attributeId, options } = attribute\r\n\r\n const oldAttribute = attributesInState.find(\r\n a => a.attributeId === attributeId\r\n )\r\n if (oldAttribute != null) {\r\n const newAttribute = { ...oldAttribute }\r\n newAttribute.options = newAttribute.options.map(option => ({\r\n ...option,\r\n selected: options.indexOf(option.name) !== -1,\r\n }))\r\n\r\n return attributesInState.map(a =>\r\n a.attributeId === attributeId ? newAttribute : a\r\n )\r\n }\r\n\r\n return attributesInState\r\n}\r\n","import { userRoleChangedType, userChangedType, authenticationChangedType } from './ActionCreators'\r\n\r\nconst initialState = {\r\n role: 'NotLoggedIn',\r\n id: null,\r\n isAuthenticated: false\r\n}\r\n\r\nexport function reducer(state, action): ProductOptionsState {\r\n state = state ?? initialState\r\n\r\n if (action.type === userRoleChangedType) {\r\n return {\r\n ...state,\r\n role: action.role,\r\n }\r\n }\r\n\r\n if (action.type === userChangedType) {\r\n return {\r\n ...state,\r\n role: action.user.role,\r\n id: action.user.id,\r\n }\r\n }\r\n\r\n if (action.type === authenticationChangedType) {\r\n return {\r\n ...state,\r\n isAuthenticated: action.isAuthenticated,\r\n }\r\n }\r\n\r\n return state\r\n}\r\n","export const showAllProjectsType = 'SHOW_ALL_PROJECTS'\r\nexport const showOwnProjectsType = 'SHOW_OWN_PROJECTS'\r\n\r\nexport const actionCreators = {\r\n showAllProjects() {\r\n return { type: showAllProjectsType }\r\n },\r\n showOwnProjects() {\r\n return { type: showOwnProjectsType }\r\n },\r\n}\r\n","import { showAllProjectsType, showOwnProjectsType } from './ActionCreators'\r\n\r\nconst initialState = {\r\n showAllProjects: false,\r\n}\r\n\r\nexport function reducer(state, action) {\r\n state = state ?? initialState\r\n\r\n if (action.type === showAllProjectsType) {\r\n return {\r\n ...state,\r\n showAllProjects: true,\r\n }\r\n } else if (action.type === showOwnProjectsType) {\r\n return {\r\n ...state,\r\n showAllProjects: false,\r\n }\r\n }\r\n\r\n return state\r\n}\r\n","import React from 'react'\r\nimport { useSelector } from 'react-redux'\r\n\r\nimport { getConfigSummary } from '../api/ConfigSummary'\r\nimport { prettifyBitrate, prettifyStorage } from '../api/prettifyNumbers'\r\n\r\nexport const ConfigSummaryTable = props => {\r\n const summary = getConfigSummary(props.cameraRows)\r\n const diskStoragePercentage = useSelector(\r\n store => store.productOptions.diskStoragePercentage\r\n )\r\n\r\n return (\r\n <div>\r\n <h5 style={{ fontWeight: 'bold' }}>Configuration summary</h5>\r\n <table width=\"300px\">\r\n <tbody>\r\n <tr>\r\n <td>IP Cameras:</td>\r\n <td align=\"right\">{+summary.numberOfCameras || 0}</td>\r\n </tr>\r\n <tr>\r\n <td>Data rate:</td>\r\n <td align=\"right\">{prettifyBitrate(summary.totalBitrate)}</td>\r\n </tr>\r\n <tr>\r\n <td>Storage required:</td>\r\n <td align=\"right\">{prettifyStorage(summary.totalStorage)}</td>\r\n </tr>\r\n <tr>\r\n <td>Storage incl. overhead:</td>\r\n <td align=\"right\">\r\n {prettifyStorage(\r\n summary.totalStorage / (diskStoragePercentage / 100)\r\n )}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n )\r\n}\r\n","import React from 'react'\r\nimport { Button, FormControl, Table } from 'react-bootstrap'\r\nimport { useTranslation } from 'react-i18next'\r\n\r\ntype Props = {\r\n columns: any[],\r\n data: any[],\r\n}\r\n\r\nexport default function (props: Props) {\r\n const { columns, data } = props\r\n const { t } = useTranslation()\r\n\r\n return (\r\n <Table className=\"table-responsive\" size=\"sm\">\r\n <thead>\r\n <tr>\r\n {columns.map(c => (\r\n <th\r\n style={{ fontWeight: 600, fontSize: '.9em', paddingLeft: 5 }}\r\n key={`${c.accessor || c.id}_head`}\r\n width={c.maxWidth}\r\n >\r\n {c.Header}\r\n </th>\r\n ))}\r\n </tr>\r\n </thead>\r\n <tbody>\r\n {data.map((row, i) => {\r\n return (\r\n <tr key={`row_${i}`}>\r\n {columns.map(c => (\r\n <td key={`${c.accessor || c.id}_${i}_cell`}>\r\n {renderCell(c, i, row[c.accessor], t)}\r\n </td>\r\n ))}\r\n </tr>\r\n )\r\n })}\r\n </tbody>\r\n </Table>\r\n )\r\n}\r\n\r\nfunction renderCell(column, rowIndex, value, t) {\r\n const { editable, accessor } = column\r\n\r\n if (editable != null) {\r\n if (editable.type === 'select') {\r\n return renderSelect(value, accessor, rowIndex, editable.options, t)\r\n } else if (editable.type === 'button') {\r\n return renderButton(rowIndex, editable.options)\r\n } else {\r\n return renderEditable(value, accessor, rowIndex, editable.options)\r\n }\r\n } else {\r\n return t(value)\r\n }\r\n}\r\n\r\nfunction renderButton(rowIndex, options) {\r\n return (\r\n <Button\r\n variant=\"danger\"\r\n style={{ borderRadius: 2 }}\r\n onClick={() => options.onClick({ index: rowIndex })}\r\n >\r\n <strong>✖</strong>\r\n </Button>\r\n )\r\n}\r\n\r\nfunction renderEditable(value, columnId, rowIndex, options) {\r\n const { onChange, minvalue, maxvalue, type, ...otherOptions } = options\r\n\r\n const cellId = `${columnId}${rowIndex}_control`\r\n const cellInfo = { index: rowIndex, column: { id: columnId } }\r\n if (type == null) {\r\n return (\r\n <input\r\n value={value}\r\n id={cellId}\r\n key={cellId}\r\n className=\"form-control\"\r\n onChange={event => {\r\n onChange(event.target.value, cellInfo)\r\n }}\r\n {...otherOptions}\r\n />\r\n )\r\n }\r\n\r\n return (\r\n <FormControl\r\n value={value}\r\n id={cellId}\r\n key={cellId}\r\n onChange={event => {\r\n if (type === 'number') {\r\n callIfWithinRange({\r\n event,\r\n maxvalue,\r\n minvalue,\r\n cellInfo,\r\n onChange,\r\n })\r\n } else {\r\n onChange(event.target.value, cellInfo)\r\n }\r\n }}\r\n {...otherOptions}\r\n />\r\n )\r\n}\r\n\r\nfunction renderSelect(value, columnId, rowIndex, cellOptions, t) {\r\n const { options, onChange, ...otherOptions } = cellOptions\r\n\r\n return (\r\n <FormControl\r\n as=\"select\"\r\n value={value}\r\n onChange={e =>\r\n onChange(e.target.value, { index: rowIndex, column: { id: columnId } })\r\n }\r\n {...otherOptions}\r\n >\r\n {options.map((o, i) => (\r\n <option value={o} key={`${columnId}${i}`}>\r\n {t(o)}\r\n </option>\r\n ))}\r\n </FormControl>\r\n )\r\n}\r\n\r\nfunction callIfWithinRange(options) {\r\n const {\r\n event,\r\n minvalue = Number.MIN_VALUE,\r\n maxvalue = Number.MAX_VALUE,\r\n onChange,\r\n cellInfo,\r\n } = options\r\n\r\n const value = parseFloat(event.target.value)\r\n if (!isNaN(value) && value.toString() === event.target.value) {\r\n if (value >= minvalue && value <= maxvalue) {\r\n onChange(value, cellInfo)\r\n }\r\n } else if (event.target.value === '') {\r\n onChange('', cellInfo)\r\n }\r\n}\r\n","// @flow\r\n\r\nimport React, { useEffect, useState } from 'react'\r\nimport { useDispatch, useSelector } from 'react-redux'\r\n\r\nimport { actionCreators } from '../store/AddCamerasStore'\r\nimport { ConfigSummaryTable } from './ConfigSummaryTable'\r\nimport EditableTable2 from './EditableTable2'\r\nimport sprites from '@milestone-sys/web-design-system/msds-spritemap.svg'\r\n\r\n\r\nimport type { CameraLine } from '../api/restTypes'\r\n\r\ntype AddCamerasProps = {\r\n resolutionList: string[],\r\n codecList: string[],\r\n imageComplexityList: string[],\r\n data: CameraLine[],\r\n cameraLinesChanged: (CameraLine[]) => void,\r\n addFirstRow: () => void,\r\n addRow: () => void,\r\n fieldUpdated: (number, any, any) => void,\r\n removeRow: number => void,\r\n t: string => string,\r\n loading: boolean,\r\n}\r\n\r\nconst getColumns = (\r\n resolutionList,\r\n codecList,\r\n imageComplexityList,\r\n dispatch\r\n) => [\r\n {\r\n id: 'removeRow',\r\n Header: '',\r\n maxWidth: 50,\r\n editable: {\r\n type: 'button',\r\n options: {\r\n onClick: cellInfo => dispatch(actionCreators.removeRow(cellInfo.index)),\r\n },\r\n },\r\n },\r\n {\r\n Header: 'Cameras',\r\n accessor: 'cameras',\r\n maxWidth: 100,\r\n editable: {\r\n options: {\r\n type: 'number',\r\n minvalue: 0,\r\n onChange: (newValue, cellInfo) =>\r\n dispatch(\r\n actionCreators.fieldUpdated(\r\n cellInfo.index,\r\n cellInfo.column.id,\r\n newValue\r\n )\r\n ),\r\n },\r\n },\r\n },\r\n {\r\n Header: 'Operation (hours)',\r\n accessor: 'operation',\r\n maxWidth: 150,\r\n editable: {\r\n options: {\r\n type: 'number',\r\n minvalue: 0,\r\n maxvalue: 24,\r\n onChange: (newValue, cellInfo) =>\r\n dispatch(\r\n actionCreators.fieldUpdated(\r\n cellInfo.index,\r\n cellInfo.column.id,\r\n newValue\r\n )\r\n ),\r\n },\r\n },\r\n },\r\n {\r\n Header: 'Recording (%)',\r\n accessor: 'recording',\r\n maxWidth: 120,\r\n editable: {\r\n options: {\r\n type: 'number',\r\n minvalue: 0,\r\n maxvalue: 100,\r\n onChange: (newValue, cellInfo) =>\r\n dispatch(\r\n actionCreators.fieldUpdated(\r\n cellInfo.index,\r\n cellInfo.column.id,\r\n newValue\r\n )\r\n ),\r\n },\r\n },\r\n },\r\n {\r\n Header: 'Days',\r\n accessor: 'days',\r\n maxWidth: 70,\r\n editable: {\r\n options: {\r\n type: 'number',\r\n minvalue: 0,\r\n onChange: (newValue, cellInfo) =>\r\n dispatch(\r\n actionCreators.fieldUpdated(\r\n cellInfo.index,\r\n cellInfo.column.id,\r\n newValue\r\n )\r\n ),\r\n },\r\n },\r\n },\r\n {\r\n Header: 'Codec',\r\n accessor: 'codec',\r\n maxWidth: 120,\r\n editable: {\r\n type: 'select',\r\n options: {\r\n options: codecList,\r\n onChange: (newValue, cellInfo) =>\r\n dispatch(\r\n actionCreators.fieldUpdated(\r\n cellInfo.index,\r\n cellInfo.column.id,\r\n newValue\r\n )\r\n ),\r\n },\r\n },\r\n },\r\n {\r\n Header: 'Image Complexity',\r\n accessor: 'imageComplexity',\r\n maxWidth: 140,\r\n editable: {\r\n type: 'select',\r\n options: {\r\n options: imageComplexityList,\r\n onChange: (newValue, cellInfo) =>\r\n dispatch(\r\n actionCreators.fieldUpdated(\r\n cellInfo.index,\r\n cellInfo.column.id,\r\n newValue\r\n )\r\n ),\r\n },\r\n },\r\n },\r\n {\r\n Header: 'Resolution',\r\n accessor: 'resolution',\r\n maxWidth: 220,\r\n editable: {\r\n type: 'select',\r\n options: {\r\n options: resolutionList,\r\n onChange: (newValue, cellInfo) =>\r\n dispatch(\r\n actionCreators.fieldUpdated(\r\n cellInfo.index,\r\n cellInfo.column.id,\r\n newValue\r\n )\r\n ),\r\n },\r\n },\r\n },\r\n {\r\n Header: 'FPS',\r\n accessor: 'fps',\r\n maxWidth: 70,\r\n editable: {\r\n options: {\r\n type: 'number',\r\n minvalue: 0,\r\n maxvalue: 200,\r\n onChange: (newValue, cellInfo) =>\r\n dispatch(\r\n actionCreators.fieldUpdated(\r\n cellInfo.index,\r\n cellInfo.column.id,\r\n newValue\r\n )\r\n ),\r\n },\r\n },\r\n },\r\n {\r\n Header: 'Data rate (kbit / sec)',\r\n accessor: 'dataRate',\r\n maxWidth: 180,\r\n editable: {\r\n options: {\r\n type: 'number',\r\n minvalue: 0,\r\n onChange: (newValue, cellInfo) =>\r\n dispatch(\r\n actionCreators.fieldUpdated(\r\n cellInfo.index,\r\n cellInfo.column.id,\r\n newValue\r\n )\r\n ),\r\n },\r\n },\r\n },\r\n {\r\n Header: 'Notes',\r\n accessor: 'notes',\r\n editable: {\r\n options: {\r\n onChange: (newValue, cellInfo) =>\r\n dispatch(\r\n actionCreators.fieldUpdated(\r\n cellInfo.index,\r\n cellInfo.column.id,\r\n newValue\r\n )\r\n ),\r\n },\r\n },\r\n },\r\n]\r\n\r\ntype Props = {\r\n editingDisabled: boolean,\r\n}\r\n\r\nexport default ({ editingDisabled }: Props) => {\r\n const dispatch = useDispatch()\r\n const state: AddCamerasProps = useSelector(state => state.cameras)\r\n const data: CameraLine[] = useSelector(\r\n state => state.recommendationState.cameraLines\r\n )\r\n const [addingFirstRow, setAddingFirstRow] = useState(false)\r\n\r\n const { resolutionList, codecList, imageComplexityList } = state\r\n\r\n useEffect(() => {\r\n dispatch(actionCreators.fetchConfig())\r\n }, [dispatch])\r\n\r\n useEffect(() => {\r\n const configLoaded =\r\n resolutionList.length !== 0 &&\r\n codecList.length !== 0 &&\r\n imageComplexityList.length !== 0\r\n if (!editingDisabled && configLoaded && !addingFirstRow) {\r\n setAddingFirstRow(true)\r\n dispatch(actionCreators.addFirstRow())\r\n }\r\n }, [\r\n addingFirstRow,\r\n dispatch,\r\n resolutionList,\r\n codecList,\r\n imageComplexityList,\r\n editingDisabled,\r\n ])\r\n\r\n let columns: any[] = getColumns(\r\n resolutionList,\r\n codecList,\r\n imageComplexityList,\r\n dispatch\r\n )\r\n if (editingDisabled) {\r\n columns = columns.map(column => ({ ...column, editable: undefined }))\r\n }\r\n\r\n return (\r\n <>\r\n {editingDisabled ? (\r\n ''\r\n ) : (\r\n <button\r\n className=\"addNewCameraLine msds-btn msds-btn--primary msds-btn--sm\"\r\n style={{ margin: 5, fontWeight: 'bold' }}\r\n onClick={() => dispatch(actionCreators.addRow())}\r\n >Add new line\r\n <div className=\"msds-icon\">\r\n <svg>\r\n <use xlinkHref={`${sprites}#plus`}></use>\r\n </svg>\r\n </div>\r\n </button>\r\n )}\r\n <EditableTable2 columns={columns} data={data} />\r\n <ConfigSummaryTable cameraRows={data} />\r\n </>\r\n )\r\n}\r\n","// @flow\r\n\r\nimport React, { Component } from 'react'\r\nimport { withTranslation } from 'react-i18next'\r\nimport { Button, ButtonGroup } from 'react-bootstrap'\r\nimport sprites from '@milestone-sys/web-design-system/msds-spritemap.svg'\r\n\r\nimport type { SelectItem } from './Project/Project'\r\nimport type { Element } from 'react'\r\n\r\nexport type ProductAttributeType = {\r\n title: string,\r\n attributeId: string,\r\n options: SelectItem[],\r\n}\r\n\r\ntype Props = {\r\n attribute: ProductAttributeType,\r\n onSelectOption: (optionName: string[]) => void,\r\n truncateList?: boolean,\r\n showRadio?: boolean,\r\n t: string => string,\r\n}\r\n\r\ntype State = {\r\n isTruncated: boolean,\r\n}\r\n\r\nclass ProductAttribute extends Component<Props, State> {\r\n constructor(props: Props) {\r\n super(props)\r\n this.clearAll = this.clearAll.bind(this)\r\n\r\n this.renderAll = this.renderAll.bind(this)\r\n this.renderSelected = this.renderSelected.bind(this)\r\n this.renderSingle = this.renderSingle.bind(this)\r\n\r\n this.state = {\r\n isTruncated: true,\r\n isChecked: true,\r\n }\r\n }\r\n\r\n toggleChange = () => {\r\n this.setState({\r\n isChecked: !this.state.isChecked,\r\n });\r\n }\r\n\r\n clearAll: () => void\r\n clearAll() {\r\n const { onSelectOption } = this.props\r\n onSelectOption([])\r\n }\r\n\r\n renderSingle: (item: SelectItem) => Element<*>\r\n renderSingle(item: SelectItem) {\r\n const { onSelectOption, t, showRadio = false } = this.props\r\n\r\n return (\r\n <Button\r\n variant=\"link\"\r\n className=\"text-left\"\r\n key={item.name}\r\n style={{ padding: 0 }}\r\n onClick={() => onSelectOption([item.name])}\r\n >\r\n {showRadio && item.selected ? <span>â–¶</span> : ''}\r\n {` ${t(item.name)}`}\r\n </Button>\r\n )\r\n }\r\n\r\n renderAll: () => Element<*>\r\n renderAll() {\r\n const defaultLength = 10\r\n\r\n const { attribute, truncateList = true } = this.props\r\n const { options } = attribute\r\n const { isTruncated } = this.state\r\n\r\n const optionsToRender = options.slice(\r\n 0,\r\n truncateList && isTruncated ? defaultLength : options.length\r\n )\r\n\r\n return (\r\n <ButtonGroup vertical size=\"sm\" className=\"product-attributes\">\r\n {optionsToRender.map((sc, i) => this.renderSingle(sc))}\r\n {truncateList && options.length > defaultLength ? (\r\n isTruncated ? (\r\n <Button\r\n variant=\"link\"\r\n className=\"text-left\"\r\n style={{ padding: 0 }}\r\n onClick={() => this.setState({ isTruncated: false })}\r\n >\r\n Show all â–¼\r\n </Button>\r\n ) : (\r\n <Button\r\n variant=\"link\"\r\n className=\"text-left\"\r\n style={{ padding: 0 }}\r\n onClick={() => this.setState({ isTruncated: true })}\r\n >\r\n Collapse â–²\r\n </Button>\r\n )\r\n ) : (\r\n ''\r\n )}\r\n </ButtonGroup>\r\n )\r\n }\r\n\r\n renderSelected: () => Element<*>\r\n renderSelected() {\r\n const { attribute } = this.props\r\n const { options } = attribute\r\n\r\n return (\r\n <div className=\"product-attributes\">\r\n {options\r\n .filter(option => option.selected)\r\n .map((sc, i) => this.renderSingle(sc))}\r\n </div>\r\n )\r\n }\r\n\r\n render() {\r\n const { attribute, truncateList = true } = this.props\r\n const { options, title } = attribute\r\n\r\n const selectedOptions = options.filter(option => option.selected)\r\n let renderedItems: Element<*>\r\n if (truncateList) {\r\n renderedItems =\r\n selectedOptions.length === 0 ? this.renderAll() : this.renderSelected()\r\n } else {\r\n renderedItems = this.renderAll()\r\n }\r\n\r\n return (\r\n <div className=\"msds-accordion__list-item msds-accordion__list-item--animate-icon-rotate\">\r\n <input \r\n defaultChecked={this.state.isChecked}\r\n onChange={this.toggleChange}\r\n type=\"checkbox\" className=\"mt-2 msds-accordion__list-item-input\" id={title}/>\r\n <label className=\"msds-accordion__list-item-header\" htmlFor={title}>\r\n <span className=\"msds-accordion__list-item-header-title\">{title}</span>\r\n <span className=\"msds-accordion__list-item-header-icon\">\r\n <svg>\r\n <use xlinkHref={`${sprites}#arrow`}></use>\r\n </svg>\r\n </span>\r\n </label>\r\n <div className=\"msds-accordion__list-item-body\">\r\n <div className=\"msds-accordion__list-item-description\">\r\n {!truncateList || selectedOptions.length === 0 ? (\r\n ''\r\n ) : (\r\n <Button\r\n variant=\"link\"\r\n size=\"sm\"\r\n style={{ padding: 0 }}\r\n onClick={this.clearAll}\r\n >\r\n × Clear\r\n </Button>\r\n )}\r\n {renderedItems}\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n }\r\n}\r\n\r\nexport default withTranslation()(ProductAttribute)\r\n","// @flow\r\n\r\nimport React from 'react'\r\nimport { useDispatch, useSelector } from 'react-redux'\r\n\r\nimport ProductAttribute from './ProductAttribute'\r\nimport { actionCreators } from '../store/RecommendationState/ActionCreators'\r\n\r\nexport default () => {\r\n const dispatch = useDispatch()\r\n\r\n const {\r\n models,\r\n diskStoragePercentage,\r\n attributes,\r\n storageConfigurations,\r\n } = useSelector(state => state.productOptions)\r\n\r\n const poweredByAttribute = attributes.find(\r\n attribute => attribute.attributeId === '31'\r\n )\r\n const remainingAttributes = attributes.filter(\r\n attribute => attribute.attributeId !== '31'\r\n )\r\n\r\n return (\r\n <div className=\"product-options\">\r\n <div className=\"msds-accordion\">\r\n {poweredByAttribute == null ? (\r\n ''\r\n ) : (\r\n <ProductAttribute\r\n key={poweredByAttribute.title}\r\n attribute={poweredByAttribute}\r\n onSelectOption={optionName =>\r\n dispatch(\r\n actionCreators.serverAttributeUpdated(\r\n parseInt(poweredByAttribute.attributeId),\r\n optionName\r\n )\r\n )\r\n }\r\n />\r\n )}\r\n\r\n <ProductAttribute\r\n key=\"models\"\r\n attribute={{\r\n title: 'Models',\r\n options: models,\r\n attributeId: 'models',\r\n }}\r\n onSelectOption={names =>\r\n dispatch(actionCreators.serverModelsUpdated(names))\r\n }\r\n />\r\n\r\n <ProductAttribute\r\n key=\"storage\"\r\n attribute={{\r\n title: 'Storage configurations',\r\n options: storageConfigurations,\r\n attributeId: 'storage',\r\n }}\r\n onSelectOption={names =>\r\n dispatch(actionCreators.storageConfigurationUpdated(names[0]))\r\n }\r\n truncateList={false}\r\n showRadio={true}\r\n />\r\n\r\n <div className=\"pt-4 disk-usage\">\r\n <h5 className=\"msds-text-body-1-bold\">Max. disk usage (%)</h5>\r\n <input\r\n type=\"range\"\r\n min=\"20\"\r\n max=\"100\"\r\n value={diskStoragePercentage}\r\n style={{ width: '60%', maxWidth: 150 }}\r\n onChange={evt =>\r\n dispatch(\r\n actionCreators.diskStoragePercentageUpdated(\r\n evt.target.valueAsNumber\r\n )\r\n )\r\n }\r\n />\r\n <span style={{ marginLeft: 10 }}>{diskStoragePercentage}%</span>\r\n </div>\r\n\r\n {remainingAttributes.map(attribute => (\r\n <ProductAttribute\r\n key={attribute.title}\r\n attribute={attribute}\r\n onSelectOption={optionName =>\r\n dispatch(\r\n actionCreators.serverAttributeUpdated(\r\n parseInt(attribute.attributeId),\r\n optionName\r\n )\r\n )\r\n }\r\n />\r\n ))}\r\n </div>\r\n </div>\r\n )\r\n}\r\n","import React from 'react'\r\n\r\nexport default function (item) {\r\n return (\r\n <>\r\n <div className=\"description-copy\"></div>\r\n <table className=\"aligncenter table-striped\">\r\n <tbody>\r\n <tr>\r\n <td width=\"207\">Form Factor</td>\r\n <td width=\"435\">{getAttributeValue('Form Factor', item)}</td>\r\n </tr>\r\n <tr>\r\n <td width=\"207\">Processor Type</td>\r\n <td width=\"435\">{getAttributeValue('Processor Type', item)}</td>\r\n </tr>\r\n <tr>\r\n <td width=\"207\">Operating System</td>\r\n <td width=\"435\">{getAttributeValue('Operating System', item)}</td>\r\n </tr>\r\n <tr>\r\n <td width=\"207\">Hard Drive Bays</td>\r\n <td width=\"435\">{getAttributeValue('Hard Drive Bays', item)}</td>\r\n </tr>\r\n <tr>\r\n <td width=\"207\">Maximum Storage</td>\r\n <td width=\"435\">{item.props.storageSize} TB</td>\r\n </tr>\r\n <tr>\r\n <td width=\"207\">RAID Support</td>\r\n <td width=\"435\">\r\n {item.props.storageConfigurations\r\n .join(', ')\r\n .replaceAll('STORAGE_CONFIGURATION_', '')}\r\n </td>\r\n </tr>\r\n <tr>\r\n <td width=\"207\">Power Supply</td>\r\n <td width=\"435\">{item.props.powerSupply} W</td>\r\n </tr>\r\n <tr>\r\n <td width=\"207\">RAM</td>\r\n <td width=\"435\">{getAttributeValue('RAM', item)}</td>\r\n </tr>\r\n <tr>\r\n <td width=\"207\">Operating System Drive</td>\r\n <td width=\"435\">{getAttributeValue('Operating System Drive', item)}</td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </>\r\n )\r\n}\r\n\r\nfunction getAttributeValue(attributeName, item) {\r\n if (attributeName) {\r\n const product = item.props\r\n const attribute = product.attributes.find(\r\n attribute => attribute.name === attributeName\r\n )\r\n return attribute ? attribute.options[0] : ''\r\n }\r\n}\r\n","// @flow\r\nimport '../style/product.scss'\r\nimport React, { Component } from 'react'\r\nimport { Container, Row, Col } from 'react-bootstrap'\r\nimport ProductDescription from './ProductDescription'\r\n\r\nimport type { ProductType } from '../api/restTypes'\r\n\r\ntype Props = {\r\n product: { original: ProductType },\r\n}\r\n\r\nexport function formatDescription(description: string = '') {\r\n if (description)\r\n return description\r\n .replace(\r\n '<table class=\"aligncenter\">',\r\n '<table class=\"aligncenter table-striped\">'\r\n )\r\n .replace('<h5>Description</h5>', '')\r\n .replace('<h5>Technical Specification</h5>', '')\r\n}\r\n\r\nexport default class Product extends Component<Props, {}> {\r\n\r\n render() {\r\n const product = this.props.product.original\r\n return (\r\n <Container fluid>\r\n <Row className=\"align-items-center\">\r\n <Col className=\"col-4\">\r\n <img\r\n style={{ maxWidth: '100%', maxHeight: '100%' }}\r\n src={product.image}\r\n alt={product.sku}\r\n />\r\n </Col>\r\n <Col className=\"productDescription col-5\">\r\n <p className=\"productTechSpec\">Technical Specification</p>\r\n {product.description && <div\r\n style={{ margin: 10 }}\r\n dangerouslySetInnerHTML={{\r\n __html: formatDescription(product.description),\r\n }}\r\n />}\r\n {!product.description && <div style={{ margin: 10 }}>\r\n <ProductDescription\r\n props={product}></ProductDescription>\r\n\r\n </div>}\r\n </Col>\r\n </Row>\r\n </Container>\r\n )\r\n }\r\n}\r\n","import React from 'react'\r\nimport { Card } from 'react-bootstrap'\r\n\r\nexport default () => (\r\n <Card className=\"my-2\">\r\n <Card.Body>\r\n <strong>\r\n Please note that the results given by our calculator are only applicable\r\n and guaranteed for our performance optimised HUSKY hardware\r\n solutions. We cannot guarantee that the performance will be valid\r\n without our optimisation methods.\r\n </strong>\r\n </Card.Body>\r\n </Card>\r\n)\r\n","import React, { useState } from 'react'\r\nimport { useSelector } from 'react-redux'\r\nimport ReactTable from 'react-table-6'\r\nimport { Button, Col, ProgressBar, Row } from 'react-bootstrap'\r\nimport { useRoleTranslation } from '../hooks/useRoleTranslation'\r\nimport Product from './Product'\r\nimport Disclaimer from './Disclaimer'\r\nimport { groupBy } from '../util/arrayHelpers'\r\nimport type { Node } from 'react'\r\nfunction getColumns(\r\n totalStorage: number,\r\n showOrderSummary: any => void,\r\n editingDisabled: boolean,\r\n tr: string => string\r\n): any[] {\r\n return [\r\n {\r\n id: 'thumbnail',\r\n Cell: row =>\r\n row.isExpanded ? (\r\n ''\r\n ) : (\r\n <img src={row.original.image} alt={row.original.sku} width={100} />\r\n ),\r\n maxWidth: 150,\r\n },\r\n {\r\n id: 'quantity',\r\n Header: 'Quantity',\r\n accessor: 'count',\r\n maxWidth: 150,\r\n },\r\n {\r\n Header: 'Model',\r\n accessor: 'model',\r\n width: 180,\r\n maxWidth: 150,\r\n },\r\n {\r\n Header: 'SKU',\r\n Cell: row => (\r\n row.original.sku\r\n ),\r\n width: 150,\r\n },\r\n {\r\n Header: 'Tech Sheet',\r\n Cell: row => (\r\n <Button\r\n style={{ padding: 0 }}\r\n variant=\"link\"\r\n href={row.original.techSheetLink}\r\n target=\"_blank\"\r\n >\r\n PDF\r\n </Button>\r\n ),\r\n maxWidth: 200,\r\n },\r\n {\r\n id: 'storageBar',\r\n className: 'storage-bar',\r\n Header: 'Storage',\r\n Cell: row => (\r\n <StorageBar\r\n storageSize={row.original.storageSize}\r\n count={row.original.count}\r\n totalStorage={totalStorage}\r\n />\r\n ),\r\n width: 150,\r\n maxWidth: 200,\r\n },\r\n {\r\n Header: '',\r\n className: 'show-summary',\r\n id: 'showSummary',\r\n Cell: row => (\r\n <button\r\n className=\"msds-btn msds-btn--tertiary msds-btn--sm\"\r\n style={{minWidth: 5 }}\r\n onClick={() => showOrderSummary(row.original)}\r\n >\r\n Print\r\n </button>\r\n ),\r\n maxWidth: 180,\r\n show: !editingDisabled,\r\n },\r\n ]\r\n}\r\ntype ButtonProps = {\r\n onClick: () => void,\r\n isSelected: boolean,\r\n children?: Node,\r\n}\r\nconst StorageBar = ({ storageSize, count, totalStorage }) => {\r\n const labelStyle = {\r\n color: '#fff',\r\n fontWeight: '600',\r\n width: '100%',\r\n textAlign: 'center',\r\n position: 'absolute',\r\n top: 0,\r\n fontSize: '.8em',\r\n }\r\n return (\r\n <div style={{ position: 'relative' }}>\r\n <ProgressBar\r\n max={storageSize * count}\r\n now={totalStorage}\r\n style={{ background: '#ccc', height: 20, lineHeight: 1 }}\r\n />\r\n <span style={labelStyle}>{`${totalStorage.toFixed(2)} TB / ${\r\n storageSize * count\r\n } TB`}</span>\r\n </div>\r\n )\r\n}\r\nfunction NumberOfResultsButton(props: ButtonProps) {\r\n const { isSelected, onClick, children } = props\r\n return (\r\n <Button\r\n size=\"sm\"\r\n variant=\"link\"\r\n style={{ textDecoration: isSelected ? 'underline' : '' }}\r\n onClick={onClick}\r\n >\r\n {children}\r\n </Button>\r\n )\r\n}\r\ntype NumberOfResults = 'single' | 'oneFromEachSku' | 'all'\r\ntype SortingFunction = (any, any) => number\r\ntype WrapperProps = {\r\n editingDisabled: boolean,\r\n recommendations: any,\r\n showOrderSummary: any => void,\r\n loading?: boolean,\r\n}\r\nfunction filter(\r\n recommendations: any[] = [],\r\n numberOfResults: NumberOfResults,\r\n sortingFunction: SortingFunction\r\n) {\r\n let filtered = recommendations\r\n filtered.sort(sortingFunction)\r\n if (numberOfResults === 'single') {\r\n const groupedByPoweredBy = groupBy(\r\n filtered,\r\n rec => rec.attributes.find(attr => attr.attributeId === 31)?.options[0]\r\n )\r\n filtered =\r\n groupedByPoweredBy.length > 0\r\n ? groupedByPoweredBy.map(group => group.values[0])\r\n : []\r\n } else if (numberOfResults === 'oneFromEachSku') {\r\n const resultObject = filtered.reduce((accu, current) => {\r\n if (!accu.hasOwnProperty(current.model)) {\r\n accu[current.model] = current\r\n }\r\n return accu\r\n }, {})\r\n filtered = Object.values(resultObject)\r\n }\r\n return [...filtered]\r\n}\r\nexport default ({\r\n editingDisabled,\r\n recommendations = [],\r\n showOrderSummary,\r\n loading,\r\n}: WrapperProps) => {\r\n const PAGE_SIZE = 10\r\n const { tr } = useRoleTranslation()\r\n const { totalStorage, sortingFunction } = useSelector(\r\n state => state.productRecommendations\r\n )\r\n const [numberOfResults, setNumberOfResults] = useState('oneFromEachSku')\r\n const filteredRecommendations = filter(\r\n recommendations.slice(),\r\n numberOfResults,\r\n sortingFunction\r\n )\r\n const columns = getColumns(\r\n totalStorage,\r\n showOrderSummary,\r\n editingDisabled,\r\n tr\r\n )\r\n return (\r\n <Row>\r\n <Col>\r\n <Row>\r\n <Col>\r\n <Disclaimer />\r\n </Col>\r\n </Row>\r\n <Row className=\"mb-2 d-flex align-center justify-content-end align-items-center\">\r\n <Col xs=\"auto\" style={{ textAlign: 'right' }}>\r\n Items per page:{' '}\r\n <NumberOfResultsButton\r\n isSelected={numberOfResults === 'oneFromEachSku'}\r\n onClick={() => setNumberOfResults('oneFromEachSku')}\r\n >\r\n Models\r\n </NumberOfResultsButton>{' '}\r\n |\r\n <NumberOfResultsButton\r\n isSelected={numberOfResults === 'all'}\r\n onClick={() => setNumberOfResults('all')}\r\n >\r\n All SKUs\r\n </NumberOfResultsButton>\r\n </Col>\r\n </Row>\r\n <Row>\r\n <Col md={{ span: 12 }}>\r\n <ReactTable\r\n columns={columns}\r\n data={filteredRecommendations}\r\n pageSize={PAGE_SIZE}\r\n minRows={1}\r\n showPagination={filteredRecommendations.length > PAGE_SIZE}\r\n showPageJump={false}\r\n showPageSizeOptions={false}\r\n noDataText=\"No products match the selected criteria\"\r\n SubComponent={row => <Product product={row} />}\r\n loading={loading}\r\n />\r\n </Col>\r\n </Row>\r\n </Col>\r\n </Row>\r\n )\r\n}\r\n","import { useMemo } from 'react'\r\nimport { useSelector } from 'react-redux'\r\nimport { useTranslation } from 'react-i18next'\r\n\r\nexport const useRoleTranslation = () => {\r\n const { t } = useTranslation()\r\n const { role } = useSelector(state => state.login)\r\n\r\n return useMemo(\r\n () => ({ tr: textId => t(textId, { lng: role.toLowerCase() }) }),\r\n [t, role]\r\n )\r\n}\r\n","// @flow\r\n\r\nimport React from 'react'\r\nimport ReactTable from 'react-table-6'\r\nimport {\r\n Button,\r\n Col,\r\n Container,\r\n Modal,\r\n Row,\r\n Table,\r\n} from 'react-bootstrap'\r\nimport { useSelector } from 'react-redux'\r\nimport { useTranslation } from 'react-i18next'\r\nimport { formatDescription } from './Product'\r\nimport ProductDescription from './ProductDescription'\r\nimport { ConfigSummaryTable } from './ConfigSummaryTable'\r\n\r\nimport type { CameraLine, ProductType } from '../api/restTypes'\r\n\r\nfunction resolveCameraLines(t, cameraLines: CameraLine[]) {\r\n return cameraLines.map<CameraLine>(row => {\r\n return {\r\n ...row,\r\n codec: t(row.codec),\r\n imageComplexity: t(row.imageComplexity),\r\n resolution: t(row.resolution),\r\n }\r\n })\r\n}\r\n\r\ntype Props = {\r\n orderedProduct: ?ProductType,\r\n hide: () => void,\r\n show: boolean,\r\n}\r\n\r\nexport default ({ orderedProduct, hide, show }: Props) => {\r\n const { t } = useTranslation()\r\n\r\n const { diskStoragePercentage } = useSelector(\r\n state => state.orderSummary\r\n )\r\n const cameraLines = useSelector(\r\n state => state.recommendationState.cameraLines\r\n )\r\n\r\n const handlePrintAction = () => {\r\n document.title = `SKU: ${product.sku}`;\r\n window.onafterprint = () => {\r\n hide()\r\n };\r\n window.print()\r\n document.title = \"Husky Calculator\" \r\n }\r\n\r\n const handleClose = () => {\r\n hide()\r\n }\r\n\r\n let product = orderedProduct\r\n if (product == null) {\r\n product = {\r\n sku: '',\r\n count: 0,\r\n description: '',\r\n image: '',\r\n model: '',\r\n }\r\n }\r\n\r\n const headerStyle = { fontWeight: 'bold' } \r\n\r\n let content\r\n \r\n return (\r\n <Modal\r\n show={show}\r\n onHide={handleClose}\r\n dialogClassName=\"modal-70w\"\r\n >\r\n <Modal.Body>\r\n <Container fluid>\r\n <Row>\r\n <Col>\r\n <div className=\"print-logos\">\r\n <img id=\"print-logo\" src=\"/logo.svg\" alt=\"\" />\r\n <div className=\"print-logo-divider\"></div>\r\n <div className=\"print-portal-logo\">Husky IVO</div> \r\n </div>\r\n </Col> \r\n <Col>\r\n <Button\r\n className=\"printButton float-right\"\r\n variant=\"danger\"\r\n onClick={hide}\r\n >\r\n ✖\r\n </Button>\r\n </Col>\r\n </Row>\r\n <Row style={{ minHeight: 850 }}>\r\n {content ? (\r\n content\r\n ) : (\r\n <>\r\n <Col md={{ span: 12 }} className=\"\" id=\"printProduct\">\r\n <Row>\r\n <Col className=\"mt-8\">\r\n <h5 style={headerStyle}>Camera Configuration</h5>\r\n <ReactTable\r\n style={{ fontSize: 16 }}\r\n columns={columns}\r\n data={cameraLines}\r\n resolveData={cameraLines =>\r\n resolveCameraLines(t, cameraLines)\r\n }\r\n showPagination={false}\r\n defaultPageSize={20}\r\n minRows={0}\r\n />\r\n\r\n <div className=\"my-8\">\r\n <ConfigSummaryTable\r\n cameraRows={cameraLines}\r\n diskStoragePercentage={diskStoragePercentage}\r\n />\r\n </div>\r\n\r\n <Row>\r\n <Col md={{ span: 8 }}>\r\n <h5 style={headerStyle}>Hardware Selected</h5>\r\n <Table className=\"mb-8\" style={{ fontSize: '1em' }} size=\"sm\">\r\n <thead>\r\n <tr>\r\n <th>\r\n <strong>{product.model}</strong>\r\n </th>\r\n <th style={{ textAlign: 'center' }}>\r\n Quantity\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr>\r\n <td>SKU: {product.sku}</td>\r\n <td style={{ textAlign: 'center' }}>\r\n {product.count}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </Table>\r\n <h5 style={headerStyle}>Technical Specification</h5>\r\n {product.description && <div\r\n dangerouslySetInnerHTML={{\r\n __html: formatDescription(product.description),\r\n }}\r\n />}\r\n {product.description !== \"\" && !product.description && <div style={{ margin: 10 }}>\r\n <ProductDescription\r\n props={product} />\r\n </div>}\r\n </Col>\r\n <Col>\r\n <img\r\n src={product.image}\r\n style={{ width: '70%' }}\r\n alt={product.sku}\r\n />\r\n </Col>\r\n </Row>\r\n </Col>\r\n </Row>\r\n <Row className=\"print-disclaimer\">\r\n <Col>\r\n Please note that the recommendations given by our Husky IVO Product Guide are only applicable and guaranteed for our performance optimized Husky IVO series. We cannot guarantee that the performance will be valid without our optimization methods.\r\n </Col>\r\n </Row>\r\n </Col>\r\n </>\r\n )}\r\n </Row>\r\n <Row>\r\n <Col>\r\n <button\r\n style={{ marginTop: 20 }}\r\n onClick={handlePrintAction}\r\n className=\"float-right msds-btn msds-btn--primary\"\r\n >\r\n Print\r\n </button>\r\n </Col>\r\n </Row>\r\n </Container>\r\n </Modal.Body>\r\n </Modal>\r\n )\r\n}\r\n\r\nconst columns = [\r\n {\r\n Header: 'Cams',\r\n accessor: 'cameras',\r\n maxWidth: 60,\r\n headerClassName: \"text-left\",\r\n },\r\n {\r\n Header: 'Ops (h)',\r\n accessor: 'operation',\r\n maxWidth: 75,\r\n headerClassName: \"text-left\",\r\n },\r\n {\r\n Header: 'Rec. %',\r\n accessor: 'recording',\r\n maxWidth: 75,\r\n headerClassName: \"text-left\",\r\n },\r\n {\r\n Header: 'Days',\r\n accessor: 'days',\r\n maxWidth: 55,\r\n headerClassName: \"text-left\",\r\n },\r\n {\r\n Header: 'Codec',\r\n accessor: 'codec',\r\n maxWidth: 70,\r\n headerClassName: \"text-left\",\r\n },\r\n {\r\n Header: 'Complexity',\r\n accessor: 'imageComplexity',\r\n maxWidth: 100,\r\n headerClassName: \"text-left\",\r\n },\r\n {\r\n Header: 'Resolution',\r\n accessor: 'resolution',\r\n maxWidth: 175,\r\n headerClassName: \"text-left\",\r\n },\r\n {\r\n Header: 'FPS',\r\n accessor: 'fps',\r\n maxWidth: 50,\r\n headerClassName: \"text-left\",\r\n },\r\n {\r\n Header: 'Rate (Kbps)',\r\n accessor: 'dataRate',\r\n maxWidth: 105,\r\n headerClassName: \"text-left\",\r\n },\r\n {\r\n Header: 'Notes',\r\n accessor: 'notes',\r\n headerClassName: \"text-left\",\r\n },\r\n]\r\n","import React from 'react'\r\nimport { Col, Row, Spinner } from 'react-bootstrap'\r\n\r\nexport default ({ text = 'Loading' }) => (\r\n <Col>\r\n <Row className=\"justify-content-md-center\">\r\n <Col md=\"auto\">\r\n <p>{text}</p>\r\n </Col>\r\n </Row>\r\n <Row className=\"justify-content-md-center\">\r\n <Col md=\"auto\">\r\n <Spinner animation=\"border\" variant=\"primary\" />\r\n </Col>\r\n </Row>\r\n </Col>\r\n)\r\n","// @flow\r\n\r\nimport React, { Component } from 'react'\r\nimport {\r\n Accordion,\r\n Card,\r\n Col,\r\n Row,\r\n Modal,\r\n} from 'react-bootstrap'\r\nimport { withTranslation } from 'react-i18next'\r\nimport AddCameras from '../AddCameras'\r\nimport { bindActionCreators } from 'redux'\r\nimport { connect } from 'react-redux'\r\nimport { withRouter } from 'react-router-dom'\r\nimport sprites from '@milestone-sys/web-design-system/msds-spritemap.svg'\r\n\r\nimport ProductOptions from '../ProductOptions'\r\nimport ProductRecommendations from '../ProductRecommendations'\r\nimport OrderSummary from '../OrderSummaryPdf'\r\nimport Loading from '../Loading'\r\nimport { actionCreators } from '../../store/ProjectStore'\r\nimport type { ProductType } from '../../api/restTypes'\r\nimport type { Sku } from '../../store/ProjectStore'\r\n\r\nexport type SelectItem = {\r\n name: string,\r\n enabled: boolean,\r\n selected: boolean,\r\n}\r\n\r\ntype ProjectProps = {\r\n loading: boolean,\r\n recommendations: any,\r\n loadModels: () => void,\r\n skus: Sku[],\r\n loadingRecommendations: boolean,\r\n match: {\r\n params: {\r\n projectId: string,\r\n },\r\n },\r\n loadProject: string => any,\r\n projectDetails: {\r\n projectReference: string,\r\n },\r\n projectCustomerId: number,\r\n currentCustomerId: number,\r\n history: {\r\n push: string => void,\r\n },\r\n projectId: string,\r\n}\r\n\r\ntype State = {\r\n showAddCameras: boolean,\r\n showOrderSummary: boolean,\r\n orderedProduct: ?ProductType,\r\n loadingProject: boolean,\r\n}\r\n\r\nclass Project extends Component<ProjectProps, State> {\r\n constructor(props) {\r\n super(props)\r\n this.state = {\r\n showAddCameras: true,\r\n showOrderSummary: false,\r\n orderedProduct: null,\r\n loadingProject: false,\r\n show: false,\r\n }\r\n this.showModal = this.showModal.bind(this)\r\n this.hideModal = this.hideModal.bind(this)\r\n\r\n this.showOrderSummary = this.showOrderSummary.bind(this)\r\n this.init = this.init.bind(this)\r\n }\r\n\r\n componentDidMount() {\r\n if (this.props.skus.length === 0) {\r\n this.props.loadModels()\r\n }\r\n\r\n this.init()\r\n }\r\n\r\n componentDidUpdate() {\r\n this.init()\r\n }\r\n\r\n init: () => void\r\n init() {\r\n const { projectId, skus, match } = this.props\r\n const { loadingProject } = this.state\r\n\r\n if (skus.length === 0) {\r\n return\r\n }\r\n\r\n if (!loadingProject && match.params.projectId !== projectId) {\r\n this.props.loadProject(match.params.projectId)\r\n this.setState({ loadingProject: true })\r\n } else if (loadingProject && match.params.projectId === projectId) {\r\n this.setState({ loadingProject: false })\r\n }\r\n }\r\n\r\n showOrderSummary: (product: ProductType) => void\r\n showOrderSummary(product: ProductType) {\r\n this.setState({\r\n showOrderSummary: !this.state.showOrderSummary,\r\n orderedProduct: product,\r\n })\r\n }\r\n\r\n showModal = () => {\r\n document.documentElement.style.overflow = 'hidden';\r\n this.setState({ show: true })\r\n }\r\n\r\n hideModal = () => {\r\n this.setState({ show: false })\r\n document.documentElement.removeAttribute(\"style\");\r\n }\r\n\r\n render() {\r\n const {\r\n loading,\r\n loadingRecommendations = true,\r\n recommendations,\r\n projectDetails,\r\n projectCustomerId,\r\n currentCustomerId,\r\n history,\r\n } = this.props\r\n\r\n const { showOrderSummary, orderedProduct } = this.state\r\n\r\n if (loading) {\r\n return <Loading />\r\n }\r\n\r\n const editingDisabled = currentCustomerId !== projectCustomerId\r\n return (\r\n <div className=\"project-wrapper\">\r\n <Row className=\"my-2\">\r\n <div className=\"d-flex align-items-center project-nav\">\r\n <a onClick={() => history.push('/')} href={() => false} role=\"button\" className=\"mt-1 mr-3 msds-btn-floating\">\r\n <svg className=\"msds-icon\">\r\n <use xlinkHref={`${sprites}#right-arrow`}></use>\r\n </svg>Back |\r\n </a>\r\n <div className=\"msds-text-dark-blue msds-text-header-3\">\r\n {projectDetails.projectReference}\r\n </div>\r\n </div>\r\n </Row>\r\n <Row md={{ span: 12 }}>\r\n <Accordion\r\n className=\"col-12\"\r\n defaultActiveKey=\"0\"\r\n style={{ width: '100%' }}\r\n >\r\n <Card>\r\n <Accordion.Toggle as={Card.Header} eventKey=\"0\" className=\"msds-shadow-medium msds-text-gray-10 msds-bg-white msds-text-body-0-bold\">\r\n Cameras\r\n </Accordion.Toggle>\r\n <Accordion.Collapse eventKey=\"0\">\r\n <Card.Body>\r\n <AddCameras editingDisabled={editingDisabled} />\r\n </Card.Body>\r\n </Accordion.Collapse>\r\n </Card>\r\n </Accordion>\r\n </Row>\r\n <Row className=\"productFiltering\">\r\n <Col className=\"d-lg-none\">\r\n <div className=\"msds-accordion msds-accordion--mobile mobile\">\r\n <div onClick={this.showModal}\r\n className=\"msds-accordion__list-item\">\r\n <div\r\n className=\"msds-accordion__list-item-header\"\r\n >\r\n <span className=\"msds-accordion__list-item-header-title\">\r\n Filters\r\n </span>\r\n <span className=\"msds-icon\">\r\n <svg>\r\n <use xlinkHref={`${sprites}#filter`}></use>\r\n </svg>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n </Col>\r\n {this.state.show && \r\n <Modal\r\n show={this.state.show}\r\n onHide={this.hideModal}\r\n animation={false}\r\n dialogClassName=\"project-modal col-sm-12 col-md-5\"\r\n >\r\n <Modal.Header closeButton className=\"msds-text-gray-8 msds-bg-gray-3\">\r\n <Modal.Title className=\"msds-text-body-0-bold\">Filters</Modal.Title>\r\n </Modal.Header>\r\n <ProductOptions />\r\n </Modal>\r\n }\r\n {!this.state.show &&\r\n <Col\r\n md={{ span: 3 }}\r\n className=\"mb-2 my-2 desktop d-none d-lg-block\"\r\n >\r\n <ProductOptions />\r\n </Col>\r\n }\r\n \r\n <Col lg={{ span: 9 }}>\r\n <OrderSummary\r\n orderedProduct={orderedProduct}\r\n hide={() => this.setState({ showOrderSummary: false })}\r\n show={showOrderSummary}\r\n />\r\n <ProductRecommendations\r\n editingDisabled={editingDisabled}\r\n recommendations={recommendations}\r\n showOrderSummary={this.showOrderSummary}\r\n loading={loadingRecommendations}\r\n />\r\n </Col>\r\n </Row>\r\n </div>\r\n )\r\n }\r\n}\r\n\r\nconst ProjectWithRouter = withRouter(props => <Project {...props} />)\r\nexport default connect(\r\n state => state.project,\r\n dispatch => bindActionCreators(actionCreators, dispatch)\r\n)(withTranslation()(ProjectWithRouter))\r\n","// @flow\r\n\r\nimport React, { useEffect, useRef, useState } from 'react'\r\nimport Col from 'react-bootstrap/Col'\r\nimport Form from 'react-bootstrap/Form'\r\n\r\ntype Props = {\r\n show: boolean,\r\n handleClose: () => void,\r\n handleCreated: () => void,\r\n doCreate: string => Promise<void>,\r\n buttonText: string,\r\n defaultValue?: string,\r\n}\r\n\r\nexport default ({\r\n show,\r\n handleClose,\r\n handleCreated,\r\n doCreate,\r\n labelText,\r\n buttonText,\r\n defaultValue = '',\r\n}: Props) => {\r\n const inputProjectName = useRef(null)\r\n const [projectReference, setProjectReference] = useState(defaultValue)\r\n\r\n useEffect(() => {\r\n if (show && inputProjectName.current != null) {\r\n inputProjectName.current.focus()\r\n }\r\n }, [inputProjectName, show])\r\n\r\n const close = () => {\r\n setProjectReference('')\r\n handleClose()\r\n }\r\n\r\n const create = async () => {\r\n if (projectReference.length === 0) return\r\n\r\n await doCreate(projectReference)\r\n handleCreated()\r\n close()\r\n }\r\n\r\n const handleKeyup = async evt => {\r\n if (evt.key === 'Enter') {\r\n await create()\r\n } else if (evt.key === 'Escape') {\r\n close()\r\n }\r\n }\r\n\r\n if (!show) {\r\n return null\r\n }\r\n\r\n return (\r\n <Form.Row>\r\n <Col sm={6}>\r\n <div className=\"msds-input msds-input msds-input--small\">\r\n <div className=\"msds-input__icon-wrapper\">\r\n <input\r\n id=\"createProjectNameInput\"\r\n ref={inputProjectName}\r\n type=\"text\"\r\n value={projectReference}\r\n onChange={evt => setProjectReference(evt.target.value)}\r\n onKeyUp={handleKeyup}\r\n className=\"msds-input__text-input\"\r\n placeholder={labelText}\r\n name=\"text-input-lg\" />\r\n <label htmlFor=\"text-input-lg\" className=\"msds-input__label\">{labelText}</label>\r\n </div>\r\n </div>\r\n </Col>\r\n <Col xs=\"auto\">\r\n <button\r\n className=\"msds-btn msds-btn--tertiary msds-btn--sm\"\r\n onClick={create}>{buttonText}</button>\r\n </Col>\r\n </Form.Row>\r\n )\r\n}\r\n","// @flow\r\n\r\nimport React from 'react'\r\nimport Modal from 'react-bootstrap/Modal'\r\n\r\nimport restApi from '../../api/restApi'\r\n\r\ntype Props = {\r\n show: boolean,\r\n projectId: ?string,\r\n projectReference: string,\r\n handleClose: () => void,\r\n handleDeleted: () => void,\r\n}\r\n\r\nexport default ({\r\n show,\r\n projectId,\r\n projectReference,\r\n handleClose,\r\n handleDeleted,\r\n}: Props) => {\r\n const doDelete = async () => {\r\n if (projectId == null) {\r\n console.error('projectId is null')\r\n return\r\n }\r\n\r\n await restApi.deleteProject(projectId)\r\n handleDeleted()\r\n handleClose()\r\n }\r\n\r\n return (\r\n <Modal show={show} onHide={handleClose}>\r\n <Modal.Header closeButton>\r\n <Modal.Title>Are you sure?</Modal.Title>\r\n </Modal.Header>\r\n <Modal.Body>\r\n Are you sure want to delete project '<strong>{projectReference}</strong>\r\n '? This action cannot be undone.\r\n </Modal.Body>\r\n <Modal.Footer>\r\n <button className=\"msds-btn msds-btn--gray msds-btn--sm\" onClick={handleClose}>\r\n Cancel\r\n </button>\r\n <button className=\"msds-btn msds-btn--danger msds-btn--sm\" onClick={doDelete}>\r\n Delete\r\n </button>\r\n </Modal.Footer>\r\n </Modal>\r\n )\r\n}\r\n","import React from 'react'\r\nimport { Row, Col } from 'react-bootstrap'\r\n\r\nexport default ({\r\n canPreviousPage,\r\n pageCount,\r\n canNextPage,\r\n nextPage,\r\n previousPage,\r\n pageIndex,\r\n}) => {\r\n return (\r\n <Row className=\"p-2 pagination-project\" style={{ width: '100%', padding: 3, margin: 0 }}>\r\n <Col style={{ padding: 0 }}>\r\n <button\r\n className=\"msds-btn msds-btn--gray msds-btn--sm\"\r\n onClick={() => previousPage()}\r\n disabled={!canPreviousPage}\r\n style={{ width: '100%' }}\r\n >\r\n Previous\r\n </button>\r\n </Col>\r\n <Col className=\"mt-2 mb-2 text-center align-self-center\">\r\n Page {pageIndex + 1} of {pageCount}\r\n </Col>\r\n <Col style={{ padding: 0 }}>\r\n <button\r\n className=\"msds-btn msds-btn--gray msds-btn--sm float-right\"\r\n onClick={() => nextPage()}\r\n disabled={!canNextPage}\r\n style={{ width: '100%' }}\r\n >\r\n Next\r\n </button>\r\n </Col>\r\n </Row>\r\n )\r\n}\r\n","// @flow\r\n\r\nimport React from 'react'\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\r\nimport {\r\n faArrowCircleRight,\r\n faClone,\r\n faEllipsisV,\r\n faEdit,\r\n faTrash,\r\n} from '@fortawesome/free-solid-svg-icons'\r\nimport { Button, Dropdown } from 'react-bootstrap'\r\nimport { useHistory } from 'react-router-dom'\r\n\r\nimport type { Node } from 'react'\r\n\r\ntype CustomToggleProps = {\r\n children?: Node,\r\n onClick: (SyntheticMouseEvent<HTMLButtonElement>) => void,\r\n ref: Node,\r\n}\r\n\r\nconst CustomToggle = React.forwardRef(\r\n ({ children, onClick }: CustomToggleProps, ref: Button) => (\r\n <Button\r\n variant=\"link\"\r\n title=\"More\"\r\n ref={ref}\r\n onClick={e => {\r\n e.preventDefault()\r\n onClick(e)\r\n }}\r\n >\r\n {children}\r\n </Button>\r\n )\r\n)\r\n\r\ntype Props = {\r\n id: string,\r\n onClick: (SyntheticMouseEvent<HTMLButtonElement>) => void,\r\n onClickDelete: (SyntheticMouseEvent<HTMLButtonElement>) => void,\r\n onClickDuplicate: () => Promise<void>,\r\n onClickEditReference: () => void,\r\n}\r\n\r\nexport default ({\r\n id,\r\n onClick,\r\n onClickDelete,\r\n onClickDuplicate,\r\n onClickEditReference,\r\n}: Props) => {\r\n const history = useHistory()\r\n\r\n return (\r\n <Dropdown alignRight onClick={onClick}>\r\n <Dropdown.Toggle as={CustomToggle}>\r\n <FontAwesomeIcon icon={faEllipsisV} color=\"black\" />\r\n </Dropdown.Toggle>\r\n <Dropdown.Menu>\r\n <Dropdown.Item\r\n eventKey=\"1\"\r\n onClick={() => history.push(`/projects/${id}`)}\r\n as=\"button\"\r\n >\r\n <FontAwesomeIcon icon={faArrowCircleRight} /> Open\r\n </Dropdown.Item>\r\n <Dropdown.Divider />\r\n <Dropdown.Item eventKey=\"3\" onClick={onClickEditReference} as=\"button\">\r\n <FontAwesomeIcon icon={faEdit} /> Edit name\r\n </Dropdown.Item>\r\n <Dropdown.Divider />\r\n <Dropdown.Item eventKey=\"2\" onClick={onClickDuplicate} as=\"button\">\r\n <FontAwesomeIcon icon={faClone} /> Duplicate\r\n </Dropdown.Item>\r\n <Dropdown.Divider />\r\n <Dropdown.Item eventKey=\"4\" onClick={onClickDelete} as=\"button\">\r\n <FontAwesomeIcon icon={faTrash} /> Delete\r\n </Dropdown.Item>\r\n </Dropdown.Menu>\r\n </Dropdown>\r\n )\r\n}\r\n","export default (rows, id, filterValue) => {\r\n return rows.filter(row => {\r\n const rowValue = row.values[id]\r\n return String(rowValue).toUpperCase().includes(filterValue.toUpperCase())\r\n })\r\n}\r\n","// @flow\r\nimport React, { useMemo, useState } from 'react'\r\nimport format from 'date-fns/fp/format'\r\nimport { Link } from 'react-router-dom'\r\nimport { InputGroup } from 'react-bootstrap'\r\nimport sprites from '@milestone-sys/web-design-system/msds-spritemap.svg'\r\n\r\nimport ProjectMenu from '../ProjectMenu'\r\nimport restApi from '../../api/restApi'\r\nimport ProjectReferenceInput from '../Project/ProjectReferenceInput'\r\nimport filterCaseInsensitive from '../../util/filterCaseInsensitive'\r\n\r\nimport type { ProjectHeader } from '../../api/restTypes'\r\n\r\ntype Cell = {\r\n row: {\r\n original: ProjectHeader,\r\n },\r\n}\r\n\r\ntype Filter = {\r\n column: {\r\n filterValue: string,\r\n setFilter: string => void,\r\n },\r\n}\r\n\r\ntype Props = {\r\n loading: boolean,\r\n setLoading: boolean => void,\r\n setSelectedProjectId: string => void,\r\n setSelectedProjectReference: string => void,\r\n setShowDeleteModal: boolean => void,\r\n}\r\n\r\nconst CellText = ({ text }: { text: string }) => (\r\n <span title={text} className=\"pr-2\">\r\n {text}\r\n </span>\r\n)\r\n\r\nexport default ({\r\n loading,\r\n setLoading,\r\n setSelectedProjectId,\r\n setSelectedProjectReference,\r\n setShowDeleteModal,\r\n}: Props) => {\r\n const [editedRowId, setEditedRowId] = useState(null)\r\n\r\n const updateProjectReference = async (projectId, newReference) => {\r\n await restApi.changeProjectReference(projectId, newReference)\r\n }\r\n\r\n return useMemo(() => {\r\n const formatLocal = format('PPp')\r\n\r\n return [\r\n {\r\n id: 'name',\r\n Cell: ({ row }: Cell) => {\r\n const id = row.original.id\r\n const reference = row.original.name\r\n const showEdit = editedRowId === id\r\n return showEdit ? (\r\n <ProjectReferenceInput\r\n show={showEdit}\r\n handleClose={() => setEditedRowId(null)}\r\n handleCreated={() => setLoading(true)}\r\n doCreate={newProjectReference =>\r\n updateProjectReference(id, newProjectReference)\r\n }\r\n buttonText=\"Update\"\r\n labelText=\"Name\"\r\n defaultValue={reference}\r\n />\r\n ) : (\r\n <Link to={`/projects/${id}`} role=\"button\" className=\"mt-1 mr-3 msds-btn-floating msds-btn-floating--sm\">\r\n <svg className=\"msds-icon\">\r\n <use xlinkHref={`${sprites}#right-arrow`}></use>\r\n </svg>{reference}\r\n </Link>\r\n )\r\n },\r\n accessor: 'name',\r\n Header: 'Name',\r\n minWidth: 300,\r\n style: {\r\n width: 400,\r\n },\r\n Filter: ({ column: { filterValue, setFilter } }: Filter) => (\r\n <InputGroup>\r\n <InputGroup.Prepend>\r\n <InputGroup.Text>\r\n <div className=\"msds-icon\">\r\n <svg>\r\n <use xlinkHref={`${sprites}#search`}>\r\n </use>\r\n </svg>\r\n </div>\r\n </InputGroup.Text>\r\n <div className=\"msds-input msds-input msds-input--small\">\r\n <input \r\n id=\"projectNameFilter\"\r\n type=\"text\"\r\n className=\"msds-input__text-input\"\r\n value={filterValue ?? ''}\r\n onChange={evt => setFilter(evt.target.value)}\r\n placeholder=\"Project name\"\r\n name=\"text-input-lg\" />\r\n <label\r\n htmlFor=\"text-input-lg\"\r\n className=\"msds-input__label\">\r\n Project name\r\n </label>\r\n </div>\r\n </InputGroup.Prepend>\r\n </InputGroup>\r\n ),\r\n filter: filterCaseInsensitive,\r\n },\r\n {\r\n id: 'created',\r\n Header: 'Created',\r\n accessor: 'created',\r\n Cell: ({ row }: Cell) => (\r\n <CellText text={formatLocal(row.original.created)} />\r\n ),\r\n style: {\r\n width: 320,\r\n },\r\n sortType: 'datetime',\r\n },\r\n {\r\n id: 'modified',\r\n Header: 'Modified',\r\n accessor: 'modified',\r\n Cell: ({ row }: Cell) => (\r\n <CellText text={formatLocal(row.original.modified)} />\r\n ),\r\n style: {\r\n width: 320,\r\n },\r\n sortType: 'datetime',\r\n },\r\n {\r\n accessor: 'cameras',\r\n Header: 'Cameras',\r\n maxWidth: 80,\r\n sortable: false,\r\n },\r\n {\r\n accessor: 'servers',\r\n Header: 'Servers',\r\n maxWidth: 80,\r\n sortable: false,\r\n },\r\n {\r\n accessor: 'clients',\r\n Header: 'Clients',\r\n maxWidth: 80,\r\n sortable: false,\r\n },\r\n {\r\n id: 'menu',\r\n accessor: 'menu',\r\n maxWidth: 40,\r\n Cell: ({ row }: Cell) => {\r\n const { id, name } = row.original\r\n return (\r\n <ProjectMenu\r\n id={id}\r\n reference={name}\r\n onClick={() => {\r\n setSelectedProjectId(id)\r\n setSelectedProjectReference(name)\r\n }}\r\n onClickDelete={evt => {\r\n setShowDeleteModal(true)\r\n evt.stopPropagation()\r\n }}\r\n onClickDuplicate={async () => {\r\n await restApi.duplicateProject(id)\r\n setLoading(true)\r\n }}\r\n onClickEditReference={() => setEditedRowId(id)}\r\n />\r\n )\r\n },\r\n sortable: false,\r\n },\r\n ]\r\n }, [\r\n editedRowId,\r\n setLoading,\r\n setSelectedProjectId,\r\n setSelectedProjectReference,\r\n setShowDeleteModal,\r\n ])\r\n}\r\n","// @flow\r\nimport React, { useMemo, useEffect, useState } from 'react'\r\nimport { Table } from 'react-bootstrap'\r\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome'\r\nimport sprites from '@milestone-sys/web-design-system/msds-spritemap.svg'\r\n\r\nimport {\r\n faCaretUp,\r\n faCaretDown,\r\n} from '@fortawesome/free-solid-svg-icons'\r\nimport { useFilters, usePagination, useSortBy, useTable } from 'react-table'\r\nimport { useSelector, useDispatch } from 'react-redux'\r\n\r\nimport restApi from '../../api/restApi'\r\nimport ProjectReferenceInput from '../Project/ProjectReferenceInput'\r\nimport DeleteProjectModal from '../Project/DeleteProjectModal'\r\nimport Loading from '../Loading'\r\nimport Pagination from '../ProjectList/Pagination'\r\nimport { actionCreators } from '../../store/ProjectList/ActionCreators'\r\nimport { initialState as defaultProject } from '../../store/RecommendationState/Reducer'\r\nimport { useIsAdmin } from '../../hooks/useIsAdmin'\r\n\r\nimport getColumns from './ProjectListColumns'\r\n\r\n// import User from '../User'\r\n\r\nexport default () => {\r\n const [loading, setLoading] = useState(true)\r\n const [data, setData] = useState([])\r\n const [showAddRow, setShowAddRow] = useState(false)\r\n const [showDeleteModal, setShowDeleteModal] = useState(false)\r\n const [selectedProjectReference, setSelectedProjectReference] = useState('')\r\n const [selectedProjectId, setSelectedProjectId] = useState(null)\r\n\r\n const { role } = useSelector(state => state.login)\r\n const { showAllProjects } = useSelector(state => state.projectList)\r\n const { isAdmin } = useIsAdmin()\r\n\r\n const columns = getColumns({\r\n loading,\r\n setLoading,\r\n setSelectedProjectId,\r\n setSelectedProjectReference,\r\n setShowDeleteModal,\r\n })\r\n\r\n useEffect(() => {\r\n const fetchData = async () => {\r\n if (!loading && data.length > 0) return\r\n setData([])\r\n\r\n if (role === 'NotLoggedIn') return\r\n\r\n const loadAllProjects = isAdmin() && showAllProjects\r\n const projects = loadAllProjects\r\n ? await restApi.listAdminProjects()\r\n : await restApi.listProjects()\r\n setData(projects)\r\n }\r\n\r\n fetchData().then(() => {\r\n setLoading(false)\r\n })\r\n }, [loading, role, showAllProjects, data.length, isAdmin])\r\n\r\n const initialState = {\r\n sortBy: useMemo(() => [{ id: 'modified', desc: true }], []),\r\n hiddenColumns: useMemo(() => {\r\n const hidden = ['servers', 'clients']\r\n if (isAdmin() && showAllProjects) {\r\n return [...hidden, 'menu']\r\n }\r\n const hiddenForRegularUser = [...hidden]\r\n return hiddenForRegularUser\r\n }, [showAllProjects, isAdmin]),\r\n pageSize: 20,\r\n }\r\n\r\n const tableInstance = useTable(\r\n {\r\n columns,\r\n data,\r\n initialState,\r\n },\r\n useFilters,\r\n useSortBy,\r\n usePagination\r\n )\r\n\r\n const {\r\n getTableBodyProps,\r\n headerGroups,\r\n prepareRow,\r\n\r\n state,\r\n page,\r\n canPreviousPage,\r\n canNextPage,\r\n pageCount,\r\n gotoPage,\r\n nextPage,\r\n previousPage,\r\n setPageSize,\r\n } = tableInstance\r\n\r\n const allHeaders = headerGroups\r\n .map(headerGroup => [...headerGroup.headers])\r\n .reduce((total, current) => total.concat(current), [])\r\n\r\n const projectNameHeader = allHeaders.filter(h => h.id === 'name')[0]\r\n\r\n const dispatch = useDispatch()\r\n\r\n const createProject = async projectReference => {\r\n await restApi.updateProject({\r\n ...defaultProject,\r\n projectDetails: { projectReference },\r\n })\r\n }\r\n\r\n return ( \r\n <div className=\"project-list-wrapper d-flex flex-column\">\r\n <DeleteProjectModal\r\n show={showDeleteModal}\r\n handleClose={() => setShowDeleteModal(false)}\r\n handleDeleted={() => setLoading(true)}\r\n projectReference={selectedProjectReference}\r\n projectId={selectedProjectId}\r\n />\r\n <>\r\n <div className=\"mt-5 mb-1 msds-btn-group--left justify-content-between\">\r\n <div className=\"flex-wrap\">\r\n <button className=\"msds-btn msds-btn--primary msds-btn--sm msds-btn--icon-left mx-1\" onClick={() => setShowAddRow(!showAddRow)}>\r\n Add project\r\n <div className=\"msds-icon\">\r\n <svg>\r\n <use xlinkHref={`${sprites}#plus`}></use>\r\n </svg>\r\n </div>\r\n </button>\r\n <button\r\n className=\"msds-btn msds-btn--gray msds-btn--sm msds-btn--icon-left mx-1\"\r\n onClick={() => setLoading(true)}\r\n >Refresh\r\n <div className=\"msds-icon\">\r\n <svg>\r\n <use xlinkHref={`${sprites}#update`}></use>\r\n </svg>\r\n </div>\r\n </button>\r\n {isAdmin() ? (\r\n <button\r\n className={showAllProjects ? 'msds-btn msds-btn--danger-dark msds-btn--sm' : 'msds-btn msds-btn--danger msds-btn--sm'}\r\n style={{border: '.0625rem solid #ff285a'}}\r\n onClick={() => {\r\n showAllProjects\r\n ? dispatch(actionCreators.showOwnProjects())\r\n : dispatch(actionCreators.showAllProjects())\r\n setLoading(true)\r\n }}\r\n >\r\n {showAllProjects ? 'Show own projects' : 'Show all projects'}\r\n </button>\r\n ) : (\r\n ''\r\n )}\r\n </div>\r\n <div className=\"m-r auto\">{projectNameHeader.render('Filter')}</div>\r\n </div>\r\n <div className=\"table-responsive-sm d-flex flex-column border\">\r\n <Table>\r\n <thead>\r\n {headerGroups.map(headerGroup => (\r\n <tr {...headerGroup.getHeaderGroupProps()}>\r\n {headerGroup.headers.map(column => (\r\n <th\r\n {...column.getHeaderProps(\r\n column.getSortByToggleProps()\r\n )}\r\n style={{ ...column.style, borderTop: 'none' }}\r\n >\r\n {column.render('Header')}{' '}\r\n {column.isSorted ? (\r\n column.isSortedDesc ? (\r\n <FontAwesomeIcon icon={faCaretDown} />\r\n ) : (\r\n <FontAwesomeIcon icon={faCaretUp} />\r\n )\r\n ) : (\r\n ''\r\n )}\r\n </th>\r\n ))}\r\n </tr>\r\n ))}\r\n </thead>\r\n <tbody {...getTableBodyProps()}>\r\n {showAddRow ? (\r\n <tr>\r\n <td className=\"create-project-input\">\r\n <ProjectReferenceInput\r\n show={showAddRow}\r\n handleClose={() => setShowAddRow(false)}\r\n handleCreated={() => setLoading(true)}\r\n doCreate={createProject}\r\n buttonText=\"Create\"\r\n labelText=\"Create Project\"\r\n />\r\n </td>\r\n </tr>\r\n ) : null}\r\n {page.map(row => {\r\n prepareRow(row)\r\n return (\r\n <tr {...row.getRowProps()}>\r\n {row.cells.map(cell => (\r\n <td {...cell.getCellProps()} className=\"\">\r\n {cell.render('Cell')}\r\n </td>\r\n ))}\r\n </tr>\r\n )\r\n })}\r\n </tbody>\r\n </Table>\r\n {loading ? <Loading /> : ''}\r\n </div>\r\n <Pagination\r\n canPreviousPage={canPreviousPage}\r\n pageCount={pageCount}\r\n canNextPage={canNextPage}\r\n nextPage={nextPage}\r\n gotoPage={gotoPage}\r\n previousPage={previousPage}\r\n pageIndex={state.pageIndex}\r\n pageSize={state.pageSize}\r\n setPageSize={setPageSize}\r\n />\r\n </>\r\n </div> \r\n )\r\n}\r\n","import { useMemo } from 'react'\r\nimport { useSelector } from 'react-redux'\r\n\r\nexport const useIsAdmin = () => {\r\n const { role } = useSelector(state => state.login)\r\n\r\n return useMemo(\r\n () => ({\r\n isAdmin: () => ['Administrator'].includes(role),\r\n }),\r\n [role]\r\n )\r\n}\r\n","import React, { Component, useState, useEffect } from 'react'\r\nimport { bindActionCreators } from 'redux'\r\nimport { connect, useSelector } from 'react-redux'\r\nimport { actionCreators } from '../store/Login/ActionCreators'\r\nimport restApi from '../api/restApi'\r\n\r\nconst User = ({ userRoleChanged, userChanged, authenticationChanged }) => {\r\n const [user, setUser] = useState({ name: 'guest', isAuthenticated: false })\r\n const isAuthenticated = useSelector(state => state.login.isAuthenticated)\r\n useEffect(() => {\r\n ;(async function () {\r\n const userInfo = await restApi.getUserInfo()\r\n if (userInfo.name == null) {\r\n await restApi.logInToWebsite()\r\n }\r\n setUser({\r\n name: userInfo.name || 'guest'\r\n })\r\n userRoleChanged(userInfo.role)\r\n userChanged(userInfo)\r\n authenticationChanged(userInfo.role !== 'NotLoggedIn')\r\n })()\r\n }, [userRoleChanged, userChanged, authenticationChanged])\r\n return ( \r\n <div className=\"container\">\r\n <div className=\"row\">\r\n <div className=\"col-12\">\r\n <div className=\"text-center\">\r\n <h2 className=\"msds-text-header-2-bold msds-text-alt-blue-3 text-uppercase mb-0\">\r\n Welcome to the <span className=\"msds-text-clear-blue\" style={{whiteSpace: \"nowrap\", fontWeight: 900}}>Husky IVO Product Guide</span>\r\n </h2>\r\n <div className=\"msds-divider mt-4 mb-4 mx-auto\"></div>\r\n <div className=\"msds-text-header-3-light\">\r\n A tool aimed at helping you better configure your installations to match your camera setup and business requirements. With this tool, you will get recommendations based on Husky IVO appliances, also taking into consideration future installation growth.\r\n </div>\r\n <br />\r\n <div className=\"msds-text-header-3-light\">\r\n Please note that the recommendations given by our Husky IVO Product Guide are only applicable and guaranteed for our performance optimized Husky IVO series. We cannot guarantee that the performance will be valid without our optimization methods.\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div> \r\n )\r\n}\r\n\r\ntype UserProps = {\r\n userRoleChanged: string => void,\r\n userChanged: string => void,\r\n authenticationChanged: string => void\r\n}\r\nclass UserClass extends Component<UserProps, {}> {\r\n render() {\r\n return <User {...this.props} />\r\n }\r\n}\r\nexport default connect(\r\n state => state.productRecommendations,\r\n dispatch => bindActionCreators(actionCreators, dispatch)\r\n)(UserClass)\r\n","import React, { useEffect } from 'react'\r\n\r\nexport const CookiePolicyPage = () => { \r\n\r\n function backEventClick() {\r\n window.history.go(-1); \r\n return false; \r\n } \r\n \r\n // Add the Cookiebot declaration script\r\n useEffect(() => { \r\n const script = document.createElement(\"script\");\r\n script.id = \"CookieDeclaration\"\r\n script.src = \"https://consent.cookiebot.com/71f1dae0-4e8b-4339-85e2-b285baec57ce/cd.js\";\r\n script.async = true;\r\n \r\n const cookiebotContainer = document.getElementById(\"cookie-declaration-container\");\r\n cookiebotContainer.appendChild(script);\r\n return () => {\r\n cookiebotContainer.removeChild(script);\r\n };\r\n });\r\n\r\n return (\r\n <div className=\"container msds-block-padding-medium mt-14\">\r\n <div className=\"row\">\r\n <div className=\"col-12\">\r\n <div className=\"d-flex flex-row justify-content-between align-items-start\">\r\n <h1 className=\"msds-text-header-1 msds-text-clear-blue mb-10\">Cookie Policy</h1>\r\n <button className=\"msds-btn msds-btn--secondary msds-btn--lg mb-4 mt-0\"\r\n onClick={() => backEventClick()}\r\n >Back \r\n </button> \r\n </div>\r\n <div id=\"cookie-declaration-container\"></div>\r\n </div> \r\n </div>\r\n </div>\r\n ) \r\n}\r\n","// @flow\r\n\r\nimport React from 'react'\r\nimport { BrowserRouter as Router, Switch, Route } from 'react-router-dom'\r\nimport { Container } from 'react-bootstrap'\r\nimport { useSelector } from 'react-redux'\r\n\r\nimport Project from './components/Project/Project'\r\nimport ProjectList from './components/ProjectList/ProjectList'\r\nimport User from './components/User'\r\nimport Loading from './components/Loading'\r\nimport { CookiePolicyPage } from './CookiePolicyPage/CookiePolicyPage'\r\n\r\nexport default () => {\r\n const isAuthenticated = useSelector(state => state.login.isAuthenticated)\r\n\r\n return (\r\n <div className=\"calculator-wrapper\">\r\n <Container fluid>\r\n <User /> \r\n {isAuthenticated && \r\n <Router>\r\n <Switch>\r\n <Route path=\"/cookie-policy\">\r\n <CookiePolicyPage />\r\n </Route> \r\n <Route path=\"/projects/:projectId\">\r\n <Project />\r\n </Route>\r\n <Route path=\"/\">\r\n <ProjectList />\r\n </Route>\r\n </Switch>\r\n </Router>\r\n }\r\n {!isAuthenticated && <Loading />}\r\n </Container>\r\n </div>\r\n )\r\n}\r\n","// In production, we register a service worker to serve assets from local cache.\r\n\r\n// This lets the app load faster on subsequent visits in production, and gives\r\n// it offline capabilities. However, it also means that developers (and users)\r\n// will only see deployed updates on the \"N+1\" visit to a page, since previously\r\n// cached resources are updated in the background.\r\n\r\n// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.\r\n// This link also includes instructions on opting out of this behavior.\r\n\r\nconst isLocalhost = Boolean(\r\n window.location.hostname === 'localhost' ||\r\n // [::1] is the IPv6 localhost address.\r\n window.location.hostname === '[::1]' ||\r\n // 127.0.0.1/8 is considered localhost for IPv4.\r\n window.location.hostname.match(\r\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\r\n )\r\n)\r\n\r\nexport default function register() {\r\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\r\n // The URL constructor is available in all browsers that support SW.\r\n const publicUrl = new URL(process.env.PUBLIC_URL, window.location)\r\n if (publicUrl.origin !== window.location.origin) {\r\n // Our service worker won't work if PUBLIC_URL is on a different origin\r\n // from what our page is served on. This might happen if a CDN is used to\r\n // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374\r\n return\r\n }\r\n\r\n window.addEventListener('load', () => {\r\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`\r\n\r\n if (isLocalhost) {\r\n // This is running on localhost. Lets check if a service worker still exists or not.\r\n checkValidServiceWorker(swUrl)\r\n } else {\r\n // Is not local host. Just register service worker\r\n registerValidSW(swUrl)\r\n }\r\n })\r\n }\r\n}\r\n\r\nfunction registerValidSW(swUrl) {\r\n navigator.serviceWorker\r\n .register(swUrl)\r\n .then(registration => {\r\n registration.onupdatefound = () => {\r\n const installingWorker = registration.installing\r\n installingWorker.onstatechange = () => {\r\n if (installingWorker.state === 'installed') {\r\n if (navigator.serviceWorker.controller) {\r\n // At this point, the old content will have been purged and\r\n // the fresh content will have been added to the cache.\r\n // It's the perfect time to display a \"New content is\r\n // available; please refresh.\" message in your web app.\r\n console.log('New content is available; please refresh.')\r\n } else {\r\n // At this point, everything has been precached.\r\n // It's the perfect time to display a\r\n // \"Content is cached for offline use.\" message.\r\n console.log('Content is cached for offline use.')\r\n }\r\n }\r\n }\r\n }\r\n })\r\n .catch(error => {\r\n console.error('Error during service worker registration:', error)\r\n })\r\n}\r\n\r\nfunction checkValidServiceWorker(swUrl) {\r\n // Check if the service worker can be found. If it can't reload the page.\r\n fetch(swUrl)\r\n .then(response => {\r\n // Ensure service worker exists, and that we really are getting a JS file.\r\n if (\r\n response.status === 404 ||\r\n response.headers.get('content-type').indexOf('javascript') === -1\r\n ) {\r\n // No service worker found. Probably a different app. Reload the page.\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister().then(() => {\r\n window.location.reload()\r\n })\r\n })\r\n } else {\r\n // Service worker found. Proceed as normal.\r\n registerValidSW(swUrl)\r\n }\r\n })\r\n .catch(() => {\r\n console.log(\r\n 'No internet connection found. App is running in offline mode.'\r\n )\r\n })\r\n}\r\n\r\nexport function unregister() {\r\n if ('serviceWorker' in navigator) {\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister()\r\n })\r\n }\r\n}\r\n","import ResizeObserver from 'resize-observer-polyfill'\r\n\r\nconst resizeObserver = new ResizeObserver(entries => {\r\n const newHeight = document.getElementsByTagName('html')[0].scrollHeight\r\n\r\n window.parent.postMessage(\r\n {\r\n frameHeight: Math.max(newHeight, 500),\r\n },\r\n '*'\r\n )\r\n})\r\n\r\nexport const registerPostHeight = () => {\r\n resizeObserver.observe(document.getElementById('root'))\r\n}\r\n","\r\nconst BurgerMenu = function () {\r\n let navigation;\r\n let navigationMenuItems;\r\n let bodyElement;\r\n let burgerMenuLink;\r\n let closeButtonElement;\r\n\r\n //Initialize the burger menu events\r\n function initialize() { \r\n cacheDom();\r\n bindEvents();\r\n }\r\n\r\n function cacheDom() {\r\n bodyElement = document.querySelector('body');\r\n navigation = document.querySelector('#MainMenu');\r\n burgerMenuLink = document.querySelector('.header-section-block__links-burger-menu-link');\r\n closeButtonElement = navigation ? navigation.querySelector('.header-section-block__navigation-menus-button-close') : null;\r\n\r\n if (navigation) { \r\n navigationMenuItems = navigation.querySelectorAll('.header-section-block__navigation-menu');\r\n }\r\n }\r\n\r\n function bindEvents() { \r\n if (burgerMenuLink) {\r\n burgerMenuLink.addEventListener(\"click\", burgerMenuLinkToggle);\r\n }\r\n \r\n if (closeButtonElement) {\r\n closeButtonElement.addEventListener(\"click\", function () { \r\n closeBurgerMenu();\r\n updatePageScrolling();\r\n }, false);\r\n }\r\n }\r\n\r\n function burgerMenuLinkToggle() { \r\n burgerMenuLink.classList.toggle('header-section-block__links-burger-menu-link--active');\r\n navigation.classList.toggle('header-section-block__navigation--show');\r\n updatePageScrolling(); \r\n }\r\n\r\n function bindBurgerMenuClick() {\r\n if (navigationMenuItems) {\r\n navigationMenuItems.forEach(function (navigationMenuItem) {\r\n if (navigationMenuItem.classList.contains('header-section-block__navigation-menu--level1') ||\r\n navigationMenuItem.classList.contains('header-section-block__navigation-menu--level2')) {\r\n navigationMenuItem.addEventListener(\"click\", onBurgerMenuClick, false);\r\n }\r\n else {\r\n const navigationMenuItemIcon = navigationMenuItem.querySelector('.header-section-block__navigation-menu-label-icon');\r\n if (navigationMenuItemIcon) {\r\n navigationMenuItemIcon.addEventListener(\"click\", onBurgerMenuIconClick, false);\r\n }\r\n }\r\n });\r\n }\r\n }\r\n\r\n function unbindBurgerMenuClick() {\r\n if (navigationMenuItems) {\r\n navigationMenuItems.forEach(function (navigationMenuItem) {\r\n if (navigationMenuItem.classList.contains('header-section-block__navigation-menu--level1') ||\r\n navigationMenuItem.classList.contains('header-section-block__navigation-menu--level2')) {\r\n navigationMenuItem.removeEventListener(\"click\", onBurgerMenuClick, false);\r\n }\r\n else {\r\n const navigationMenuItemIcon = navigationMenuItem.querySelector('.header-section-block__navigation-menu-label-icon');\r\n if (navigationMenuItemIcon) {\r\n navigationMenuItemIcon.removeEventListener(\"click\", onBurgerMenuIconClick, false);\r\n }\r\n }\r\n }); \r\n }\r\n }\r\n\r\n function onBurgerMenuClick() {\r\n this.classList.toggle('header-section-block__navigation-menu--active');\r\n }\r\n\r\n function onBurgerMenuIconClick() {\r\n this.closest('.header-section-block__navigation-menu').classList.toggle('header-section-block__navigation-menu--active');\r\n }\r\n\r\n function onOutsideBurgerMenuClick(event) {\r\n if (event) {\r\n //Check if the click is inside the burger menu. if not then we close the mega menu and reset any level 1 active menu. \r\n if (event.target.closest(\".header-section-block__links-burger-menu-link\") ||\r\n event.target.closest(\".header-section-block__navigation-menus\")) {\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n }\r\n\r\n function closeBurgerMenu() {\r\n if (burgerMenuLink.classList.contains('header-section-block__links-burger-menu-link--active')) {\r\n burgerMenuLink.classList.remove('header-section-block__links-burger-menu-link--active');\r\n }\r\n if (navigation.classList.contains('header-section-block__navigation--show')) {\r\n navigation.classList.remove('header-section-block__navigation--show');\r\n }\r\n if (navigation) {\r\n navigation.querySelectorAll('.header-section-block__navigation-menu').forEach(function (element) {\r\n element.classList.remove('header-section-block__navigation-menu--active');\r\n });\r\n }\r\n }\r\n\r\n function onBurgerMenuWindowResize() {\r\n closeBurgerMenu();\r\n }\r\n\r\n function updatePageScrolling() {\r\n if (isOpened() && !bodyElement.classList.contains('no-scroll')) {\r\n bodyElement.classList.add('no-scroll');\r\n }\r\n if (!isOpened() && bodyElement.classList.contains('no-scroll')) {\r\n bodyElement.classList.remove('no-scroll');\r\n }\r\n }\r\n\r\n function isOpened() {\r\n return burgerMenuLink.classList.contains('header-section-block__links-burger-menu-link--active');\r\n }\r\n\r\n return {\r\n initialize: initialize,\r\n bindBurgerMenuClick: bindBurgerMenuClick,\r\n unbindBurgerMenuClick: unbindBurgerMenuClick,\r\n onOutsideBurgerMenuClick: onOutsideBurgerMenuClick,\r\n onBurgerMenuWindowResize: onBurgerMenuWindowResize,\r\n closeBurgerMenu: closeBurgerMenu,\r\n isOpened: isOpened\r\n }\r\n}\r\n\r\nexport default BurgerMenu;\r\n","const Device = function () {\r\n function isXSmall() {\r\n return document.querySelector('body').clientWidth < 576;\r\n }\r\n\r\n function isSmall() {\r\n return document.querySelector('body').clientWidth >= 576 && document.querySelector('body').clientWidth < 768;\r\n }\r\n\r\n function isMedium() {\r\n return document.querySelector('body').clientWidth >= 768 && document.querySelector('body').clientWidth < 992;\r\n }\r\n\r\n function isLarge() {\r\n return document.querySelector('body').clientWidth >= 992 && document.querySelector('body').clientWidth < 1200;\r\n }\r\n\r\n function isXLarge() {\r\n return document.querySelector('body').clientWidth >= 1200 && document.querySelector('body').clientWidth < 1400;\r\n }\r\n\r\n function isXXLarge() {\r\n return document.querySelector('body').clientWidth >= 1400;\r\n }\r\n\r\n function isDesktop() { \r\n //checks if the page has no vertical scroll bar\r\n if (window.innerWidth === window.innerWidth - document.documentElement.clientWidth) {\r\n return document.body.clientWidth >= 1200;\r\n }\r\n\r\n return document.body.clientWidth >= 1183; //corresponds to Bootstrap xl breakpoint - scrollbar width (17px)\r\n }\r\n\r\n function isAndroid() {\r\n return navigator.userAgent.toLowerCase().indexOf(\"android\") > -1;\r\n }\r\n\r\n function isCurrentClientWidth() {\r\n return document.body.clientWidth;\r\n }\r\n\r\n return {\r\n isXSmall: isXSmall,\r\n isSmall: isSmall,\r\n isMedium: isMedium,\r\n isLarge: isLarge,\r\n isXLarge: isXLarge,\r\n isXXLarge: isXXLarge,\r\n isDesktop: isDesktop,\r\n isAndroid: isAndroid,\r\n isCurrentClientWidth: isCurrentClientWidth\r\n }\r\n}\r\n\r\nexport default Device;\r\n","import BurgerMenu from './burgerMenu';\r\nimport Device from './device';\r\n\r\nconst HeaderSectionBlock = function () {\r\n\r\n let device;\r\n let bodyElement;\r\n let navigation;\r\n let navigationMenus;\r\n let burgerMenu;\r\n let currentOpenedComponent; \r\n let isInitialized = false; \r\n \r\n function initialize() { \r\n if (isInitialized) return; // Prevents re-initialization\r\n isInitialized = true;\r\n\r\n setTimeout(() => { \r\n if (!document.querySelector(\"#HeaderSection .header-section-block__container\"))\r\n return;\r\n \r\n //initialize global variables\r\n cacheDom();\r\n \r\n //Initialize all header components\r\n burgerMenu.initialize();\r\n \r\n //Initialize events\r\n bindEvents();\r\n \r\n //Set the header UI\r\n updateHeaderLayout();\r\n }, 500); \r\n }\r\n\r\n function cacheDom() {\r\n bodyElement = document.querySelector('body');\r\n navigation = document.querySelector('.header-section-block__navigation');\r\n \r\n if (navigation) {\r\n navigationMenus = navigation.querySelector('.header-section-block__navigation-menus');\r\n } \r\n device = new Device();\r\n burgerMenu = new BurgerMenu(); \r\n }\r\n\r\n function bindEvents() {\r\n document.addEventListener(\"click\", function (event) {\r\n onWindowClick(event);\r\n }, false);\r\n window.addEventListener(\"resize\", function () {\r\n onWindowResize();\r\n }, false);\r\n }\r\n\r\n function updateHeaderLayout() {\r\n if (device.isDesktop()) {\r\n burgerMenu.unbindBurgerMenuClick(); \r\n }\r\n else { \r\n burgerMenu.bindBurgerMenuClick();\r\n }\r\n }\r\n\r\n function resetDesktopNavigationState() {\r\n navigationMenus.querySelectorAll('.header-section-block__navigation-menu').forEach(function (element) {\r\n element.classList.remove('header-section-block__navigation-menu--active')\r\n });\r\n }\r\n\r\n function onWindowClick(event) {\r\n if (device.isDesktop()) {\r\n onOutsideDesktopUIClick(event);\r\n }\r\n else {\r\n onOutsideMobileUIClick(event);\r\n }\r\n }\r\n\r\n function onOutsideDesktopUIClick(event) {\r\n\r\n if (event) {\r\n checkOpenedComponent();\r\n }\r\n }\r\n\r\n function onOutsideMobileUIClick(event) {\r\n if (event) {\r\n //check current opened component\r\n checkOpenedComponent();\r\n\r\n //Check if Burger Menu is opened if so the close it and reset the page scrolling\r\n if (burgerMenu.isOpened()) {\r\n if (!checkMultipleComponentsAreOpened() && burgerMenu.onOutsideBurgerMenuClick(event)) {\r\n burgerMenu.closeBurgerMenu();\r\n resetPageScrolling();\r\n }\r\n return;\r\n }\r\n }\r\n }\r\n\r\n function checkOpenedComponent() { \r\n if ((burgerMenu.isOpened() && currentOpenedComponent == null) ||\r\n (burgerMenu.isOpened() && currentOpenedComponent != burgerMenu)) {\r\n updateUIForBurgerMenuComponentOpened();\r\n }\r\n }\r\n\r\n function updateUIForBurgerMenuComponentOpened() {\r\n currentOpenedComponent = burgerMenu;\r\n }\r\n\r\n function checkMultipleComponentsAreOpened() {\r\n let counter = 0;\r\n if (burgerMenu.isOpened()) {\r\n counter++;\r\n }\r\n if (counter > 1) {\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n function resetPageScrolling() {\r\n if (!device.isDesktop() || (device.isDesktop() && bodyElement.classList.contains('no-scroll'))) {\r\n bodyElement.classList.remove('no-scroll');\r\n }\r\n }\r\n\r\n function onWindowResize() {\r\n if (device.isDesktop()) {\r\n resetDesktopNavigationState();\r\n }\r\n else {\r\n burgerMenu.onBurgerMenuWindowResize(); \r\n if (bodyElement.classList.contains('no-scroll')) {\r\n bodyElement.classList.remove('no-scroll');\r\n } \r\n }\r\n\r\n updateHeaderLayout();\r\n }\r\n\r\n return {\r\n initialize: initialize\r\n }\r\n}\r\n\r\nconst headerSectionBlock = new HeaderSectionBlock();\r\nwindow.headerSectionBlock = headerSectionBlock;\r\n\r\n//Listen for the event\r\nwindow.addEventListener(\"externalnavigationload\", function (evt) { \r\n headerSectionBlock.initialize();\r\n});\r\n\r\n//Wait for DOM to load, before initializing the header section block\r\nwindow.addEventListener('DOMContentLoaded', function () { \r\n headerSectionBlock.initialize()\r\n}, false);\r\n","import React, { useEffect } from 'react'\r\nimport { useSelector } from 'react-redux'\r\nimport restApi from '../../api/restApi'\r\nimport { getMilestoneUrl } from '../../api/Config';\r\nimport \"./header.scss\";\r\nimport \"./headersectionblock.js\";\r\n\r\nexport function Header() {\r\n const milestoneUrl = getMilestoneUrl();\r\n const isAuthenticated = useSelector(state => state.login.isAuthenticated)\r\n const logInEvent = async () => await restApi.logInToWebsite()\r\n const logOutEvent = async () => await restApi.logOut()\r\n\r\n useEffect(() => {\r\n // Initialize the header section block when the component mounts\r\n if (window.headerSectionBlock && typeof window.headerSectionBlock.initialize === 'function') {\r\n window.headerSectionBlock.initialize();\r\n }\r\n }, []); \r\n\r\n return (\r\n <div id=\"HeaderSection\" className=\"header-section-sticky\">\r\n <div className=\"row g-0 no-gutters\">\r\n <div className=\"header-section-block col-12\">\r\n <div className=\"header-section-block__container header-section-block__container--desktop top-margin-for-old-pages\">\r\n <div className=\"header-section-block__logos\">\r\n <a className=\"header-section-block__milestone-logo\" \r\n target=\"_blank\" \r\n href={milestoneUrl}></a> \r\n <div className=\"header-section-block__logo-divider\"></div>\r\n <a className=\"header-section-block__portal-logo\" \r\n href=\"/\">Husky IVO</a> \r\n </div>\r\n <nav id=\"MainMenu\" className=\"header-section-block__navigation\">\r\n <div className=\"header-section-block__navigation-menus\">\r\n <div className=\"d-inline-block d-md-none hidden-lg header-section-block__navigation-menus-button-close-container\">\r\n <div className=\"header-section-block__navigation-menus-button-close ms-icon\">\r\n <svg viewBox=\"0 0 128 128\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlnsXlink=\"http://www.w3.org/1999/xlink\">\r\n <path fill=\"unset\" d=\"M63.646 54.433L99.079 19 109 28.921 73.567 64.354 108.29 99.08 98.371 109 63.645 74.276 29.63 108.29l-9.921-9.92 34.015-34.017L19 29.63l9.921-9.921z\" />\r\n </svg>\r\n </div>\r\n </div>\r\n <div className=\"header-section-block__burger-links\">\r\n <div className=\"d-block d-md-none header-section-block__login-button\">\r\n {isAuthenticated ? (\r\n <button className=\"ml-2 msds-btn msds-btn--secondary msds-btn--sm\" \r\n onClick={logOutEvent}>\r\n Log out\r\n </button>\r\n ) : (\r\n <button className=\"ml-2 msds-btn msds-btn--secondary msds-btn--sm\"\r\n onClick={logInEvent}\r\n >\r\n Log in\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n </nav>\r\n <div className=\"header-section-block__links\">\r\n {isAuthenticated ? (\r\n <button className=\"button-tile-block msds-btn msds-btn--secondary msds-btn--sm\" \r\n onClick={logOutEvent}>\r\n Log out\r\n </button>\r\n ) : (\r\n <button className=\"button-tile-block msds-btn msds-btn--secondary msds-btn--sm\"\r\n onClick={logInEvent}\r\n >\r\n Log in\r\n </button>\r\n )} \r\n <button className=\"header-section-block__links-burger-menu-link\" type=\"button\">\r\n <div className=\"ms-icon\">\r\n <svg viewBox=\"0 0 132 132\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M4 30h120v8H4zm0 30h120v8H4zm0 30h120v8H4z\" fillRule=\"evenodd\" />\r\n </svg>\r\n </div>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n}\r\n","import React from 'react'\r\nimport \"@milestone-sys/web-design-system/main.css\";\r\nimport { getMilestoneUrl } from '../../api/Config';\r\nimport \"./footer.scss\";\r\n\r\nexport function Footer() { \r\n const milestoneUrl = getMilestoneUrl();\r\n const aboutUsLink = milestoneUrl + \"/company/about-milestone/about-us/\";\r\n const contactUsLink = milestoneUrl + \"/support/contact-us/contact-us/\";\r\n const officesLink = milestoneUrl + \"/company/about-milestone/global-offices/\";\r\n const careersLink = milestoneUrl + \"/company/career/working-in-milestone/\";\r\n const signUpForNewsLink = \"https://pardot.milestonesys.com/marketing-communication\";\r\n const shareYourFeedbackLink = \"https://pardot.milestonesys.com/l/53942/2022-01-03/l3mbx7\";\r\n const termsOfUseLink = milestoneUrl + \"/terms-of-use/\";\r\n const privacyPolicyLink = milestoneUrl + \"/privacy-policy/\";\r\n const cookiePolicyLink = milestoneUrl + \"/cookie-policy-milestone-systems/\";\r\n const mapPolicyLink = milestoneUrl + \"/minimum-advertised-price-policy/\";\r\n const makeAWhistleblowerReportLink = milestoneUrl + \"/company/about-milestone/csr/whistleblower/\";\r\n const modernSlaveryActLink = milestoneUrl + \"/company/about-milestone/csr/modern-slavery-act/\";\r\n const currentYear = new Date().getFullYear();\r\n \r\n return (\r\n <div className=\"footer-column col-12\" id=\"FooterSection\">\r\n <div className=\"container\">\r\n <div className=\"row\"> \r\n <div className=\"col-12 col-sm-8 mb-6\">\r\n <div className=\"row\">\r\n <div className=\"col-12 col-xs-12\">\r\n <div className=\"footer-column__links-list footer-column__links-list--with-heading\">\r\n <div className=\"footer-column__links-list-item\">\r\n <span className=\"footer-column__links-list-item-link\">COMPANY</span>\r\n </div>\r\n </div>\r\n </div>\r\n <div className=\"col-6 mb-6\">\r\n <ul className=\"footer-column__links-list mt-0\">\r\n <li className=\"footer-column__links-list-item\">\r\n <a className=\"footer-column__links-list-item-link\" href={aboutUsLink}>About Us</a>\r\n </li>\r\n <li className=\"footer-column__links-list-item\">\r\n <a className=\"footer-column__links-list-item-link\" href={contactUsLink}>Contact Us</a>\r\n </li>\r\n <li className=\"footer-column__links-list-item\">\r\n <a className=\"footer-column__links-list-item-link\" href={officesLink}>Offices</a>\r\n </li>\r\n <li className=\"footer-column__links-list-item\">\r\n <a className=\"footer-column__links-list-item-link\" href={careersLink}>Careers</a>\r\n </li>\r\n <li className=\"footer-column__links-list-item\">\r\n <a className=\"footer-column__links-list-item-link\" \r\n href={signUpForNewsLink}\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\">Sign up for news</a>\r\n </li>\r\n <li className=\"footer-column__links-list-item\">\r\n <a className=\"footer-column__links-list-item-link\" \r\n href={shareYourFeedbackLink}\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\">Share your feedback</a>\r\n </li>\r\n </ul>\r\n </div>\r\n \r\n <div className=\"col-6 mb-6\">\r\n <ul className=\"footer-column__links-list mt-0\">\r\n <li className=\"footer-column__links-list-item\">\r\n <a className=\"footer-column__links-list-item-link\" href={termsOfUseLink}>Terms of Use</a>\r\n </li>\r\n <li className=\"footer-column__links-list-item\">\r\n <a className=\"footer-column__links-list-item-link\" href={privacyPolicyLink}>Privacy Policy</a>\r\n </li>\r\n <li className=\"footer-column__links-list-item\">\r\n <a className=\"footer-column__links-list-item-link\" href={cookiePolicyLink}>Cookie Policy</a>\r\n </li>\r\n <li className=\"footer-column__links-list-item\">\r\n <a className=\"footer-column__links-list-item-link\" href={mapPolicyLink}>MAP Policy</a>\r\n </li>\r\n <li className=\"footer-column__links-list-item\">\r\n <a className=\"footer-column__links-list-item-link\" href={makeAWhistleblowerReportLink}>Make a whistleblower report</a>\r\n </li>\r\n <li className=\"footer-column__links-list-item\">\r\n <a className=\"footer-column__links-list-item-link\" href={modernSlaveryActLink}>Modern Slavery Act</a>\r\n </li>\r\n </ul>\r\n </div>\r\n </div> \r\n </div> \r\n <div className=\"col-6 col-sm-4 mb-6\"> \r\n <div className=\"footer-column__milestone-logo\"></div>\r\n <p className=\"footer-column__text\">\r\n For any compliance matters please contact us by sending an email to compliance@milestonesys.com\r\n <br />\r\n <br />\r\n Copyright © {currentYear} Milestone Systems A/S. All rights reserved.\r\n </p>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n}\r\n","import './style/style.scss'\r\nimport React from 'react'\r\nimport ReactDOM from 'react-dom'\r\nimport { Provider } from 'react-redux'\r\nimport { loadConfig } from \"./api/Config\"\r\nimport i18n from './api/i18n' // eslint-disable-line no-unused-vars\r\nimport configureStore from './store/configureStore'\r\nimport App from './App'\r\nimport { unregister } from './registerServiceWorker'\r\nimport 'react-table-6/react-table.css'\r\nimport { registerPostHeight } from './postFrameHeight'\r\nimport { Header } from './components/Header/Header'\r\nimport { Footer } from './components/Footer/Footer'\r\n\r\nloadConfig(); // Ensure environment is set on page load\r\n\r\n// Get the application-wide store instance, prepopulating with state from the server where available.\r\nconst initialState = window.initialReduxState\r\nconst store = configureStore(initialState)\r\n\r\nconst rootElement = document.getElementById('root')\r\n\r\nunregister()\r\nregisterPostHeight()\r\n\r\nReactDOM.render(\r\n <Provider store={store}>\r\n <Header />\r\n <App />\r\n <Footer />\r\n </Provider>,\r\n rootElement\r\n)\r\n","import { applyMiddleware, combineReducers, compose, createStore } from 'redux'\r\nimport thunk from 'redux-thunk'\r\nimport * as AddCameras from './AddCamerasStore'\r\nimport * as Project from './ProjectStore'\r\nimport * as ProductRecommendations from './ProductRecommendations/Reducer'\r\nimport * as OrderSummary from './OrderSummary/Reducer'\r\nimport * as RecommendationState from './RecommendationState/Reducer'\r\nimport * as ProductOptions from './ProductOptions/Reducer'\r\nimport * as Login from './Login/Reducer'\r\nimport * as ProjectList from './ProjectList/Reducer'\r\n\r\nexport default function configureStore(initialState) {\r\n const reducers = {\r\n cameras: AddCameras.reducer,\r\n productRecommendations: ProductRecommendations.reducer,\r\n orderSummary: OrderSummary.reducer,\r\n recommendationState: RecommendationState.reducer,\r\n productOptions: ProductOptions.reducer,\r\n project: Project.reducer,\r\n login: Login.reducer,\r\n projectList: ProjectList.reducer,\r\n }\r\n\r\n const middleware = [thunk]\r\n\r\n // In development, use the browser's Redux dev tools extension if installed\r\n const enhancers = []\r\n const isDevelopment = process.env.NODE_ENV === 'development'\r\n if (\r\n isDevelopment &&\r\n typeof window !== 'undefined' &&\r\n window.devToolsExtension\r\n ) {\r\n enhancers.push(window.devToolsExtension())\r\n }\r\n\r\n const rootReducer = combineReducers({\r\n ...reducers,\r\n })\r\n\r\n return createStore(\r\n rootReducer,\r\n initialState,\r\n compose(applyMiddleware(...middleware), ...enhancers)\r\n )\r\n}\r\n"],"sourceRoot":""}